blob: 2de87a16323b83ed65352efbc2b9af1e5f85cafc [file] [log] [blame]
Joe Gregorioccc79542011-02-19 00:05:26 -05001#!/usr/bin/python2.4
2#
3# Copyright 2010 Google Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17
Joe Gregorio0bc70912011-05-24 15:30:49 -040018"""Oauth2client tests
Joe Gregorioccc79542011-02-19 00:05:26 -050019
Joe Gregorio0bc70912011-05-24 15:30:49 -040020Unit tests for oauth2client.
Joe Gregorioccc79542011-02-19 00:05:26 -050021"""
22
23__author__ = 'jcgregorio@google.com (Joe Gregorio)'
24
Joe Gregorio8b4c1732011-12-06 11:28:29 -050025import base64
Joe Gregorio562b7312011-09-15 09:06:38 -040026import datetime
Joe Gregorioe1de4162011-02-23 11:30:29 -050027import httplib2
Joe Gregorio32d852d2012-06-14 09:08:18 -040028import os
Joe Gregorioccc79542011-02-19 00:05:26 -050029import unittest
30import urlparse
Joe Gregorioe1de4162011-02-23 11:30:29 -050031
Joe Gregorioccc79542011-02-19 00:05:26 -050032try:
33 from urlparse import parse_qs
34except ImportError:
35 from cgi import parse_qs
36
Joe Gregorio83f2ee62012-12-06 15:25:54 -050037from apiclient.http import HttpMock
Joe Gregorioccc79542011-02-19 00:05:26 -050038from apiclient.http import HttpMockSequence
Joe Gregorio549230c2012-01-11 10:38:05 -050039from oauth2client.anyjson import simplejson
Joe Gregorioc29aaa92012-07-16 16:16:31 -040040from oauth2client.clientsecrets import _loadfile
Joe Gregorioccc79542011-02-19 00:05:26 -050041from oauth2client.client import AccessTokenCredentials
42from oauth2client.client import AccessTokenCredentialsError
43from oauth2client.client import AccessTokenRefreshError
JacobMoshenko8e905102011-06-20 09:53:10 -040044from oauth2client.client import AssertionCredentials
Joe Gregorio08cdcb82012-03-14 00:09:33 -040045from oauth2client.client import Credentials
Joe Gregorioccc79542011-02-19 00:05:26 -050046from oauth2client.client import FlowExchangeError
Joe Gregorio08cdcb82012-03-14 00:09:33 -040047from oauth2client.client import MemoryCache
Joe Gregorio83f2ee62012-12-06 15:25:54 -050048from oauth2client.client import NonAsciiHeaderError
Joe Gregorioccc79542011-02-19 00:05:26 -050049from oauth2client.client import OAuth2Credentials
50from oauth2client.client import OAuth2WebServerFlow
Joe Gregoriof2326c02012-02-09 12:18:44 -050051from oauth2client.client import OOB_CALLBACK_URN
Joe Gregorio8b4c1732011-12-06 11:28:29 -050052from oauth2client.client import VerifyJwtTokenError
53from oauth2client.client import _extract_id_token
Joe Gregorio32d852d2012-06-14 09:08:18 -040054from oauth2client.client import credentials_from_clientsecrets_and_code
Joe Gregorio83f2ee62012-12-06 15:25:54 -050055from oauth2client.client import credentials_from_code
Joe Gregorioc29aaa92012-07-16 16:16:31 -040056from oauth2client.client import flow_from_clientsecrets
Joe Gregorio32d852d2012-06-14 09:08:18 -040057
58DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
59
Joe Gregorio68a8cfe2012-08-03 16:17:40 -040060
Joe Gregorio32d852d2012-06-14 09:08:18 -040061def datafile(filename):
62 return os.path.join(DATA_DIR, filename)
Joe Gregorioccc79542011-02-19 00:05:26 -050063
Joe Gregorio68a8cfe2012-08-03 16:17:40 -040064
Joe Gregorioc29aaa92012-07-16 16:16:31 -040065def load_and_cache(existing_file, fakename, cache_mock):
66 client_type, client_info = _loadfile(datafile(existing_file))
67 cache_mock.cache[fakename] = {client_type: client_info}
68
Joe Gregorio68a8cfe2012-08-03 16:17:40 -040069
Joe Gregorioc29aaa92012-07-16 16:16:31 -040070class CacheMock(object):
71 def __init__(self):
72 self.cache = {}
73
74 def get(self, key, namespace=''):
75 # ignoring namespace for easier testing
76 return self.cache.get(key, None)
77
78 def set(self, key, value, namespace=''):
79 # ignoring namespace for easier testing
80 self.cache[key] = value
81
Joe Gregorioccc79542011-02-19 00:05:26 -050082
Joe Gregorio08cdcb82012-03-14 00:09:33 -040083class CredentialsTests(unittest.TestCase):
84
85 def test_to_from_json(self):
86 credentials = Credentials()
87 json = credentials.to_json()
88 restored = Credentials.new_from_json(json)
89
90
Joe Gregorio83f2ee62012-12-06 15:25:54 -050091class BasicCredentialsTests(unittest.TestCase):
Joe Gregorioccc79542011-02-19 00:05:26 -050092
93 def setUp(self):
94 access_token = "foo"
95 client_id = "some_client_id"
96 client_secret = "cOuDdkfjxxnv+"
97 refresh_token = "1/0/a.df219fjls0"
Joe Gregorio562b7312011-09-15 09:06:38 -040098 token_expiry = datetime.datetime.utcnow()
Joe Gregorioccc79542011-02-19 00:05:26 -050099 token_uri = "https://www.google.com/accounts/o8/oauth2/token"
100 user_agent = "refresh_checker/1.0"
101 self.credentials = OAuth2Credentials(
102 access_token, client_id, client_secret,
103 refresh_token, token_expiry, token_uri,
104 user_agent)
105
106 def test_token_refresh_success(self):
Joe Gregorio7c7c6b12012-07-16 16:31:01 -0400107 # Older API (GData) respond with 403
108 for status_code in ['401', '403']:
109 http = HttpMockSequence([
110 ({'status': status_code}, ''),
111 ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'),
112 ({'status': '200'}, 'echo_request_headers'),
113 ])
114 http = self.credentials.authorize(http)
115 resp, content = http.request("http://example.com")
116 self.assertEqual('Bearer 1/3w', content['Authorization'])
117 self.assertFalse(self.credentials.access_token_expired)
Joe Gregorioccc79542011-02-19 00:05:26 -0500118
119 def test_token_refresh_failure(self):
Joe Gregorio7c7c6b12012-07-16 16:31:01 -0400120 # Older API (GData) respond with 403
121 for status_code in ['401', '403']:
122 http = HttpMockSequence([
123 ({'status': status_code}, ''),
124 ({'status': '400'}, '{"error":"access_denied"}'),
125 ])
126 http = self.credentials.authorize(http)
127 try:
128 http.request("http://example.com")
129 self.fail("should raise AccessTokenRefreshError exception")
130 except AccessTokenRefreshError:
131 pass
132 self.assertTrue(self.credentials.access_token_expired)
Joe Gregorioccc79542011-02-19 00:05:26 -0500133
134 def test_non_401_error_response(self):
135 http = HttpMockSequence([
136 ({'status': '400'}, ''),
137 ])
138 http = self.credentials.authorize(http)
139 resp, content = http.request("http://example.com")
140 self.assertEqual(400, resp.status)
141
Joe Gregorio562b7312011-09-15 09:06:38 -0400142 def test_to_from_json(self):
143 json = self.credentials.to_json()
144 instance = OAuth2Credentials.from_json(json)
Joe Gregorio654f4a22012-02-09 14:15:44 -0500145 self.assertEqual(OAuth2Credentials, type(instance))
Joe Gregorio1daa71b2011-09-15 18:12:14 -0400146 instance.token_expiry = None
147 self.credentials.token_expiry = None
148
Joe Gregorio654f4a22012-02-09 14:15:44 -0500149 self.assertEqual(instance.__dict__, self.credentials.__dict__)
Joe Gregorio562b7312011-09-15 09:06:38 -0400150
Joe Gregorio83f2ee62012-12-06 15:25:54 -0500151 def test_no_unicode_in_request_params(self):
152 access_token = u'foo'
153 client_id = u'some_client_id'
154 client_secret = u'cOuDdkfjxxnv+'
155 refresh_token = u'1/0/a.df219fjls0'
156 token_expiry = unicode(datetime.datetime.utcnow())
157 token_uri = u'https://www.google.com/accounts/o8/oauth2/token'
158 user_agent = u'refresh_checker/1.0'
159 credentials = OAuth2Credentials(access_token, client_id, client_secret,
160 refresh_token, token_expiry, token_uri,
161 user_agent)
162
163 http = HttpMock(headers={'status': '200'})
164 http = credentials.authorize(http)
165 http.request(u'http://example.com', method=u'GET', headers={
166 u'foo': u'bar'
167 })
168 for k, v in http.headers.iteritems():
169 self.assertEqual(str, type(k))
170 self.assertEqual(str, type(v))
171
172 # Test again with unicode strings that can't simple be converted to ASCII.
173 try:
174 http.request(
175 u'http://example.com', method=u'GET', headers={u'foo': u'\N{COMET}'})
176 self.fail('Expected exception to be raised.')
177 except NonAsciiHeaderError:
178 pass
179
Joe Gregorioccc79542011-02-19 00:05:26 -0500180
181class AccessTokenCredentialsTests(unittest.TestCase):
182
183 def setUp(self):
184 access_token = "foo"
185 user_agent = "refresh_checker/1.0"
186 self.credentials = AccessTokenCredentials(access_token, user_agent)
187
188 def test_token_refresh_success(self):
Joe Gregorio7c7c6b12012-07-16 16:31:01 -0400189 # Older API (GData) respond with 403
190 for status_code in ['401', '403']:
191 http = HttpMockSequence([
192 ({'status': status_code}, ''),
193 ])
194 http = self.credentials.authorize(http)
195 try:
196 resp, content = http.request("http://example.com")
197 self.fail("should throw exception if token expires")
198 except AccessTokenCredentialsError:
199 pass
200 except Exception:
201 self.fail("should only throw AccessTokenCredentialsError")
Joe Gregorioccc79542011-02-19 00:05:26 -0500202
203 def test_non_401_error_response(self):
204 http = HttpMockSequence([
205 ({'status': '400'}, ''),
206 ])
207 http = self.credentials.authorize(http)
Joe Gregorio83cd4392011-06-20 10:11:35 -0400208 resp, content = http.request('http://example.com')
Joe Gregorioccc79542011-02-19 00:05:26 -0500209 self.assertEqual(400, resp.status)
210
Joe Gregorio83cd4392011-06-20 10:11:35 -0400211 def test_auth_header_sent(self):
212 http = HttpMockSequence([
213 ({'status': '200'}, 'echo_request_headers'),
214 ])
215 http = self.credentials.authorize(http)
216 resp, content = http.request('http://example.com')
Joe Gregorio654f4a22012-02-09 14:15:44 -0500217 self.assertEqual('Bearer foo', content['Authorization'])
Joe Gregorioccc79542011-02-19 00:05:26 -0500218
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500219
JacobMoshenko8e905102011-06-20 09:53:10 -0400220class TestAssertionCredentials(unittest.TestCase):
221 assertion_text = "This is the assertion"
222 assertion_type = "http://www.google.com/assertionType"
223
224 class AssertionCredentialsTestImpl(AssertionCredentials):
225
226 def _generate_assertion(self):
227 return TestAssertionCredentials.assertion_text
228
229 def setUp(self):
230 user_agent = "fun/2.0"
231 self.credentials = self.AssertionCredentialsTestImpl(self.assertion_type,
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400232 user_agent=user_agent)
JacobMoshenko8e905102011-06-20 09:53:10 -0400233
234 def test_assertion_body(self):
235 body = urlparse.parse_qs(self.credentials._generate_refresh_request_body())
Joe Gregorio654f4a22012-02-09 14:15:44 -0500236 self.assertEqual(self.assertion_text, body['assertion'][0])
237 self.assertEqual(self.assertion_type, body['assertion_type'][0])
JacobMoshenko8e905102011-06-20 09:53:10 -0400238
239 def test_assertion_refresh(self):
240 http = HttpMockSequence([
241 ({'status': '200'}, '{"access_token":"1/3w"}'),
242 ({'status': '200'}, 'echo_request_headers'),
243 ])
244 http = self.credentials.authorize(http)
245 resp, content = http.request("http://example.com")
Joe Gregorio654f4a22012-02-09 14:15:44 -0500246 self.assertEqual('Bearer 1/3w', content['Authorization'])
JacobMoshenko8e905102011-06-20 09:53:10 -0400247
248
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500249class ExtractIdTokenText(unittest.TestCase):
250 """Tests _extract_id_token()."""
251
252 def test_extract_success(self):
253 body = {'foo': 'bar'}
254 payload = base64.urlsafe_b64encode(simplejson.dumps(body)).strip('=')
255 jwt = 'stuff.' + payload + '.signature'
256
257 extracted = _extract_id_token(jwt)
Joe Gregorio654f4a22012-02-09 14:15:44 -0500258 self.assertEqual(extracted, body)
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500259
260 def test_extract_failure(self):
261 body = {'foo': 'bar'}
262 payload = base64.urlsafe_b64encode(simplejson.dumps(body)).strip('=')
263 jwt = 'stuff.' + payload
264
265 self.assertRaises(VerifyJwtTokenError, _extract_id_token, jwt)
266
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400267
Joe Gregorioccc79542011-02-19 00:05:26 -0500268class OAuth2WebServerFlowTest(unittest.TestCase):
269
270 def setUp(self):
271 self.flow = OAuth2WebServerFlow(
272 client_id='client_id+1',
273 client_secret='secret+1',
274 scope='foo',
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400275 redirect_uri=OOB_CALLBACK_URN,
Joe Gregorioccc79542011-02-19 00:05:26 -0500276 user_agent='unittest-sample/1.0',
277 )
278
279 def test_construct_authorize_url(self):
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400280 authorize_url = self.flow.step1_get_authorize_url()
Joe Gregorioccc79542011-02-19 00:05:26 -0500281
282 parsed = urlparse.urlparse(authorize_url)
283 q = parse_qs(parsed[4])
Joe Gregorio654f4a22012-02-09 14:15:44 -0500284 self.assertEqual('client_id+1', q['client_id'][0])
285 self.assertEqual('code', q['response_type'][0])
286 self.assertEqual('foo', q['scope'][0])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400287 self.assertEqual(OOB_CALLBACK_URN, q['redirect_uri'][0])
Joe Gregorio654f4a22012-02-09 14:15:44 -0500288 self.assertEqual('offline', q['access_type'][0])
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400289
Joe Gregorio32f73192012-10-23 16:13:44 -0400290 def test_override_flow_via_kwargs(self):
291 """Passing kwargs to override defaults."""
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400292 flow = OAuth2WebServerFlow(
293 client_id='client_id+1',
294 client_secret='secret+1',
295 scope='foo',
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400296 redirect_uri=OOB_CALLBACK_URN,
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400297 user_agent='unittest-sample/1.0',
Joe Gregorio32f73192012-10-23 16:13:44 -0400298 access_type='online',
299 response_type='token'
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400300 )
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400301 authorize_url = flow.step1_get_authorize_url()
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400302
303 parsed = urlparse.urlparse(authorize_url)
304 q = parse_qs(parsed[4])
Joe Gregorio654f4a22012-02-09 14:15:44 -0500305 self.assertEqual('client_id+1', q['client_id'][0])
Joe Gregorio32f73192012-10-23 16:13:44 -0400306 self.assertEqual('token', q['response_type'][0])
Joe Gregorio654f4a22012-02-09 14:15:44 -0500307 self.assertEqual('foo', q['scope'][0])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400308 self.assertEqual(OOB_CALLBACK_URN, q['redirect_uri'][0])
Joe Gregorio654f4a22012-02-09 14:15:44 -0500309 self.assertEqual('online', q['access_type'][0])
Joe Gregorioccc79542011-02-19 00:05:26 -0500310
311 def test_exchange_failure(self):
312 http = HttpMockSequence([
JacobMoshenko8e905102011-06-20 09:53:10 -0400313 ({'status': '400'}, '{"error":"invalid_request"}'),
Joe Gregorioccc79542011-02-19 00:05:26 -0500314 ])
315
316 try:
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400317 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioccc79542011-02-19 00:05:26 -0500318 self.fail("should raise exception if exchange doesn't get 200")
319 except FlowExchangeError:
320 pass
321
Joe Gregorioddb969a2012-07-11 11:04:12 -0400322 def test_urlencoded_exchange_failure(self):
323 http = HttpMockSequence([
324 ({'status': '400'}, "error=invalid_request"),
325 ])
326
327 try:
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400328 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioddb969a2012-07-11 11:04:12 -0400329 self.fail("should raise exception if exchange doesn't get 200")
330 except FlowExchangeError, e:
331 self.assertEquals('invalid_request', str(e))
332
333 def test_exchange_failure_with_json_error(self):
334 # Some providers have "error" attribute as a JSON object
335 # in place of regular string.
336 # This test makes sure no strange object-to-string coversion
337 # exceptions are being raised instead of FlowExchangeError.
338 http = HttpMockSequence([
339 ({'status': '400'},
340 """ {"error": {
341 "type": "OAuthException",
342 "message": "Error validating verification code."} }"""),
343 ])
344
345 try:
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400346 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioddb969a2012-07-11 11:04:12 -0400347 self.fail("should raise exception if exchange doesn't get 200")
348 except FlowExchangeError, e:
349 pass
350
Joe Gregorioccc79542011-02-19 00:05:26 -0500351 def test_exchange_success(self):
352 http = HttpMockSequence([
353 ({'status': '200'},
354 """{ "access_token":"SlAV32hkKG",
355 "expires_in":3600,
356 "refresh_token":"8xLOxBtZp8" }"""),
357 ])
358
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400359 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorio654f4a22012-02-09 14:15:44 -0500360 self.assertEqual('SlAV32hkKG', credentials.access_token)
361 self.assertNotEqual(None, credentials.token_expiry)
362 self.assertEqual('8xLOxBtZp8', credentials.refresh_token)
Joe Gregorioccc79542011-02-19 00:05:26 -0500363
Joe Gregorioddb969a2012-07-11 11:04:12 -0400364 def test_urlencoded_exchange_success(self):
365 http = HttpMockSequence([
366 ({'status': '200'}, "access_token=SlAV32hkKG&expires_in=3600"),
367 ])
368
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400369 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioddb969a2012-07-11 11:04:12 -0400370 self.assertEqual('SlAV32hkKG', credentials.access_token)
371 self.assertNotEqual(None, credentials.token_expiry)
372
373 def test_urlencoded_expires_param(self):
374 http = HttpMockSequence([
375 # Note the "expires=3600" where you'd normally
376 # have if named "expires_in"
377 ({'status': '200'}, "access_token=SlAV32hkKG&expires=3600"),
378 ])
379
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400380 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioddb969a2012-07-11 11:04:12 -0400381 self.assertNotEqual(None, credentials.token_expiry)
382
Joe Gregorioccc79542011-02-19 00:05:26 -0500383 def test_exchange_no_expires_in(self):
384 http = HttpMockSequence([
385 ({'status': '200'}, """{ "access_token":"SlAV32hkKG",
386 "refresh_token":"8xLOxBtZp8" }"""),
387 ])
388
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400389 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorio654f4a22012-02-09 14:15:44 -0500390 self.assertEqual(None, credentials.token_expiry)
Joe Gregorioccc79542011-02-19 00:05:26 -0500391
Joe Gregorioddb969a2012-07-11 11:04:12 -0400392 def test_urlencoded_exchange_no_expires_in(self):
393 http = HttpMockSequence([
394 # This might be redundant but just to make sure
395 # urlencoded access_token gets parsed correctly
396 ({'status': '200'}, "access_token=SlAV32hkKG"),
397 ])
398
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400399 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorioddb969a2012-07-11 11:04:12 -0400400 self.assertEqual(None, credentials.token_expiry)
401
Joe Gregorio4b4002f2012-06-14 15:41:01 -0400402 def test_exchange_fails_if_no_code(self):
403 http = HttpMockSequence([
404 ({'status': '200'}, """{ "access_token":"SlAV32hkKG",
405 "refresh_token":"8xLOxBtZp8" }"""),
406 ])
407
408 code = {'error': 'thou shall not pass'}
409 try:
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400410 credentials = self.flow.step2_exchange(code, http=http)
Joe Gregorio4b4002f2012-06-14 15:41:01 -0400411 self.fail('should raise exception if no code in dictionary.')
412 except FlowExchangeError, e:
413 self.assertTrue('shall not pass' in str(e))
414
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500415 def test_exchange_id_token_fail(self):
416 http = HttpMockSequence([
417 ({'status': '200'}, """{ "access_token":"SlAV32hkKG",
418 "refresh_token":"8xLOxBtZp8",
419 "id_token": "stuff.payload"}"""),
420 ])
421
422 self.assertRaises(VerifyJwtTokenError, self.flow.step2_exchange,
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400423 'some random code', http=http)
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500424
425 def test_exchange_id_token_fail(self):
426 body = {'foo': 'bar'}
427 payload = base64.urlsafe_b64encode(simplejson.dumps(body)).strip('=')
Joe Gregoriobd512b52011-12-06 15:39:26 -0500428 jwt = (base64.urlsafe_b64encode('stuff')+ '.' + payload + '.' +
429 base64.urlsafe_b64encode('signature'))
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500430
431 http = HttpMockSequence([
432 ({'status': '200'}, """{ "access_token":"SlAV32hkKG",
433 "refresh_token":"8xLOxBtZp8",
434 "id_token": "%s"}""" % jwt),
435 ])
436
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400437 credentials = self.flow.step2_exchange('some random code', http=http)
Joe Gregorio654f4a22012-02-09 14:15:44 -0500438 self.assertEqual(credentials.id_token, body)
Joe Gregorio8b4c1732011-12-06 11:28:29 -0500439
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400440
441class FlowFromCachedClientsecrets(unittest.TestCase):
Joe Gregorioc29aaa92012-07-16 16:16:31 -0400442
443 def test_flow_from_clientsecrets_cached(self):
444 cache_mock = CacheMock()
445 load_and_cache('client_secrets.json', 'some_secrets', cache_mock)
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400446
447 flow = flow_from_clientsecrets(
448 'some_secrets', '', redirect_uri='oob', cache=cache_mock)
Joe Gregorioc29aaa92012-07-16 16:16:31 -0400449 self.assertEquals('foo_client_secret', flow.client_secret)
450
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400451
Joe Gregorio32d852d2012-06-14 09:08:18 -0400452class CredentialsFromCodeTests(unittest.TestCase):
453 def setUp(self):
454 self.client_id = 'client_id_abc'
455 self.client_secret = 'secret_use_code'
456 self.scope = 'foo'
457 self.code = '12345abcde'
458 self.redirect_uri = 'postmessage'
459
460 def test_exchange_code_for_token(self):
461 http = HttpMockSequence([
462 ({'status': '200'},
463 """{ "access_token":"asdfghjkl",
464 "expires_in":3600 }"""),
465 ])
466 credentials = credentials_from_code(self.client_id, self.client_secret,
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400467 self.scope, self.code, redirect_uri=self.redirect_uri,
468 http=http)
Joe Gregorio32d852d2012-06-14 09:08:18 -0400469 self.assertEquals(credentials.access_token, 'asdfghjkl')
470 self.assertNotEqual(None, credentials.token_expiry)
471
472 def test_exchange_code_for_token_fail(self):
473 http = HttpMockSequence([
474 ({'status': '400'}, '{"error":"invalid_request"}'),
475 ])
476
477 try:
478 credentials = credentials_from_code(self.client_id, self.client_secret,
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400479 self.scope, self.code, redirect_uri=self.redirect_uri,
480 http=http)
Joe Gregorio32d852d2012-06-14 09:08:18 -0400481 self.fail("should raise exception if exchange doesn't get 200")
482 except FlowExchangeError:
483 pass
484
Joe Gregorio32d852d2012-06-14 09:08:18 -0400485 def test_exchange_code_and_file_for_token(self):
486 http = HttpMockSequence([
487 ({'status': '200'},
488 """{ "access_token":"asdfghjkl",
489 "expires_in":3600 }"""),
490 ])
491 credentials = credentials_from_clientsecrets_and_code(
492 datafile('client_secrets.json'), self.scope,
493 self.code, http=http)
494 self.assertEquals(credentials.access_token, 'asdfghjkl')
495 self.assertNotEqual(None, credentials.token_expiry)
496
Joe Gregorioc29aaa92012-07-16 16:16:31 -0400497 def test_exchange_code_and_cached_file_for_token(self):
498 http = HttpMockSequence([
499 ({'status': '200'}, '{ "access_token":"asdfghjkl"}'),
500 ])
501 cache_mock = CacheMock()
502 load_and_cache('client_secrets.json', 'some_secrets', cache_mock)
503
504 credentials = credentials_from_clientsecrets_and_code(
505 'some_secrets', self.scope,
506 self.code, http=http, cache=cache_mock)
507 self.assertEquals(credentials.access_token, 'asdfghjkl')
508
Joe Gregorio32d852d2012-06-14 09:08:18 -0400509 def test_exchange_code_and_file_for_token_fail(self):
510 http = HttpMockSequence([
511 ({'status': '400'}, '{"error":"invalid_request"}'),
512 ])
513
514 try:
515 credentials = credentials_from_clientsecrets_and_code(
516 datafile('client_secrets.json'), self.scope,
517 self.code, http=http)
518 self.fail("should raise exception if exchange doesn't get 200")
519 except FlowExchangeError:
520 pass
521
522
Joe Gregorio08cdcb82012-03-14 00:09:33 -0400523class MemoryCacheTests(unittest.TestCase):
524
525 def test_get_set_delete(self):
526 m = MemoryCache()
527 self.assertEqual(None, m.get('foo'))
528 self.assertEqual(None, m.delete('foo'))
529 m.set('foo', 'bar')
530 self.assertEqual('bar', m.get('foo'))
531 m.delete('foo')
532 self.assertEqual(None, m.get('foo'))
533
534
Joe Gregorioccc79542011-02-19 00:05:26 -0500535if __name__ == '__main__':
536 unittest.main()