blob: e9d5553edd50d168f27f459ffc05455b8a559ffa [file] [log] [blame]
Joe Gregorioba9ea7f2010-08-19 15:49:04 -04001#!/usr/bin/python2.4
Joe Gregoriof863f7a2011-02-24 03:24:44 -05002# -*- coding: utf-8 -*-
Joe Gregorioba9ea7f2010-08-19 15:49:04 -04003#
Joe Gregorio6d5e94f2010-08-25 23:49:30 -04004# Copyright 2010 Google Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040018
19"""Discovery document tests
20
21Unit tests for objects created from discovery documents.
22"""
23
24__author__ = 'jcgregorio@google.com (Joe Gregorio)'
25
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040026import httplib2
27import os
Joe Gregorioc80ac9d2012-08-21 14:09:09 -040028import sys
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040029import unittest
Joe Gregorio00cf1d92010-09-27 09:22:03 -040030import urlparse
Joe Gregorio910b9b12012-06-12 09:36:30 -040031import StringIO
32
Joe Gregorioa98733f2011-09-16 10:12:28 -040033
ade@google.comc5eb46f2010-09-27 23:35:39 +010034try:
35 from urlparse import parse_qs
36except ImportError:
37 from cgi import parse_qs
Joe Gregorio00cf1d92010-09-27 09:22:03 -040038
ade@google.com6a8c1cb2011-09-06 17:40:00 +010039from apiclient.discovery import build, build_from_document, key2param
Joe Gregorioc0e0fe92011-03-04 16:16:55 -050040from apiclient.errors import HttpError
Joe Gregorio49396552011-03-08 10:39:00 -050041from apiclient.errors import InvalidJsonError
Joe Gregoriofdf7c802011-06-30 12:33:38 -040042from apiclient.errors import MediaUploadSizeError
Joe Gregoriod0bd3882011-11-22 09:49:47 -050043from apiclient.errors import ResumableUploadError
Joe Gregoriofdf7c802011-06-30 12:33:38 -040044from apiclient.errors import UnacceptableMimeTypeError
Joe Gregoriod0bd3882011-11-22 09:49:47 -050045from apiclient.http import HttpMock
46from apiclient.http import HttpMockSequence
47from apiclient.http import MediaFileUpload
Joe Gregorio910b9b12012-06-12 09:36:30 -040048from apiclient.http import MediaIoBaseUpload
Joe Gregorioc80ac9d2012-08-21 14:09:09 -040049from apiclient.http import MediaUpload
Joe Gregoriod0bd3882011-11-22 09:49:47 -050050from apiclient.http import MediaUploadProgress
51from apiclient.http import tunnel_patch
Joe Gregorio910b9b12012-06-12 09:36:30 -040052from oauth2client.anyjson import simplejson
Joe Gregoriocb8103d2011-02-11 23:20:52 -050053
54DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
55
Joe Gregorioa98733f2011-09-16 10:12:28 -040056
Joe Gregoriocb8103d2011-02-11 23:20:52 -050057def datafile(filename):
58 return os.path.join(DATA_DIR, filename)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040059
60
Joe Gregorioc5c5a372010-09-22 11:42:32 -040061class Utilities(unittest.TestCase):
62 def test_key2param(self):
63 self.assertEqual('max_results', key2param('max-results'))
64 self.assertEqual('x007_bond', key2param('007-bond'))
65
66
Joe Gregorioc0e0fe92011-03-04 16:16:55 -050067class DiscoveryErrors(unittest.TestCase):
68
Joe Gregorio68a8cfe2012-08-03 16:17:40 -040069 def test_tests_should_be_run_with_strict_positional_enforcement(self):
70 try:
71 plus = build('plus', 'v1', None)
72 self.fail("should have raised a TypeError exception over missing http=.")
73 except TypeError:
74 pass
75
Joe Gregorioc0e0fe92011-03-04 16:16:55 -050076 def test_failed_to_parse_discovery_json(self):
77 self.http = HttpMock(datafile('malformed.json'), {'status': '200'})
78 try:
Joe Gregorio68a8cfe2012-08-03 16:17:40 -040079 plus = build('plus', 'v1', http=self.http)
Joe Gregorioc0e0fe92011-03-04 16:16:55 -050080 self.fail("should have raised an exception over malformed JSON.")
Joe Gregorio49396552011-03-08 10:39:00 -050081 except InvalidJsonError:
82 pass
Joe Gregorioc0e0fe92011-03-04 16:16:55 -050083
84
ade@google.com6a8c1cb2011-09-06 17:40:00 +010085class DiscoveryFromDocument(unittest.TestCase):
Joe Gregorioa98733f2011-09-16 10:12:28 -040086
ade@google.com6a8c1cb2011-09-06 17:40:00 +010087 def test_can_build_from_local_document(self):
Joe Gregorio7b70f432011-11-09 10:18:51 -050088 discovery = file(datafile('plus.json')).read()
89 plus = build_from_document(discovery, base="https://www.googleapis.com/")
90 self.assertTrue(plus is not None)
Joe Gregorioa98733f2011-09-16 10:12:28 -040091
ade@google.com6a8c1cb2011-09-06 17:40:00 +010092 def test_building_with_base_remembers_base(self):
Joe Gregorio7b70f432011-11-09 10:18:51 -050093 discovery = file(datafile('plus.json')).read()
Joe Gregorioa98733f2011-09-16 10:12:28 -040094
ade@google.com6a8c1cb2011-09-06 17:40:00 +010095 base = "https://www.example.com/"
Joe Gregorio7b70f432011-11-09 10:18:51 -050096 plus = build_from_document(discovery, base=base)
Joe Gregorioa2838152012-07-16 11:52:17 -040097 self.assertEquals("https://www.googleapis.com/plus/v1/", plus._baseUrl)
ade@google.com6a8c1cb2011-09-06 17:40:00 +010098
99
Joe Gregorioa98733f2011-09-16 10:12:28 -0400100class DiscoveryFromHttp(unittest.TestCase):
Joe Gregorio583d9e42011-09-16 15:54:15 -0400101 def setUp(self):
Joe Bedafb463cb2011-09-19 17:39:49 -0700102 self.old_environ = os.environ.copy()
Joe Gregorioa98733f2011-09-16 10:12:28 -0400103
Joe Gregorio583d9e42011-09-16 15:54:15 -0400104 def tearDown(self):
105 os.environ = self.old_environ
106
107 def test_userip_is_added_to_discovery_uri(self):
Joe Gregorioa98733f2011-09-16 10:12:28 -0400108 # build() will raise an HttpError on a 400, use this to pick the request uri
109 # out of the raised exception.
Joe Gregorio583d9e42011-09-16 15:54:15 -0400110 os.environ['REMOTE_ADDR'] = '10.0.0.1'
Joe Gregorioa98733f2011-09-16 10:12:28 -0400111 try:
112 http = HttpMockSequence([
113 ({'status': '400'}, file(datafile('zoo.json'), 'r').read()),
114 ])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400115 zoo = build('zoo', 'v1', http=http, developerKey='foo',
Joe Gregorioa98733f2011-09-16 10:12:28 -0400116 discoveryServiceUrl='http://example.com')
117 self.fail('Should have raised an exception.')
118 except HttpError, e:
Joe Gregorio583d9e42011-09-16 15:54:15 -0400119 self.assertEqual(e.uri, 'http://example.com?userIp=10.0.0.1')
Joe Gregorioa98733f2011-09-16 10:12:28 -0400120
Joe Gregorio583d9e42011-09-16 15:54:15 -0400121 def test_userip_missing_is_not_added_to_discovery_uri(self):
Joe Gregorioa98733f2011-09-16 10:12:28 -0400122 # build() will raise an HttpError on a 400, use this to pick the request uri
123 # out of the raised exception.
124 try:
125 http = HttpMockSequence([
126 ({'status': '400'}, file(datafile('zoo.json'), 'r').read()),
127 ])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400128 zoo = build('zoo', 'v1', http=http, developerKey=None,
Joe Gregorioa98733f2011-09-16 10:12:28 -0400129 discoveryServiceUrl='http://example.com')
130 self.fail('Should have raised an exception.')
131 except HttpError, e:
132 self.assertEqual(e.uri, 'http://example.com')
133
134
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400135class Discovery(unittest.TestCase):
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400136
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400137 def test_method_error_checking(self):
Joe Gregorio7b70f432011-11-09 10:18:51 -0500138 self.http = HttpMock(datafile('plus.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400139 plus = build('plus', 'v1', http=self.http)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400140
141 # Missing required parameters
142 try:
Joe Gregorio7b70f432011-11-09 10:18:51 -0500143 plus.activities().list()
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400144 self.fail()
145 except TypeError, e:
146 self.assertTrue('Missing' in str(e))
147
Joe Gregorio2467afa2012-06-20 12:21:25 -0400148 # Missing required parameters even if supplied as None.
149 try:
150 plus.activities().list(collection=None, userId=None)
151 self.fail()
152 except TypeError, e:
153 self.assertTrue('Missing' in str(e))
154
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400155 # Parameter doesn't match regex
156 try:
Joe Gregorio7b70f432011-11-09 10:18:51 -0500157 plus.activities().list(collection='not_a_collection_name', userId='me')
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400158 self.fail()
159 except TypeError, e:
Joe Gregorioca876e42011-02-22 19:39:42 -0500160 self.assertTrue('not an allowed value' in str(e))
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400161
162 # Unexpected parameter
163 try:
Joe Gregorio7b70f432011-11-09 10:18:51 -0500164 plus.activities().list(flubber=12)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400165 self.fail()
166 except TypeError, e:
167 self.assertTrue('unexpected' in str(e))
168
Joe Gregoriobee86832011-02-22 10:00:19 -0500169 def _check_query_types(self, request):
170 parsed = urlparse.urlparse(request.uri)
171 q = parse_qs(parsed[4])
172 self.assertEqual(q['q'], ['foo'])
173 self.assertEqual(q['i'], ['1'])
174 self.assertEqual(q['n'], ['1.0'])
175 self.assertEqual(q['b'], ['false'])
176 self.assertEqual(q['a'], ['[1, 2, 3]'])
177 self.assertEqual(q['o'], ['{\'a\': 1}'])
178 self.assertEqual(q['e'], ['bar'])
179
180 def test_type_coercion(self):
Joe Gregoriof4153422011-03-18 22:45:18 -0400181 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400182 zoo = build('zoo', 'v1', http=http)
Joe Gregoriobee86832011-02-22 10:00:19 -0500183
Joe Gregorioa98733f2011-09-16 10:12:28 -0400184 request = zoo.query(
185 q="foo", i=1.0, n=1.0, b=0, a=[1,2,3], o={'a':1}, e='bar')
Joe Gregoriobee86832011-02-22 10:00:19 -0500186 self._check_query_types(request)
Joe Gregorioa98733f2011-09-16 10:12:28 -0400187 request = zoo.query(
188 q="foo", i=1, n=1, b=False, a=[1,2,3], o={'a':1}, e='bar')
Joe Gregoriobee86832011-02-22 10:00:19 -0500189 self._check_query_types(request)
Joe Gregoriof863f7a2011-02-24 03:24:44 -0500190
Joe Gregorioa98733f2011-09-16 10:12:28 -0400191 request = zoo.query(
Craig Citro1e742822012-03-01 12:59:22 -0800192 q="foo", i="1", n="1", b="", a=[1,2,3], o={'a':1}, e='bar', er='two')
Joe Gregorio6804c7a2011-11-18 14:30:32 -0500193
194 request = zoo.query(
Craig Citro1e742822012-03-01 12:59:22 -0800195 q="foo", i="1", n="1", b="", a=[1,2,3], o={'a':1}, e='bar',
196 er=['one', 'three'], rr=['foo', 'bar'])
Joe Gregoriobee86832011-02-22 10:00:19 -0500197 self._check_query_types(request)
198
Craig Citro1e742822012-03-01 12:59:22 -0800199 # Five is right out.
Joe Gregorio20c26e52012-03-02 15:58:31 -0500200 self.assertRaises(TypeError, zoo.query, er=['one', 'five'])
Craig Citro1e742822012-03-01 12:59:22 -0800201
Joe Gregorio13217952011-02-22 15:37:38 -0500202 def test_optional_stack_query_parameters(self):
Joe Gregoriof4153422011-03-18 22:45:18 -0400203 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400204 zoo = build('zoo', 'v1', http=http)
Joe Gregoriof4153422011-03-18 22:45:18 -0400205 request = zoo.query(trace='html', fields='description')
Joe Gregorio13217952011-02-22 15:37:38 -0500206
Joe Gregorioca876e42011-02-22 19:39:42 -0500207 parsed = urlparse.urlparse(request.uri)
208 q = parse_qs(parsed[4])
209 self.assertEqual(q['trace'], ['html'])
Joe Gregoriof4153422011-03-18 22:45:18 -0400210 self.assertEqual(q['fields'], ['description'])
211
Joe Gregorio2467afa2012-06-20 12:21:25 -0400212 def test_string_params_value_of_none_get_dropped(self):
Joe Gregorio4b4002f2012-06-14 15:41:01 -0400213 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400214 zoo = build('zoo', 'v1', http=http)
Joe Gregorio2467afa2012-06-20 12:21:25 -0400215 request = zoo.query(trace=None, fields='description')
216
217 parsed = urlparse.urlparse(request.uri)
218 q = parse_qs(parsed[4])
219 self.assertFalse('trace' in q)
Joe Gregorio4b4002f2012-06-14 15:41:01 -0400220
Joe Gregorioe08a1662011-12-07 09:48:22 -0500221 def test_model_added_query_parameters(self):
222 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400223 zoo = build('zoo', 'v1', http=http)
Joe Gregorioe08a1662011-12-07 09:48:22 -0500224 request = zoo.animals().get(name='Lion')
225
226 parsed = urlparse.urlparse(request.uri)
227 q = parse_qs(parsed[4])
228 self.assertEqual(q['alt'], ['json'])
229 self.assertEqual(request.headers['accept'], 'application/json')
230
231 def test_fallback_to_raw_model(self):
232 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400233 zoo = build('zoo', 'v1', http=http)
Joe Gregorioe08a1662011-12-07 09:48:22 -0500234 request = zoo.animals().getmedia(name='Lion')
235
236 parsed = urlparse.urlparse(request.uri)
237 q = parse_qs(parsed[4])
238 self.assertTrue('alt' not in q)
239 self.assertEqual(request.headers['accept'], '*/*')
240
Joe Gregoriof4153422011-03-18 22:45:18 -0400241 def test_patch(self):
242 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400243 zoo = build('zoo', 'v1', http=http)
Joe Gregoriof4153422011-03-18 22:45:18 -0400244 request = zoo.animals().patch(name='lion', body='{"description": "foo"}')
245
246 self.assertEqual(request.method, 'PATCH')
247
248 def test_tunnel_patch(self):
249 http = HttpMockSequence([
250 ({'status': '200'}, file(datafile('zoo.json'), 'r').read()),
251 ({'status': '200'}, 'echo_request_headers_as_json'),
252 ])
253 http = tunnel_patch(http)
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400254 zoo = build('zoo', 'v1', http=http)
Joe Gregorioa98733f2011-09-16 10:12:28 -0400255 resp = zoo.animals().patch(
256 name='lion', body='{"description": "foo"}').execute()
Joe Gregoriof4153422011-03-18 22:45:18 -0400257
258 self.assertTrue('x-http-method-override' in resp)
Joe Gregorioca876e42011-02-22 19:39:42 -0500259
Joe Gregorio7b70f432011-11-09 10:18:51 -0500260 def test_plus_resources(self):
261 self.http = HttpMock(datafile('plus.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400262 plus = build('plus', 'v1', http=self.http)
Joe Gregorio7b70f432011-11-09 10:18:51 -0500263 self.assertTrue(getattr(plus, 'activities'))
264 self.assertTrue(getattr(plus, 'people'))
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400265
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400266 def test_full_featured(self):
267 # Zoo should exercise all discovery facets
268 # and should also have no future.json file.
Joe Gregoriocb8103d2011-02-11 23:20:52 -0500269 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400270 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400271 self.assertTrue(getattr(zoo, 'animals'))
Joe Gregoriof863f7a2011-02-24 03:24:44 -0500272
Joe Gregoriof4153422011-03-18 22:45:18 -0400273 request = zoo.animals().list(name='bat', projection="full")
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400274 parsed = urlparse.urlparse(request.uri)
275 q = parse_qs(parsed[4])
276 self.assertEqual(q['name'], ['bat'])
Joe Gregoriof4153422011-03-18 22:45:18 -0400277 self.assertEqual(q['projection'], ['full'])
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400278
Joe Gregorio3fada332011-01-07 17:07:45 -0500279 def test_nested_resources(self):
Joe Gregoriocb8103d2011-02-11 23:20:52 -0500280 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400281 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio3fada332011-01-07 17:07:45 -0500282 self.assertTrue(getattr(zoo, 'animals'))
283 request = zoo.my().favorites().list(max_results="5")
284 parsed = urlparse.urlparse(request.uri)
285 q = parse_qs(parsed[4])
286 self.assertEqual(q['max-results'], ['5'])
287
Joe Gregoriod92897c2011-07-07 11:44:56 -0400288 def test_methods_with_reserved_names(self):
289 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400290 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod92897c2011-07-07 11:44:56 -0400291 self.assertTrue(getattr(zoo, 'animals'))
292 request = zoo.global_().print_().assert_(max_results="5")
293 parsed = urlparse.urlparse(request.uri)
Joe Gregorioa2838152012-07-16 11:52:17 -0400294 self.assertEqual(parsed[2], '/zoo/v1/global/print/assert')
Joe Gregoriod92897c2011-07-07 11:44:56 -0400295
Joe Gregorio7a6df3a2011-01-31 21:55:21 -0500296 def test_top_level_functions(self):
Joe Gregoriocb8103d2011-02-11 23:20:52 -0500297 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400298 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio7a6df3a2011-01-31 21:55:21 -0500299 self.assertTrue(getattr(zoo, 'query'))
300 request = zoo.query(q="foo")
301 parsed = urlparse.urlparse(request.uri)
302 q = parse_qs(parsed[4])
303 self.assertEqual(q['q'], ['foo'])
Joe Gregorio2379ecc2010-10-26 10:51:28 -0400304
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400305 def test_simple_media_uploads(self):
306 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400307 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400308 doc = getattr(zoo.animals().insert, '__doc__')
309 self.assertTrue('media_body' in doc)
310
Joe Gregorio84d3c1f2011-07-25 10:39:45 -0400311 def test_simple_media_upload_no_max_size_provided(self):
312 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400313 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio84d3c1f2011-07-25 10:39:45 -0400314 request = zoo.animals().crossbreed(media_body=datafile('small.png'))
315 self.assertEquals('image/png', request.headers['content-type'])
316 self.assertEquals('PNG', request.body[1:4])
317
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400318 def test_simple_media_raise_correct_exceptions(self):
319 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400320 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400321
322 try:
323 zoo.animals().insert(media_body=datafile('smiley.png'))
324 self.fail("should throw exception if media is too large.")
325 except MediaUploadSizeError:
326 pass
327
328 try:
329 zoo.animals().insert(media_body=datafile('small.jpg'))
330 self.fail("should throw exception if mimetype is unacceptable.")
331 except UnacceptableMimeTypeError:
332 pass
333
334 def test_simple_media_good_upload(self):
335 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400336 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400337
338 request = zoo.animals().insert(media_body=datafile('small.png'))
339 self.assertEquals('image/png', request.headers['content-type'])
340 self.assertEquals('PNG', request.body[1:4])
Joe Gregoriode860442012-03-02 15:55:52 -0500341 self.assertEqual(
Joe Gregorioa2838152012-07-16 11:52:17 -0400342 'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=media&alt=json',
Joe Gregoriode860442012-03-02 15:55:52 -0500343 request.uri)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400344
345 def test_multipart_media_raise_correct_exceptions(self):
346 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400347 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400348
349 try:
350 zoo.animals().insert(media_body=datafile('smiley.png'), body={})
351 self.fail("should throw exception if media is too large.")
352 except MediaUploadSizeError:
353 pass
354
355 try:
356 zoo.animals().insert(media_body=datafile('small.jpg'), body={})
357 self.fail("should throw exception if mimetype is unacceptable.")
358 except UnacceptableMimeTypeError:
359 pass
360
361 def test_multipart_media_good_upload(self):
362 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400363 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400364
365 request = zoo.animals().insert(media_body=datafile('small.png'), body={})
Joe Gregorioa98733f2011-09-16 10:12:28 -0400366 self.assertTrue(request.headers['content-type'].startswith(
367 'multipart/related'))
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400368 self.assertEquals('--==', request.body[0:4])
Joe Gregoriode860442012-03-02 15:55:52 -0500369 self.assertEqual(
Joe Gregorioa2838152012-07-16 11:52:17 -0400370 'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=multipart&alt=json',
Joe Gregoriode860442012-03-02 15:55:52 -0500371 request.uri)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400372
373 def test_media_capable_method_without_media(self):
374 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400375 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriofdf7c802011-06-30 12:33:38 -0400376
377 request = zoo.animals().insert(body={})
378 self.assertTrue(request.headers['content-type'], 'application/json')
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400379
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500380 def test_resumable_multipart_media_good_upload(self):
381 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400382 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500383
384 media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
385 request = zoo.animals().insert(media_body=media_upload, body={})
386 self.assertTrue(request.headers['content-type'].startswith(
Joe Gregorio945be3e2012-01-27 17:01:06 -0500387 'application/json'))
388 self.assertEquals('{"data": {}}', request.body)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500389 self.assertEquals(media_upload, request.resumable)
390
391 self.assertEquals('image/png', request.resumable.mimetype())
392
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500393 self.assertNotEquals(request.body, None)
394 self.assertEquals(request.resumable_uri, None)
395
396 http = HttpMockSequence([
397 ({'status': '200',
398 'location': 'http://upload.example.com'}, ''),
399 ({'status': '308',
400 'location': 'http://upload.example.com/2',
401 'range': '0-12'}, ''),
402 ({'status': '308',
403 'location': 'http://upload.example.com/3',
Joe Gregorio945be3e2012-01-27 17:01:06 -0500404 'range': '0-%d' % (media_upload.size() - 2)}, ''),
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500405 ({'status': '200'}, '{"foo": "bar"}'),
406 ])
407
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400408 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500409 self.assertEquals(None, body)
410 self.assertTrue(isinstance(status, MediaUploadProgress))
411 self.assertEquals(13, status.resumable_progress)
412
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500413 # Two requests should have been made and the resumable_uri should have been
414 # updated for each one.
415 self.assertEquals(request.resumable_uri, 'http://upload.example.com/2')
416
417 self.assertEquals(media_upload, request.resumable)
418 self.assertEquals(13, request.resumable_progress)
419
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400420 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500421 self.assertEquals(request.resumable_uri, 'http://upload.example.com/3')
Joe Gregorio945be3e2012-01-27 17:01:06 -0500422 self.assertEquals(media_upload.size()-1, request.resumable_progress)
423 self.assertEquals('{"data": {}}', request.body)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500424
425 # Final call to next_chunk should complete the upload.
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400426 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500427 self.assertEquals(body, {"foo": "bar"})
428 self.assertEquals(status, None)
429
430
431 def test_resumable_media_good_upload(self):
432 """Not a multipart upload."""
433 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400434 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500435
436 media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
437 request = zoo.animals().insert(media_body=media_upload, body=None)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500438 self.assertEquals(media_upload, request.resumable)
439
440 self.assertEquals('image/png', request.resumable.mimetype())
441
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500442 self.assertEquals(request.body, None)
443 self.assertEquals(request.resumable_uri, None)
444
445 http = HttpMockSequence([
446 ({'status': '200',
447 'location': 'http://upload.example.com'}, ''),
448 ({'status': '308',
449 'location': 'http://upload.example.com/2',
450 'range': '0-12'}, ''),
451 ({'status': '308',
452 'location': 'http://upload.example.com/3',
Joe Gregorio945be3e2012-01-27 17:01:06 -0500453 'range': '0-%d' % (media_upload.size() - 2)}, ''),
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500454 ({'status': '200'}, '{"foo": "bar"}'),
455 ])
456
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400457 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500458 self.assertEquals(None, body)
459 self.assertTrue(isinstance(status, MediaUploadProgress))
460 self.assertEquals(13, status.resumable_progress)
461
462 # Two requests should have been made and the resumable_uri should have been
463 # updated for each one.
464 self.assertEquals(request.resumable_uri, 'http://upload.example.com/2')
465
466 self.assertEquals(media_upload, request.resumable)
467 self.assertEquals(13, request.resumable_progress)
468
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400469 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500470 self.assertEquals(request.resumable_uri, 'http://upload.example.com/3')
Joe Gregorio945be3e2012-01-27 17:01:06 -0500471 self.assertEquals(media_upload.size()-1, request.resumable_progress)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500472 self.assertEquals(request.body, None)
473
474 # Final call to next_chunk should complete the upload.
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400475 status, body = request.next_chunk(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500476 self.assertEquals(body, {"foo": "bar"})
477 self.assertEquals(status, None)
478
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500479 def test_resumable_media_good_upload_from_execute(self):
480 """Not a multipart upload."""
481 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400482 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500483
484 media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
485 request = zoo.animals().insert(media_body=media_upload, body=None)
Joe Gregoriode860442012-03-02 15:55:52 -0500486 self.assertEqual(
Joe Gregorioa2838152012-07-16 11:52:17 -0400487 'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=resumable&alt=json',
Joe Gregoriode860442012-03-02 15:55:52 -0500488 request.uri)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500489
490 http = HttpMockSequence([
491 ({'status': '200',
492 'location': 'http://upload.example.com'}, ''),
493 ({'status': '308',
494 'location': 'http://upload.example.com/2',
495 'range': '0-12'}, ''),
496 ({'status': '308',
497 'location': 'http://upload.example.com/3',
Joe Gregorio945be3e2012-01-27 17:01:06 -0500498 'range': '0-%d' % media_upload.size()}, ''),
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500499 ({'status': '200'}, '{"foo": "bar"}'),
500 ])
501
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400502 body = request.execute(http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500503 self.assertEquals(body, {"foo": "bar"})
504
505 def test_resumable_media_fail_unknown_response_code_first_request(self):
506 """Not a multipart upload."""
507 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400508 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500509
510 media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
511 request = zoo.animals().insert(media_body=media_upload, body=None)
512
513 http = HttpMockSequence([
514 ({'status': '400',
515 'location': 'http://upload.example.com'}, ''),
516 ])
517
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400518 self.assertRaises(ResumableUploadError, request.execute, http=http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500519
520 def test_resumable_media_fail_unknown_response_code_subsequent_request(self):
521 """Not a multipart upload."""
522 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400523 zoo = build('zoo', 'v1', http=self.http)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500524
525 media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
526 request = zoo.animals().insert(media_body=media_upload, body=None)
527
528 http = HttpMockSequence([
529 ({'status': '200',
530 'location': 'http://upload.example.com'}, ''),
531 ({'status': '400'}, ''),
532 ])
533
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400534 self.assertRaises(HttpError, request.execute, http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400535 self.assertTrue(request._in_error_state)
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500536
Joe Gregorio910b9b12012-06-12 09:36:30 -0400537 http = HttpMockSequence([
538 ({'status': '308',
539 'range': '0-5'}, ''),
540 ({'status': '308',
541 'range': '0-6'}, ''),
542 ])
543
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400544 status, body = request.next_chunk(http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400545 self.assertEquals(status.resumable_progress, 7,
546 'Should have first checked length and then tried to PUT more.')
547 self.assertFalse(request._in_error_state)
548
549 # Put it back in an error state.
550 http = HttpMockSequence([
551 ({'status': '400'}, ''),
552 ])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400553 self.assertRaises(HttpError, request.execute, http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400554 self.assertTrue(request._in_error_state)
555
556 # Pretend the last request that 400'd actually succeeded.
557 http = HttpMockSequence([
558 ({'status': '200'}, '{"foo": "bar"}'),
559 ])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400560 status, body = request.next_chunk(http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400561 self.assertEqual(body, {'foo': 'bar'})
562
Joe Gregorioc80ac9d2012-08-21 14:09:09 -0400563 def test_media_io_base_stream_unlimited_chunksize_resume(self):
564 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
565 zoo = build('zoo', 'v1', http=self.http)
566
567 try:
568 import io
569
570 # Set up a seekable stream and try to upload in single chunk.
571 fd = io.BytesIO('01234"56789"')
572 media_upload = MediaIoBaseUpload(
573 fd=fd, mimetype='text/plain', chunksize=-1, resumable=True)
574
575 request = zoo.animals().insert(media_body=media_upload, body=None)
576
577 # The single chunk fails, restart at the right point.
578 http = HttpMockSequence([
579 ({'status': '200',
580 'location': 'http://upload.example.com'}, ''),
581 ({'status': '308',
582 'location': 'http://upload.example.com/2',
583 'range': '0-4'}, ''),
584 ({'status': '200'}, 'echo_request_body'),
585 ])
586
587 body = request.execute(http=http)
588 self.assertEqual('56789', body)
589
590 except ImportError:
591 pass
592
Joe Gregorio5c120db2012-08-23 09:13:55 -0400593
594 def test_media_io_base_stream_chunksize_resume(self):
595 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
596 zoo = build('zoo', 'v1', http=self.http)
597
598 try:
599 import io
600
601 # Set up a seekable stream and try to upload in chunks.
602 fd = io.BytesIO('0123456789')
603 media_upload = MediaIoBaseUpload(
604 fd=fd, mimetype='text/plain', chunksize=5, resumable=True)
605
606 request = zoo.animals().insert(media_body=media_upload, body=None)
607
608 # The single chunk fails, pull the content sent out of the exception.
609 http = HttpMockSequence([
610 ({'status': '200',
611 'location': 'http://upload.example.com'}, ''),
612 ({'status': '400'}, 'echo_request_body'),
613 ])
614
615 try:
616 body = request.execute(http=http)
617 except HttpError, e:
618 self.assertEqual('01234', e.content)
619
620 except ImportError:
621 pass
622
623
Joe Gregorio910b9b12012-06-12 09:36:30 -0400624 def test_resumable_media_handle_uploads_of_unknown_size(self):
625 http = HttpMockSequence([
626 ({'status': '200',
627 'location': 'http://upload.example.com'}, ''),
628 ({'status': '200'}, 'echo_request_headers_as_json'),
629 ])
630
631 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400632 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400633
Joe Gregorio910b9b12012-06-12 09:36:30 -0400634 # Create an upload that doesn't know the full size of the media.
Joe Gregorioc80ac9d2012-08-21 14:09:09 -0400635 class IoBaseUnknownLength(MediaUpload):
636 def chunksize(self):
637 return 10
638
639 def mimetype(self):
640 return 'image/png'
641
642 def size(self):
643 return None
644
645 def resumable(self):
646 return True
647
648 def getbytes(self, begin, length):
649 return '0123456789'
650
651 upload = IoBaseUnknownLength()
Joe Gregorio910b9b12012-06-12 09:36:30 -0400652
653 request = zoo.animals().insert(media_body=upload, body=None)
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400654 status, body = request.next_chunk(http=http)
Joe Gregorio5c120db2012-08-23 09:13:55 -0400655 self.assertEqual(body, {
656 'Content-Range': 'bytes 0-9/*',
657 'Content-Length': '10',
658 })
Joe Gregorio44454e42012-06-15 08:38:53 -0400659
Joe Gregorioc80ac9d2012-08-21 14:09:09 -0400660 def test_resumable_media_no_streaming_on_unsupported_platforms(self):
661 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
662 zoo = build('zoo', 'v1', http=self.http)
663
664 class IoBaseHasStream(MediaUpload):
665 def chunksize(self):
666 return 10
667
668 def mimetype(self):
669 return 'image/png'
670
671 def size(self):
672 return None
673
674 def resumable(self):
675 return True
676
677 def getbytes(self, begin, length):
678 return '0123456789'
679
680 def has_stream(self):
681 return True
682
683 def stream(self):
684 raise NotImplementedError()
685
686 upload = IoBaseHasStream()
687
688 orig_version = sys.version_info
689 sys.version_info = (2, 5, 5, 'final', 0)
690
691 request = zoo.animals().insert(media_body=upload, body=None)
692
693 http = HttpMockSequence([
694 ({'status': '200',
695 'location': 'http://upload.example.com'}, ''),
696 ({'status': '200'}, 'echo_request_headers_as_json'),
697 ])
698
699 # This should not raise an exception because stream() shouldn't be called.
700 status, body = request.next_chunk(http=http)
Joe Gregorio5c120db2012-08-23 09:13:55 -0400701 self.assertEqual(body, {
702 'Content-Range': 'bytes 0-9/*',
703 'Content-Length': '10'
704 })
Joe Gregorioc80ac9d2012-08-21 14:09:09 -0400705
706 sys.version_info = (2, 6, 5, 'final', 0)
707
708 request = zoo.animals().insert(media_body=upload, body=None)
709
710 # This should raise an exception because stream() will be called.
711 http = HttpMockSequence([
712 ({'status': '200',
713 'location': 'http://upload.example.com'}, ''),
714 ({'status': '200'}, 'echo_request_headers_as_json'),
715 ])
716
717 self.assertRaises(NotImplementedError, request.next_chunk, http=http)
718
719 sys.version_info = orig_version
720
Joe Gregorio44454e42012-06-15 08:38:53 -0400721 def test_resumable_media_handle_uploads_of_unknown_size_eof(self):
722 http = HttpMockSequence([
723 ({'status': '200',
724 'location': 'http://upload.example.com'}, ''),
725 ({'status': '200'}, 'echo_request_headers_as_json'),
726 ])
727
728 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400729 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio44454e42012-06-15 08:38:53 -0400730
Joe Gregorio4a2c29f2012-07-12 12:52:47 -0400731 fd = StringIO.StringIO('data goes here')
Joe Gregorio44454e42012-06-15 08:38:53 -0400732
733 # Create an upload that doesn't know the full size of the media.
734 upload = MediaIoBaseUpload(
Joe Gregorio4a2c29f2012-07-12 12:52:47 -0400735 fd=fd, mimetype='image/png', chunksize=15, resumable=True)
Joe Gregorio44454e42012-06-15 08:38:53 -0400736
737 request = zoo.animals().insert(media_body=upload, body=None)
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400738 status, body = request.next_chunk(http=http)
Joe Gregorio5c120db2012-08-23 09:13:55 -0400739 self.assertEqual(body, {
740 'Content-Range': 'bytes 0-13/14',
741 'Content-Length': '14',
742 })
Joe Gregorio910b9b12012-06-12 09:36:30 -0400743
744 def test_resumable_media_handle_resume_of_upload_of_unknown_size(self):
745 http = HttpMockSequence([
746 ({'status': '200',
747 'location': 'http://upload.example.com'}, ''),
748 ({'status': '400'}, ''),
749 ])
750
751 self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400752 zoo = build('zoo', 'v1', http=self.http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400753
754 # Create an upload that doesn't know the full size of the media.
Joe Gregorio4a2c29f2012-07-12 12:52:47 -0400755 fd = StringIO.StringIO('data goes here')
Joe Gregorio910b9b12012-06-12 09:36:30 -0400756
757 upload = MediaIoBaseUpload(
Joe Gregorio4a2c29f2012-07-12 12:52:47 -0400758 fd=fd, mimetype='image/png', chunksize=500, resumable=True)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400759
760 request = zoo.animals().insert(media_body=upload, body=None)
761
762 # Put it in an error state.
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400763 self.assertRaises(HttpError, request.next_chunk, http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400764
765 http = HttpMockSequence([
766 ({'status': '400',
767 'range': '0-5'}, 'echo_request_headers_as_json'),
768 ])
769 try:
770 # Should resume the upload by first querying the status of the upload.
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400771 request.next_chunk(http=http)
Joe Gregorio910b9b12012-06-12 09:36:30 -0400772 except HttpError, e:
773 expected = {
Joe Gregorioc80ac9d2012-08-21 14:09:09 -0400774 'Content-Range': 'bytes */14',
Joe Gregorio910b9b12012-06-12 09:36:30 -0400775 'content-length': '0'
776 }
777 self.assertEqual(expected, simplejson.loads(e.content),
778 'Should send an empty body when requesting the current upload status.')
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500779
Joe Gregorio708388c2012-06-15 13:43:04 -0400780
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400781class Next(unittest.TestCase):
Joe Gregorio00cf1d92010-09-27 09:22:03 -0400782
Joe Gregorio3c676f92011-07-25 10:38:14 -0400783 def test_next_successful_none_on_no_next_page_token(self):
784 self.http = HttpMock(datafile('tasks.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400785 tasks = build('tasks', 'v1', http=self.http)
Joe Gregorio3c676f92011-07-25 10:38:14 -0400786 request = tasks.tasklists().list()
787 self.assertEqual(None, tasks.tasklists().list_next(request, {}))
788
789 def test_next_successful_with_next_page_token(self):
790 self.http = HttpMock(datafile('tasks.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400791 tasks = build('tasks', 'v1', http=self.http)
Joe Gregorio3c676f92011-07-25 10:38:14 -0400792 request = tasks.tasklists().list()
Joe Gregorioa98733f2011-09-16 10:12:28 -0400793 next_request = tasks.tasklists().list_next(
794 request, {'nextPageToken': '123abc'})
Joe Gregorio3c676f92011-07-25 10:38:14 -0400795 parsed = list(urlparse.urlparse(next_request.uri))
796 q = parse_qs(parsed[4])
797 self.assertEqual(q['pageToken'][0], '123abc')
798
Joe Gregorio555f33c2011-08-19 14:56:07 -0400799 def test_next_with_method_with_no_properties(self):
800 self.http = HttpMock(datafile('latitude.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400801 service = build('latitude', 'v1', http=self.http)
Joe Gregorio555f33c2011-08-19 14:56:07 -0400802 request = service.currentLocation().get()
Joe Gregorio00cf1d92010-09-27 09:22:03 -0400803
Joe Gregorioa98733f2011-09-16 10:12:28 -0400804
Joe Gregorio708388c2012-06-15 13:43:04 -0400805class MediaGet(unittest.TestCase):
806
807 def test_get_media(self):
808 http = HttpMock(datafile('zoo.json'), {'status': '200'})
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400809 zoo = build('zoo', 'v1', http=http)
Joe Gregorio708388c2012-06-15 13:43:04 -0400810 request = zoo.animals().get_media(name='Lion')
811
812 parsed = urlparse.urlparse(request.uri)
813 q = parse_qs(parsed[4])
814 self.assertEqual(q['alt'], ['media'])
815 self.assertEqual(request.headers['accept'], '*/*')
816
817 http = HttpMockSequence([
818 ({'status': '200'}, 'standing in for media'),
819 ])
Joe Gregorio68a8cfe2012-08-03 16:17:40 -0400820 response = request.execute(http=http)
Joe Gregorio708388c2012-06-15 13:43:04 -0400821 self.assertEqual('standing in for media', response)
822
823
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400824if __name__ == '__main__':
825 unittest.main()