From 8299c5867f878c99f51ae593f97b38f0b511ff61 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Wed, 10 Aug 2016 14:05:16 -0700 Subject: [PATCH] Clean up usage of HTTP mocks in tests. --- tests/contrib/appengine/test_appengine.py | 86 +++++++++++----- tests/contrib/test_gce.py | 25 +++-- tests/contrib/test_metadata.py | 77 ++++++++------- tests/http_mock.py | 11 ++- tests/test_client.py | 77 ++++++++------- tests/test_service_account.py | 114 ++++++++++++---------- tests/test_transport.py | 43 ++++---- 7 files changed, 254 insertions(+), 179 deletions(-) diff --git a/tests/contrib/appengine/test_appengine.py b/tests/contrib/appengine/test_appengine.py index 6890b64..a638994 100644 --- a/tests/contrib/appengine/test_appengine.py +++ b/tests/contrib/appengine/test_appengine.py @@ -29,6 +29,7 @@ from google.appengine.ext import ndb from google.appengine.ext import testbed import mock from six.moves import urllib +from six.moves import urllib_parse import unittest2 import webapp2 from webtest import TestApp @@ -50,6 +51,8 @@ DEFAULT_RESP = """\ "refresh_token": "foo_refresh_token" } """ +BASIC_TOKEN = 'bar' +BASIC_RESP = json.dumps({'access_token': BASIC_TOKEN}) def datafile(filename): @@ -356,13 +359,6 @@ class CredentialsPropertyTest(unittest2.TestCase): 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): def setUp(self): @@ -407,6 +403,23 @@ class StorageByKeyNameTest(unittest2.TestCase): storage._model = appengine.CredentialsNDBModel 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): storage = appengine.StorageByKeyName( appengine.CredentialsModel, 'foo', 'credentials') @@ -414,9 +427,12 @@ class StorageByKeyNameTest(unittest2.TestCase): self.assertEqual(None, storage.get()) 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') - 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): storage = appengine.StorageByKeyName( @@ -425,16 +441,17 @@ class StorageByKeyNameTest(unittest2.TestCase): self.assertEqual(None, storage.get()) 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') - self.assertEqual('bar', credmodel.credentials.access_token) + self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token) # Now remove the item from the cache. memcache.delete('foo') # Check that getting refreshes the cache. credentials = storage.get() - self.assertEqual('bar', credentials.access_token) + self.assertEqual(BASIC_TOKEN, credentials.access_token) self.assertNotEqual(None, memcache.get('foo')) # Deleting should clear the cache. @@ -443,6 +460,9 @@ class StorageByKeyNameTest(unittest2.TestCase): self.assertEqual(None, credentials) self.assertEqual(None, memcache.get('foo')) + # Verify mock. + self._verify_basic_refresh(http) + def test_get_and_put_set_store_on_cache_retrieval(self): storage = appengine.StorageByKeyName( appengine.CredentialsModel, 'foo', 'credentials', cache=memcache) @@ -455,9 +475,13 @@ class StorageByKeyNameTest(unittest2.TestCase): old_creds = storage.get() self.assertEqual(old_creds.access_token, 'foo') old_creds.invalid = True - old_creds._refresh(_http_request) + http = http_mock.HttpMock(data=BASIC_RESP) + old_creds._refresh(http) 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): # Start empty @@ -467,12 +491,16 @@ class StorageByKeyNameTest(unittest2.TestCase): # Refresh storage and retrieve without using 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') - self.assertEqual('bar', credmodel.credentials.access_token) + self.assertEqual(BASIC_TOKEN, credmodel.credentials.access_token) self.assertEqual(credmodel.credentials.to_json(), self.credentials.to_json()) + # Verify mock. + self._verify_basic_refresh(http) + def test_delete_ndb(self): # Start empty storage = appengine.StorageByKeyName( @@ -498,14 +526,18 @@ class StorageByKeyNameTest(unittest2.TestCase): # Set NDB store and refresh to add to 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 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(), credmodel.credentials.to_json()) + # Verify mock. + self._verify_basic_refresh(http) + def test_get_and_put_mixed_db_storage_ndb_get(self): # Start empty storage = appengine.StorageByKeyName( @@ -514,14 +546,18 @@ class StorageByKeyNameTest(unittest2.TestCase): # Set DB store and refresh to add to 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 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(), credmodel.credentials.to_json()) + # Verify mock. + self._verify_basic_refresh(http) + def test_delete_db_ndb_mixed(self): # Start empty storage_ndb = appengine.StorageByKeyName( @@ -981,11 +1017,11 @@ class DecoratorTests(unittest2.TestCase): 'oauth2client.contrib.appengine.clientsecrets.loadfile') with loadfile_patch as loadfile_mock: loadfile_mock.return_value = (clientsecrets.TYPE_WEB, { - "client_id": "foo_client_id", - "client_secret": "foo_client_secret", - "redirect_uris": [], - "auth_uri": "https://accounts.google.com/o/oauth2/v2/auth", - "token_uri": "https://www.googleapis.com/oauth2/v4/token", + 'client_id': 'foo_client_id', + 'client_secret': 'foo_client_secret', + 'redirect_uris': [], + 'auth_uri': oauth2client.GOOGLE_AUTH_URI, + 'token_uri': oauth2client.GOOGLE_TOKEN_URI, # No revoke URI }) diff --git a/tests/contrib/test_gce.py b/tests/contrib/test_gce.py index dbd7ff3..ba5a742 100644 --- a/tests/contrib/test_gce.py +++ b/tests/contrib/test_gce.py @@ -19,19 +19,20 @@ import json import mock from six.moves import http_client -from tests.contrib.test_metadata import request_mock import unittest2 from oauth2client import client +from oauth2client.contrib import _metadata from oauth2client.contrib import gce +from .. import http_mock -__author__ = 'jcgregorio@google.com (Joe Gregorio)' SERVICE_ACCOUNT_INFO = { 'scopes': ['a', 'b'], 'email': 'a@example.com', 'aliases': ['default'] } +METADATA_PATH = 'instance/service-accounts/a@example.com/token' class AppAssertionCredentialsTests(unittest2.TestCase): @@ -85,16 +86,24 @@ class AppAssertionCredentialsTests(unittest2.TestCase): get_info.assert_not_called() def test_refresh_token_failed_fetch(self): - http_request = request_mock( - http_client.NOT_FOUND, - 'application/json', - json.dumps({'access_token': 'a', 'expires_in': 100}) - ) + headers = { + 'status': http_client.NOT_FOUND, + 'content-type': 'application/json', + } + response = json.dumps({'access_token': 'a', 'expires_in': 100}) + http = http_mock.HttpMock(headers=headers, data=response) credentials = gce.AppAssertionCredentials() credentials.invalid = False credentials.service_account_email = 'a@example.com' 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): credentials = gce.AppAssertionCredentials() diff --git a/tests/contrib/test_metadata.py b/tests/contrib/test_metadata.py index 3929fd0..5c03a78 100644 --- a/tests/contrib/test_metadata.py +++ b/tests/contrib/test_metadata.py @@ -28,52 +28,59 @@ DATA = {'foo': 'bar'} EXPECTED_URL = ( 'http://metadata.google.internal/computeMetadata/v1/instance' '/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): - response = http_mock.ResponseMock( - {'status': status, 'content-type': content_type}) - request_method = mock.Mock( - return_value=(response, content.encode('utf-8'))) - # Make sure the mock doesn't have a request attr. - del request_method.request - return request_method + headers = {'status': status, 'content-type': content_type} + http = http_mock.HttpMock(headers=headers, + data=content.encode('utf-8')) + return http class TestMetadata(unittest2.TestCase): def test_get_success_json(self): - http_request = request_mock( + http = request_mock( http_client.OK, 'application/json', json.dumps(DATA)) self.assertEqual( - _metadata.get(http_request, PATH), + _metadata.get(http, PATH), 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): - http_request = request_mock( + http = request_mock( http_client.OK, 'text/html', '

