Increase coverage % for oauth2client.appengine.
Reviewed in http://codereview.appspot.com/5795070/.
diff --git a/tests/test_oauth2client_appengine.py b/tests/test_oauth2client_appengine.py
index 680cea2..a11c5e9 100644
--- a/tests/test_oauth2client_appengine.py
+++ b/tests/test_oauth2client_appengine.py
@@ -25,6 +25,7 @@
import base64
import datetime
import httplib2
+import os
import time
import unittest
import urlparse
@@ -42,30 +43,51 @@
from google.appengine.api import apiproxy_stub
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import app_identity
-from google.appengine.api import users
from google.appengine.api import memcache
+from google.appengine.api import users
from google.appengine.api.memcache import memcache_stub
from google.appengine.ext import db
from google.appengine.ext import testbed
from google.appengine.runtime import apiproxy_errors
from oauth2client.anyjson import simplejson
from oauth2client.appengine import AppAssertionCredentials
+from oauth2client.appengine import FlowProperty
from oauth2client.appengine import CredentialsModel
from oauth2client.appengine import OAuth2Decorator
from oauth2client.appengine import OAuth2Handler
from oauth2client.appengine import StorageByKeyName
+from oauth2client.appengine import oauth2decorator_from_clientsecrets
from oauth2client.client import AccessTokenRefreshError
+from oauth2client.client import Credentials
from oauth2client.client import FlowExchangeError
from oauth2client.client import OAuth2Credentials
+from oauth2client.client import flow_from_clientsecrets
from webtest import TestApp
+DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
+
+
+def datafile(filename):
+ return os.path.join(DATA_DIR, filename)
+
+
class UserMock(object):
"""Mock the app engine user service"""
+ def __call__(self):
+ return self
+
def user_id(self):
return 'foo_user'
+class UserNotLoggedInMock(object):
+ """Mock the app engine user service"""
+
+ def __call__(self):
+ return None
+
+
class Http2Mock(object):
"""Mock httplib2.Http"""
status = 200
@@ -131,12 +153,41 @@
apiproxy_stub_map.apiproxy.RegisterStub(
'memcache', memcache_stub.MemcacheServiceStub())
- scope = "http://www.googleapis.com/scope"
+ scope = ["http://www.googleapis.com/scope"]
credentials = AppAssertionCredentials(scope)
http = httplib2.Http()
credentials.refresh(http)
self.assertEqual('a_token_123', credentials.access_token)
+ json = credentials.to_json()
+ credentials = Credentials.new_from_json(json)
+ self.assertEqual(scope[0], credentials.scope)
+
+
+class TestFlowModel(db.Model):
+ flow = FlowProperty()
+
+
+class FlowPropertyTest(unittest.TestCase):
+
+ def setUp(self):
+ self.testbed = testbed.Testbed()
+ self.testbed.activate()
+ self.testbed.init_datastore_v3_stub()
+
+ def tearDown(self):
+ self.testbed.deactivate()
+
+ def test_flow_get_put(self):
+ instance = TestFlowModel(
+ flow=flow_from_clientsecrets(datafile('client_secrets.json'), 'foo'),
+ key_name='foo'
+ )
+ instance.put()
+ retrieved = TestFlowModel.get_by_key_name('foo')
+
+ self.assertEqual('foo_client_id', retrieved.flow.client_id)
+
def _http_request(*args, **kwargs):
resp = httplib2.Response({'status': '200'})
@@ -206,7 +257,6 @@
self.assertEqual(None, memcache.get('foo'))
-
class DecoratorTests(unittest.TestCase):
def setUp(self):
@@ -220,6 +270,10 @@
client_secret='foo_client_secret',
scope=['foo_scope', 'bar_scope'],
user_agent='foo')
+
+ self._finish_setup(decorator, user_mock=UserMock)
+
+ def _finish_setup(self, decorator, user_mock):
self.decorator = decorator
class TestRequiredHandler(webapp2.RequestHandler):
@@ -244,7 +298,7 @@
handler=TestAwareHandler, name='bar')],
debug=True)
self.app = TestApp(application)
- users.get_current_user = UserMock
+ users.get_current_user = user_mock()
self.httplib2_orig = httplib2.Http
httplib2.Http = Http2Mock
@@ -350,6 +404,16 @@
self.decorator.credentials.access_token)
+ def test_error_in_step2(self):
+ # An initial request to an oauth_aware decorated path should not redirect.
+ response = self.app.get('/bar_path/2012/01')
+ url = self.decorator.authorize_url()
+ response = self.app.get('/oauth2callback', {
+ 'error': 'BadStuffHappened'
+ })
+ self.assertEqual('200 OK', response.status)
+ self.assertTrue('BadStuffHappened' in response.body)
+
def test_kwargs_are_passed_to_underlying_flow(self):
decorator = OAuth2Decorator(client_id='foo_client_id',
client_secret='foo_client_secret',
@@ -362,6 +426,76 @@
self.assertEqual('foo_user_agent', decorator.flow.user_agent)
self.assertEqual(None, decorator.flow.params.get('user_agent', None))
+ def test_decorator_from_client_secrets(self):
+ decorator = oauth2decorator_from_clientsecrets(
+ datafile('client_secrets.json'),
+ scope=['foo_scope', 'bar_scope'])
+ self._finish_setup(decorator, user_mock=UserMock)
+
+ self.assertFalse(decorator._in_error)
+ self.decorator = decorator
+ self.test_required()
+ http = self.decorator.http()
+ self.assertEquals('foo_access_token', http.request.credentials.access_token)
+
+ def test_decorator_from_client_secrets_not_logged_in_required(self):
+ decorator = oauth2decorator_from_clientsecrets(
+ datafile('client_secrets.json'),
+ scope=['foo_scope', 'bar_scope'], message='NotLoggedInMessage')
+ self.decorator = decorator
+ self._finish_setup(decorator, user_mock=UserNotLoggedInMock)
+
+ self.assertFalse(decorator._in_error)
+
+ # An initial request to an oauth_required decorated path should be a
+ # redirect to login.
+ response = self.app.get('/foo_path')
+ self.assertTrue(response.status.startswith('302'))
+ self.assertTrue('Login' in str(response))
+
+ def test_decorator_from_client_secrets_not_logged_in_aware(self):
+ decorator = oauth2decorator_from_clientsecrets(
+ datafile('client_secrets.json'),
+ scope=['foo_scope', 'bar_scope'], message='NotLoggedInMessage')
+ self.decorator = decorator
+ self._finish_setup(decorator, user_mock=UserNotLoggedInMock)
+
+ # An initial request to an oauth_aware decorated path should be a
+ # redirect to login.
+ response = self.app.get('/bar_path/2012/03')
+ self.assertTrue(response.status.startswith('302'))
+ self.assertTrue('Login' in str(response))
+
+ def test_decorator_from_unfilled_client_secrets_required(self):
+ MESSAGE = 'File is missing'
+ decorator = oauth2decorator_from_clientsecrets(
+ datafile('unfilled_client_secrets.json'),
+ scope=['foo_scope', 'bar_scope'], message=MESSAGE)
+ self._finish_setup(decorator, user_mock=UserNotLoggedInMock)
+ self.assertTrue(decorator._in_error)
+ self.assertEqual(MESSAGE, decorator._message)
+
+ # An initial request to an oauth_required decorated path should be an
+ # error message.
+ response = self.app.get('/foo_path')
+ self.assertTrue(response.status.startswith('200'))
+ self.assertTrue(MESSAGE in str(response))
+
+ def test_decorator_from_unfilled_client_secrets_aware(self):
+ MESSAGE = 'File is missing'
+ decorator = oauth2decorator_from_clientsecrets(
+ datafile('unfilled_client_secrets.json'),
+ scope=['foo_scope', 'bar_scope'], message=MESSAGE)
+ self._finish_setup(decorator, user_mock=UserNotLoggedInMock)
+ self.assertTrue(decorator._in_error)
+ self.assertEqual(MESSAGE, decorator._message)
+
+ # An initial request to an oauth_aware decorated path should be an
+ # error message.
+ response = self.app.get('/bar_path/2012/03')
+ self.assertTrue(response.status.startswith('200'))
+ self.assertTrue(MESSAGE in str(response))
+
if __name__ == '__main__':
unittest.main()