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