Hello World!

') self.assertEqual( - _metadata.get(http_request, PATH), + _metadata.get(http, PATH), '

Hello World!

' ) - 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): - http_request = request_mock( + http = request_mock( http_client.NOT_FOUND, 'text/html', '

Error

') 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( 'oauth2client.client._UTCNOW', @@ -88,18 +95,22 @@ class TestMetadata(unittest2.TestCase): self.assertEqual(token, 'a') self.assertEqual( expiry, datetime.datetime.min + datetime.timedelta(seconds=100)) - http.assert_called_once_with( - EXPECTED_URL + '/token', - **EXPECTED_KWARGS - ) + # Verify mocks. 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): - http_request = request_mock( + http = request_mock( 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) - http_request.assert_called_once_with( - EXPECTED_URL + '/?recursive=True', - **EXPECTED_KWARGS - ) + # Verify mock. + self.assertEqual(http.requests, 1) + self.assertEqual(http.uri, EXPECTED_URL + '/?recursive=True') + self.assertEqual(http.method, 'GET') + self.assertIsNone(http.body) + self.assertEqual(http.headers, _metadata.METADATA_HEADERS) diff --git a/tests/http_mock.py b/tests/http_mock.py index 70d0e97..f1be78e 100644 --- a/tests/http_mock.py +++ b/tests/http_mock.py @@ -46,6 +46,7 @@ class HttpMock(object): self.method = None self.body = None self.headers = None + self.requests = 0 def request(self, uri, method='GET', @@ -57,6 +58,8 @@ class HttpMock(object): self.method = method self.body = body self.headers = headers + self.redirections = redirections + self.requests += 1 return ResponseMock(self.response_headers), self.data @@ -89,7 +92,6 @@ class HttpMockSequence(object): iterable: iterable, a sequence of pairs of (headers, body) """ self._iterable = iterable - self.follow_redirects = True self.requests = [] def request(self, uri, @@ -99,7 +101,12 @@ class HttpMockSequence(object): redirections=1, connection_type=None): 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. body_stream_content = (body.read() if getattr(body, 'read', None) else None) diff --git a/tests/test_client.py b/tests/test_client.py index 31e09c7..b0af01d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,10 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Oauth2client tests - -Unit tests for oauth2client. -""" +"""Unit tests for oauth2client.client.""" import base64 import contextlib @@ -705,8 +702,9 @@ class GoogleCredentialsTests(unittest2.TestCase): # Make sure the well-known file actually doesn't exist. self.assertTrue(os.path.exists(get_well_known.return_value)) - method_name = \ - 'oauth2client.client._get_application_default_credential_from_file' + method_name = ( + 'oauth2client.client.' + '_get_application_default_credential_from_file') result_creds = object() with mock.patch(method_name, 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 testcase.token_from_revoke = None - def do_revoke_stub(http_request, token): + def do_revoke_stub(http, 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 http = http_mock.HttpMock(headers={'status': status}) @@ -1216,24 +1214,25 @@ class BasicCredentialsTests(unittest2.TestCase): def _do_refresh_request_test_helper(self, response, content, error_msg, logger, gen_body, gen_headers, store=None): + token_uri = 'http://token_uri' credentials = client.OAuth2Credentials(None, None, None, None, - None, None, None) + None, token_uri, None) credentials.store = store - http_request = mock.Mock() - # Make sure the mock doesn't have a request attr. - del http_request.request - http_request.return_value = response, content + http = http_mock.HttpMock(headers=response, data=content) with self.assertRaises( 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.status, response.status) - http_request.assert_called_once_with( - None, method='POST', body=gen_body.return_value, - headers=gen_headers.return_value, redirections=5, - connection_type=None) + + # Verify mocks. + self.assertEqual(http.requests, 1) + 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') failure_template = 'Failed to retrieve access token: %s' @@ -1288,22 +1287,20 @@ class BasicCredentialsTests(unittest2.TestCase): None, None, None, None, None, None, None, revoke_uri=oauth2client.GOOGLE_REVOKE_URI) credentials.store = store - http_request = mock.Mock() - # Make sure the mock doesn't have a request attr. - del http_request.request - http_request.return_value = response, content + + http = http_mock.HttpMock(headers=response, data=content) token = u's3kr3tz' if response.status == http_client.OK: self.assertFalse(credentials.invalid) - self.assertIsNone(credentials._do_revoke(http_request, token)) + self.assertIsNone(credentials._do_revoke(http, token)) self.assertTrue(credentials.invalid) if store is not None: store.delete.assert_called_once_with() else: self.assertFalse(credentials.invalid) 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. self.assertFalse(credentials.invalid) self.assertEqual(exc_manager.exception.args, (error_msg,)) @@ -1311,9 +1308,13 @@ class BasicCredentialsTests(unittest2.TestCase): store.delete.assert_not_called() revoke_uri = oauth2client.GOOGLE_REVOKE_URI + '?token=' + token - http_request.assert_called_once_with( - revoke_uri, method='GET', body=None, headers=None, - redirections=5, connection_type=None) + + # Verify mocks. + 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') @@ -1359,21 +1360,18 @@ class BasicCredentialsTests(unittest2.TestCase): credentials = client.OAuth2Credentials( None, None, None, None, None, None, None, token_info_uri=oauth2client.GOOGLE_TOKEN_INFO_URI) - http_request = mock.Mock() - # Make sure the mock doesn't have a request attr. - del http_request.request - http_request.return_value = response, content + http = http_mock.HttpMock(headers=response, data=content) token = u's3kr3tz' if response.status == http_client.OK: self.assertEqual(credentials.scopes, set()) self.assertIsNone( - credentials._do_retrieve_scopes(http_request, token)) + credentials._do_retrieve_scopes(http, token)) self.assertEqual(credentials.scopes, scopes) else: self.assertEqual(credentials.scopes, set()) 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. self.assertEqual(credentials.scopes, set()) self.assertEqual(exc_manager.exception.args, (error_msg,)) @@ -1381,12 +1379,13 @@ class BasicCredentialsTests(unittest2.TestCase): token_uri = client._update_query_params( oauth2client.GOOGLE_TOKEN_INFO_URI, {'fields': 'scope', 'access_token': token}) - self.assertEqual(len(http_request.mock_calls), 1) - scopes_call = http_request.mock_calls[0] - call_args = scopes_call[1] - self.assertEqual(len(call_args), 1) - called_uri = call_args[0] - assertUrisEqual(self, token_uri, called_uri) + + # Verify mocks. + self.assertEqual(http.requests, 1) + assertUrisEqual(self, token_uri, http.uri) + self.assertEqual(http.method, 'GET') + self.assertIsNone(http.body) + self.assertIsNone(http.headers) logger.info.assert_called_once_with('Refreshing scopes') def test__do_retrieve_scopes_success_bad_json(self): diff --git a/tests/test_service_account.py b/tests/test_service_account.py index 9ccb76f..e97504e 100644 --- a/tests/test_service_account.py +++ b/tests/test_service_account.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Oauth2client tests. +"""oauth2client tests. Unit tests for service account credentials implemented using RSA. """ @@ -24,13 +24,15 @@ import tempfile import mock import rsa -from six import BytesIO +import six +from six.moves import http_client import unittest2 from oauth2client import client from oauth2client import crypt from oauth2client import service_account -from .http_mock import HttpMockSequence +from oauth2client import transport +from . import http_mock def data_filename(filename): @@ -180,7 +182,7 @@ class ServiceAccountCredentialsTests(unittest2.TestCase): scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri)) creds_from_file_contents = ( 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, scopes=scopes, token_uri=token_uri, revoke_uri=revoke_uri)) for creds in (creds_from_filename, creds_from_file_contents): @@ -301,10 +303,10 @@ class ServiceAccountCredentialsTests(unittest2.TestCase): 'access_token': token2, 'expires_in': lifetime, } - http = HttpMockSequence([ - ({'status': '200'}, + http = http_mock.HttpMockSequence([ + ({'status': http_client.OK}, json.dumps(token_response_first).encode('utf-8')), - ({'status': '200'}, + ({'status': http_client.OK}, json.dumps(token_response_second).encode('utf-8')), ]) @@ -479,31 +481,34 @@ class JWTAccessCredentialsTests(unittest2.TestCase): utcnow.return_value = T1_DATE time.return_value = T1 - def mock_request(uri, method='GET', body=None, headers=None, - redirections=0, connection_type=None): - self.assertEqual(uri, self.url) - bearer, token = headers[b'Authorization'].split() + http = http_mock.HttpMockSequence([ + ({'status': http_client.OK}, b''), + ({'status': http_client.OK}, b''), + ]) + + 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( - token, - {'key': datafile('public_cert.pem')}, - audience=self.url) + token, certs, audience=self.url) self.assertEqual(payload['iss'], self.service_account_email) self.assertEqual(payload['sub'], self.service_account_email) self.assertEqual(payload['iat'], T1) self.assertEqual(payload['exp'], T1_EXPIRY) - self.assertEqual(uri, self.url) 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('time.time') @@ -515,37 +520,41 @@ class JWTAccessCredentialsTests(unittest2.TestCase): self.service_account_email, self.signer, private_key_id=self.private_key_id, client_id=self.client_id) - def mock_request(uri, method='GET', body=None, headers=None, - redirections=0, connection_type=None): - self.assertEqual(uri, self.url) - bearer, token = headers[b'Authorization'].split() - payload = crypt.verify_signed_jwt_with_certs( - token, - {'key': datafile('public_cert.pem')}, - audience=self.url) - self.assertEqual(payload['iss'], self.service_account_email) - self.assertEqual(payload['sub'], self.service_account_email) - self.assertEqual(payload['iat'], T1) - self.assertEqual(payload['exp'], T1_EXPIRY) - self.assertEqual(uri, self.url) - self.assertEqual(bearer, b'Bearer') - response = mock.Mock(status=200) - return response, b'' + http = http_mock.HttpMockSequence([ + ({'status': http_client.OK}, b''), + ]) - h = mock.Mock() - h.request = mock_request - jwt.authorize(h) - h.request(self.url) + 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( + token, certs, audience=self.url) + self.assertEqual(payload['iss'], self.service_account_email) + self.assertEqual(payload['sub'], self.service_account_email) + self.assertEqual(payload['iat'], T1) + self.assertEqual(payload['exp'], T1_EXPIRY) + self.assertEqual(bearer, b'Bearer') + @mock.patch('oauth2client.client._UTCNOW') def test_authorize_stale_token(self, utcnow): utcnow.return_value = T1_DATE # Create an initial token - h = HttpMockSequence([({'status': '200'}, b''), - ({'status': '200'}, b'')]) + h = http_mock.HttpMockSequence([ + ({'status': http_client.OK}, b''), + ({'status': http_client.OK}, b''), + ]) self.jwt.authorize(h) h.request(self.url) token_1 = self.jwt.access_token @@ -561,10 +570,11 @@ class JWTAccessCredentialsTests(unittest2.TestCase): def test_authorize_401(self, utcnow): utcnow.return_value = T1_DATE - h = HttpMockSequence([ - ({'status': '200'}, b''), - ({'status': '401'}, b''), - ({'status': '200'}, b'')]) + h = http_mock.HttpMockSequence([ + ({'status': http_client.OK}, b''), + ({'status': http_client.UNAUTHORIZED}, b''), + ({'status': http_client.OK}, b''), + ]) self.jwt.authorize(h) h.request(self.url) token_1 = self.jwt.access_token diff --git a/tests/test_transport.py b/tests/test_transport.py index fdf1f73..46b2b79 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -18,6 +18,7 @@ import unittest2 from oauth2client import client from oauth2client import transport +from . import http_mock class TestMemoryCache(unittest2.TestCase): @@ -146,33 +147,35 @@ class Test_request(unittest2.TestCase): redirections = 3 def test_with_request_attr(self): - http = mock.Mock() mock_result = object() - mock_request = mock.Mock(return_value=mock_result) - http.request = mock_request + headers = {'foo': 'bar'} + http = http_mock.HttpMock(headers=headers, data=mock_result) - result = transport.request(http, self.uri, method=self.method, - body=self.body, - redirections=self.redirections) - self.assertIs(result, mock_result) - # Verify mock. - mock_request.assert_called_once_with(self.uri, method=self.method, - body=self.body, - redirections=self.redirections, - headers=None, - connection_type=None) + response, content = transport.request( + http, self.uri, method=self.method, body=self.body, + redirections=self.redirections) + self.assertEqual(response, headers) + self.assertIs(content, mock_result) + # Verify mocks. + self.assertEqual(http.requests, 1) + self.assertEqual(http.uri, self.uri) + self.assertEqual(http.method, self.method) + self.assertEqual(http.body, self.body) + self.assertIsNone(http.headers) def test_with_callable_http(self): + headers = {} mock_result = object() - http = mock.Mock(return_value=mock_result) - del http.request # Make sure the mock doesn't have a request attr. + http = http_mock.HttpMock(headers=headers, data=mock_result) result = transport.request(http, self.uri, method=self.method, body=self.body, redirections=self.redirections) - self.assertIs(result, mock_result) + self.assertEqual(result, (headers, mock_result)) # Verify mock. - http.assert_called_once_with(self.uri, method=self.method, - body=self.body, - redirections=self.redirections, - headers=None, connection_type=None) + self.assertEqual(http.requests, 1) + self.assertEqual(http.uri, self.uri) + self.assertEqual(http.method, self.method) + self.assertEqual(http.body, self.body) + self.assertIsNone(http.headers) + self.assertEqual(http.redirections, self.redirections)