Clean up usage of HTTP mocks in tests.

This commit is contained in:
Danny Hermes
2016-08-10 14:05:16 -07:00
parent 724181f46b
commit 8299c5867f
7 changed files with 254 additions and 179 deletions

View File

@@ -29,6 +29,7 @@ from google.appengine.ext import ndb
from google.appengine.ext import testbed from google.appengine.ext import testbed
import mock import mock
from six.moves import urllib from six.moves import urllib
from six.moves import urllib_parse
import unittest2 import unittest2
import webapp2 import webapp2
from webtest import TestApp from webtest import TestApp
@@ -50,6 +51,8 @@ DEFAULT_RESP = """\
"refresh_token": "foo_refresh_token" "refresh_token": "foo_refresh_token"
} }
""" """
BASIC_TOKEN = 'bar'
BASIC_RESP = json.dumps({'access_token': BASIC_TOKEN})
def datafile(filename): def datafile(filename):
@@ -356,13 +359,6 @@ class CredentialsPropertyTest(unittest2.TestCase):
appengine.CredentialsProperty().validate(42) appengine.CredentialsProperty().validate(42)
def _http_request(*args, **kwargs):
resp = http_mock.ResponseMock()
content = json.dumps({'access_token': 'bar'})
return resp, content
class StorageByKeyNameTest(unittest2.TestCase): class StorageByKeyNameTest(unittest2.TestCase):
def setUp(self): def setUp(self):
@@ -407,6 +403,23 @@ class StorageByKeyNameTest(unittest2.TestCase):
storage._model = appengine.CredentialsNDBModel storage._model = appengine.CredentialsNDBModel
self.assertTrue(storage._is_ndb()) self.assertTrue(storage._is_ndb())
def _verify_basic_refresh(self, http):
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, oauth2client.GOOGLE_TOKEN_URI)
self.assertEqual(http.method, 'POST')
expected_body = {
'grant_type': ['refresh_token'],
'client_id': [self.credentials.client_id],
'client_secret': [self.credentials.client_secret],
'refresh_token': [self.credentials.refresh_token],
}
self.assertEqual(urllib_parse.parse_qs(http.body), expected_body)
expected_headers = {
'content-type': 'application/x-www-form-urlencoded',
'user-agent': self.credentials.user_agent,
}
self.assertEqual(http.headers, expected_headers)
def test_get_and_put_simple(self): def test_get_and_put_simple(self):
storage = appengine.StorageByKeyName( storage = appengine.StorageByKeyName(
appengine.CredentialsModel, 'foo', 'credentials') appengine.CredentialsModel, 'foo', 'credentials')
@@ -414,9 +427,12 @@ class StorageByKeyNameTest(unittest2.TestCase):
self.assertEqual(None, storage.get()) self.assertEqual(None, storage.get())
self.credentials.set_store(storage) self.credentials.set_store(storage)
self.credentials._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
self.credentials._refresh(http)
credmodel = appengine.CredentialsModel.get_by_key_name('foo') credmodel = appengine.CredentialsModel.get_by_key_name('foo')
self.assertEqual('bar', credmodel.credentials.access_token) self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token)
# Verify mock.
self._verify_basic_refresh(http)
def test_get_and_put_cached(self): def test_get_and_put_cached(self):
storage = appengine.StorageByKeyName( storage = appengine.StorageByKeyName(
@@ -425,16 +441,17 @@ class StorageByKeyNameTest(unittest2.TestCase):
self.assertEqual(None, storage.get()) self.assertEqual(None, storage.get())
self.credentials.set_store(storage) self.credentials.set_store(storage)
self.credentials._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
self.credentials._refresh(http)
credmodel = appengine.CredentialsModel.get_by_key_name('foo') credmodel = appengine.CredentialsModel.get_by_key_name('foo')
self.assertEqual('bar', credmodel.credentials.access_token) self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token)
# Now remove the item from the cache. # Now remove the item from the cache.
memcache.delete('foo') memcache.delete('foo')
# Check that getting refreshes the cache. # Check that getting refreshes the cache.
credentials = storage.get() credentials = storage.get()
self.assertEqual('bar', credentials.access_token) self.assertEqual(BASIC_TOKEN, credentials.access_token)
self.assertNotEqual(None, memcache.get('foo')) self.assertNotEqual(None, memcache.get('foo'))
# Deleting should clear the cache. # Deleting should clear the cache.
@@ -443,6 +460,9 @@ class StorageByKeyNameTest(unittest2.TestCase):
self.assertEqual(None, credentials) self.assertEqual(None, credentials)
self.assertEqual(None, memcache.get('foo')) self.assertEqual(None, memcache.get('foo'))
# Verify mock.
self._verify_basic_refresh(http)
def test_get_and_put_set_store_on_cache_retrieval(self): def test_get_and_put_set_store_on_cache_retrieval(self):
storage = appengine.StorageByKeyName( storage = appengine.StorageByKeyName(
appengine.CredentialsModel, 'foo', 'credentials', cache=memcache) appengine.CredentialsModel, 'foo', 'credentials', cache=memcache)
@@ -455,9 +475,13 @@ class StorageByKeyNameTest(unittest2.TestCase):
old_creds = storage.get() old_creds = storage.get()
self.assertEqual(old_creds.access_token, 'foo') self.assertEqual(old_creds.access_token, 'foo')
old_creds.invalid = True old_creds.invalid = True
old_creds._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
old_creds._refresh(http)
new_creds = storage.get() new_creds = storage.get()
self.assertEqual(new_creds.access_token, 'bar') self.assertEqual(new_creds.access_token, BASIC_TOKEN)
# Verify mock.
self._verify_basic_refresh(http)
def test_get_and_put_ndb(self): def test_get_and_put_ndb(self):
# Start empty # Start empty
@@ -467,12 +491,16 @@ class StorageByKeyNameTest(unittest2.TestCase):
# Refresh storage and retrieve without using storage # Refresh storage and retrieve without using storage
self.credentials.set_store(storage) self.credentials.set_store(storage)
self.credentials._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
self.credentials._refresh(http)
credmodel = appengine.CredentialsNDBModel.get_by_id('foo') credmodel = appengine.CredentialsNDBModel.get_by_id('foo')
self.assertEqual('bar', credmodel.credentials.access_token) self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token)
self.assertEqual(credmodel.credentials.to_json(), self.assertEqual(credmodel.credentials.to_json(),
self.credentials.to_json()) self.credentials.to_json())
# Verify mock.
self._verify_basic_refresh(http)
def test_delete_ndb(self): def test_delete_ndb(self):
# Start empty # Start empty
storage = appengine.StorageByKeyName( storage = appengine.StorageByKeyName(
@@ -498,14 +526,18 @@ class StorageByKeyNameTest(unittest2.TestCase):
# Set NDB store and refresh to add to storage # Set NDB store and refresh to add to storage
self.credentials.set_store(storage) self.credentials.set_store(storage)
self.credentials._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
self.credentials._refresh(http)
# Retrieve same key from DB model to confirm mixing works # Retrieve same key from DB model to confirm mixing works
credmodel = appengine.CredentialsModel.get_by_key_name('foo') credmodel = appengine.CredentialsModel.get_by_key_name('foo')
self.assertEqual('bar', credmodel.credentials.access_token) self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token)
self.assertEqual(self.credentials.to_json(), self.assertEqual(self.credentials.to_json(),
credmodel.credentials.to_json()) credmodel.credentials.to_json())
# Verify mock.
self._verify_basic_refresh(http)
def test_get_and_put_mixed_db_storage_ndb_get(self): def test_get_and_put_mixed_db_storage_ndb_get(self):
# Start empty # Start empty
storage = appengine.StorageByKeyName( storage = appengine.StorageByKeyName(
@@ -514,14 +546,18 @@ class StorageByKeyNameTest(unittest2.TestCase):
# Set DB store and refresh to add to storage # Set DB store and refresh to add to storage
self.credentials.set_store(storage) self.credentials.set_store(storage)
self.credentials._refresh(_http_request) http = http_mock.HttpMock(data=BASIC_RESP)
self.credentials._refresh(http)
# Retrieve same key from NDB model to confirm mixing works # Retrieve same key from NDB model to confirm mixing works
credmodel = appengine.CredentialsNDBModel.get_by_id('foo') credmodel = appengine.CredentialsNDBModel.get_by_id('foo')
self.assertEqual('bar', credmodel.credentials.access_token) self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token)
self.assertEqual(self.credentials.to_json(), self.assertEqual(self.credentials.to_json(),
credmodel.credentials.to_json()) credmodel.credentials.to_json())
# Verify mock.
self._verify_basic_refresh(http)
def test_delete_db_ndb_mixed(self): def test_delete_db_ndb_mixed(self):
# Start empty # Start empty
storage_ndb = appengine.StorageByKeyName( storage_ndb = appengine.StorageByKeyName(
@@ -981,11 +1017,11 @@ class DecoratorTests(unittest2.TestCase):
'oauth2client.contrib.appengine.clientsecrets.loadfile') 'oauth2client.contrib.appengine.clientsecrets.loadfile')
with loadfile_patch as loadfile_mock: with loadfile_patch as loadfile_mock:
loadfile_mock.return_value = (clientsecrets.TYPE_WEB, { loadfile_mock.return_value = (clientsecrets.TYPE_WEB, {
"client_id": "foo_client_id", 'client_id': 'foo_client_id',
"client_secret": "foo_client_secret", 'client_secret': 'foo_client_secret',
"redirect_uris": [], 'redirect_uris': [],
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth", 'auth_uri': oauth2client.GOOGLE_AUTH_URI,
"token_uri": "https://www.googleapis.com/oauth2/v4/token", 'token_uri': oauth2client.GOOGLE_TOKEN_URI,
# No revoke URI # No revoke URI
}) })

View File

@@ -19,19 +19,20 @@ import json
import mock import mock
from six.moves import http_client from six.moves import http_client
from tests.contrib.test_metadata import request_mock
import unittest2 import unittest2
from oauth2client import client from oauth2client import client
from oauth2client.contrib import _metadata
from oauth2client.contrib import gce from oauth2client.contrib import gce
from .. import http_mock
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
SERVICE_ACCOUNT_INFO = { SERVICE_ACCOUNT_INFO = {
'scopes': ['a', 'b'], 'scopes': ['a', 'b'],
'email': 'a@example.com', 'email': 'a@example.com',
'aliases': ['default'] 'aliases': ['default']
} }
METADATA_PATH = 'instance/service-accounts/a@example.com/token'
class AppAssertionCredentialsTests(unittest2.TestCase): class AppAssertionCredentialsTests(unittest2.TestCase):
@@ -85,16 +86,24 @@ class AppAssertionCredentialsTests(unittest2.TestCase):
get_info.assert_not_called() get_info.assert_not_called()
def test_refresh_token_failed_fetch(self): def test_refresh_token_failed_fetch(self):
http_request = request_mock( headers = {
http_client.NOT_FOUND, 'status': http_client.NOT_FOUND,
'application/json', 'content-type': 'application/json',
json.dumps({'access_token': 'a', 'expires_in': 100}) }
) response = json.dumps({'access_token': 'a', 'expires_in': 100})
http = http_mock.HttpMock(headers=headers, data=response)
credentials = gce.AppAssertionCredentials() credentials = gce.AppAssertionCredentials()
credentials.invalid = False credentials.invalid = False
credentials.service_account_email = 'a@example.com' credentials.service_account_email = 'a@example.com'
with self.assertRaises(client.HttpAccessTokenRefreshError): with self.assertRaises(client.HttpAccessTokenRefreshError):
credentials._refresh(http_request) credentials._refresh(http)
# Verify mock.
self.assertEqual(http.requests, 1)
expected_uri = _metadata.METADATA_ROOT + METADATA_PATH
self.assertEqual(http.uri, expected_uri)
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)
def test_serialization_data(self): def test_serialization_data(self):
credentials = gce.AppAssertionCredentials() credentials = gce.AppAssertionCredentials()

View File

@@ -28,52 +28,59 @@ DATA = {'foo': 'bar'}
EXPECTED_URL = ( EXPECTED_URL = (
'http://metadata.google.internal/computeMetadata/v1/instance' 'http://metadata.google.internal/computeMetadata/v1/instance'
'/service-accounts/default') '/service-accounts/default')
EXPECTED_KWARGS = {
'headers': _metadata.METADATA_HEADERS,
'body': None,
'connection_type': None,
'method': 'GET',
'redirections': 5,
}
def request_mock(status, content_type, content): def request_mock(status, content_type, content):
response = http_mock.ResponseMock( headers = {'status': status, 'content-type': content_type}
{'status': status, 'content-type': content_type}) http = http_mock.HttpMock(headers=headers,
request_method = mock.Mock( data=content.encode('utf-8'))
return_value=(response, content.encode('utf-8'))) return http
# Make sure the mock doesn't have a request attr.
del request_method.request
return request_method
class TestMetadata(unittest2.TestCase): class TestMetadata(unittest2.TestCase):
def test_get_success_json(self): def test_get_success_json(self):
http_request = request_mock( http = request_mock(
http_client.OK, 'application/json', json.dumps(DATA)) http_client.OK, 'application/json', json.dumps(DATA))
self.assertEqual( self.assertEqual(
_metadata.get(http_request, PATH), _metadata.get(http, PATH),
DATA DATA
) )
http_request.assert_called_once_with(EXPECTED_URL, **EXPECTED_KWARGS)
# Verify mocks.
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, EXPECTED_URL)
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)
def test_get_success_string(self): def test_get_success_string(self):
http_request = request_mock( http = request_mock(
http_client.OK, 'text/html', '<p>Hello World!</p>') http_client.OK, 'text/html', '<p>Hello World!</p>')
self.assertEqual( self.assertEqual(
_metadata.get(http_request, PATH), _metadata.get(http, PATH),
'<p>Hello World!</p>' '<p>Hello World!</p>'
) )
http_request.assert_called_once_with(EXPECTED_URL, **EXPECTED_KWARGS)
# Verify mocks.
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, EXPECTED_URL)
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)
def test_get_failure(self): def test_get_failure(self):
http_request = request_mock( http = request_mock(
http_client.NOT_FOUND, 'text/html', '<p>Error</p>') http_client.NOT_FOUND, 'text/html', '<p>Error</p>')
with self.assertRaises(http_client.HTTPException): with self.assertRaises(http_client.HTTPException):
_metadata.get(http_request, PATH) _metadata.get(http, PATH)
http_request.assert_called_once_with(EXPECTED_URL, **EXPECTED_KWARGS) # Verify mocks.
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, EXPECTED_URL)
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)
@mock.patch( @mock.patch(
'oauth2client.client._UTCNOW', 'oauth2client.client._UTCNOW',
@@ -88,18 +95,22 @@ class TestMetadata(unittest2.TestCase):
self.assertEqual(token, 'a') self.assertEqual(token, 'a')
self.assertEqual( self.assertEqual(
expiry, datetime.datetime.min + datetime.timedelta(seconds=100)) expiry, datetime.datetime.min + datetime.timedelta(seconds=100))
http.assert_called_once_with( # Verify mocks.
EXPECTED_URL + '/token',
**EXPECTED_KWARGS
)
now.assert_called_once_with() now.assert_called_once_with()
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, EXPECTED_URL + '/token')
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)
def test_service_account_info(self): def test_service_account_info(self):
http_request = request_mock( http = request_mock(
http_client.OK, 'application/json', json.dumps(DATA)) http_client.OK, 'application/json', json.dumps(DATA))
info = _metadata.get_service_account_info(http_request) info = _metadata.get_service_account_info(http)
self.assertEqual(info, DATA) self.assertEqual(info, DATA)
http_request.assert_called_once_with( # Verify mock.
EXPECTED_URL + '/?recursive=True', self.assertEqual(http.requests, 1)
**EXPECTED_KWARGS self.assertEqual(http.uri, EXPECTED_URL + '/?recursive=True')
) self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertEqual(http.headers, _metadata.METADATA_HEADERS)

View File

@@ -46,6 +46,7 @@ class HttpMock(object):
self.method = None self.method = None
self.body = None self.body = None
self.headers = None self.headers = None
self.requests = 0
def request(self, uri, def request(self, uri,
method='GET', method='GET',
@@ -57,6 +58,8 @@ class HttpMock(object):
self.method = method self.method = method
self.body = body self.body = body
self.headers = headers self.headers = headers
self.redirections = redirections
self.requests += 1
return ResponseMock(self.response_headers), self.data return ResponseMock(self.response_headers), self.data
@@ -89,7 +92,6 @@ class HttpMockSequence(object):
iterable: iterable, a sequence of pairs of (headers, body) iterable: iterable, a sequence of pairs of (headers, body)
""" """
self._iterable = iterable self._iterable = iterable
self.follow_redirects = True
self.requests = [] self.requests = []
def request(self, uri, def request(self, uri,
@@ -99,7 +101,12 @@ class HttpMockSequence(object):
redirections=1, redirections=1,
connection_type=None): connection_type=None):
resp, content = self._iterable.pop(0) resp, content = self._iterable.pop(0)
self.requests.append({'uri': uri, 'body': body, 'headers': headers}) self.requests.append({
'method': method,
'uri': uri,
'body': body,
'headers': headers,
})
# Read any underlying stream before sending the request. # Read any underlying stream before sending the request.
body_stream_content = (body.read() body_stream_content = (body.read()
if getattr(body, 'read', None) else None) if getattr(body, 'read', None) else None)

View File

@@ -12,10 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Oauth2client tests """Unit tests for oauth2client.client."""
Unit tests for oauth2client.
"""
import base64 import base64
import contextlib import contextlib
@@ -705,8 +702,9 @@ class GoogleCredentialsTests(unittest2.TestCase):
# Make sure the well-known file actually doesn't exist. # Make sure the well-known file actually doesn't exist.
self.assertTrue(os.path.exists(get_well_known.return_value)) self.assertTrue(os.path.exists(get_well_known.return_value))
method_name = \ method_name = (
'oauth2client.client._get_application_default_credential_from_file' 'oauth2client.client.'
'_get_application_default_credential_from_file')
result_creds = object() result_creds = object()
with mock.patch(method_name, with mock.patch(method_name,
return_value=result_creds) as get_from_file: return_value=result_creds) as get_from_file:
@@ -846,9 +844,9 @@ def _token_revoke_test_helper(testcase, status, revoke_raise,
actual_do_revoke = testcase.credentials._do_revoke actual_do_revoke = testcase.credentials._do_revoke
testcase.token_from_revoke = None testcase.token_from_revoke = None
def do_revoke_stub(http_request, token): def do_revoke_stub(http, token):
testcase.token_from_revoke = token testcase.token_from_revoke = token
return actual_do_revoke(http_request, token) return actual_do_revoke(http, token)
testcase.credentials._do_revoke = do_revoke_stub testcase.credentials._do_revoke = do_revoke_stub
http = http_mock.HttpMock(headers={'status': status}) http = http_mock.HttpMock(headers={'status': status})
@@ -1216,24 +1214,25 @@ class BasicCredentialsTests(unittest2.TestCase):
def _do_refresh_request_test_helper(self, response, content, def _do_refresh_request_test_helper(self, response, content,
error_msg, logger, gen_body, error_msg, logger, gen_body,
gen_headers, store=None): gen_headers, store=None):
token_uri = 'http://token_uri'
credentials = client.OAuth2Credentials(None, None, None, None, credentials = client.OAuth2Credentials(None, None, None, None,
None, None, None) None, token_uri, None)
credentials.store = store credentials.store = store
http_request = mock.Mock() http = http_mock.HttpMock(headers=response, data=content)
# Make sure the mock doesn't have a request attr.
del http_request.request
http_request.return_value = response, content
with self.assertRaises( with self.assertRaises(
client.HttpAccessTokenRefreshError) as exc_manager: client.HttpAccessTokenRefreshError) as exc_manager:
credentials._do_refresh_request(http_request) credentials._do_refresh_request(http)
self.assertEqual(exc_manager.exception.args, (error_msg,)) self.assertEqual(exc_manager.exception.args, (error_msg,))
self.assertEqual(exc_manager.exception.status, response.status) self.assertEqual(exc_manager.exception.status, response.status)
http_request.assert_called_once_with(
None, method='POST', body=gen_body.return_value, # Verify mocks.
headers=gen_headers.return_value, redirections=5, self.assertEqual(http.requests, 1)
connection_type=None) self.assertEqual(http.uri, token_uri)
self.assertEqual(http.method, 'POST')
self.assertEqual(http.body, gen_body.return_value)
self.assertEqual(http.headers, gen_headers.return_value)
call1 = mock.call('Refreshing access_token') call1 = mock.call('Refreshing access_token')
failure_template = 'Failed to retrieve access token: %s' failure_template = 'Failed to retrieve access token: %s'
@@ -1288,22 +1287,20 @@ class BasicCredentialsTests(unittest2.TestCase):
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
revoke_uri=oauth2client.GOOGLE_REVOKE_URI) revoke_uri=oauth2client.GOOGLE_REVOKE_URI)
credentials.store = store credentials.store = store
http_request = mock.Mock()
# Make sure the mock doesn't have a request attr. http = http_mock.HttpMock(headers=response, data=content)
del http_request.request
http_request.return_value = response, content
token = u's3kr3tz' token = u's3kr3tz'
if response.status == http_client.OK: if response.status == http_client.OK:
self.assertFalse(credentials.invalid) self.assertFalse(credentials.invalid)
self.assertIsNone(credentials._do_revoke(http_request, token)) self.assertIsNone(credentials._do_revoke(http, token))
self.assertTrue(credentials.invalid) self.assertTrue(credentials.invalid)
if store is not None: if store is not None:
store.delete.assert_called_once_with() store.delete.assert_called_once_with()
else: else:
self.assertFalse(credentials.invalid) self.assertFalse(credentials.invalid)
with self.assertRaises(client.TokenRevokeError) as exc_manager: with self.assertRaises(client.TokenRevokeError) as exc_manager:
credentials._do_revoke(http_request, token) credentials._do_revoke(http, token)
# Make sure invalid was not flipped on. # Make sure invalid was not flipped on.
self.assertFalse(credentials.invalid) self.assertFalse(credentials.invalid)
self.assertEqual(exc_manager.exception.args, (error_msg,)) self.assertEqual(exc_manager.exception.args, (error_msg,))
@@ -1311,9 +1308,13 @@ class BasicCredentialsTests(unittest2.TestCase):
store.delete.assert_not_called() store.delete.assert_not_called()
revoke_uri = oauth2client.GOOGLE_REVOKE_URI + '?token=' + token revoke_uri = oauth2client.GOOGLE_REVOKE_URI + '?token=' + token
http_request.assert_called_once_with(
revoke_uri, method='GET', body=None, headers=None, # Verify mocks.
redirections=5, connection_type=None) self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, revoke_uri)
self.assertEqual(http.method, 'GET')
self.assertIsNone(http.body)
self.assertIsNone(http.headers)
logger.info.assert_called_once_with('Revoking token') logger.info.assert_called_once_with('Revoking token')
@@ -1359,21 +1360,18 @@ class BasicCredentialsTests(unittest2.TestCase):
credentials = client.OAuth2Credentials( credentials = client.OAuth2Credentials(
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
token_info_uri=oauth2client.GOOGLE_TOKEN_INFO_URI) token_info_uri=oauth2client.GOOGLE_TOKEN_INFO_URI)
http_request = mock.Mock() http = http_mock.HttpMock(headers=response, data=content)
# Make sure the mock doesn't have a request attr.
del http_request.request
http_request.return_value = response, content
token = u's3kr3tz' token = u's3kr3tz'
if response.status == http_client.OK: if response.status == http_client.OK:
self.assertEqual(credentials.scopes, set()) self.assertEqual(credentials.scopes, set())
self.assertIsNone( self.assertIsNone(
credentials._do_retrieve_scopes(http_request, token)) credentials._do_retrieve_scopes(http, token))
self.assertEqual(credentials.scopes, scopes) self.assertEqual(credentials.scopes, scopes)
else: else:
self.assertEqual(credentials.scopes, set()) self.assertEqual(credentials.scopes, set())
with self.assertRaises(client.Error) as exc_manager: with self.assertRaises(client.Error) as exc_manager:
credentials._do_retrieve_scopes(http_request, token) credentials._do_retrieve_scopes(http, token)
# Make sure scopes were not changed. # Make sure scopes were not changed.
self.assertEqual(credentials.scopes, set()) self.assertEqual(credentials.scopes, set())
self.assertEqual(exc_manager.exception.args, (error_msg,)) self.assertEqual(exc_manager.exception.args, (error_msg,))
@@ -1381,12 +1379,13 @@ class BasicCredentialsTests(unittest2.TestCase):
token_uri = client._update_query_params( token_uri = client._update_query_params(
oauth2client.GOOGLE_TOKEN_INFO_URI, oauth2client.GOOGLE_TOKEN_INFO_URI,
{'fields': 'scope', 'access_token': token}) {'fields': 'scope', 'access_token': token})
self.assertEqual(len(http_request.mock_calls), 1)
scopes_call = http_request.mock_calls[0] # Verify mocks.
call_args = scopes_call[1] self.assertEqual(http.requests, 1)
self.assertEqual(len(call_args), 1) assertUrisEqual(self, token_uri, http.uri)
called_uri = call_args[0] self.assertEqual(http.method, 'GET')
assertUrisEqual(self, token_uri, called_uri) self.assertIsNone(http.body)
self.assertIsNone(http.headers)
logger.info.assert_called_once_with('Refreshing scopes') logger.info.assert_called_once_with('Refreshing scopes')
def test__do_retrieve_scopes_success_bad_json(self): def test__do_retrieve_scopes_success_bad_json(self):

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Oauth2client tests. """oauth2client tests.
Unit tests for service account credentials implemented using RSA. Unit tests for service account credentials implemented using RSA.
""" """
@@ -24,13 +24,15 @@ import tempfile
import mock import mock
import rsa import rsa
from six import BytesIO import six
from six.moves import http_client
import unittest2 import unittest2
from oauth2client import client from oauth2client import client
from oauth2client import crypt from oauth2client import crypt
from oauth2client import service_account from oauth2client import service_account
from .http_mock import HttpMockSequence from oauth2client import transport
from . import http_mock
def data_filename(filename): def data_filename(filename):
@@ -180,7 +182,7 @@ class ServiceAccountCredentialsTests(unittest2.TestCase):
scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri)) scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri))
creds_from_file_contents = ( creds_from_file_contents = (
service_account.ServiceAccountCredentials.from_p12_keyfile_buffer( service_account.ServiceAccountCredentials.from_p12_keyfile_buffer(
service_account_email, BytesIO(key_contents), service_account_email, six.BytesIO(key_contents),
private_key_password=private_key_password, private_key_password=private_key_password,
scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri)) scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri))
for creds in (creds_from_filename, creds_from_file_contents): for creds in (creds_from_filename, creds_from_file_contents):
@@ -301,10 +303,10 @@ class ServiceAccountCredentialsTests(unittest2.TestCase):
'access_token': token2, 'access_token': token2,
'expires_in': lifetime, 'expires_in': lifetime,
} }
http = HttpMockSequence([ http = http_mock.HttpMockSequence([
({'status': '200'}, ({'status': http_client.OK},
json.dumps(token_response_first).encode('utf-8')), json.dumps(token_response_first).encode('utf-8')),
({'status': '200'}, ({'status': http_client.OK},
json.dumps(token_response_second).encode('utf-8')), json.dumps(token_response_second).encode('utf-8')),
]) ])
@@ -479,31 +481,34 @@ class JWTAccessCredentialsTests(unittest2.TestCase):
utcnow.return_value = T1_DATE utcnow.return_value = T1_DATE
time.return_value = T1 time.return_value = T1
def mock_request(uri, method='GET', body=None, headers=None, http = http_mock.HttpMockSequence([
redirections=0, connection_type=None): ({'status': http_client.OK}, b''),
self.assertEqual(uri, self.url) ({'status': http_client.OK}, b''),
bearer, token = headers[b'Authorization'].split() ])
self.jwt.authorize(http)
transport.request(http, self.url)
# Ensure we use the cached token
utcnow.return_value = T2_DATE
transport.request(http, self.url)
# Verify mocks.
certs = {'key': datafile('public_cert.pem')}
self.assertEqual(len(http.requests), 2)
for info in http.requests:
self.assertEqual(info['method'], 'GET')
self.assertEqual(info['uri'], self.url)
self.assertIsNone(info['body'])
self.assertEqual(len(info['headers']), 1)
bearer, token = info['headers'][b'Authorization'].split()
payload = crypt.verify_signed_jwt_with_certs( payload = crypt.verify_signed_jwt_with_certs(
token, token, certs, audience=self.url)
{'key': datafile('public_cert.pem')},
audience=self.url)
self.assertEqual(payload['iss'], self.service_account_email) self.assertEqual(payload['iss'], self.service_account_email)
self.assertEqual(payload['sub'], self.service_account_email) self.assertEqual(payload['sub'], self.service_account_email)
self.assertEqual(payload['iat'], T1) self.assertEqual(payload['iat'], T1)
self.assertEqual(payload['exp'], T1_EXPIRY) self.assertEqual(payload['exp'], T1_EXPIRY)
self.assertEqual(uri, self.url)
self.assertEqual(bearer, b'Bearer') self.assertEqual(bearer, b'Bearer')
response = mock.Mock(status=200)
return response, b''
h = mock.Mock()
h.request = mock_request
self.jwt.authorize(h)
h.request(self.url)
# Ensure we use the cached token
utcnow.return_value = T2_DATE
h.request(self.url)
@mock.patch('oauth2client.client._UTCNOW') @mock.patch('oauth2client.client._UTCNOW')
@mock.patch('time.time') @mock.patch('time.time')
@@ -515,37 +520,41 @@ class JWTAccessCredentialsTests(unittest2.TestCase):
self.service_account_email, self.signer, self.service_account_email, self.signer,
private_key_id=self.private_key_id, client_id=self.client_id) private_key_id=self.private_key_id, client_id=self.client_id)
def mock_request(uri, method='GET', body=None, headers=None, http = http_mock.HttpMockSequence([
redirections=0, connection_type=None): ({'status': http_client.OK}, b''),
self.assertEqual(uri, self.url) ])
bearer, token = headers[b'Authorization'].split()
jwt.authorize(http)
transport.request(http, self.url)
# Ensure we do not cache the token
self.assertIsNone(jwt.access_token)
# Verify mocks.
self.assertEqual(len(http.requests), 1)
info = http.requests[0]
self.assertEqual(info['method'], 'GET')
self.assertEqual(info['uri'], self.url)
self.assertIsNone(info['body'])
self.assertEqual(len(info['headers']), 1)
bearer, token = info['headers'][b'Authorization'].split()
certs = {'key': datafile('public_cert.pem')}
payload = crypt.verify_signed_jwt_with_certs( payload = crypt.verify_signed_jwt_with_certs(
token, token, certs, audience=self.url)
{'key': datafile('public_cert.pem')},
audience=self.url)
self.assertEqual(payload['iss'], self.service_account_email) self.assertEqual(payload['iss'], self.service_account_email)
self.assertEqual(payload['sub'], self.service_account_email) self.assertEqual(payload['sub'], self.service_account_email)
self.assertEqual(payload['iat'], T1) self.assertEqual(payload['iat'], T1)
self.assertEqual(payload['exp'], T1_EXPIRY) self.assertEqual(payload['exp'], T1_EXPIRY)
self.assertEqual(uri, self.url)
self.assertEqual(bearer, b'Bearer') self.assertEqual(bearer, b'Bearer')
response = mock.Mock(status=200)
return response, b''
h = mock.Mock()
h.request = mock_request
jwt.authorize(h)
h.request(self.url)
# Ensure we do not cache the token
self.assertIsNone(jwt.access_token)
@mock.patch('oauth2client.client._UTCNOW') @mock.patch('oauth2client.client._UTCNOW')
def test_authorize_stale_token(self, utcnow): def test_authorize_stale_token(self, utcnow):
utcnow.return_value = T1_DATE utcnow.return_value = T1_DATE
# Create an initial token # Create an initial token
h = HttpMockSequence([({'status': '200'}, b''), h = http_mock.HttpMockSequence([
({'status': '200'}, b'')]) ({'status': http_client.OK}, b''),
({'status': http_client.OK}, b''),
])
self.jwt.authorize(h) self.jwt.authorize(h)
h.request(self.url) h.request(self.url)
token_1 = self.jwt.access_token token_1 = self.jwt.access_token
@@ -561,10 +570,11 @@ class JWTAccessCredentialsTests(unittest2.TestCase):
def test_authorize_401(self, utcnow): def test_authorize_401(self, utcnow):
utcnow.return_value = T1_DATE utcnow.return_value = T1_DATE
h = HttpMockSequence([ h = http_mock.HttpMockSequence([
({'status': '200'}, b''), ({'status': http_client.OK}, b''),
({'status': '401'}, b''), ({'status': http_client.UNAUTHORIZED}, b''),
({'status': '200'}, b'')]) ({'status': http_client.OK}, b''),
])
self.jwt.authorize(h) self.jwt.authorize(h)
h.request(self.url) h.request(self.url)
token_1 = self.jwt.access_token token_1 = self.jwt.access_token

View File

@@ -18,6 +18,7 @@ import unittest2
from oauth2client import client from oauth2client import client
from oauth2client import transport from oauth2client import transport
from . import http_mock
class TestMemoryCache(unittest2.TestCase): class TestMemoryCache(unittest2.TestCase):
@@ -146,33 +147,35 @@ class Test_request(unittest2.TestCase):
redirections = 3 redirections = 3
def test_with_request_attr(self): def test_with_request_attr(self):
http = mock.Mock()
mock_result = object() mock_result = object()
mock_request = mock.Mock(return_value=mock_result) headers = {'foo': 'bar'}
http.request = mock_request http = http_mock.HttpMock(headers=headers, data=mock_result)
result = transport.request(http, self.uri, method=self.method, response, content = transport.request(
body=self.body, http, self.uri, method=self.method, body=self.body,
redirections=self.redirections) redirections=self.redirections)
self.assertIs(result, mock_result) self.assertEqual(response, headers)
# Verify mock. self.assertIs(content, mock_result)
mock_request.assert_called_once_with(self.uri, method=self.method, # Verify mocks.
body=self.body, self.assertEqual(http.requests, 1)
redirections=self.redirections, self.assertEqual(http.uri, self.uri)
headers=None, self.assertEqual(http.method, self.method)
connection_type=None) self.assertEqual(http.body, self.body)
self.assertIsNone(http.headers)
def test_with_callable_http(self): def test_with_callable_http(self):
headers = {}
mock_result = object() mock_result = object()
http = mock.Mock(return_value=mock_result) http = http_mock.HttpMock(headers=headers, data=mock_result)
del http.request # Make sure the mock doesn't have a request attr.
result = transport.request(http, self.uri, method=self.method, result = transport.request(http, self.uri, method=self.method,
body=self.body, body=self.body,
redirections=self.redirections) redirections=self.redirections)
self.assertIs(result, mock_result) self.assertEqual(result, (headers, mock_result))
# Verify mock. # Verify mock.
http.assert_called_once_with(self.uri, method=self.method, self.assertEqual(http.requests, 1)
body=self.body, self.assertEqual(http.uri, self.uri)
redirections=self.redirections, self.assertEqual(http.method, self.method)
headers=None, connection_type=None) self.assertEqual(http.body, self.body)
self.assertIsNone(http.headers)
self.assertEqual(http.redirections, self.redirections)