blob: 68578039e63af7af69c6bfb11a262d90c92787c0 [file] [log] [blame]
Craig Citro15744b12015-03-02 13:34:32 -08001#!/usr/bin/env python
Joe Gregorioba9ea7f2010-08-19 15:49:04 -04002#
Craig Citro751b7fb2014-09-23 11:20:38 -07003# Copyright 2014 Google Inc. All Rights Reserved.
Joe Gregorio6d5e94f2010-08-25 23:49:30 -04004#
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.
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040016
Joe Gregorio6d5e94f2010-08-25 23:49:30 -040017"""JSON Model tests
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040018
Joe Gregorio6d5e94f2010-08-25 23:49:30 -040019Unit tests for the JSON model.
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040020"""
INADA Naokid898a372015-03-04 03:52:46 +090021from __future__ import absolute_import
22import six
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040023
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070024__author__ = "jcgregorio@google.com (Joe Gregorio)"
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040025
Joe Gregorio34044bc2011-03-07 16:58:33 -050026import copy
Craig Citro6ae34d72014-08-18 23:10:09 -070027import json
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040028import os
Bu Sun Kimf706cfd2020-04-20 14:05:05 -070029import pkg_resources
Bu Sun Kim07f647c2019-08-09 14:55:24 -070030import platform
Pat Ferate497a90f2015-03-09 09:52:54 -070031import unittest2 as unittest
Joe Gregorioc5c5a372010-09-22 11:42:32 -040032import httplib2
John Asmuth864311d2014-04-24 15:46:08 -040033import googleapiclient.model
ade@google.comd69e5e42010-08-31 15:28:20 +010034
John Asmuth864311d2014-04-24 15:46:08 -040035from googleapiclient.errors import HttpError
36from googleapiclient.model import JsonModel
Joe Gregorio34044bc2011-03-07 16:58:33 -050037
Pat Ferated5b61bd2015-03-03 16:04:11 -080038from six.moves.urllib.parse import parse_qs
ade@google.comd69e5e42010-08-31 15:28:20 +010039
Bu Sun Kimf706cfd2020-04-20 14:05:05 -070040_LIBRARY_VERSION = pkg_resources.get_distribution("google-api-python-client").version
41
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040042
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040043class Model(unittest.TestCase):
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070044 def test_json_no_body(self):
45 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040046
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070047 headers = {}
48 path_params = {}
49 query_params = {}
50 body = None
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040051
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070052 headers, unused_params, query, body = model.request(
53 headers, path_params, query_params, body
54 )
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040055
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070056 self.assertEqual(headers["accept"], "application/json")
57 self.assertTrue("content-type" not in headers)
58 self.assertNotEqual(query, "")
59 self.assertEqual(body, None)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040060
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070061 def test_json_body(self):
62 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040063
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070064 headers = {}
65 path_params = {}
66 query_params = {}
67 body = {}
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040068
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070069 headers, unused_params, query, body = model.request(
70 headers, path_params, query_params, body
71 )
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040072
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070073 self.assertEqual(headers["accept"], "application/json")
74 self.assertEqual(headers["content-type"], "application/json")
75 self.assertNotEqual(query, "")
76 self.assertEqual(body, "{}")
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040077
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070078 def test_json_body_data_wrapper(self):
79 model = JsonModel(data_wrapper=True)
Joe Gregoriod433b2a2011-02-22 10:51:51 -050080
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070081 headers = {}
82 path_params = {}
83 query_params = {}
84 body = {}
Joe Gregoriod433b2a2011-02-22 10:51:51 -050085
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070086 headers, unused_params, query, body = model.request(
87 headers, path_params, query_params, body
88 )
Joe Gregoriod433b2a2011-02-22 10:51:51 -050089
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070090 self.assertEqual(headers["accept"], "application/json")
91 self.assertEqual(headers["content-type"], "application/json")
92 self.assertNotEqual(query, "")
93 self.assertEqual(body, '{"data": {}}')
Joe Gregoriod433b2a2011-02-22 10:51:51 -050094
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070095 def test_json_body_default_data(self):
96 """Test that a 'data' wrapper doesn't get added if one is already present."""
97 model = JsonModel(data_wrapper=True)
Joe Gregorio8963ff92010-10-11 13:14:43 -040098
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070099 headers = {}
100 path_params = {}
101 query_params = {}
102 body = {"data": "foo"}
Joe Gregorio8963ff92010-10-11 13:14:43 -0400103
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700104 headers, unused_params, query, body = model.request(
105 headers, path_params, query_params, body
106 )
Joe Gregorio8963ff92010-10-11 13:14:43 -0400107
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700108 self.assertEqual(headers["accept"], "application/json")
109 self.assertEqual(headers["content-type"], "application/json")
110 self.assertNotEqual(query, "")
111 self.assertEqual(body, '{"data": "foo"}')
Joe Gregorio8963ff92010-10-11 13:14:43 -0400112
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700113 def test_json_build_query(self):
114 model = JsonModel(data_wrapper=False)
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400115
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700116 headers = {}
117 path_params = {}
118 query_params = {
119 "foo": 1,
120 "bar": u"\N{COMET}",
121 "baz": ["fe", "fi", "fo", "fum"], # Repeated parameters
122 "qux": [],
Joe Gregorio34044bc2011-03-07 16:58:33 -0500123 }
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700124 body = {}
Joe Gregorio34044bc2011-03-07 16:58:33 -0500125
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700126 headers, unused_params, query, body = model.request(
127 headers, path_params, query_params, body
128 )
Joe Gregorio34044bc2011-03-07 16:58:33 -0500129
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700130 self.assertEqual(headers["accept"], "application/json")
131 self.assertEqual(headers["content-type"], "application/json")
Ali Afshar81fde8e2012-10-23 11:14:28 -0700132
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700133 query_dict = parse_qs(query[1:])
134 self.assertEqual(query_dict["foo"], ["1"])
135 if six.PY3:
136 # Python 3, no need to encode
137 self.assertEqual(query_dict["bar"], [u"\N{COMET}"])
138 else:
139 # Python 2, encode string
140 self.assertEqual(query_dict["bar"], [u"\N{COMET}".encode("utf-8")])
141 self.assertEqual(query_dict["baz"], ["fe", "fi", "fo", "fum"])
142 self.assertTrue("qux" not in query_dict)
143 self.assertEqual(body, "{}")
Ali Afshar81fde8e2012-10-23 11:14:28 -0700144
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700145 def test_user_agent(self):
146 model = JsonModel(data_wrapper=False)
147
148 headers = {"user-agent": "my-test-app/1.23.4"}
149 path_params = {}
150 query_params = {}
151 body = {}
152
153 headers, unused_params, unused_query, body = model.request(
154 headers, path_params, query_params, body
155 )
156
157 self.assertEqual(headers["user-agent"], "my-test-app/1.23.4 (gzip)")
158
159 def test_x_goog_api_client(self):
160 model = JsonModel(data_wrapper=False)
161
162 # test header composition for cloud clients that wrap discovery
163 headers = {"x-goog-api-client": "gccl/1.23.4"}
164 path_params = {}
165 query_params = {}
166 body = {}
167
168 headers, unused_params, unused_query, body = model.request(
169 headers, path_params, query_params, body
170 )
171
172 self.assertEqual(
173 headers["x-goog-api-client"],
174 "gccl/1.23.4"
175 + " gdcl/"
Bu Sun Kimf706cfd2020-04-20 14:05:05 -0700176 + _LIBRARY_VERSION
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700177 + " gl-python/"
178 + platform.python_version(),
179 )
180
181 def test_bad_response(self):
182 model = JsonModel(data_wrapper=False)
183 resp = httplib2.Response({"status": "401"})
184 resp.reason = "Unauthorized"
185 content = b'{"error": {"message": "not authorized"}}'
186
187 try:
188 content = model.response(resp, content)
189 self.fail("Should have thrown an exception")
190 except HttpError as e:
191 self.assertTrue("not authorized" in str(e))
192
193 resp["content-type"] = "application/json"
194
195 try:
196 content = model.response(resp, content)
197 self.fail("Should have thrown an exception")
198 except HttpError as e:
199 self.assertTrue("not authorized" in str(e))
200
201 def test_good_response(self):
202 model = JsonModel(data_wrapper=True)
203 resp = httplib2.Response({"status": "200"})
204 resp.reason = "OK"
205 content = '{"data": "is good"}'
206
207 content = model.response(resp, content)
208 self.assertEqual(content, "is good")
209
210 def test_good_response_wo_data(self):
211 model = JsonModel(data_wrapper=False)
212 resp = httplib2.Response({"status": "200"})
213 resp.reason = "OK"
214 content = '{"foo": "is good"}'
215
216 content = model.response(resp, content)
217 self.assertEqual(content, {"foo": "is good"})
218
219 def test_good_response_wo_data_str(self):
220 model = JsonModel(data_wrapper=False)
221 resp = httplib2.Response({"status": "200"})
222 resp.reason = "OK"
223 content = '"data goes here"'
224
225 content = model.response(resp, content)
226 self.assertEqual(content, "data goes here")
227
228 def test_no_content_response(self):
229 model = JsonModel(data_wrapper=False)
230 resp = httplib2.Response({"status": "204"})
231 resp.reason = "No Content"
232 content = ""
233
234 content = model.response(resp, content)
235 self.assertEqual(content, {})
236
237 def test_logging(self):
238 class MockLogging(object):
239 def __init__(self):
240 self.info_record = []
241 self.debug_record = []
242
243 def info(self, message, *args):
244 self.info_record.append(message % args)
245
246 def debug(self, message, *args):
247 self.debug_record.append(message % args)
248
249 class MockResponse(dict):
250 def __init__(self, items):
251 super(MockResponse, self).__init__()
252 self.status = items["status"]
253 for key, value in six.iteritems(items):
254 self[key] = value
255
256 old_logging = googleapiclient.model.LOGGER
257 googleapiclient.model.LOGGER = MockLogging()
258 googleapiclient.model.dump_request_response = True
259 model = JsonModel()
260 request_body = {"field1": "value1", "field2": "value2"}
261 body_string = model.request({}, {}, {}, request_body)[-1]
262 json_body = json.loads(body_string)
263 self.assertEqual(request_body, json_body)
264
265 response = {
266 "status": 200,
267 "response_field_1": "response_value_1",
268 "response_field_2": "response_value_2",
269 }
270 response_body = model.response(MockResponse(response), body_string)
271 self.assertEqual(request_body, response_body)
272 self.assertEqual(
273 googleapiclient.model.LOGGER.info_record[:2],
274 ["--request-start--", "-headers-start-"],
275 )
276 self.assertTrue(
277 "response_field_1: response_value_1"
278 in googleapiclient.model.LOGGER.info_record
279 )
280 self.assertTrue(
281 "response_field_2: response_value_2"
282 in googleapiclient.model.LOGGER.info_record
283 )
284 self.assertEqual(
285 json.loads(googleapiclient.model.LOGGER.info_record[-2]), request_body
286 )
287 self.assertEqual(
288 googleapiclient.model.LOGGER.info_record[-1], "--response-end--"
289 )
290 googleapiclient.model.LOGGER = old_logging
291
292 def test_no_data_wrapper_deserialize(self):
293 model = JsonModel(data_wrapper=False)
294 resp = httplib2.Response({"status": "200"})
295 resp.reason = "OK"
296 content = '{"data": "is good"}'
297 content = model.response(resp, content)
298 self.assertEqual(content, {"data": "is good"})
299
300 def test_data_wrapper_deserialize(self):
301 model = JsonModel(data_wrapper=True)
302 resp = httplib2.Response({"status": "200"})
303 resp.reason = "OK"
304 content = '{"data": "is good"}'
305 content = model.response(resp, content)
306 self.assertEqual(content, "is good")
307
308 def test_data_wrapper_deserialize_nodata(self):
309 model = JsonModel(data_wrapper=True)
310 resp = httplib2.Response({"status": "200"})
311 resp.reason = "OK"
312 content = '{"atad": "is good"}'
313 content = model.response(resp, content)
314 self.assertEqual(content, {"atad": "is good"})
Ali Afshar81fde8e2012-10-23 11:14:28 -0700315
316
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700317if __name__ == "__main__":
318 unittest.main()