blob: fec71913d81f3e2f2248314a663fc9aeadb99d12 [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
24__author__ = 'jcgregorio@google.com (Joe Gregorio)'
25
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
29import unittest
Joe Gregorioc5c5a372010-09-22 11:42:32 -040030import httplib2
John Asmuth864311d2014-04-24 15:46:08 -040031import googleapiclient.model
ade@google.comd69e5e42010-08-31 15:28:20 +010032
John Asmuth864311d2014-04-24 15:46:08 -040033from googleapiclient import __version__
34from googleapiclient.errors import HttpError
35from googleapiclient.model import JsonModel
Joe Gregorio34044bc2011-03-07 16:58:33 -050036
ade@google.comd69e5e42010-08-31 15:28:20 +010037# Python 2.5 requires different modules
38try:
39 from urlparse import parse_qs
40except ImportError:
41 from cgi import parse_qs
42
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040043
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040044class Model(unittest.TestCase):
45 def test_json_no_body(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -050046 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040047
48 headers = {}
ade@google.com850cf552010-08-20 23:24:56 +010049 path_params = {}
50 query_params = {}
51 body = None
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040052
Joe Gregorio5a4c3282013-07-29 13:48:06 -040053 headers, unused_params, query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -040054 headers, path_params, query_params, body)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040055
56 self.assertEqual(headers['accept'], 'application/json')
57 self.assertTrue('content-type' not in headers)
58 self.assertNotEqual(query, '')
59 self.assertEqual(body, None)
60
61 def test_json_body(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -050062 model = JsonModel(data_wrapper=False)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040063
64 headers = {}
ade@google.com850cf552010-08-20 23:24:56 +010065 path_params = {}
66 query_params = {}
67 body = {}
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040068
Joe Gregorio5a4c3282013-07-29 13:48:06 -040069 headers, unused_params, query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -040070 headers, path_params, query_params, body)
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040071
72 self.assertEqual(headers['accept'], 'application/json')
73 self.assertEqual(headers['content-type'], 'application/json')
74 self.assertNotEqual(query, '')
Joe Gregorio913e70d2010-11-05 15:38:23 -040075 self.assertEqual(body, '{}')
Joe Gregorioba9ea7f2010-08-19 15:49:04 -040076
Joe Gregoriod433b2a2011-02-22 10:51:51 -050077 def test_json_body_data_wrapper(self):
78 model = JsonModel(data_wrapper=True)
79
80 headers = {}
81 path_params = {}
82 query_params = {}
83 body = {}
84
Joe Gregorio5a4c3282013-07-29 13:48:06 -040085 headers, unused_params, query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -040086 headers, path_params, query_params, body)
Joe Gregoriod433b2a2011-02-22 10:51:51 -050087
88 self.assertEqual(headers['accept'], 'application/json')
89 self.assertEqual(headers['content-type'], 'application/json')
90 self.assertNotEqual(query, '')
91 self.assertEqual(body, '{"data": {}}')
92
Joe Gregorio8963ff92010-10-11 13:14:43 -040093 def test_json_body_default_data(self):
94 """Test that a 'data' wrapper doesn't get added if one is already present."""
Joe Gregoriod433b2a2011-02-22 10:51:51 -050095 model = JsonModel(data_wrapper=True)
Joe Gregorio8963ff92010-10-11 13:14:43 -040096
97 headers = {}
98 path_params = {}
99 query_params = {}
100 body = {'data': 'foo'}
101
Joe Gregorio5a4c3282013-07-29 13:48:06 -0400102 headers, unused_params, query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -0400103 headers, path_params, query_params, body)
Joe Gregorio8963ff92010-10-11 13:14:43 -0400104
105 self.assertEqual(headers['accept'], 'application/json')
106 self.assertEqual(headers['content-type'], 'application/json')
107 self.assertNotEqual(query, '')
108 self.assertEqual(body, '{"data": "foo"}')
109
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400110 def test_json_build_query(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500111 model = JsonModel(data_wrapper=False)
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400112
113 headers = {}
114 path_params = {}
Joe Gregorio61d7e962011-02-22 22:52:07 -0500115 query_params = {'foo': 1, 'bar': u'\N{COMET}',
116 'baz': ['fe', 'fi', 'fo', 'fum'], # Repeated parameters
117 'qux': []}
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400118 body = {}
119
Joe Gregorio5a4c3282013-07-29 13:48:06 -0400120 headers, unused_params, query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -0400121 headers, path_params, query_params, body)
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400122
123 self.assertEqual(headers['accept'], 'application/json')
124 self.assertEqual(headers['content-type'], 'application/json')
125
Joe Gregorio61d7e962011-02-22 22:52:07 -0500126 query_dict = parse_qs(query[1:])
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400127 self.assertEqual(query_dict['foo'], ['1'])
128 self.assertEqual(query_dict['bar'], [u'\N{COMET}'.encode('utf-8')])
Joe Gregorio61d7e962011-02-22 22:52:07 -0500129 self.assertEqual(query_dict['baz'], ['fe', 'fi', 'fo', 'fum'])
130 self.assertTrue('qux' not in query_dict)
Joe Gregorio913e70d2010-11-05 15:38:23 -0400131 self.assertEqual(body, '{}')
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400132
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400133 def test_user_agent(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500134 model = JsonModel(data_wrapper=False)
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400135
136 headers = {'user-agent': 'my-test-app/1.23.4'}
137 path_params = {}
138 query_params = {}
139 body = {}
140
Joe Gregorio5a4c3282013-07-29 13:48:06 -0400141 headers, unused_params, unused_query, body = model.request(
Joe Gregorioa314b1f2013-04-05 16:25:11 -0400142 headers, path_params, query_params, body)
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400143
Joe Gregorioa314b1f2013-04-05 16:25:11 -0400144 self.assertEqual(headers['user-agent'],
Joe Gregorioc02f5632013-05-13 11:28:56 -0400145 'my-test-app/1.23.4 google-api-python-client/' + __version__ +
146 ' (gzip)')
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400147
148 def test_bad_response(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500149 model = JsonModel(data_wrapper=False)
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400150 resp = httplib2.Response({'status': '401'})
151 resp.reason = 'Unauthorized'
Joe Gregoriod4e14562011-01-04 09:51:45 -0500152 content = '{"error": {"message": "not authorized"}}'
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400153
154 try:
155 content = model.response(resp, content)
156 self.fail('Should have thrown an exception')
INADA Naokic1505df2014-08-20 15:19:53 +0900157 except HttpError as e:
Joe Gregorio20b54fb2012-07-26 09:59:35 -0400158 self.assertTrue('not authorized' in str(e))
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400159
160 resp['content-type'] = 'application/json'
161
162 try:
163 content = model.response(resp, content)
164 self.fail('Should have thrown an exception')
INADA Naokic1505df2014-08-20 15:19:53 +0900165 except HttpError as e:
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400166 self.assertTrue('not authorized' in str(e))
167
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400168 def test_good_response(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500169 model = JsonModel(data_wrapper=True)
Joe Gregorioc5c5a372010-09-22 11:42:32 -0400170 resp = httplib2.Response({'status': '200'})
171 resp.reason = 'OK'
172 content = '{"data": "is good"}'
173
174 content = model.response(resp, content)
175 self.assertEqual(content, 'is good')
Joe Gregoriofe695fb2010-08-30 12:04:04 -0400176
Joe Gregorio78a508d2010-10-26 16:36:36 -0400177 def test_good_response_wo_data(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500178 model = JsonModel(data_wrapper=False)
Joe Gregorio78a508d2010-10-26 16:36:36 -0400179 resp = httplib2.Response({'status': '200'})
180 resp.reason = 'OK'
181 content = '{"foo": "is good"}'
182
183 content = model.response(resp, content)
184 self.assertEqual(content, {'foo': 'is good'})
185
186 def test_good_response_wo_data_str(self):
Joe Gregoriod433b2a2011-02-22 10:51:51 -0500187 model = JsonModel(data_wrapper=False)
Joe Gregorio78a508d2010-10-26 16:36:36 -0400188 resp = httplib2.Response({'status': '200'})
189 resp.reason = 'OK'
190 content = '"data goes here"'
191
192 content = model.response(resp, content)
193 self.assertEqual(content, 'data goes here')
194
Matt McDonald2a5f4132011-04-29 16:32:27 -0400195 def test_no_content_response(self):
196 model = JsonModel(data_wrapper=False)
197 resp = httplib2.Response({'status': '204'})
198 resp.reason = 'No Content'
199 content = ''
Joe Gregorio34044bc2011-03-07 16:58:33 -0500200
Matt McDonald2a5f4132011-04-29 16:32:27 -0400201 content = model.response(resp, content)
202 self.assertEqual(content, {})
Joe Gregorio34044bc2011-03-07 16:58:33 -0500203
Matt McDonald2a5f4132011-04-29 16:32:27 -0400204 def test_logging(self):
Joe Gregorio34044bc2011-03-07 16:58:33 -0500205 class MockLogging(object):
206 def __init__(self):
207 self.info_record = []
208 self.debug_record = []
209 def info(self, message, *args):
210 self.info_record.append(message % args)
211
212 def debug(self, message, *args):
213 self.debug_record.append(message % args)
214
215 class MockResponse(dict):
216 def __init__(self, items):
217 super(MockResponse, self).__init__()
218 self.status = items['status']
INADA Naokid898a372015-03-04 03:52:46 +0900219 for key, value in six.iteritems(items):
Joe Gregorio34044bc2011-03-07 16:58:33 -0500220 self[key] = value
John Asmuth864311d2014-04-24 15:46:08 -0400221 old_logging = googleapiclient.model.logging
222 googleapiclient.model.logging = MockLogging()
223 googleapiclient.model.dump_request_response = True
Matt McDonald2a5f4132011-04-29 16:32:27 -0400224 model = JsonModel()
Joe Gregorio34044bc2011-03-07 16:58:33 -0500225 request_body = {
226 'field1': 'value1',
227 'field2': 'value2'
228 }
229 body_string = model.request({}, {}, {}, request_body)[-1]
Craig Citro6ae34d72014-08-18 23:10:09 -0700230 json_body = json.loads(body_string)
Joe Gregorio34044bc2011-03-07 16:58:33 -0500231 self.assertEqual(request_body, json_body)
232
233 response = {'status': 200,
234 'response_field_1': 'response_value_1',
235 'response_field_2': 'response_value_2'}
236 response_body = model.response(MockResponse(response), body_string)
237 self.assertEqual(request_body, response_body)
John Asmuth864311d2014-04-24 15:46:08 -0400238 self.assertEqual(googleapiclient.model.logging.info_record[:2],
Joe Gregorioafdf50b2011-03-08 09:41:52 -0500239 ['--request-start--',
240 '-headers-start-'])
241 self.assertTrue('response_field_1: response_value_1' in
John Asmuth864311d2014-04-24 15:46:08 -0400242 googleapiclient.model.logging.info_record)
Joe Gregorioafdf50b2011-03-08 09:41:52 -0500243 self.assertTrue('response_field_2: response_value_2' in
John Asmuth864311d2014-04-24 15:46:08 -0400244 googleapiclient.model.logging.info_record)
Craig Citro6ae34d72014-08-18 23:10:09 -0700245 self.assertEqual(json.loads(googleapiclient.model.logging.info_record[-2]),
Joe Gregorio34044bc2011-03-07 16:58:33 -0500246 request_body)
John Asmuth864311d2014-04-24 15:46:08 -0400247 self.assertEqual(googleapiclient.model.logging.info_record[-1],
Joe Gregorio34044bc2011-03-07 16:58:33 -0500248 '--response-end--')
John Asmuth864311d2014-04-24 15:46:08 -0400249 googleapiclient.model.logging = old_logging
Joe Gregorio34044bc2011-03-07 16:58:33 -0500250
Ali Afshar81fde8e2012-10-23 11:14:28 -0700251 def test_no_data_wrapper_deserialize(self):
252 model = JsonModel(data_wrapper=False)
253 resp = httplib2.Response({'status': '200'})
254 resp.reason = 'OK'
255 content = '{"data": "is good"}'
256 content = model.response(resp, content)
257 self.assertEqual(content, {'data': 'is good'})
258
259 def test_data_wrapper_deserialize(self):
260 model = JsonModel(data_wrapper=True)
261 resp = httplib2.Response({'status': '200'})
262 resp.reason = 'OK'
263 content = '{"data": "is good"}'
264 content = model.response(resp, content)
265 self.assertEqual(content, 'is good')
266
267 def test_data_wrapper_deserialize_nodata(self):
268 model = JsonModel(data_wrapper=True)
269 resp = httplib2.Response({'status': '200'})
270 resp.reason = 'OK'
271 content = '{"atad": "is good"}'
272 content = model.response(resp, content)
273 self.assertEqual(content, {'atad': 'is good'})
274
275
Joe Gregorio34044bc2011-03-07 16:58:33 -0500276
Joe Gregorioba9ea7f2010-08-19 15:49:04 -0400277if __name__ == '__main__':
278 unittest.main()