blob: 208a3f59bde7a98c6aef9a966efda03c9b094a81 [file] [log] [blame]
Joe Gregorio432f17e2011-05-22 23:18:00 -04001#!/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
18"""Discovery document tests
19
20Unit tests for objects created from discovery documents.
21"""
22
23__author__ = 'jcgregorio@google.com (Joe Gregorio)'
24
25import httplib2
26import unittest
27import urlparse
28
29try:
30 from urlparse import parse_qs
31except ImportError:
32 from cgi import parse_qs
33
34from apiclient.http import HttpMockSequence
35from apiclient.anyjson import simplejson
36from webtest import TestApp
37from oauth2client.client import AccessTokenRefreshError
38from oauth2client.client import FlowExchangeError
39from oauth2client.appengine import OAuth2Decorator
40from google.appengine.ext import webapp
41from google.appengine.api import users
42from oauth2client.appengine import OAuth2Handler
43from google.appengine.ext import testbed
44
45
46class UserMock(object):
47 """Mock the app engine user service"""
48 def user_id(self):
49 return 'foo_user'
50
51
52class Http2Mock(object):
53 """Mock httplib2.Http"""
54 status = 200
55 content = {
56 'access_token': 'foo_access_token',
57 'refresh_token': 'foo_refresh_token',
58 'expires_in': 3600
59 }
60
61 def request(self, token_uri, method, body, headers, *args, **kwargs):
62 self.body = body
63 self.headers = headers
64 return (self, simplejson.dumps(self.content))
65
66
67class DecoratorTests(unittest.TestCase):
68
69 def setUp(self):
70 self.testbed = testbed.Testbed()
71 self.testbed.activate()
72 self.testbed.init_datastore_v3_stub()
73 self.testbed.init_memcache_stub()
74 self.testbed.init_user_stub()
75
76 decorator = OAuth2Decorator(client_id='foo_client_id',
77 client_secret='foo_client_secret',
78 scope='foo_scope',
79 user_agent='foo_user_agent')
80 self.decorator = decorator
81
82
83 class TestRequiredHandler(webapp.RequestHandler):
84 @decorator.oauth_required
85 def get(self):
86 pass
87
88
89 class TestAwareHandler(webapp.RequestHandler):
90 @decorator.oauth_aware
91 def get(self):
92 self.response.out.write('Hello World!')
93
94
95 application = webapp.WSGIApplication([('/oauth2callback', OAuth2Handler),
96 ('/foo_path', TestRequiredHandler),
97 ('/bar_path', TestAwareHandler)],
98 debug=True)
99 self.app = TestApp(application)
100 users.get_current_user = UserMock
101 httplib2.Http = Http2Mock
102
103 def tearDown(self):
104 self.testbed.deactivate()
105
106 def test_required(self):
107 # An initial request to an oauth_required decorated path should be a
108 # redirect to start the OAuth dance.
109 response = self.app.get('/foo_path')
110 self.assertTrue(response.status.startswith('302'))
111 q = parse_qs(response.headers['Location'].split('?', 1)[1])
112 self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0])
113 self.assertEqual('foo_client_id', q['client_id'][0])
114 self.assertEqual('foo_scope', q['scope'][0])
115 self.assertEqual('http://localhost/foo_path', q['state'][0])
116 self.assertEqual('code', q['response_type'][0])
117 self.assertEqual(False, self.decorator.has_credentials())
118
119 # Now simulate the callback to /oauth2callback
120 response = self.app.get('/oauth2callback', {
121 'code': 'foo_access_code',
122 'state': 'foo_path'
123 })
124 self.assertEqual('http://localhost/foo_path', response.headers['Location'])
125 self.assertEqual(None, self.decorator.credentials)
126
127 # Now requesting the decorated path should work
128 response = self.app.get('/foo_path')
129 self.assertEqual('200 OK', response.status)
130 self.assertEqual(True, self.decorator.has_credentials())
131 self.assertEqual('foo_refresh_token', self.decorator.credentials.refresh_token)
132 self.assertEqual('foo_access_token', self.decorator.credentials.access_token)
133
134 # Invalidate the stored Credentials
135 self.decorator.credentials._invalid = True
136 self.decorator.credentials.store(self.decorator.credentials)
137
138 # Invalid Credentials should start the OAuth dance again
139 response = self.app.get('/foo_path')
140 self.assertTrue(response.status.startswith('302'))
141 q = parse_qs(response.headers['Location'].split('?', 1)[1])
142 self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0])
143
144 def test_aware(self):
145 # An initial request to an oauth_aware decorated path should not redirect
146 response = self.app.get('/bar_path')
147 self.assertEqual('Hello World!', response.body)
148 self.assertEqual('200 OK', response.status)
149 self.assertEqual(False, self.decorator.has_credentials())
150 url = self.decorator.authorize_url()
151 q = parse_qs(url.split('?', 1)[1])
152 self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0])
153 self.assertEqual('foo_client_id', q['client_id'][0])
154 self.assertEqual('foo_scope', q['scope'][0])
155 self.assertEqual('http://localhost/bar_path', q['state'][0])
156 self.assertEqual('code', q['response_type'][0])
157
158 # Now simulate the callback to /oauth2callback
159 url = self.decorator.authorize_url()
160 response = self.app.get('/oauth2callback', {
161 'code': 'foo_access_code',
162 'state': 'bar_path'
163 })
164 self.assertEqual('http://localhost/bar_path', response.headers['Location'])
165 self.assertEqual(False, self.decorator.has_credentials())
166
167 # Now requesting the decorated path will have credentials
168 response = self.app.get('/bar_path')
169 self.assertEqual('200 OK', response.status)
170 self.assertEqual('Hello World!', response.body)
171 self.assertEqual(True, self.decorator.has_credentials())
172 self.assertEqual('foo_refresh_token', self.decorator.credentials.refresh_token)
173 self.assertEqual('foo_access_token', self.decorator.credentials.access_token)
174
175if __name__ == '__main__':
176 unittest.main()