blob: 64ad3bcf983a72c1df753e8db991f4ef01fe2e9f [file] [log] [blame]
Matthew Treinisha33037e2013-12-05 23:16:39 +00001# Copyright 2013 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import httplib2
vponomaryov67b58fe2014-02-06 19:05:41 +020016import json
Matthew Treinisha33037e2013-12-05 23:16:39 +000017
18from tempest.common import rest_client
Matthew Treinish28f164c2014-03-04 18:55:06 +000019from tempest.common import xml_utils as xml
Matthew Treinish684d8992014-01-30 16:27:40 +000020from tempest import config
Matthew Treinisha33037e2013-12-05 23:16:39 +000021from tempest import exceptions
22from tempest.openstack.common.fixture import mockpatch
23from tempest.tests import base
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000024from tempest.tests import fake_auth_provider
Matthew Treinisha33037e2013-12-05 23:16:39 +000025from tempest.tests import fake_config
26from tempest.tests import fake_http
27
28
29class BaseRestClientTestClass(base.TestCase):
30
vponomaryov67b58fe2014-02-06 19:05:41 +020031 url = 'fake_endpoint'
32
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000033 def _get_region(self):
34 return 'fake region'
Matthew Treinisha33037e2013-12-05 23:16:39 +000035
36 def setUp(self):
37 super(BaseRestClientTestClass, self).setUp()
Matthew Treinishff598482014-02-28 16:13:58 -050038 self.useFixture(fake_config.ConfigFixture())
39 self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000040 self.rest_client = rest_client.RestClient(
41 fake_auth_provider.FakeAuthProvider())
Matthew Treinisha33037e2013-12-05 23:16:39 +000042 self.stubs.Set(httplib2.Http, 'request', self.fake_http.request)
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000043 self.useFixture(mockpatch.PatchObject(self.rest_client, '_get_region',
44 side_effect=self._get_region()))
Matthew Treinisha33037e2013-12-05 23:16:39 +000045 self.useFixture(mockpatch.PatchObject(self.rest_client,
Sean Dague89a85912014-03-19 16:37:29 -040046 '_log_request'))
Matthew Treinisha33037e2013-12-05 23:16:39 +000047
48
49class TestRestClientHTTPMethods(BaseRestClientTestClass):
50 def setUp(self):
51 self.fake_http = fake_http.fake_httplib2()
52 super(TestRestClientHTTPMethods, self).setUp()
53 self.useFixture(mockpatch.PatchObject(self.rest_client,
54 '_error_checker'))
55
56 def test_post(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020057 __, return_dict = self.rest_client.post(self.url, {}, {})
Matthew Treinisha33037e2013-12-05 23:16:39 +000058 self.assertEqual('POST', return_dict['method'])
59
60 def test_get(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020061 __, return_dict = self.rest_client.get(self.url)
Matthew Treinisha33037e2013-12-05 23:16:39 +000062 self.assertEqual('GET', return_dict['method'])
63
64 def test_delete(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020065 __, return_dict = self.rest_client.delete(self.url)
Matthew Treinisha33037e2013-12-05 23:16:39 +000066 self.assertEqual('DELETE', return_dict['method'])
67
68 def test_patch(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020069 __, return_dict = self.rest_client.patch(self.url, {}, {})
Matthew Treinisha33037e2013-12-05 23:16:39 +000070 self.assertEqual('PATCH', return_dict['method'])
71
72 def test_put(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020073 __, return_dict = self.rest_client.put(self.url, {}, {})
Matthew Treinisha33037e2013-12-05 23:16:39 +000074 self.assertEqual('PUT', return_dict['method'])
75
76 def test_head(self):
77 self.useFixture(mockpatch.PatchObject(self.rest_client,
78 'response_checker'))
vponomaryov67b58fe2014-02-06 19:05:41 +020079 __, return_dict = self.rest_client.head(self.url)
Matthew Treinisha33037e2013-12-05 23:16:39 +000080 self.assertEqual('HEAD', return_dict['method'])
81
82 def test_copy(self):
vponomaryov67b58fe2014-02-06 19:05:41 +020083 __, return_dict = self.rest_client.copy(self.url)
Matthew Treinisha33037e2013-12-05 23:16:39 +000084 self.assertEqual('COPY', return_dict['method'])
85
86
87class TestRestClientNotFoundHandling(BaseRestClientTestClass):
88 def setUp(self):
89 self.fake_http = fake_http.fake_httplib2(404)
90 super(TestRestClientNotFoundHandling, self).setUp()
91
92 def test_post(self):
93 self.assertRaises(exceptions.NotFound, self.rest_client.post,
vponomaryov67b58fe2014-02-06 19:05:41 +020094 self.url, {}, {})
95
96
97class TestRestClientHeadersJSON(TestRestClientHTTPMethods):
98 TYPE = "json"
99
100 def _verify_headers(self, resp):
101 self.assertEqual(self.rest_client._get_type(), self.TYPE)
102 resp = dict((k.lower(), v) for k, v in resp.iteritems())
103 self.assertEqual(self.header_value, resp['accept'])
104 self.assertEqual(self.header_value, resp['content-type'])
105
106 def setUp(self):
107 super(TestRestClientHeadersJSON, self).setUp()
108 self.rest_client.TYPE = self.TYPE
109 self.header_value = 'application/%s' % self.rest_client._get_type()
110
111 def test_post(self):
112 resp, __ = self.rest_client.post(self.url, {})
113 self._verify_headers(resp)
114
115 def test_get(self):
116 resp, __ = self.rest_client.get(self.url)
117 self._verify_headers(resp)
118
119 def test_delete(self):
120 resp, __ = self.rest_client.delete(self.url)
121 self._verify_headers(resp)
122
123 def test_patch(self):
124 resp, __ = self.rest_client.patch(self.url, {})
125 self._verify_headers(resp)
126
127 def test_put(self):
128 resp, __ = self.rest_client.put(self.url, {})
129 self._verify_headers(resp)
130
131 def test_head(self):
132 self.useFixture(mockpatch.PatchObject(self.rest_client,
133 'response_checker'))
134 resp, __ = self.rest_client.head(self.url)
135 self._verify_headers(resp)
136
137 def test_copy(self):
138 resp, __ = self.rest_client.copy(self.url)
139 self._verify_headers(resp)
140
141
Sergey Murashov4fccd322014-03-22 09:58:52 +0400142class TestRestClientUpdateHeaders(BaseRestClientTestClass):
143 def setUp(self):
144 self.fake_http = fake_http.fake_httplib2()
145 super(TestRestClientUpdateHeaders, self).setUp()
146 self.useFixture(mockpatch.PatchObject(self.rest_client,
147 '_error_checker'))
148 self.headers = {'X-Configuration-Session': 'session_id'}
149
150 def test_post_update_headers(self):
151 __, return_dict = self.rest_client.post(self.url, {},
152 extra_headers=True,
153 headers=self.headers)
154
155 self.assertDictContainsSubset(
156 {'X-Configuration-Session': 'session_id',
157 'Content-Type': 'application/json',
158 'Accept': 'application/json'},
159 return_dict['headers']
160 )
161
162 def test_get_update_headers(self):
163 __, return_dict = self.rest_client.get(self.url,
164 extra_headers=True,
165 headers=self.headers)
166
167 self.assertDictContainsSubset(
168 {'X-Configuration-Session': 'session_id',
169 'Content-Type': 'application/json',
170 'Accept': 'application/json'},
171 return_dict['headers']
172 )
173
174 def test_delete_update_headers(self):
175 __, return_dict = self.rest_client.delete(self.url,
176 extra_headers=True,
177 headers=self.headers)
178
179 self.assertDictContainsSubset(
180 {'X-Configuration-Session': 'session_id',
181 'Content-Type': 'application/json',
182 'Accept': 'application/json'},
183 return_dict['headers']
184 )
185
186 def test_patch_update_headers(self):
187 __, return_dict = self.rest_client.patch(self.url, {},
188 extra_headers=True,
189 headers=self.headers)
190
191 self.assertDictContainsSubset(
192 {'X-Configuration-Session': 'session_id',
193 'Content-Type': 'application/json',
194 'Accept': 'application/json'},
195 return_dict['headers']
196 )
197
198 def test_put_update_headers(self):
199 __, return_dict = self.rest_client.put(self.url, {},
200 extra_headers=True,
201 headers=self.headers)
202
203 self.assertDictContainsSubset(
204 {'X-Configuration-Session': 'session_id',
205 'Content-Type': 'application/json',
206 'Accept': 'application/json'},
207 return_dict['headers']
208 )
209
210 def test_head_update_headers(self):
211 self.useFixture(mockpatch.PatchObject(self.rest_client,
212 'response_checker'))
213
214 __, return_dict = self.rest_client.head(self.url,
215 extra_headers=True,
216 headers=self.headers)
217
218 self.assertDictContainsSubset(
219 {'X-Configuration-Session': 'session_id',
220 'Content-Type': 'application/json',
221 'Accept': 'application/json'},
222 return_dict['headers']
223 )
224
225 def test_copy_update_headers(self):
226 __, return_dict = self.rest_client.copy(self.url,
227 extra_headers=True,
228 headers=self.headers)
229
230 self.assertDictContainsSubset(
231 {'X-Configuration-Session': 'session_id',
232 'Content-Type': 'application/json',
233 'Accept': 'application/json'},
234 return_dict['headers']
235 )
236
237
vponomaryov67b58fe2014-02-06 19:05:41 +0200238class TestRestClientHeadersXML(TestRestClientHeadersJSON):
239 TYPE = "xml"
240
241 # These two tests are needed in one exemplar
242 def test_send_json_accept_xml(self):
243 resp, __ = self.rest_client.get(self.url,
244 self.rest_client.get_headers("xml",
245 "json"))
246 resp = dict((k.lower(), v) for k, v in resp.iteritems())
247 self.assertEqual("application/json", resp["content-type"])
248 self.assertEqual("application/xml", resp["accept"])
249
250 def test_send_xml_accept_json(self):
251 resp, __ = self.rest_client.get(self.url,
252 self.rest_client.get_headers("json",
253 "xml"))
254 resp = dict((k.lower(), v) for k, v in resp.iteritems())
255 self.assertEqual("application/json", resp["accept"])
256 self.assertEqual("application/xml", resp["content-type"])
257
258
259class TestRestClientParseRespXML(BaseRestClientTestClass):
260 TYPE = "xml"
261
262 keys = ["fake_key1", "fake_key2"]
263 values = ["fake_value1", "fake_value2"]
Dirk Muellerb9a57152014-02-21 15:48:32 +0100264 item_expected = dict((key, value) for (key, value) in zip(keys, values))
vponomaryov67b58fe2014-02-06 19:05:41 +0200265 list_expected = {"body_list": [
266 {keys[0]: values[0]},
267 {keys[1]: values[1]},
268 ]}
269 dict_expected = {"body_dict": {
270 keys[0]: values[0],
271 keys[1]: values[1],
272 }}
273
274 def setUp(self):
275 self.fake_http = fake_http.fake_httplib2()
276 super(TestRestClientParseRespXML, self).setUp()
277 self.rest_client.TYPE = self.TYPE
278
279 def test_parse_resp_body_item(self):
280 body_item = xml.Element("item", **self.item_expected)
281 body = self.rest_client._parse_resp(str(xml.Document(body_item)))
282 self.assertEqual(self.item_expected, body)
283
284 def test_parse_resp_body_list(self):
285 self.rest_client.list_tags = ["fake_list", ]
286 body_list = xml.Element(self.rest_client.list_tags[0])
287 for i in range(2):
288 body_list.append(xml.Element("fake_item",
289 **self.list_expected["body_list"][i]))
290 body = self.rest_client._parse_resp(str(xml.Document(body_list)))
291 self.assertEqual(self.list_expected["body_list"], body)
292
293 def test_parse_resp_body_dict(self):
294 self.rest_client.dict_tags = ["fake_dict", ]
295 body_dict = xml.Element(self.rest_client.dict_tags[0])
296
297 for i in range(2):
298 body_dict.append(xml.Element("fake_item", xml.Text(self.values[i]),
299 key=self.keys[i]))
300
301 body = self.rest_client._parse_resp(str(xml.Document(body_dict)))
302 self.assertEqual(self.dict_expected["body_dict"], body)
303
304
305class TestRestClientParseRespJSON(TestRestClientParseRespXML):
306 TYPE = "json"
307
308 def test_parse_resp_body_item(self):
309 body = self.rest_client._parse_resp(json.dumps(self.item_expected))
310 self.assertEqual(self.item_expected, body)
311
312 def test_parse_resp_body_list(self):
313 body = self.rest_client._parse_resp(json.dumps(self.list_expected))
314 self.assertEqual(self.list_expected["body_list"], body)
315
316 def test_parse_resp_body_dict(self):
317 body = self.rest_client._parse_resp(json.dumps(self.dict_expected))
318 self.assertEqual(self.dict_expected["body_dict"], body)
319
320 def test_parse_resp_two_top_keys(self):
321 dict_two_keys = self.dict_expected.copy()
322 dict_two_keys.update({"second_key": ""})
323 body = self.rest_client._parse_resp(json.dumps(dict_two_keys))
324 self.assertEqual(dict_two_keys, body)
325
326 def test_parse_resp_one_top_key_without_list_or_dict(self):
327 data = {"one_top_key": "not_list_or_dict_value"}
328 body = self.rest_client._parse_resp(json.dumps(data))
329 self.assertEqual(data, body)
vponomaryov6cb6d192014-03-07 09:39:05 +0200330
331
332class TestRestClientErrorCheckerJSON(base.TestCase):
333 c_type = "application/json"
334
335 def set_data(self, r_code, enc=None, r_body=None):
336 if enc is None:
337 enc = self.c_type
338 resp_dict = {'status': r_code, 'content-type': enc}
339 resp = httplib2.Response(resp_dict)
340 data = {
341 "method": "fake_method",
342 "url": "fake_url",
343 "headers": "fake_headers",
344 "body": "fake_body",
345 "resp": resp,
346 "resp_body": '{"resp_body": "fake_resp_body"}',
347 }
348 if r_body is not None:
349 data.update({"resp_body": r_body})
350 return data
351
352 def setUp(self):
353 super(TestRestClientErrorCheckerJSON, self).setUp()
Matthew Treinishff598482014-02-28 16:13:58 -0500354 self.useFixture(fake_config.ConfigFixture())
355 self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
vponomaryov6cb6d192014-03-07 09:39:05 +0200356 self.rest_client = rest_client.RestClient(
357 fake_auth_provider.FakeAuthProvider())
358
359 def test_response_less_than_400(self):
360 self.rest_client._error_checker(**self.set_data("399"))
361
362 def test_response_400(self):
363 self.assertRaises(exceptions.BadRequest,
364 self.rest_client._error_checker,
365 **self.set_data("400"))
366
367 def test_response_401(self):
368 self.assertRaises(exceptions.Unauthorized,
369 self.rest_client._error_checker,
370 **self.set_data("401"))
371
372 def test_response_403(self):
373 self.assertRaises(exceptions.Unauthorized,
374 self.rest_client._error_checker,
375 **self.set_data("403"))
376
377 def test_response_404(self):
378 self.assertRaises(exceptions.NotFound,
379 self.rest_client._error_checker,
380 **self.set_data("404"))
381
382 def test_response_409(self):
383 self.assertRaises(exceptions.Conflict,
384 self.rest_client._error_checker,
385 **self.set_data("409"))
386
387 def test_response_413(self):
388 self.assertRaises(exceptions.OverLimit,
389 self.rest_client._error_checker,
390 **self.set_data("413"))
391
392 def test_response_422(self):
393 self.assertRaises(exceptions.UnprocessableEntity,
394 self.rest_client._error_checker,
395 **self.set_data("422"))
396
397 def test_response_500_with_text(self):
398 # _parse_resp is expected to return 'str'
399 self.assertRaises(exceptions.ServerFault,
400 self.rest_client._error_checker,
401 **self.set_data("500"))
402
403 def test_response_501_with_text(self):
404 self.assertRaises(exceptions.ServerFault,
405 self.rest_client._error_checker,
406 **self.set_data("501"))
407
408 def test_response_500_with_dict(self):
409 r_body = '{"resp_body": {"err": "fake_resp_body"}}'
410 self.assertRaises(exceptions.ServerFault,
411 self.rest_client._error_checker,
412 **self.set_data("500", r_body=r_body))
413
414 def test_response_501_with_dict(self):
415 r_body = '{"resp_body": {"err": "fake_resp_body"}}'
416 self.assertRaises(exceptions.ServerFault,
417 self.rest_client._error_checker,
418 **self.set_data("501", r_body=r_body))
419
420 def test_response_bigger_than_400(self):
421 # Any response code, that bigger than 400, and not in
422 # (401, 403, 404, 409, 413, 422, 500, 501)
423 self.assertRaises(exceptions.UnexpectedResponseCode,
424 self.rest_client._error_checker,
425 **self.set_data("402"))
426
427
428class TestRestClientErrorCheckerXML(TestRestClientErrorCheckerJSON):
429 c_type = "application/xml"
430
431
432class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
433 c_type = "text/plain"
434
435 def test_fake_content_type(self):
436 # This test is required only in one exemplar
437 # Any response code, that bigger than 400, and not in
438 # (401, 403, 404, 409, 413, 422, 500, 501)
439 self.assertRaises(exceptions.InvalidContentType,
440 self.rest_client._error_checker,
441 **self.set_data("405", enc="fake_enc"))
Matthew Treinishead51df2014-03-15 18:56:43 +0000442
443
444class TestRestClientUtils(BaseRestClientTestClass):
445
446 def _is_resource_deleted(self, resource_id):
447 if not isinstance(self.retry_pass, int):
448 return False
449 if self.retry_count >= self.retry_pass:
450 return True
451 self.retry_count = self.retry_count + 1
452 return False
453
454 def setUp(self):
455 self.fake_http = fake_http.fake_httplib2()
456 super(TestRestClientUtils, self).setUp()
457 self.retry_count = 0
458 self.retry_pass = None
459 self.original_deleted_method = self.rest_client.is_resource_deleted
460 self.rest_client.is_resource_deleted = self._is_resource_deleted
461
462 def test_wait_for_resource_deletion(self):
463 self.retry_pass = 2
464 # Ensure timeout long enough for loop execution to hit retry count
465 self.rest_client.build_timeout = 500
466 sleep_mock = self.patch('time.sleep')
467 self.rest_client.wait_for_resource_deletion('1234')
468 self.assertEqual(len(sleep_mock.mock_calls), 2)
469
470 def test_wait_for_resource_deletion_not_deleted(self):
471 self.patch('time.sleep')
472 # Set timeout to be very quick to force exception faster
473 self.rest_client.build_timeout = 1
474 self.assertRaises(exceptions.TimeoutException,
475 self.rest_client.wait_for_resource_deletion,
476 '1234')
477
478 def test_wait_for_deletion_with_unimplemented_deleted_method(self):
479 self.rest_client.is_resource_deleted = self.original_deleted_method
480 self.assertRaises(NotImplementedError,
481 self.rest_client.wait_for_resource_deletion,
482 '1234')
Masayuki Igawa4e942a32014-03-17 11:02:09 +0900483
484
485class TestNegativeRestClient(BaseRestClientTestClass):
486
487 def setUp(self):
488 self.fake_http = fake_http.fake_httplib2()
489 super(TestNegativeRestClient, self).setUp()
490 self.negative_rest_client = rest_client.NegativeRestClient(
491 fake_auth_provider.FakeAuthProvider())
492 self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
493 '_log_request'))
494
495 def test_post(self):
496 __, return_dict = self.negative_rest_client.send_request('POST',
497 self.url,
498 [], {})
499 self.assertEqual('POST', return_dict['method'])
500
501 def test_get(self):
502 __, return_dict = self.negative_rest_client.send_request('GET',
503 self.url,
504 [])
505 self.assertEqual('GET', return_dict['method'])
506
507 def test_delete(self):
508 __, return_dict = self.negative_rest_client.send_request('DELETE',
509 self.url,
510 [])
511 self.assertEqual('DELETE', return_dict['method'])
512
513 def test_patch(self):
514 __, return_dict = self.negative_rest_client.send_request('PATCH',
515 self.url,
516 [], {})
517 self.assertEqual('PATCH', return_dict['method'])
518
519 def test_put(self):
520 __, return_dict = self.negative_rest_client.send_request('PUT',
521 self.url,
522 [], {})
523 self.assertEqual('PUT', return_dict['method'])
524
525 def test_head(self):
526 self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
527 'response_checker'))
528 __, return_dict = self.negative_rest_client.send_request('HEAD',
529 self.url,
530 [])
531 self.assertEqual('HEAD', return_dict['method'])
532
533 def test_copy(self):
534 __, return_dict = self.negative_rest_client.send_request('COPY',
535 self.url,
536 [])
537 self.assertEqual('COPY', return_dict['method'])
538
539 def test_other(self):
540 self.assertRaises(AssertionError,
541 self.negative_rest_client.send_request,
542 'OTHER', self.url, [])