Skip to content
This repository has been archived by the owner on Jan 18, 2025. It is now read-only.

Commit

Permalink
Use transport.request in tests.
Browse files Browse the repository at this point in the history
In the process

- "spring clean" the modules that were touched
- use HttpMock when HttpMockSequence not needed
- add some verifications on new HttpMock's
  • Loading branch information
dhermes committed Aug 11, 2016
1 parent b7f3eca commit 1a0c4db
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 119 deletions.
62 changes: 42 additions & 20 deletions tests/contrib/test_multiprocess_file_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@

import fasteners
import mock
from six import StringIO
import six
from six.moves import urllib_parse

from oauth2client import client
from oauth2client.contrib import multiprocess_file_storage

from ..http_mock import HttpMockSequence
from .. import http_mock


@contextlib.contextmanager
Expand Down Expand Up @@ -68,11 +69,7 @@ def _generate_token_response_http(new_token='new_token'):
'access_token': new_token,
'expires_in': '3600',
})
http = HttpMockSequence([
({'status': '200'}, token_response),
])

return http
return http_mock.HttpMock(data=token_response)


class MultiprocessStorageBehaviorTests(unittest.TestCase):
Expand Down Expand Up @@ -115,6 +112,23 @@ def test_basic_operations(self):

self.assertIsNone(credentials)

def _verify_refresh_payload(self, http, credentials):
self.assertEqual(http.requests, 1)
self.assertEqual(http.uri, credentials.token_uri)
self.assertEqual(http.method, 'POST')
expected_body = {
'grant_type': ['refresh_token'],
'client_id': [credentials.client_id],
'client_secret': [credentials.client_secret],
'refresh_token': [credentials.refresh_token],
}
self.assertEqual(urllib_parse.parse_qs(http.body), expected_body)
expected_headers = {
'content-type': 'application/x-www-form-urlencoded',
'user-agent': credentials.user_agent,
}
self.assertEqual(http.headers, expected_headers)

def test_single_process_refresh(self):
store = multiprocess_file_storage.MultiprocessFileStorage(
self.filename, 'single-process')
Expand All @@ -128,6 +142,9 @@ def test_single_process_refresh(self):
retrieved = store.get()
self.assertEqual(retrieved.access_token, 'new_token')

# Verify mocks.
self._verify_refresh_payload(http, credentials)

def test_multi_process_refresh(self):
# This will test that two processes attempting to refresh credentials
# will only refresh once.
Expand All @@ -136,6 +153,7 @@ def test_multi_process_refresh(self):
credentials = _create_test_credentials()
credentials.set_store(store)
store.put(credentials)
actual_token = 'b'

def child_process_func(
die_event, ready_event, check_event): # pragma: NO COVER
Expand All @@ -156,10 +174,12 @@ def replacement_acquire_lock(*args, **kwargs):

credentials.store.acquire_lock = replacement_acquire_lock

http = _generate_token_response_http('b')
http = _generate_token_response_http(actual_token)
credentials.refresh(http)
self.assertEqual(credentials.access_token, actual_token)

self.assertEqual(credentials.access_token, 'b')
# Verify mock http.
self._verify_refresh_payload(http, credentials)

check_event = multiprocessing.Event()
with scoped_child_process(child_process_func, check_event=check_event):
Expand All @@ -168,15 +188,17 @@ def replacement_acquire_lock(*args, **kwargs):
store._backend._process_lock.acquire(blocking=False))
check_event.set()

# The child process will refresh first, so we should end up
# with 'b' as the token.
http = mock.Mock()
http = _generate_token_response_http('not ' + actual_token)
credentials.refresh(http=http)
self.assertEqual(credentials.access_token, 'b')
self.assertFalse(http.request.called)
# The child process will refresh first, so we should end up
# with `actual_token`' as the token.
self.assertEqual(credentials.access_token, actual_token)

# Make sure the refresh did not make a request.
self.assertEqual(http.requests, 0)

retrieved = store.get()
self.assertEqual(retrieved.access_token, 'b')
self.assertEqual(retrieved.access_token, actual_token)

def test_read_only_file_fail_lock(self):
credentials = _create_test_credentials()
Expand Down Expand Up @@ -233,7 +255,7 @@ def test__get_backend(self):

def test__read_write_credentials_file(self):
credentials = _create_test_credentials()
contents = StringIO()
contents = six.StringIO()

multiprocess_file_storage._write_credentials_file(
contents, {'key': credentials})
Expand All @@ -253,23 +275,23 @@ def test__read_write_credentials_file(self):
# the invalid one but still load the valid one.
data['credentials']['invalid'] = '123'
results = multiprocess_file_storage._load_credentials_file(
StringIO(json.dumps(data)))
six.StringIO(json.dumps(data)))
self.assertNotIn('invalid', results)
self.assertEqual(
results['key'].access_token, credentials.access_token)

def test__load_credentials_file_invalid_json(self):
contents = StringIO('{[')
contents = six.StringIO('{[')
self.assertEqual(
multiprocess_file_storage._load_credentials_file(contents), {})

def test__load_credentials_file_no_file_version(self):
contents = StringIO('{}')
contents = six.StringIO('{}')
self.assertEqual(
multiprocess_file_storage._load_credentials_file(contents), {})

def test__load_credentials_file_bad_file_version(self):
contents = StringIO(json.dumps({'file_version': 1}))
contents = six.StringIO(json.dumps({'file_version': 1}))
self.assertEqual(
multiprocess_file_storage._load_credentials_file(contents), {})

