blob: 416b7be93eb1f01e7e30e0553ec684b753263c95 [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
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040022
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070023__author__ = "jcgregorio@google.com (Joe Gregorio)"
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040024
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -040025import httplib2
Craig Citro6ae34d72014-08-18 23:10:09 -070026import json
Bu Sun Kimf706cfd2020-04-20 14:05:05 -070027import pkg_resources
Bu Sun Kim07f647c2019-08-09 14:55:24 -070028import platform
Pat Ferate497a90f2015-03-09 09:52:54 -070029import unittest2 as unittest
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -040030import urllib
31
John Asmuth864311d2014-04-24 15:46:08 -040032import googleapiclient.model
ade@google.comd69e5e42010-08-31 15:28:20 +010033
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -040034
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
Bu Sun Kimf706cfd2020-04-20 14:05:05 -070038_LIBRARY_VERSION = pkg_resources.get_distribution("google-api-python-client").version
39
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040040
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040041class Model(unittest.TestCase):
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070042 def test_json_no_body(self):
43 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040044
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070045 headers = {}
46 path_params = {}
47 query_params = {}
48 body = None
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040049
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070050 headers, unused_params, query, body = model.request(
51 headers, path_params, query_params, body
52 )
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040053
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070054 self.assertEqual(headers["accept"], "application/json")
55 self.assertTrue("content-type" not in headers)
56 self.assertNotEqual(query, "")
57 self.assertEqual(body, None)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040058
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070059 def test_json_body(self):
60 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040061
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070062 headers = {}
63 path_params = {}
64 query_params = {}
65 body = {}
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040066
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070067 headers, unused_params, query, body = model.request(
68 headers, path_params, query_params, body
69 )
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040070
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070071 self.assertEqual(headers["accept"], "application/json")
72 self.assertEqual(headers["content-type"], "application/json")
73 self.assertNotEqual(query, "")
74 self.assertEqual(body, "{}")
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040075
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070076 def test_json_body_data_wrapper(self):
77 model = JsonModel(data_wrapper=True)
Joe Gregoriod433b2a2011-02-22 10:51:51 -050078
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070079 headers = {}
80 path_params = {}
81 query_params = {}
82 body = {}
Joe Gregoriod433b2a2011-02-22 10:51:51 -050083
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070084 headers, unused_params, query, body = model.request(
85 headers, path_params, query_params, body
86 )
Joe Gregoriod433b2a2011-02-22 10:51:51 -050087
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070088 self.assertEqual(headers["accept"], "application/json")
89 self.assertEqual(headers["content-type"], "application/json")
90 self.assertNotEqual(query, "")
91 self.assertEqual(body, '{"data": {}}')
Joe Gregoriod433b2a2011-02-22 10:51:51 -050092
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070093 def test_json_body_default_data(self):
94 """Test that a 'data' wrapper doesn't get added if one is already present."""
95 model = JsonModel(data_wrapper=True)
Joe Gregorio8963ff92010-10-11 13:14:43 -040096
Bu Sun Kim66bb32c2019-10-30 10:11:58 -070097 headers = {}
98 path_params = {}
99 query_params = {}
100 body = {"data": "foo"}
Joe Gregorio8963ff92010-10-11 13:14:43 -0400101
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700102 headers, unused_params, query, body = model.request(
103 headers, path_params, query_params, body
104 )
Joe Gregorio8963ff92010-10-11 13:14:43 -0400105
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700106 self.assertEqual(headers["accept"], "application/json")
107 self.assertEqual(headers["content-type"], "application/json")
108 self.assertNotEqual(query, "")
109 self.assertEqual(body, '{"data": "foo"}')
Joe Gregorio8963ff92010-10-11 13:14:43 -0400110
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700111 def test_json_build_query(self):
112 model = JsonModel(data_wrapper=False)
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400113
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700114 headers = {}
115 path_params = {}
116 query_params = {
117 "foo": 1,
118 "bar": u"\N{COMET}",
119 "baz": ["fe", "fi", "fo", "fum"], # Repeated parameters
120 "qux": [],
Joe Gregorio34044bc2011-03-07 16:58:33 -0500121 }
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700122 body = {}
Joe Gregorio34044bc2011-03-07 16:58:33 -0500123
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700124 headers, unused_params, query, body = model.request(
125 headers, path_params, query_params, body
126 )
Joe Gregorio34044bc2011-03-07 16:58:33 -0500127
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700128 self.assertEqual(headers["accept"], "application/json")
129 self.assertEqual(headers["content-type"], "application/json")
Ali Afshar81fde8e2012-10-23 11:14:28 -0700130
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -0400131 query_dict = urllib.parse.parse_qs(query[1:])
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700132 self.assertEqual(query_dict["foo"], ["1"])
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -0400133 self.assertEqual(query_dict["bar"], [u"\N{COMET}"])
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700134 self.assertEqual(query_dict["baz"], ["fe", "fi", "fo", "fum"])
135 self.assertTrue("qux" not in query_dict)
136 self.assertEqual(body, "{}")
Ali Afshar81fde8e2012-10-23 11:14:28 -0700137
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700138 def test_user_agent(self):
139 model = JsonModel(data_wrapper=False)
140
141 headers = {"user-agent": "my-test-app/1.23.4"}
142 path_params = {}
143 query_params = {}
144 body = {}
145
146 headers, unused_params, unused_query, body = model.request(
147 headers, path_params, query_params, body
148 )
149
150 self.assertEqual(headers["user-agent"], "my-test-app/1.23.4 (gzip)")
151
152 def test_x_goog_api_client(self):
153 model = JsonModel(data_wrapper=False)
154
155 # test header composition for cloud clients that wrap discovery
156 headers = {"x-goog-api-client": "gccl/1.23.4"}
157 path_params = {}
158 query_params = {}
159 body = {}
160
161 headers, unused_params, unused_query, body = model.request(
162 headers, path_params, query_params, body
163 )
164
165 self.assertEqual(
166 headers["x-goog-api-client"],
167 "gccl/1.23.4"
168 + " gdcl/"
Bu Sun Kimf706cfd2020-04-20 14:05:05 -0700169 + _LIBRARY_VERSION
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700170 + " gl-python/"
171 + platform.python_version(),
172 )
173
174 def test_bad_response(self):
175 model = JsonModel(data_wrapper=False)
176 resp = httplib2.Response({"status": "401"})
177 resp.reason = "Unauthorized"
178 content = b'{"error": {"message": "not authorized"}}'
179
180 try:
181 content = model.response(resp, content)
182 self.fail("Should have thrown an exception")
183 except HttpError as e:
184 self.assertTrue("not authorized" in str(e))
185
186 resp["content-type"] = "application/json"
187
188 try:
189 content = model.response(resp, content)
190 self.fail("Should have thrown an exception")
191 except HttpError as e:
192 self.assertTrue("not authorized" in str(e))
193
194 def test_good_response(self):
195 model = JsonModel(data_wrapper=True)
196 resp = httplib2.Response({"status": "200"})
197 resp.reason = "OK"
198 content = '{"data": "is good"}'
199
200 content = model.response(resp, content)
201 self.assertEqual(content, "is good")
202
203 def test_good_response_wo_data(self):
204 model = JsonModel(data_wrapper=False)
205 resp = httplib2.Response({"status": "200"})
206 resp.reason = "OK"
207 content = '{"foo": "is good"}'
208
209 content = model.response(resp, content)
210 self.assertEqual(content, {"foo": "is good"})
211
212 def test_good_response_wo_data_str(self):
213 model = JsonModel(data_wrapper=False)
214 resp = httplib2.Response({"status": "200"})
215 resp.reason = "OK"
216 content = '"data goes here"'
217
218 content = model.response(resp, content)
219 self.assertEqual(content, "data goes here")
220
221 def test_no_content_response(self):
222 model = JsonModel(data_wrapper=False)
223 resp = httplib2.Response({"status": "204"})
224 resp.reason = "No Content"
225 content = ""
226
227 content = model.response(resp, content)
228 self.assertEqual(content, {})
229
230 def test_logging(self):
231 class MockLogging(object):
232 def __init__(self):
233 self.info_record = []
234 self.debug_record = []
235
236 def info(self, message, *args):
237 self.info_record.append(message % args)
238
239 def debug(self, message, *args):
240 self.debug_record.append(message % args)
241
242 class MockResponse(dict):
243 def __init__(self, items):
244 super(MockResponse, self).__init__()
245 self.status = items["status"]
Anthonios Partheniou9f7b4102021-07-23 12:18:25 -0400246 for key, value in items.items():
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700247 self[key] = value
248
249 old_logging = googleapiclient.model.LOGGER
250 googleapiclient.model.LOGGER = MockLogging()
251 googleapiclient.model.dump_request_response = True
252 model = JsonModel()
253 request_body = {"field1": "value1", "field2": "value2"}
254 body_string = model.request({}, {}, {}, request_body)[-1]
255 json_body = json.loads(body_string)
256 self.assertEqual(request_body, json_body)
257
258 response = {
259 "status": 200,
260 "response_field_1": "response_value_1",
261 "response_field_2": "response_value_2",
262 }
263 response_body = model.response(MockResponse(response), body_string)
264 self.assertEqual(request_body, response_body)
265 self.assertEqual(
266 googleapiclient.model.LOGGER.info_record[:2],
267 ["--request-start--", "-headers-start-"],
268 )
269 self.assertTrue(
270 "response_field_1: response_value_1"
271 in googleapiclient.model.LOGGER.info_record
272 )
273 self.assertTrue(
274 "response_field_2: response_value_2"
275 in googleapiclient.model.LOGGER.info_record
276 )
277 self.assertEqual(
278 json.loads(googleapiclient.model.LOGGER.info_record[-2]), request_body
279 )
280 self.assertEqual(
281 googleapiclient.model.LOGGER.info_record[-1], "--response-end--"
282 )
283 googleapiclient.model.LOGGER = old_logging
284
285 def test_no_data_wrapper_deserialize(self):
286 model = JsonModel(data_wrapper=False)
287 resp = httplib2.Response({"status": "200"})
288 resp.reason = "OK"
289 content = '{"data": "is good"}'
290 content = model.response(resp, content)
291 self.assertEqual(content, {"data": "is good"})
292
293 def test_data_wrapper_deserialize(self):
294 model = JsonModel(data_wrapper=True)
295 resp = httplib2.Response({"status": "200"})
296 resp.reason = "OK"
297 content = '{"data": "is good"}'
298 content = model.response(resp, content)
299 self.assertEqual(content, "is good")
300
301 def test_data_wrapper_deserialize_nodata(self):
302 model = JsonModel(data_wrapper=True)
303 resp = httplib2.Response({"status": "200"})
304 resp.reason = "OK"
305 content = '{"atad": "is good"}'
306 content = model.response(resp, content)
307 self.assertEqual(content, {"atad": "is good"})
Ali Afshar81fde8e2012-10-23 11:14:28 -0700308
309
Bu Sun Kim66bb32c2019-10-30 10:11:58 -0700310if __name__ == "__main__":
311 unittest.main()