blob: a23d1daac5d54e00492871e4d1b1caf3f4bfb5a3 [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 Gregorio562b7312011-09-15 09:06:38 -040025import datetime
Joe Gregorioe1de4162011-02-23 11:30:29 -050026import httplib2
Joe Gregorioccc79542011-02-19 00:05:26 -050027import unittest
28import urlparse
Joe Gregorioe1de4162011-02-23 11:30:29 -050029
Joe Gregorioccc79542011-02-19 00:05:26 -050030try:
31 from urlparse import parse_qs
32except ImportError:
33 from cgi import parse_qs
34
Joe Gregorio562b7312011-09-15 09:06:38 -040035try: # pragma: no cover
36 import simplejson
37except ImportError: # pragma: no cover
38 try:
39 # Try to import from django, should work on App Engine
40 from django.utils import simplejson
41 except ImportError:
42 # Should work for Python2.6 and higher.
43 import json as simplejson
44
Joe Gregorioccc79542011-02-19 00:05:26 -050045from apiclient.http import HttpMockSequence
46from oauth2client.client import AccessTokenCredentials
47from oauth2client.client import AccessTokenCredentialsError
48from oauth2client.client import AccessTokenRefreshError
JacobMoshenko8e905102011-06-20 09:53:10 -040049from oauth2client.client import AssertionCredentials
Joe Gregorioccc79542011-02-19 00:05:26 -050050from oauth2client.client import FlowExchangeError
51from oauth2client.client import OAuth2Credentials
52from oauth2client.client import OAuth2WebServerFlow
53
54
55class OAuth2CredentialsTests(unittest.TestCase):
56
57 def setUp(self):
58 access_token = "foo"
59 client_id = "some_client_id"
60 client_secret = "cOuDdkfjxxnv+"
61 refresh_token = "1/0/a.df219fjls0"
Joe Gregorio562b7312011-09-15 09:06:38 -040062 token_expiry = datetime.datetime.utcnow()
Joe Gregorioccc79542011-02-19 00:05:26 -050063 token_uri = "https://www.google.com/accounts/o8/oauth2/token"
64 user_agent = "refresh_checker/1.0"
65 self.credentials = OAuth2Credentials(
66 access_token, client_id, client_secret,
67 refresh_token, token_expiry, token_uri,
68 user_agent)
69
70 def test_token_refresh_success(self):
71 http = HttpMockSequence([
72 ({'status': '401'}, ''),
73 ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'),
74 ({'status': '200'}, 'echo_request_headers'),
75 ])
76 http = self.credentials.authorize(http)
77 resp, content = http.request("http://example.com")
78 self.assertEqual(content['authorization'], 'OAuth 1/3w')
79
80 def test_token_refresh_failure(self):
81 http = HttpMockSequence([
82 ({'status': '401'}, ''),
83 ({'status': '400'}, '{"error":"access_denied"}'),
84 ])
85 http = self.credentials.authorize(http)
86 try:
87 http.request("http://example.com")
88 self.fail("should raise AccessTokenRefreshError exception")
89 except AccessTokenRefreshError:
90 pass
91
92 def test_non_401_error_response(self):
93 http = HttpMockSequence([
94 ({'status': '400'}, ''),
95 ])
96 http = self.credentials.authorize(http)
97 resp, content = http.request("http://example.com")
98 self.assertEqual(400, resp.status)
99
Joe Gregorio562b7312011-09-15 09:06:38 -0400100 def test_to_from_json(self):
101 json = self.credentials.to_json()
102 instance = OAuth2Credentials.from_json(json)
103 self.assertEquals(type(instance), OAuth2Credentials)
Joe Gregorio1daa71b2011-09-15 18:12:14 -0400104 instance.token_expiry = None
105 self.credentials.token_expiry = None
106
Joe Gregorio562b7312011-09-15 09:06:38 -0400107 self.assertEquals(self.credentials.__dict__, instance.__dict__)
108
Joe Gregorioccc79542011-02-19 00:05:26 -0500109
110class AccessTokenCredentialsTests(unittest.TestCase):
111
112 def setUp(self):
113 access_token = "foo"
114 user_agent = "refresh_checker/1.0"
115 self.credentials = AccessTokenCredentials(access_token, user_agent)
116
117 def test_token_refresh_success(self):
118 http = HttpMockSequence([
119 ({'status': '401'}, ''),
120 ])
121 http = self.credentials.authorize(http)
122 try:
123 resp, content = http.request("http://example.com")
124 self.fail("should throw exception if token expires")
125 except AccessTokenCredentialsError:
126 pass
127 except Exception:
128 self.fail("should only throw AccessTokenCredentialsError")
129
130 def test_non_401_error_response(self):
131 http = HttpMockSequence([
132 ({'status': '400'}, ''),
133 ])
134 http = self.credentials.authorize(http)
Joe Gregorio83cd4392011-06-20 10:11:35 -0400135 resp, content = http.request('http://example.com')
Joe Gregorioccc79542011-02-19 00:05:26 -0500136 self.assertEqual(400, resp.status)
137
Joe Gregorio83cd4392011-06-20 10:11:35 -0400138 def test_auth_header_sent(self):
139 http = HttpMockSequence([
140 ({'status': '200'}, 'echo_request_headers'),
141 ])
142 http = self.credentials.authorize(http)
143 resp, content = http.request('http://example.com')
144 self.assertEqual(content['authorization'], 'OAuth foo')
Joe Gregorioccc79542011-02-19 00:05:26 -0500145
JacobMoshenko8e905102011-06-20 09:53:10 -0400146class TestAssertionCredentials(unittest.TestCase):
147 assertion_text = "This is the assertion"
148 assertion_type = "http://www.google.com/assertionType"
149
150 class AssertionCredentialsTestImpl(AssertionCredentials):
151
152 def _generate_assertion(self):
153 return TestAssertionCredentials.assertion_text
154
155 def setUp(self):
156 user_agent = "fun/2.0"
157 self.credentials = self.AssertionCredentialsTestImpl(self.assertion_type,
158 user_agent)
159
160 def test_assertion_body(self):
161 body = urlparse.parse_qs(self.credentials._generate_refresh_request_body())
162 self.assertEqual(body['assertion'][0], self.assertion_text)
163 self.assertEqual(body['assertion_type'][0], self.assertion_type)
164
165 def test_assertion_refresh(self):
166 http = HttpMockSequence([
167 ({'status': '200'}, '{"access_token":"1/3w"}'),
168 ({'status': '200'}, 'echo_request_headers'),
169 ])
170 http = self.credentials.authorize(http)
171 resp, content = http.request("http://example.com")
172 self.assertEqual(content['authorization'], 'OAuth 1/3w')
173
174
Joe Gregorioccc79542011-02-19 00:05:26 -0500175class OAuth2WebServerFlowTest(unittest.TestCase):
176
177 def setUp(self):
178 self.flow = OAuth2WebServerFlow(
179 client_id='client_id+1',
180 client_secret='secret+1',
181 scope='foo',
182 user_agent='unittest-sample/1.0',
183 )
184
185 def test_construct_authorize_url(self):
186 authorize_url = self.flow.step1_get_authorize_url('oob')
187
188 parsed = urlparse.urlparse(authorize_url)
189 q = parse_qs(parsed[4])
190 self.assertEqual(q['client_id'][0], 'client_id+1')
191 self.assertEqual(q['response_type'][0], 'code')
192 self.assertEqual(q['scope'][0], 'foo')
193 self.assertEqual(q['redirect_uri'][0], 'oob')
Joe Gregorio69a0aca2011-11-03 10:47:32 -0400194 self.assertEqual(q['access_type'][0], 'offline')
195
196 def test_override_flow_access_type(self):
197 """Passing access_type overrides the default."""
198 flow = OAuth2WebServerFlow(
199 client_id='client_id+1',
200 client_secret='secret+1',
201 scope='foo',
202 user_agent='unittest-sample/1.0',
203 access_type='online'
204 )
205 authorize_url = flow.step1_get_authorize_url('oob')
206
207 parsed = urlparse.urlparse(authorize_url)
208 q = parse_qs(parsed[4])
209 self.assertEqual(q['client_id'][0], 'client_id+1')
210 self.assertEqual(q['response_type'][0], 'code')
211 self.assertEqual(q['scope'][0], 'foo')
212 self.assertEqual(q['redirect_uri'][0], 'oob')
213 self.assertEqual(q['access_type'][0], 'online')
Joe Gregorioccc79542011-02-19 00:05:26 -0500214
215 def test_exchange_failure(self):
216 http = HttpMockSequence([
JacobMoshenko8e905102011-06-20 09:53:10 -0400217 ({'status': '400'}, '{"error":"invalid_request"}'),
Joe Gregorioccc79542011-02-19 00:05:26 -0500218 ])
219
220 try:
221 credentials = self.flow.step2_exchange('some random code', http)
222 self.fail("should raise exception if exchange doesn't get 200")
223 except FlowExchangeError:
224 pass
225
226 def test_exchange_success(self):
227 http = HttpMockSequence([
228 ({'status': '200'},
229 """{ "access_token":"SlAV32hkKG",
230 "expires_in":3600,
231 "refresh_token":"8xLOxBtZp8" }"""),
232 ])
233
234 credentials = self.flow.step2_exchange('some random code', http)
235 self.assertEqual(credentials.access_token, 'SlAV32hkKG')
236 self.assertNotEqual(credentials.token_expiry, None)
237 self.assertEqual(credentials.refresh_token, '8xLOxBtZp8')
238
Joe Gregorioccc79542011-02-19 00:05:26 -0500239 def test_exchange_no_expires_in(self):
240 http = HttpMockSequence([
241 ({'status': '200'}, """{ "access_token":"SlAV32hkKG",
242 "refresh_token":"8xLOxBtZp8" }"""),
243 ])
244
245 credentials = self.flow.step2_exchange('some random code', http)
246 self.assertEqual(credentials.token_expiry, None)
247
248
249if __name__ == '__main__':
250 unittest.main()