Expand Down
2 changes: 1 addition & 1 deletion tests/http_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class HttpMockSequence(object):
({'status': '200'}, b'{"access_token":"1/3w","expires_in":3600}'),
({'status': '200'}, 'echo_request_headers'),
])
resp, content = http.request("http://examples.com")
resp, content = http.request('http://examples.com')
There are special values you can pass in for content to trigger
behavours that are helpful in testing.
Expand Down
51 changes: 28 additions & 23 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from oauth2client import client
from oauth2client import clientsecrets
from oauth2client import service_account
from oauth2client import transport
from . import http_mock

__author__ = '[email protected] (Joe Gregorio)'
Expand Down Expand Up @@ -899,7 +900,7 @@ def test_token_refresh_success(self):
({'status': http_client.OK}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(b'Bearer 1/3w', content[b'Authorization'])
self.assertFalse(self.credentials.access_token_expired)
self.assertEqual(token_response, self.credentials.token_response)
Expand All @@ -918,7 +919,7 @@ def test_recursive_authorize(self):
http = http_mock.HttpMock(data=encoded_response)
http = self.credentials.authorize(http)
http = self.credentials.authorize(http)
http.request('http://example.com')
transport.request(http, 'http://example.com')

def test_token_refresh_failure(self):
for status_code in client.REFRESH_STATUS_CODES:
Expand All @@ -930,7 +931,7 @@ def test_token_refresh_failure(self):
http = self.credentials.authorize(http)
with self.assertRaises(
client.HttpAccessTokenRefreshError) as exc_manager:
http.request('http://example.com')
transport.request(http, 'http://example.com')
self.assertEqual(http_client.BAD_REQUEST,
exc_manager.exception.status)
self.assertTrue(self.credentials.access_token_expired)
Expand All @@ -957,7 +958,7 @@ def test_token_revoke_fallback(self):
def test_non_401_error_response(self):
http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(http_client.BAD_REQUEST, resp.status)
self.assertEqual(None, self.credentials.token_response)

Expand Down Expand Up @@ -1001,16 +1002,18 @@ def test_unicode_header_checks(self):
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)
transport.request(
http, u'http://example.com', method=u'GET', headers=headers)
for k, v in cleaned_headers.items():
self.assertTrue(k in http.headers)
self.assertEqual(v, http.headers[k])

# Next, test that we do fail on unicode.
unicode_str = six.unichr(40960) + 'abcd'
with self.assertRaises(client.NonAsciiHeaderError):
http.request(u'http://example.com', method=u'GET',
headers={u'foo': unicode_str})
transport.request(
http, u'http://example.com', method=u'GET',
headers={u'foo': unicode_str})

def test_no_unicode_in_request_params(self):
access_token = u'foo'
Expand All @@ -1027,17 +1030,18 @@ def test_no_unicode_in_request_params(self):

http = http_mock.HttpMock()
http = credentials.authorize(http)
http.request(u'http://example.com', method=u'GET',
headers={u'foo': u'bar'})
transport.request(
http, u'http://example.com', method=u'GET',
headers={u'foo': u'bar'})
for k, v in six.iteritems(http.headers):
self.assertIsInstance(k, six.binary_type)
self.assertIsInstance(v, six.binary_type)

# Test again with unicode strings that can't simply be converted
# to ASCII.
with self.assertRaises(client.NonAsciiHeaderError):
http.request(
u'http://example.com', method=u'GET',
transport.request(
http, u'http://example.com', method=u'GET',
headers={u'foo': u'\N{COMET}'})

self.credentials.token_response = 'foobar'
Expand Down Expand Up @@ -1473,7 +1477,7 @@ def test_refresh_updates_id_token(self):
({'status': '200'}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(self.credentials.id_token, body)


Expand All @@ -1492,7 +1496,7 @@ def test_token_refresh_success(self):
headers={'status': status_code}, data=b'')
http = self.credentials.authorize(http)
with self.assertRaises(client.AccessTokenCredentialsError):
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')

def test_token_revoke_success(self):
_token_revoke_test_helper(
Expand All @@ -1507,15 +1511,15 @@ def test_token_revoke_failure(self):
def test_non_401_error_response(self):
http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(http_client.BAD_REQUEST, resp.status)

def test_auth_header_sent(self):
http = http_mock.HttpMockSequence([
({'status': '200'}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(b'Bearer foo', content[b'Authorization'])


Expand Down Expand Up @@ -1551,7 +1555,7 @@ def test_assertion_refresh(self):
({'status': '200'}, 'echo_request_headers'),
])
http = self.credentials.authorize(http)
resp, content = http.request('http://example.com')
resp, content = transport.request(http, 'http://example.com')
self.assertEqual(b'Bearer 1/3w', content[b'Authorization'])

def test_token_revoke_success(self):
Expand Down Expand Up @@ -1742,16 +1746,17 @@ def _step1_get_device_and_user_codes_helper(
device_code, user_code, None, ver_url, None)
self.assertEqual(result, expected)
self.assertEqual(len(http.requests), 1)
self.assertEqual(
http.requests[0]['uri'], oauth2client.GOOGLE_DEVICE_URI)
body = http.requests[0]['body']
self.assertEqual(urllib.parse.parse_qs(body),
{'client_id': [flow.client_id],
'scope': [flow.scope]})
info = http.requests[0]
self.assertEqual(info['uri'], oauth2client.GOOGLE_DEVICE_URI)
expected_body = {
'client_id': [flow.client_id],
'scope': [flow.scope],
}
self.assertEqual(urllib.parse.parse_qs(info['body']), expected_body)
headers = {'content-type': 'application/x-www-form-urlencoded'}
if extra_headers is not None:
headers.update(extra_headers)
self.assertEqual(http.requests[0]['headers'], headers)
self.assertEqual(info['headers'], headers)

def test_step1_get_device_and_user_codes(self):
self._step1_get_device_and_user_codes_helper()
Expand Down
Loading

0 comments on commit 1a0c4db

Please sign in to comment.