blob: b7054dc55fcef70214c4f5e54f95d85e06ab872c [file] [log] [blame]
Joe Gregorio6bcbcea2011-03-10 15:26:05 -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"""Http tests
18
19Unit tests for the apiclient.http.
20"""
21
22__author__ = 'jcgregorio@google.com (Joe Gregorio)'
23
Joe Gregorio7cbceab2011-06-27 10:46:54 -040024# Do not remove the httplib2 import
25import httplib2
Joe Gregoriod0bd3882011-11-22 09:49:47 -050026import os
Joe Gregorio6bcbcea2011-03-10 15:26:05 -050027import unittest
28
Joe Gregorio66f57522011-11-30 11:00:00 -050029from apiclient.errors import BatchError
30from apiclient.http import BatchHttpRequest
Joe Gregorio6bcbcea2011-03-10 15:26:05 -050031from apiclient.http import HttpMockSequence
Joe Gregoriod0bd3882011-11-22 09:49:47 -050032from apiclient.http import HttpRequest
Joe Gregoriod0bd3882011-11-22 09:49:47 -050033from apiclient.http import MediaFileUpload
Joe Gregorio66f57522011-11-30 11:00:00 -050034from apiclient.http import MediaUpload
35from apiclient.http import set_user_agent
36from apiclient.model import JsonModel
Joe Gregorio6bcbcea2011-03-10 15:26:05 -050037
38
Joe Gregoriod0bd3882011-11-22 09:49:47 -050039DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
40
41
42def datafile(filename):
43 return os.path.join(DATA_DIR, filename)
44
Joe Gregorio6bcbcea2011-03-10 15:26:05 -050045class TestUserAgent(unittest.TestCase):
46
47 def test_set_user_agent(self):
48 http = HttpMockSequence([
49 ({'status': '200'}, 'echo_request_headers'),
50 ])
51
52 http = set_user_agent(http, "my_app/5.5")
53 resp, content = http.request("http://example.com")
54 self.assertEqual(content['user-agent'], 'my_app/5.5')
55
56 def test_set_user_agent_nested(self):
57 http = HttpMockSequence([
58 ({'status': '200'}, 'echo_request_headers'),
59 ])
60
61 http = set_user_agent(http, "my_app/5.5")
62 http = set_user_agent(http, "my_library/0.1")
63 resp, content = http.request("http://example.com")
64 self.assertEqual(content['user-agent'], 'my_app/5.5 my_library/0.1')
65
Joe Gregoriod0bd3882011-11-22 09:49:47 -050066 def test_media_file_upload_to_from_json(self):
67 upload = MediaFileUpload(
68 datafile('small.png'), chunksize=500, resumable=True)
69 self.assertEquals('image/png', upload.mimetype())
70 self.assertEquals(190, upload.size())
71 self.assertEquals(True, upload.resumable())
72 self.assertEquals(500, upload.chunksize())
73 self.assertEquals('PNG', upload.getbytes(1, 3))
74
75 json = upload.to_json()
76 new_upload = MediaUpload.new_from_json(json)
77
78 self.assertEquals('image/png', new_upload.mimetype())
79 self.assertEquals(190, new_upload.size())
80 self.assertEquals(True, new_upload.resumable())
81 self.assertEquals(500, new_upload.chunksize())
82 self.assertEquals('PNG', new_upload.getbytes(1, 3))
83
84 def test_http_request_to_from_json(self):
85
86 def _postproc(*kwargs):
87 pass
88
89 http = httplib2.Http()
90 media_upload = MediaFileUpload(
91 datafile('small.png'), chunksize=500, resumable=True)
92 req = HttpRequest(
93 http,
94 _postproc,
95 'http://example.com',
96 method='POST',
97 body='{}',
98 headers={'content-type': 'multipart/related; boundary="---flubber"'},
99 methodId='foo',
100 resumable=media_upload)
101
102 json = req.to_json()
103 new_req = HttpRequest.from_json(json, http, _postproc)
104
Joe Gregorio66f57522011-11-30 11:00:00 -0500105 self.assertEquals(new_req.headers,
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500106 {'content-type':
107 'multipart/related; boundary="---flubber"'})
108 self.assertEquals(new_req.uri, 'http://example.com')
109 self.assertEquals(new_req.body, '{}')
110 self.assertEquals(new_req.http, http)
111 self.assertEquals(new_req.resumable.to_json(), media_upload.to_json())
Joe Gregoriobd512b52011-12-06 15:39:26 -0500112 self.assertEquals(new_req.multipart_boundary, '---flubber--')
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500113
Joe Gregorio66f57522011-11-30 11:00:00 -0500114EXPECTED = """POST /someapi/v1/collection/?foo=bar HTTP/1.1
115Content-Type: application/json
116MIME-Version: 1.0
117Host: www.googleapis.com\r\n\r\n{}"""
118
119
120RESPONSE = """HTTP/1.1 200 OK
121Content-Type application/json
122Content-Length: 14
123ETag: "etag/pony"\r\n\r\n{"answer": 42}"""
124
125
126BATCH_RESPONSE = """--batch_foobarbaz
127Content-Type: application/http
128Content-Transfer-Encoding: binary
129Content-ID: <randomness+1>
130
131HTTP/1.1 200 OK
132Content-Type application/json
133Content-Length: 14
134ETag: "etag/pony"\r\n\r\n{"foo": 42}
135
136--batch_foobarbaz
137Content-Type: application/http
138Content-Transfer-Encoding: binary
139Content-ID: <randomness+2>
140
141HTTP/1.1 200 OK
142Content-Type application/json
143Content-Length: 14
144ETag: "etag/sheep"\r\n\r\n{"baz": "qux"}
145--batch_foobarbaz--"""
146
147class TestBatch(unittest.TestCase):
148
149 def setUp(self):
150 model = JsonModel()
151 self.request1 = HttpRequest(
152 None,
153 model.response,
154 'https://www.googleapis.com/someapi/v1/collection/?foo=bar',
155 method='POST',
156 body='{}',
157 headers={'content-type': 'application/json'})
158
159 self.request2 = HttpRequest(
160 None,
161 model.response,
162 'https://www.googleapis.com/someapi/v1/collection/?foo=bar',
163 method='POST',
164 body='{}',
165 headers={'content-type': 'application/json'})
166
167
168 def test_id_to_from_content_id_header(self):
169 batch = BatchHttpRequest()
170 self.assertEquals('12', batch._header_to_id(batch._id_to_header('12')))
171
172 def test_invalid_content_id_header(self):
173 batch = BatchHttpRequest()
174 self.assertRaises(BatchError, batch._header_to_id, '[foo+x]')
175 self.assertRaises(BatchError, batch._header_to_id, 'foo+1')
176 self.assertRaises(BatchError, batch._header_to_id, '<foo>')
177
178 def test_serialize_request(self):
179 batch = BatchHttpRequest()
180 request = HttpRequest(
181 None,
182 None,
183 'https://www.googleapis.com/someapi/v1/collection/?foo=bar',
184 method='POST',
185 body='{}',
186 headers={'content-type': 'application/json'},
187 methodId=None,
188 resumable=None)
189 s = batch._serialize_request(request).splitlines()
190 self.assertEquals(s, EXPECTED.splitlines())
191
192 def test_deserialize_response(self):
193 batch = BatchHttpRequest()
194 resp, content = batch._deserialize_response(RESPONSE)
195
196 self.assertEquals(resp.status, 200)
197 self.assertEquals(resp.reason, 'OK')
198 self.assertEquals(resp.version, 11)
199 self.assertEquals(content, '{"answer": 42}')
200
201 def test_new_id(self):
202 batch = BatchHttpRequest()
203
204 id_ = batch._new_id()
205 self.assertEquals(id_, '1')
206
207 id_ = batch._new_id()
208 self.assertEquals(id_, '2')
209
210 batch.add(self.request1, request_id='3')
211
212 id_ = batch._new_id()
213 self.assertEquals(id_, '4')
214
215 def test_add(self):
216 batch = BatchHttpRequest()
217 batch.add(self.request1, request_id='1')
218 self.assertRaises(KeyError, batch.add, self.request1, request_id='1')
219
220 def test_add_fail_for_resumable(self):
221 batch = BatchHttpRequest()
222
223 upload = MediaFileUpload(
224 datafile('small.png'), chunksize=500, resumable=True)
225 self.request1.resumable = upload
226 self.assertRaises(BatchError, batch.add, self.request1, request_id='1')
227
228 def test_execute(self):
229 class Callbacks(object):
230 def __init__(self):
231 self.responses = {}
232
233 def f(self, request_id, response):
234 self.responses[request_id] = response
235
236 batch = BatchHttpRequest()
237 callbacks = Callbacks()
238
239 batch.add(self.request1, callback=callbacks.f)
240 batch.add(self.request2, callback=callbacks.f)
241 http = HttpMockSequence([
242 ({'status': '200',
243 'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
244 BATCH_RESPONSE),
245 ])
246 batch.execute(http)
247 self.assertEqual(callbacks.responses['1'], {'foo': 42})
248 self.assertEqual(callbacks.responses['2'], {'baz': 'qux'})
249
250 def test_execute_global_callback(self):
251 class Callbacks(object):
252 def __init__(self):
253 self.responses = {}
254
255 def f(self, request_id, response):
256 self.responses[request_id] = response
257
258 callbacks = Callbacks()
259 batch = BatchHttpRequest(callback=callbacks.f)
260
261 batch.add(self.request1)
262 batch.add(self.request2)
263 http = HttpMockSequence([
264 ({'status': '200',
265 'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
266 BATCH_RESPONSE),
267 ])
268 batch.execute(http)
269 self.assertEqual(callbacks.responses['1'], {'foo': 42})
270 self.assertEqual(callbacks.responses['2'], {'baz': 'qux'})
Joe Gregoriod0bd3882011-11-22 09:49:47 -0500271
Joe Gregorio6bcbcea2011-03-10 15:26:05 -0500272if __name__ == '__main__':
273 unittest.main()