blob: bb463e5d5e0b49222374bda094879516acb4f0bb [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
vponomaryov67b58fe2014-02-06 19:05:41 +020015import json
Matthew Treinisha33037e2013-12-05 23:16:39 +000016
Matthew Treinish96e9e882014-06-09 18:37:19 -040017import httplib2
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 Treinish684d8992014-01-30 16:27:40 +000021from tempest import config
Matthew Treinisha33037e2013-12-05 23:16:39 +000022from tempest import exceptions
Matthew Treinisha33037e2013-12-05 23:16:39 +000023from 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
Sean Daguefc072542014-11-24 11:50:25 -0500238class TestRestClientParseRespJSON(BaseRestClientTestClass):
239 TYPE = "json"
vponomaryov67b58fe2014-02-06 19:05:41 +0200240
241 keys = ["fake_key1", "fake_key2"]
242 values = ["fake_value1", "fake_value2"]
Dirk Muellerb9a57152014-02-21 15:48:32 +0100243 item_expected = dict((key, value) for (key, value) in zip(keys, values))
vponomaryov67b58fe2014-02-06 19:05:41 +0200244 list_expected = {"body_list": [
245 {keys[0]: values[0]},
246 {keys[1]: values[1]},
247 ]}
248 dict_expected = {"body_dict": {
249 keys[0]: values[0],
250 keys[1]: values[1],
251 }}
252
253 def setUp(self):
254 self.fake_http = fake_http.fake_httplib2()
Sean Daguefc072542014-11-24 11:50:25 -0500255 super(TestRestClientParseRespJSON, self).setUp()
vponomaryov67b58fe2014-02-06 19:05:41 +0200256 self.rest_client.TYPE = self.TYPE
257
258 def test_parse_resp_body_item(self):
vponomaryov67b58fe2014-02-06 19:05:41 +0200259 body = self.rest_client._parse_resp(json.dumps(self.item_expected))
260 self.assertEqual(self.item_expected, body)
261
262 def test_parse_resp_body_list(self):
263 body = self.rest_client._parse_resp(json.dumps(self.list_expected))
264 self.assertEqual(self.list_expected["body_list"], body)
265
266 def test_parse_resp_body_dict(self):
267 body = self.rest_client._parse_resp(json.dumps(self.dict_expected))
268 self.assertEqual(self.dict_expected["body_dict"], body)
269
270 def test_parse_resp_two_top_keys(self):
271 dict_two_keys = self.dict_expected.copy()
272 dict_two_keys.update({"second_key": ""})
273 body = self.rest_client._parse_resp(json.dumps(dict_two_keys))
274 self.assertEqual(dict_two_keys, body)
275
276 def test_parse_resp_one_top_key_without_list_or_dict(self):
277 data = {"one_top_key": "not_list_or_dict_value"}
278 body = self.rest_client._parse_resp(json.dumps(data))
279 self.assertEqual(data, body)
vponomaryov6cb6d192014-03-07 09:39:05 +0200280
281
282class TestRestClientErrorCheckerJSON(base.TestCase):
283 c_type = "application/json"
284
285 def set_data(self, r_code, enc=None, r_body=None):
286 if enc is None:
287 enc = self.c_type
288 resp_dict = {'status': r_code, 'content-type': enc}
289 resp = httplib2.Response(resp_dict)
290 data = {
291 "method": "fake_method",
292 "url": "fake_url",
293 "headers": "fake_headers",
294 "body": "fake_body",
295 "resp": resp,
296 "resp_body": '{"resp_body": "fake_resp_body"}',
297 }
298 if r_body is not None:
299 data.update({"resp_body": r_body})
300 return data
301
302 def setUp(self):
303 super(TestRestClientErrorCheckerJSON, self).setUp()
Matthew Treinishff598482014-02-28 16:13:58 -0500304 self.useFixture(fake_config.ConfigFixture())
305 self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
vponomaryov6cb6d192014-03-07 09:39:05 +0200306 self.rest_client = rest_client.RestClient(
307 fake_auth_provider.FakeAuthProvider())
308
309 def test_response_less_than_400(self):
310 self.rest_client._error_checker(**self.set_data("399"))
311
312 def test_response_400(self):
313 self.assertRaises(exceptions.BadRequest,
314 self.rest_client._error_checker,
315 **self.set_data("400"))
316
317 def test_response_401(self):
318 self.assertRaises(exceptions.Unauthorized,
319 self.rest_client._error_checker,
320 **self.set_data("401"))
321
322 def test_response_403(self):
323 self.assertRaises(exceptions.Unauthorized,
324 self.rest_client._error_checker,
325 **self.set_data("403"))
326
327 def test_response_404(self):
328 self.assertRaises(exceptions.NotFound,
329 self.rest_client._error_checker,
330 **self.set_data("404"))
331
332 def test_response_409(self):
333 self.assertRaises(exceptions.Conflict,
334 self.rest_client._error_checker,
335 **self.set_data("409"))
336
337 def test_response_413(self):
338 self.assertRaises(exceptions.OverLimit,
339 self.rest_client._error_checker,
340 **self.set_data("413"))
341
342 def test_response_422(self):
343 self.assertRaises(exceptions.UnprocessableEntity,
344 self.rest_client._error_checker,
345 **self.set_data("422"))
346
347 def test_response_500_with_text(self):
348 # _parse_resp is expected to return 'str'
349 self.assertRaises(exceptions.ServerFault,
350 self.rest_client._error_checker,
351 **self.set_data("500"))
352
353 def test_response_501_with_text(self):
354 self.assertRaises(exceptions.ServerFault,
355 self.rest_client._error_checker,
356 **self.set_data("501"))
357
358 def test_response_500_with_dict(self):
359 r_body = '{"resp_body": {"err": "fake_resp_body"}}'
360 self.assertRaises(exceptions.ServerFault,
361 self.rest_client._error_checker,
362 **self.set_data("500", r_body=r_body))
363
364 def test_response_501_with_dict(self):
365 r_body = '{"resp_body": {"err": "fake_resp_body"}}'
366 self.assertRaises(exceptions.ServerFault,
367 self.rest_client._error_checker,
368 **self.set_data("501", r_body=r_body))
369
370 def test_response_bigger_than_400(self):
371 # Any response code, that bigger than 400, and not in
372 # (401, 403, 404, 409, 413, 422, 500, 501)
373 self.assertRaises(exceptions.UnexpectedResponseCode,
374 self.rest_client._error_checker,
375 **self.set_data("402"))
376
377
vponomaryov6cb6d192014-03-07 09:39:05 +0200378class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
379 c_type = "text/plain"
380
381 def test_fake_content_type(self):
382 # This test is required only in one exemplar
383 # Any response code, that bigger than 400, and not in
384 # (401, 403, 404, 409, 413, 422, 500, 501)
385 self.assertRaises(exceptions.InvalidContentType,
386 self.rest_client._error_checker,
387 **self.set_data("405", enc="fake_enc"))
Matthew Treinishead51df2014-03-15 18:56:43 +0000388
389
390class TestRestClientUtils(BaseRestClientTestClass):
391
392 def _is_resource_deleted(self, resource_id):
393 if not isinstance(self.retry_pass, int):
394 return False
395 if self.retry_count >= self.retry_pass:
396 return True
397 self.retry_count = self.retry_count + 1
398 return False
399
400 def setUp(self):
401 self.fake_http = fake_http.fake_httplib2()
402 super(TestRestClientUtils, self).setUp()
403 self.retry_count = 0
404 self.retry_pass = None
405 self.original_deleted_method = self.rest_client.is_resource_deleted
406 self.rest_client.is_resource_deleted = self._is_resource_deleted
407
408 def test_wait_for_resource_deletion(self):
409 self.retry_pass = 2
410 # Ensure timeout long enough for loop execution to hit retry count
411 self.rest_client.build_timeout = 500
412 sleep_mock = self.patch('time.sleep')
413 self.rest_client.wait_for_resource_deletion('1234')
414 self.assertEqual(len(sleep_mock.mock_calls), 2)
415
416 def test_wait_for_resource_deletion_not_deleted(self):
417 self.patch('time.sleep')
418 # Set timeout to be very quick to force exception faster
419 self.rest_client.build_timeout = 1
420 self.assertRaises(exceptions.TimeoutException,
421 self.rest_client.wait_for_resource_deletion,
422 '1234')
423
424 def test_wait_for_deletion_with_unimplemented_deleted_method(self):
425 self.rest_client.is_resource_deleted = self.original_deleted_method
426 self.assertRaises(NotImplementedError,
427 self.rest_client.wait_for_resource_deletion,
428 '1234')
Masayuki Igawa4e942a32014-03-17 11:02:09 +0900429
430
431class TestNegativeRestClient(BaseRestClientTestClass):
432
433 def setUp(self):
434 self.fake_http = fake_http.fake_httplib2()
435 super(TestNegativeRestClient, self).setUp()
436 self.negative_rest_client = rest_client.NegativeRestClient(
437 fake_auth_provider.FakeAuthProvider())
438 self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
439 '_log_request'))
440
441 def test_post(self):
442 __, return_dict = self.negative_rest_client.send_request('POST',
443 self.url,
444 [], {})
445 self.assertEqual('POST', return_dict['method'])
446
447 def test_get(self):
448 __, return_dict = self.negative_rest_client.send_request('GET',
449 self.url,
450 [])
451 self.assertEqual('GET', return_dict['method'])
452
453 def test_delete(self):
454 __, return_dict = self.negative_rest_client.send_request('DELETE',
455 self.url,
456 [])
457 self.assertEqual('DELETE', return_dict['method'])
458
459 def test_patch(self):
460 __, return_dict = self.negative_rest_client.send_request('PATCH',
461 self.url,
462 [], {})
463 self.assertEqual('PATCH', return_dict['method'])
464
465 def test_put(self):
466 __, return_dict = self.negative_rest_client.send_request('PUT',
467 self.url,
468 [], {})
469 self.assertEqual('PUT', return_dict['method'])
470
471 def test_head(self):
472 self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
473 'response_checker'))
474 __, return_dict = self.negative_rest_client.send_request('HEAD',
475 self.url,
476 [])
477 self.assertEqual('HEAD', return_dict['method'])
478
479 def test_copy(self):
480 __, return_dict = self.negative_rest_client.send_request('COPY',
481 self.url,
482 [])
483 self.assertEqual('COPY', return_dict['method'])
484
485 def test_other(self):
486 self.assertRaises(AssertionError,
487 self.negative_rest_client.send_request,
488 'OTHER', self.url, [])
Matthew Treinish2b2483e2014-05-08 23:26:10 -0400489
490
491class TestExpectedSuccess(BaseRestClientTestClass):
492
493 def setUp(self):
494 self.fake_http = fake_http.fake_httplib2()
495 super(TestExpectedSuccess, self).setUp()
496
497 def test_expected_succes_int_match(self):
498 expected_code = 202
499 read_code = 202
500 resp = self.rest_client.expected_success(expected_code, read_code)
501 # Assert None resp on success
502 self.assertFalse(resp)
503
504 def test_expected_succes_int_no_match(self):
505 expected_code = 204
506 read_code = 202
507 self.assertRaises(exceptions.InvalidHttpSuccessCode,
508 self.rest_client.expected_success,
509 expected_code, read_code)
510
511 def test_expected_succes_list_match(self):
512 expected_code = [202, 204]
513 read_code = 202
514 resp = self.rest_client.expected_success(expected_code, read_code)
515 # Assert None resp on success
516 self.assertFalse(resp)
517
518 def test_expected_succes_list_no_match(self):
519 expected_code = [202, 204]
520 read_code = 200
521 self.assertRaises(exceptions.InvalidHttpSuccessCode,
522 self.rest_client.expected_success,
523 expected_code, read_code)
524
525 def test_non_success_expected_int(self):
526 expected_code = 404
527 read_code = 202
528 self.assertRaises(AssertionError, self.rest_client.expected_success,
529 expected_code, read_code)
530
531 def test_non_success_expected_list(self):
532 expected_code = [404, 202]
533 read_code = 202
534 self.assertRaises(AssertionError, self.rest_client.expected_success,
535 expected_code, read_code)