Removes usage of httplib2 in unit tests.

The only remaining unit test module utilizing httplib2
is test_transport since it utilizes httplib2 directly
at the moment.
This commit is contained in:
Danny Hermes
2016-08-02 15:51:12 -07:00
parent cd825cc561
commit 256d48dab8
7 changed files with 218 additions and 234 deletions

View File

@@ -31,7 +31,6 @@ from google.appengine.api.memcache import memcache_stub
from google.appengine.ext import db
from google.appengine.ext import ndb
from google.appengine.ext import testbed
import httplib2
import mock
from six.moves import urllib
import unittest2
@@ -42,11 +41,19 @@ import oauth2client
from oauth2client import client
from oauth2client import clientsecrets
from oauth2client.contrib import appengine
from ..http_mock import CacheMock
from .. import http_mock
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
DATA_DIR = os.path.join(os.path.dirname(__file__), '..', 'data')
DEFAULT_RESP = """\
{
"access_token": "foo_access_token",
"expires_in": 3600,
"extra": "value",
"refresh_token": "foo_refresh_token"
}
"""
def datafile(filename):
@@ -75,22 +82,6 @@ class UserNotLoggedInMock(object):
return None
class Http2Mock(object):
"""Mock httplib2.Http"""
status = 200
content = {
'access_token': 'foo_access_token',
'refresh_token': 'foo_refresh_token',
'expires_in': 3600,
'extra': 'value',
}
def request(self, token_uri, method, body, headers, *args, **kwargs):
self.body = body
self.headers = headers
return self, json.dumps(self.content)
class TestAppAssertionCredentials(unittest2.TestCase):
account_name = "service_account_name@appspot.com"
signature = "signature"
@@ -139,7 +130,7 @@ class TestAppAssertionCredentials(unittest2.TestCase):
scope = 'http://www.googleapis.com/scope'
credentials = appengine.AppAssertionCredentials(scope)
http = httplib2.Http()
http = http_mock.HttpMock(data=DEFAULT_RESP)
with self.assertRaises(client.AccessTokenRefreshError):
credentials.refresh(http)
@@ -155,7 +146,7 @@ class TestAppAssertionCredentials(unittest2.TestCase):
"http://www.googleapis.com/scope",
"http://www.googleapis.com/scope2"]
credentials = appengine.AppAssertionCredentials(scope)
http = httplib2.Http()
http = http_mock.HttpMock(data=DEFAULT_RESP)
credentials.refresh(http)
self.assertEqual('a_token_123', credentials.access_token)
@@ -168,7 +159,7 @@ class TestAppAssertionCredentials(unittest2.TestCase):
scope = ('http://www.googleapis.com/scope '
'http://www.googleapis.com/scope2')
credentials = appengine.AppAssertionCredentials(scope)
http = httplib2.Http()
http = http_mock.HttpMock(data=DEFAULT_RESP)
credentials.refresh(http)
self.assertEqual('a_token_123', credentials.access_token)
self.assertEqual(
@@ -184,7 +175,7 @@ class TestAppAssertionCredentials(unittest2.TestCase):
autospec=True) as get_access_token:
credentials = appengine.AppAssertionCredentials(
scope, service_account_id=account_id)
http = httplib2.Http()
http = http_mock.HttpMock(data=DEFAULT_RESP)
credentials.refresh(http)
self.assertEqual('a_token_456', credentials.access_token)
@@ -370,7 +361,7 @@ class CredentialsPropertyTest(unittest2.TestCase):
def _http_request(*args, **kwargs):
resp = httplib2.Response({'status': '200'})
resp = http_mock.ResponseMock()
content = json.dumps({'access_token': 'bar'})
return resp, content
@@ -630,12 +621,9 @@ class DecoratorTests(unittest2.TestCase):
})
self.current_user = user_mock()
users.get_current_user = self.current_user
self.httplib2_orig = httplib2.Http
httplib2.Http = Http2Mock
def tearDown(self):
self.testbed.deactivate()
httplib2.Http = self.httplib2_orig
def test_in_error(self):
# NOTE: This branch is never reached. _in_error is not set by any code
@@ -655,7 +643,9 @@ class DecoratorTests(unittest2.TestCase):
app.router.match_routes[0].handler.__name__,
'OAuth2Handler')
def test_required(self):
@mock.patch('oauth2client.transport.get_http_object')
def test_required(self, new_http):
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# An initial request to an oauth_required decorated path should be a
# redirect to start the OAuth dance.
self.assertEqual(self.decorator.flow, None)
@@ -688,7 +678,7 @@ class DecoratorTests(unittest2.TestCase):
response_query = urllib.parse.parse_qs(parts[1])
response = response_query[
self.decorator._token_response_param][0]
self.assertEqual(Http2Mock.content,
self.assertEqual(json.loads(DEFAULT_RESP),
json.loads(urllib.parse.unquote(response)))
self.assertEqual(self.decorator.flow, self.decorator._tls.flow)
self.assertEqual(self.decorator.credentials,
@@ -736,7 +726,12 @@ class DecoratorTests(unittest2.TestCase):
self.assertEqual('http://localhost/oauth2callback',
query_params['redirect_uri'][0])
def test_storage_delete(self):
# Check the mocks were called.
new_http.assert_called_once_with()
@mock.patch('oauth2client.transport.get_http_object')
def test_storage_delete(self, new_http):
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# An initial request to an oauth_required decorated path should be a
# redirect to start the OAuth dance.
response = self.app.get('/foo_path')
@@ -772,7 +767,12 @@ class DecoratorTests(unittest2.TestCase):
parse_state_value.assert_called_once_with(
'foo_path:xsrfkey123', self.current_user)
def test_aware(self):
# Check the mocks were called.
new_http.assert_called_once_with()
@mock.patch('oauth2client.transport.get_http_object')
def test_aware(self, new_http):
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# An initial request to an oauth_aware decorated path should
# not redirect.
response = self.app.get('http://localhost/bar_path/2012/01')
@@ -825,6 +825,9 @@ class DecoratorTests(unittest2.TestCase):
self.should_raise = False
self.assertEqual(None, self.decorator.credentials)
# Check the mocks were called.
new_http.assert_called_once_with()
def test_error_in_step2(self):
# An initial request to an oauth_aware decorated path should
# not redirect.
@@ -855,10 +858,14 @@ class DecoratorTests(unittest2.TestCase):
self.assertEqual(decorator.flow, decorator._tls.flow)
def test_token_response_param(self):
# No need to set-up a mock since test_required() does.
self.decorator._token_response_param = 'foobar'
self.test_required()
def test_decorator_from_client_secrets(self):
@mock.patch('oauth2client.transport.get_http_object')
def test_decorator_from_client_secrets(self, new_http):
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# Execute test after setting up mock.
decorator = appengine.OAuth2DecoratorFromClientSecrets(
datafile('client_secrets.json'),
scope=['foo_scope', 'bar_scope'])
@@ -877,6 +884,9 @@ class DecoratorTests(unittest2.TestCase):
self.assertEqual(self.decorator._revoke_uri,
self.decorator.credentials.revoke_uri)
# Check the mocks were called.
new_http.assert_called_once_with()
def test_decorator_from_client_secrets_toplevel(self):
decorator_patch = mock.patch(
'oauth2client.contrib.appengine.OAuth2DecoratorFromClientSecrets')
@@ -915,7 +925,7 @@ class DecoratorTests(unittest2.TestCase):
self.assertIn('prompt', decorator._kwargs)
def test_decorator_from_cached_client_secrets(self):
cache_mock = CacheMock()
cache_mock = http_mock.CacheMock()
load_and_cache('client_secrets.json', 'secret', cache_mock)
decorator = appengine.OAuth2DecoratorFromClientSecrets(
# filename, scope, message=None, cache=None
@@ -991,7 +1001,10 @@ class DecoratorTests(unittest2.TestCase):
# This is never set, but it's consistent with other tests.
self.assertFalse(decorator._in_error)
def test_invalid_state(self):
@mock.patch('oauth2client.transport.get_http_object')
def test_invalid_state(self, new_http):
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# Execute test after setting up mock.
with mock.patch.object(appengine, '_parse_state_value',
return_value=None, autospec=True):
# Now simulate the callback to /oauth2callback.
@@ -1002,6 +1015,9 @@ class DecoratorTests(unittest2.TestCase):
self.assertEqual('200 OK', response.status)
self.assertEqual('The authorization request failed', response.body)
# Check the mocks were called.
new_http.assert_called_once_with()
class DecoratorXsrfSecretTests(unittest2.TestCase):
"""Test xsrf_secret_key."""

View File

@@ -19,7 +19,6 @@ import json
import logging
import flask
import httplib2
import mock
import six.moves.http_client as httplib
import six.moves.urllib.parse as urlparse
@@ -29,39 +28,20 @@ import oauth2client
from oauth2client import client
from oauth2client import clientsecrets
from oauth2client.contrib import flask_util
from .. import http_mock
__author__ = 'jonwayne@google.com (Jon Wayne Parrott)'
class Http2Mock(object):
"""Mock httplib2.Http for code exchange / refresh"""
def __init__(self, status=httplib.OK, **kwargs):
self.status = status
self.content = {
'access_token': 'foo_access_token',
'refresh_token': 'foo_refresh_token',
'expires_in': 3600,
'extra': 'value',
}
self.content.update(kwargs)
def request(self, token_uri, method, body, headers, *args, **kwargs):
self.body = body
self.headers = headers
return (self, json.dumps(self.content).encode('utf-8'))
def __enter__(self):
self.httplib2_orig = httplib2.Http
httplib2.Http = self
return self
def __exit__(self, exc_type, exc_value, traceback):
httplib2.Http = self.httplib2_orig
def __call__(self, *args, **kwargs):
return self
DEFAULT_RESP = """\
{
"access_token": "foo_access_token",
"expires_in": 3600,
"extra": "value",
"refresh_token": "foo_refresh_token"
}
"""
class FlaskOAuth2Tests(unittest2.TestCase):
@@ -246,7 +226,12 @@ class FlaskOAuth2Tests(unittest2.TestCase):
def test_callback_view(self):
self.oauth2.storage = mock.Mock()
with self.app.test_client() as client:
with Http2Mock() as http:
with mock.patch(
'oauth2client.transport.get_http_object') as new_http:
# Set-up mock.
new_http.return_value = http = http_mock.HttpMock(
data=DEFAULT_RESP)
# Run tests.
state = self._setup_callback_state(client)
response = client.get(
@@ -258,6 +243,9 @@ class FlaskOAuth2Tests(unittest2.TestCase):
self.assertIn('codez', http.body)
self.assertTrue(self.oauth2.storage.put.called)
# Check the mocks were called.
new_http.assert_called_once_with()
def test_authorize_callback(self):
self.oauth2.authorize_callback = mock.Mock()
self.test_callback_view()
@@ -296,11 +284,20 @@ class FlaskOAuth2Tests(unittest2.TestCase):
with self.app.test_client() as client:
state = self._setup_callback_state(client)
with Http2Mock(status=httplib.INTERNAL_SERVER_ERROR):
with mock.patch(
'oauth2client.transport.get_http_object') as new_http:
# Set-up mock.
new_http.return_value = http_mock.HttpMock(
headers={'status': httplib.INTERNAL_SERVER_ERROR},
data=DEFAULT_RESP)
# Run tests.
response = client.get(
'/oauth2callback?state={0}&code=codez'.format(state))
self.assertEqual(response.status_code, httplib.BAD_REQUEST)
# Check the mocks were called.
new_http.assert_called_once_with()
# Invalid state json
with self.app.test_client() as client:
with client.session_transaction() as session:
@@ -495,7 +492,10 @@ class FlaskOAuth2Tests(unittest2.TestCase):
def test_incremental_auth_exchange(self):
self._create_incremental_auth_app()
with Http2Mock():
with mock.patch('oauth2client.transport.get_http_object') as new_http:
# Set-up mock.
new_http.return_value = http_mock.HttpMock(data=DEFAULT_RESP)
# Run tests.
with self.app.test_client() as client:
state = self._setup_callback_state(
client,
@@ -511,16 +511,21 @@ class FlaskOAuth2Tests(unittest2.TestCase):
self.assertTrue(
credentials.has_scopes(['email', 'one', 'two']))
# Check the mocks were called.
new_http.assert_called_once_with()
def test_refresh(self):
token_val = 'new_token'
json_resp = '{"access_token": "%s"}' % (token_val,)
http = http_mock.HttpMock(data=json_resp)
with self.app.test_request_context():
with mock.patch('flask.session'):
self.oauth2.storage.put(self._generate_credentials())
self.oauth2.credentials.refresh(
Http2Mock(access_token='new_token'))
self.oauth2.credentials.refresh(http)
self.assertEqual(
self.oauth2.storage.get().access_token, 'new_token')
self.oauth2.storage.get().access_token, token_val)
def test_delete(self):
with self.app.test_request_context():

View File

@@ -17,7 +17,6 @@
import datetime
import json
import httplib2
import mock
from six.moves import http_client
from tests.contrib.test_metadata import request_mock
@@ -129,12 +128,12 @@ class AppAssertionCredentialsTests(unittest2.TestCase):
service_account='default')
@mock.patch('oauth2client.contrib._metadata.get_service_account_info',
side_effect=httplib2.HttpLib2Error('No Such Email'))
side_effect=http_client.HTTPException('No Such Email'))
def test_retrieve_scopes_bad_email(self, metadata):
http_request = mock.MagicMock()
http_mock = mock.MagicMock(request=http_request)
credentials = gce.AppAssertionCredentials(email='b@example.com')
with self.assertRaises(httplib2.HttpLib2Error):
with self.assertRaises(http_client.HTTPException):
credentials.retrieve_scopes(http_mock)
metadata.assert_called_once_with(http_request,

View File

@@ -15,12 +15,13 @@
import datetime
import json
import httplib2
import mock
from six.moves import http_client
import unittest2
from oauth2client.contrib import _metadata
from .. import http_mock
PATH = 'instance/service-accounts/default'
DATA = {'foo': 'bar'}
@@ -31,12 +32,9 @@ EXPECTED_KWARGS = dict(headers=_metadata.METADATA_HEADERS)
def request_mock(status, content_type, content):
return mock.MagicMock(return_value=(
httplib2.Response(
{'status': status, 'content-type': content_type}
),
content.encode('utf-8')
))
resp = http_mock.ResponseMock(
{'status': status, 'content-type': content_type})
return mock.Mock(return_value=(resp, content.encode('utf-8')))
class TestMetadata(unittest2.TestCase):

View File

@@ -12,17 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Copy of googleapiclient.http's mock functionality."""
"""HTTP helpers mock functionality."""
import httplib2
# TODO(craigcitro): Find a cleaner way to share this code with googleapiclient.
class ResponseMock(dict):
"""Mock HTTP response"""
def __init__(self, vals=None):
if vals is None:
vals = {}
self.update(vals)
self.status = int(self.get('status', 200))
class HttpMock(object):
"""Mock of httplib2.Http"""
"""Mock of HTTP object."""
def __init__(self, headers=None):
def __init__(self, headers=None, data=None):
"""HttpMock constructor.
Args:
@@ -30,7 +36,7 @@ class HttpMock(object):
"""
if headers is None:
headers = {'status': '200'}
self.data = None
self.data = data
self.response_headers = headers
self.headers = None
self.uri = None
@@ -48,15 +54,15 @@ class HttpMock(object):
self.method = method
self.body = body
self.headers = headers
return httplib2.Response(self.response_headers), self.data
return ResponseMock(self.response_headers), self.data
class HttpMockSequence(object):
"""Mock of httplib2.Http
"""Mock of HTTP object with multiple return values.
Mocks a sequence of calls to request returning different responses for each
call. Create an instance initialized with the desired response headers
and content and then use as if an httplib2.Http instance::
and content and then use as if an HttpMock instance::
http = HttpMockSequence([
({'status': '401'}, b''),
@@ -99,7 +105,7 @@ class HttpMockSequence(object):
elif content == 'echo_request_body':
content = (body
if body_stream_content is None else body_stream_content)
return httplib2.Response(resp), content
return ResponseMock(resp), content
class CacheMock(object):

View File

@@ -27,7 +27,6 @@ import socket
import sys
import tempfile
import httplib2
import mock
import six
from six.moves import http_client
@@ -40,9 +39,7 @@ from oauth2client import client
from oauth2client import clientsecrets
from oauth2client import service_account
from oauth2client import util
from .http_mock import CacheMock
from .http_mock import HttpMock
from .http_mock import HttpMockSequence
from . import http_mock
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
@@ -855,7 +852,7 @@ def _token_revoke_test_helper(testcase, status, revoke_raise,
return actual_do_revoke(http_request, token)
testcase.credentials._do_revoke = do_revoke_stub
http = HttpMock(headers={'status': status})
http = http_mock.HttpMock(headers={'status': status})
if revoke_raise:
testcase.assertRaises(client.TokenRevokeError,
testcase.credentials.revoke, http)
@@ -898,11 +895,11 @@ class BasicCredentialsTests(unittest2.TestCase):
def test_token_refresh_success(self):
for status_code in client.REFRESH_STATUS_CODES:
token_response = {'access_token': '1/3w', 'expires_in': 3600}
http = HttpMockSequence([
json_resp = json.dumps(token_response).encode('utf-8')
http = http_mock.HttpMockSequence([
({'status': status_code}, b''),
({'status': '200'}, json.dumps(token_response).encode(
'utf-8')),
({'status': '200'}, 'echo_request_headers'),
({'status': http_client.OK}, json_resp),
({'status': http_client.OK}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
@@ -911,28 +908,24 @@ class BasicCredentialsTests(unittest2.TestCase):
self.assertEqual(token_response, self.credentials.token_response)
def test_recursive_authorize(self):
"""Tests that OAuth2Credentials doesn't intro. new method constraints.
Formerly, OAuth2Credentials.authorize monkeypatched the request method
of its httplib2.Http argument with a wrapper annotated with
@util.positional(1). Since the original method has no such annotation,
that meant that the wrapper was violating the contract of the original
method by adding a new requirement to it. And in fact the wrapper
itself doesn't even respect that requirement. So before the removal of
the annotation, this test would fail.
"""
# Tests that OAuth2Credentials doesn't intro. new method constraints.
# Formerly, OAuth2Credentials.authorize monkeypatched the request method
# of the passed in HTTP object with a wrapper annotated with
# @util.positional(1). Since the original method has no such annotation,
# that meant that the wrapper was violating the contract of the original
# method by adding a new requirement to it. And in fact the wrapper
# itself doesn't even respect that requirement. So before the removal of
# the annotation, this test would fail.
token_response = {'access_token': '1/3w', 'expires_in': 3600}
encoded_response = json.dumps(token_response).encode('utf-8')
http = HttpMockSequence([
({'status': '200'}, encoded_response),
])
http = http_mock.HttpMock(data=encoded_response)
http = self.credentials.authorize(http)
http = self.credentials.authorize(http)
http.request('http://example.com')
def test_token_refresh_failure(self):
for status_code in client.REFRESH_STATUS_CODES:
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': status_code}, b''),
({'status': http_client.BAD_REQUEST},
b'{"error":"access_denied"}'),
@@ -965,9 +958,7 @@ class BasicCredentialsTests(unittest2.TestCase):
self.credentials = self.credentials.from_json(original_credentials)
def test_non_401_error_response(self):
http = HttpMockSequence([
({'status': '400'}, b''),
])
http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
self.assertEqual(http_client.BAD_REQUEST, resp.status)
@@ -1010,7 +1001,7 @@ class BasicCredentialsTests(unittest2.TestCase):
# First, test that we correctly encode basic objects, making sure
# to include a bytes object. Note that oauth2client will normalize
# everything to bytes, no matter what python version we're in.
http = credentials.authorize(HttpMock())
http = credentials.authorize(http_mock.HttpMock())
headers = {u'foo': 3, b'bar': True, 'baz': b'abc'}
cleaned_headers = {b'foo': b'3', b'bar': b'True', b'baz': b'abc'}
http.request(u'http://example.com', method=u'GET', headers=headers)
@@ -1037,7 +1028,7 @@ class BasicCredentialsTests(unittest2.TestCase):
access_token, client_id, client_secret, refresh_token,
token_expiry, token_uri, user_agent, revoke_uri=revoke_uri)
http = HttpMock()
http = http_mock.HttpMock()
http = credentials.authorize(http)
http.request(u'http://example.com', method=u'GET',
headers={u'foo': u'bar'})
@@ -1107,7 +1098,7 @@ class BasicCredentialsTests(unittest2.TestCase):
'access_token': token2,
'expires_in': lifetime,
}
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': '200'}, json.dumps(token_response_first).encode(
'utf-8')),
({'status': '200'}, json.dumps(token_response_second).encode(
@@ -1181,11 +1172,12 @@ class BasicCredentialsTests(unittest2.TestCase):
# Specify a token so we can use it in the response.
credentials.access_token = 'ya29-s3kr3t'
with mock.patch('httplib2.Http',
return_value=object) as http_kls:
with mock.patch('oauth2client.transport.get_http_object',
return_value=object()) as new_http:
token_info = credentials.get_access_token()
expires_in.assert_called_once_with()
refresh_mock.assert_called_once_with(http_kls.return_value)
refresh_mock.assert_called_once_with(new_http.return_value)
new_http.assert_called_once_with()
self.assertIsInstance(token_info, client.AccessTokenInfo)
self.assertEqual(token_info.access_token,
@@ -1249,33 +1241,26 @@ class BasicCredentialsTests(unittest2.TestCase):
store.locked_put.assert_called_once_with(credentials)
def test__do_refresh_request_non_json_failure(self):
response = httplib2.Response({
'status': int(http_client.BAD_REQUEST),
})
response = http_mock.ResponseMock({'status': http_client.BAD_REQUEST})
content = u'Bad request'
error_msg = 'Invalid response {0}.'.format(int(response.status))
self._do_refresh_request_test_helper(response, content, error_msg)
def test__do_refresh_request_basic_failure(self):
response = httplib2.Response({
'status': int(http_client.INTERNAL_SERVER_ERROR),
})
response = http_mock.ResponseMock(
{'status': http_client.INTERNAL_SERVER_ERROR})
content = u'{}'
error_msg = 'Invalid response {0}.'.format(int(response.status))
self._do_refresh_request_test_helper(response, content, error_msg)
def test__do_refresh_request_failure_w_json_error(self):
response = httplib2.Response({
'status': http_client.BAD_GATEWAY,
})
response = http_mock.ResponseMock({'status': http_client.BAD_GATEWAY})
error_msg = 'Hi I am an error not a bearer'
content = json.dumps({'error': error_msg})
self._do_refresh_request_test_helper(response, content, error_msg)
def test__do_refresh_request_failure_w_json_error_and_store(self):
response = httplib2.Response({
'status': http_client.BAD_GATEWAY,
})
response = http_mock.ResponseMock({'status': http_client.BAD_GATEWAY})
error_msg = 'Where are we going wearer?'
content = json.dumps({'error': error_msg})
store = mock.MagicMock()
@@ -1283,9 +1268,8 @@ class BasicCredentialsTests(unittest2.TestCase):
store=store)
def test__do_refresh_request_failure_w_json_error_and_desc(self):
response = httplib2.Response({
'status': http_client.SERVICE_UNAVAILABLE,
})
response = http_mock.ResponseMock(
{'status': http_client.SERVICE_UNAVAILABLE})
base_error = 'Ruckus'
error_desc = 'Can you describe the ruckus'
content = json.dumps({
@@ -1328,46 +1312,35 @@ class BasicCredentialsTests(unittest2.TestCase):
logger.info.assert_called_once_with('Revoking token')
def test__do_revoke_success(self):
response = httplib2.Response({
'status': http_client.OK,
})
response = http_mock.ResponseMock()
self._do_revoke_test_helper(response, b'', None)
def test__do_revoke_success_with_store(self):
response = httplib2.Response({
'status': http_client.OK,
})
response = http_mock.ResponseMock()
store = mock.MagicMock()
self._do_revoke_test_helper(response, b'', None, store=store)
def test__do_revoke_non_json_failure(self):
response = httplib2.Response({
'status': http_client.BAD_REQUEST,
})
response = http_mock.ResponseMock({'status': http_client.BAD_REQUEST})
content = u'Bad request'
error_msg = 'Invalid response {0}.'.format(response.status)
self._do_revoke_test_helper(response, content, error_msg)
def test__do_revoke_basic_failure(self):
response = httplib2.Response({
'status': http_client.INTERNAL_SERVER_ERROR,
})
response = http_mock.ResponseMock(
{'status': http_client.INTERNAL_SERVER_ERROR})
content = u'{}'
error_msg = 'Invalid response {0}.'.format(response.status)
self._do_revoke_test_helper(response, content, error_msg)
def test__do_revoke_failure_w_json_error(self):
response = httplib2.Response({
'status': http_client.BAD_GATEWAY,
})
response = http_mock.ResponseMock({'status': http_client.BAD_GATEWAY})
error_msg = 'Hi I am an error not a bearer'
content = json.dumps({'error': error_msg})
self._do_revoke_test_helper(response, content, error_msg)
def test__do_revoke_failure_w_json_error_and_store(self):
response = httplib2.Response({
'status': http_client.BAD_GATEWAY,
})
response = http_mock.ResponseMock({'status': http_client.BAD_GATEWAY})
error_msg = 'Where are we going wearer?'
content = json.dumps({'error': error_msg})
store = mock.MagicMock()
@@ -1409,41 +1382,32 @@ class BasicCredentialsTests(unittest2.TestCase):
logger.info.assert_called_once_with('Refreshing scopes')
def test__do_retrieve_scopes_success_bad_json(self):
response = httplib2.Response({
'status': http_client.OK,
})
response = http_mock.ResponseMock()
invalid_json = b'{'
with self.assertRaises(ValueError):
self._do_retrieve_scopes_test_helper(response, invalid_json, None)
def test__do_retrieve_scopes_success(self):
response = httplib2.Response({
'status': http_client.OK,
})
response = http_mock.ResponseMock()
content = b'{"scope": "foo bar"}'
self._do_retrieve_scopes_test_helper(response, content, None,
scopes=set(['foo', 'bar']))
def test__do_retrieve_scopes_non_json_failure(self):
response = httplib2.Response({
'status': http_client.BAD_REQUEST,
})
response = http_mock.ResponseMock({'status': http_client.BAD_REQUEST})
content = u'Bad request'
error_msg = 'Invalid response {0}.'.format(response.status)
self._do_retrieve_scopes_test_helper(response, content, error_msg)
def test__do_retrieve_scopes_basic_failure(self):
response = httplib2.Response({
'status': http_client.INTERNAL_SERVER_ERROR,
})
response = http_mock.ResponseMock(
{'status': http_client.INTERNAL_SERVER_ERROR})
content = u'{}'
error_msg = 'Invalid response {0}.'.format(response.status)
self._do_retrieve_scopes_test_helper(response, content, error_msg)
def test__do_retrieve_scopes_failure_w_json_error(self):
response = httplib2.Response({
'status': http_client.BAD_GATEWAY,
})
response = http_mock.ResponseMock({'status': http_client.BAD_GATEWAY})
error_msg = 'Error desc I sit at a desk'
content = json.dumps({'error_description': error_msg})
self._do_retrieve_scopes_test_helper(response, content, error_msg)
@@ -1467,7 +1431,7 @@ class BasicCredentialsTests(unittest2.TestCase):
def test_retrieve_scopes(self):
info_response_first = {'scope': 'foo bar'}
info_response_second = {'error_description': 'abcdef'}
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': '200'}, json.dumps(info_response_first).encode(
'utf-8')),
({'status': '400'}, json.dumps(info_response_second).encode(
@@ -1496,7 +1460,7 @@ class BasicCredentialsTests(unittest2.TestCase):
b' "expires_in":3600,'
b' "id_token": "' + jwt + b'"'
b'}')
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': status_code}, b''),
({'status': '200'}, token_response),
({'status': '200'}, 'echo_request_headers'),
@@ -1517,9 +1481,8 @@ class AccessTokenCredentialsTests(unittest2.TestCase):
def test_token_refresh_success(self):
for status_code in client.REFRESH_STATUS_CODES:
http = HttpMockSequence([
({'status': status_code}, b''),
])
http = http_mock.HttpMock(
headers={'status': status_code}, data=b'')
http = self.credentials.authorize(http)
with self.assertRaises(client.AccessTokenCredentialsError):
resp, content = http.request('http://example.com')
@@ -1535,15 +1498,13 @@ class AccessTokenCredentialsTests(unittest2.TestCase):
valid_bool_value=False, token_attr='access_token')
def test_non_401_error_response(self):
http = HttpMockSequence([
({'status': '400'}, b''),
])
http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
self.assertEqual(http_client.BAD_REQUEST, resp.status)
def test_auth_header_sent(self):
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': '200'}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
@@ -1578,7 +1539,7 @@ class TestAssertionCredentials(unittest2.TestCase):
body['grant_type'][0])
def test_assertion_refresh(self):
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': '200'}, b'{"access_token":"1/3w"}'),
({'status': '200'}, 'echo_request_headers'),
])
@@ -1758,12 +1719,15 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
'user_code': user_code,
'verification_url': ver_url,
})
http = HttpMockSequence([
http = http_mock.HttpMockSequence([
({'status': http_client.OK}, content),
])
if default_http:
with mock.patch('httplib2.Http', return_value=http):
with mock.patch('oauth2client.transport.get_http_object',
return_value=http) as new_http:
result = flow.step1_get_device_and_user_codes()
# Check the mock was called.
new_http.assert_called_once_with()
else:
result = flow.step1_get_device_and_user_codes(http=http)
@@ -1803,9 +1767,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
def _step1_get_device_and_user_codes_fail_helper(self, status,
content, error_msg):
flow = client.OAuth2WebServerFlow('CID', scope='foo')
http = HttpMockSequence([
({'status': status}, content),
])
http = http_mock.HttpMock(headers={'status': status}, data=content)
with self.assertRaises(client.OAuth2DeviceCodeError) as exc_manager:
flow.step1_get_device_and_user_codes(http=http)
@@ -1849,17 +1811,19 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
client.OAuth2WebServerFlow('client_id+1')
def test_exchange_failure(self):
http = HttpMockSequence([
({'status': '400'}, b'{"error":"invalid_request"}'),
])
http = http_mock.HttpMock(
headers={'status': http_client.BAD_REQUEST},
data=b'{"error":"invalid_request"}',
)
with self.assertRaises(client.FlowExchangeError):
self.flow.step2_exchange(code='some random code', http=http)
def test_urlencoded_exchange_failure(self):
http = HttpMockSequence([
({'status': '400'}, b'error=invalid_request'),
])
http = http_mock.HttpMock(
headers={'status': http_client.BAD_REQUEST},
data=b'error=invalid_request',
)
with self.assertRaisesRegexp(client.FlowExchangeError,
'invalid_request'):
@@ -1876,7 +1840,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "type": "OAuthException"'
b' }'
b'}')
http = HttpMockSequence([({'status': '400'}, payload)])
http = http_mock.HttpMock(data=payload)
with self.assertRaises(client.FlowExchangeError):
self.flow.step2_exchange(code='some random code', http=http)
@@ -1887,7 +1851,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "expires_in":3600,'
b' "refresh_token":"8xLOxBtZp8"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
credentials = self.flow.step2_exchange(
code=code, device_flow_info=device_flow_info, http=http)
self.assertEqual('SlAV32hkKG', credentials.access_token)
@@ -1916,8 +1880,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
' "expires_in":' + expires_in + ','
' "refresh_token":"' + refresh_token + '"'
'}')
http = HttpMockSequence(
[({'status': '200'}, _helpers._to_bytes(payload))])
http = http_mock.HttpMock(data=_helpers._to_bytes(payload))
credentials = self.flow.step2_exchange(code=binary_code, http=http)
self.assertEqual(access_token, credentials.access_token)
self.assertIsNotNone(credentials.token_expiry)
@@ -1943,7 +1906,9 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "expires_in":3600,'
b' "refresh_token":"8xLOxBtZp8"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMockSequence([
({'status': http_client.OK}, payload),
])
credentials = self.flow.step2_exchange(code=not_a_dict, http=http)
self.assertEqual('SlAV32hkKG', credentials.access_token)
@@ -1951,6 +1916,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
self.assertEqual('8xLOxBtZp8', credentials.refresh_token)
self.assertEqual('dummy_revoke_uri', credentials.revoke_uri)
self.assertEqual(set(['foo']), credentials.scopes)
self.assertEqual(len(http.requests), 1)
request_code = urllib.parse.parse_qs(
http.requests[0]['body'])['code'][0]
self.assertEqual(code, request_code)
@@ -1965,13 +1931,14 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
user_agent='unittest-sample/1.0',
revoke_uri='dummy_revoke_uri',
)
http = HttpMockSequence([
({'status': '200'}, b'access_token=SlAV32hkKG'),
http = http_mock.HttpMockSequence([
({'status': http_client.OK}, b'access_token=SlAV32hkKG'),
])
credentials = flow.step2_exchange(code='some random code', http=http)
self.assertEqual('SlAV32hkKG', credentials.access_token)
self.assertEqual(len(http.requests), 1)
test_request = http.requests[0]
# Did we pass the Authorization header?
self.assertEqual(test_request['headers']['Authorization'], auth_header)
@@ -1979,9 +1946,8 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
self.assertTrue('client_secret' not in test_request['body'])
def test_urlencoded_exchange_success(self):
http = HttpMockSequence([
({'status': '200'}, b'access_token=SlAV32hkKG&expires_in=3600'),
])
http = http_mock.HttpMock(
data=b'access_token=SlAV32hkKG&expires_in=3600')
credentials = self.flow.step2_exchange(code='some random code',
http=http)
@@ -1989,12 +1955,9 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
self.assertNotEqual(None, credentials.token_expiry)
def test_urlencoded_expires_param(self):
http = HttpMockSequence([
# Note the 'expires=3600' where you'd normally
# have if named 'expires_in'
({'status': '200'}, b'access_token=SlAV32hkKG&expires=3600'),
])
# Note the 'expires=3600' where you'd normally
# have if named 'expires_in'
http = http_mock.HttpMock(data=b'access_token=SlAV32hkKG&expires=3600')
credentials = self.flow.step2_exchange(code='some random code',
http=http)
self.assertNotEqual(None, credentials.token_expiry)
@@ -2004,18 +1967,16 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "access_token":"SlAV32hkKG",'
b' "refresh_token":"8xLOxBtZp8"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
credentials = self.flow.step2_exchange(code='some random code',
http=http)
self.assertEqual(None, credentials.token_expiry)
def test_urlencoded_exchange_no_expires_in(self):
http = HttpMockSequence([
# This might be redundant but just to make sure
# urlencoded access_token gets parsed correctly
({'status': '200'}, b'access_token=SlAV32hkKG'),
])
# This might be redundant but just to make sure
# urlencoded access_token gets parsed correctly
http = http_mock.HttpMock(data=b'access_token=SlAV32hkKG')
credentials = self.flow.step2_exchange(code='some random code',
http=http)
@@ -2026,7 +1987,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "access_token":"SlAV32hkKG",'
b' "refresh_token":"8xLOxBtZp8"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
code = {'error': 'thou shall not pass'}
with self.assertRaisesRegexp(
@@ -2039,7 +2000,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "refresh_token":"8xLOxBtZp8",'
b' "id_token": "stuff.payload"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
with self.assertRaises(client.VerifyJwtTokenError):
self.flow.step2_exchange(code='some random code', http=http)
@@ -2056,7 +2017,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
b' "refresh_token":"8xLOxBtZp8",'
b' "id_token": "' + jwt + b'"'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
credentials = self.flow.step2_exchange(code='some random code',
http=http)
self.assertEqual(credentials.id_token, body)
@@ -2065,7 +2026,7 @@ class OAuth2WebServerFlowTest(unittest2.TestCase):
class FlowFromCachedClientsecrets(unittest2.TestCase):
def test_flow_from_clientsecrets_cached(self):
cache_mock = CacheMock()
cache_mock = http_mock.CacheMock()
load_and_cache('client_secrets.json', 'some_secrets', cache_mock)
flow = client.flow_from_clientsecrets(
@@ -2180,9 +2141,7 @@ class CredentialsFromCodeTests(unittest2.TestCase):
def test_exchange_code_for_token(self):
token = 'asdfghjkl'
payload = json.dumps({'access_token': token, 'expires_in': 3600})
http = HttpMockSequence([
({'status': '200'}, payload.encode('utf-8')),
])
http = http_mock.HttpMock(data=payload.encode('utf-8'))
credentials = client.credentials_from_code(
self.client_id, self.client_secret, self.scope,
self.code, http=http, redirect_uri=self.redirect_uri)
@@ -2191,9 +2150,10 @@ class CredentialsFromCodeTests(unittest2.TestCase):
self.assertEqual(set(['foo']), credentials.scopes)
def test_exchange_code_for_token_fail(self):
http = HttpMockSequence([
({'status': '400'}, b'{"error":"invalid_request"}'),
])
http = http_mock.HttpMock(
headers={'status': http_client.BAD_REQUEST},
data=b'{"error":"invalid_request"}',
)
with self.assertRaises(client.FlowExchangeError):
client.credentials_from_code(
@@ -2205,7 +2165,7 @@ class CredentialsFromCodeTests(unittest2.TestCase):
b' "access_token":"asdfghjkl",'
b' "expires_in":3600'
b'}')
http = HttpMockSequence([({'status': '200'}, payload)])
http = http_mock.HttpMock(data=payload)
credentials = client.credentials_from_clientsecrets_and_code(
datafile('client_secrets.json'), self.scope,
self.code, http=http)
@@ -2214,10 +2174,8 @@ class CredentialsFromCodeTests(unittest2.TestCase):
self.assertEqual(set(['foo']), credentials.scopes)
def test_exchange_code_and_cached_file_for_token(self):
http = HttpMockSequence([
({'status': '200'}, b'{ "access_token":"asdfghjkl"}'),
])
cache_mock = CacheMock()
http = http_mock.HttpMock(data=b'{ "access_token":"asdfghjkl"}')
cache_mock = http_mock.CacheMock()
load_and_cache('client_secrets.json', 'some_secrets', cache_mock)
credentials = client.credentials_from_clientsecrets_and_code(
@@ -2227,9 +2185,10 @@ class CredentialsFromCodeTests(unittest2.TestCase):
self.assertEqual(set(['foo']), credentials.scopes)
def test_exchange_code_and_file_for_token_fail(self):
http = HttpMockSequence([
({'status': '400'}, b'{"error":"invalid_request"}'),
])
http = http_mock.HttpMock(
headers={'status': http_client.BAD_REQUEST},
data=b'{"error":"invalid_request"}',
)
with self.assertRaises(client.FlowExchangeError):
client.credentials_from_clientsecrets_and_code(

View File

@@ -22,7 +22,6 @@ import json
import os
import tempfile
import httplib2
import mock
import rsa
from six import BytesIO
@@ -488,9 +487,10 @@ class JWTAccessCredentialsTests(unittest2.TestCase):
self.assertEqual(payload['exp'], T1_EXPIRY)
self.assertEqual(uri, self.url)
self.assertEqual(bearer, b'Bearer')
return (httplib2.Response({'status': '200'}), b'')
response = mock.Mock(status=200)
return response, b''
h = httplib2.Http()
h = mock.Mock()
h.request = mock_request
self.jwt.authorize(h)
h.request(self.url)
@@ -523,9 +523,10 @@ class JWTAccessCredentialsTests(unittest2.TestCase):
self.assertEqual(payload['exp'], T1_EXPIRY)
self.assertEqual(uri, self.url)
self.assertEqual(bearer, b'Bearer')
return httplib2.Response({'status': '200'}), b''
response = mock.Mock(status=200)
return response, b''
h = httplib2.Http()
h = mock.Mock()
h.request = mock_request
jwt.authorize(h)
h.request(self.url)