diff --git a/requirements.txt b/requirements.txt index 7c426e6681..a2ec16e30a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,6 @@ pbr>=1.6 # Apache-2.0 cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0 anyjson>=0.3.3 # BSD -httplib2>=0.7.5 # MIT jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT testtools>=1.4.0 # MIT paramiko>=1.16.0 # LGPL @@ -25,3 +24,4 @@ PyYAML>=3.1.0 # MIT stevedore>=1.5.0 # Apache-2.0 PrettyTable<0.8,>=0.7 # BSD os-testr>=0.4.1 # Apache-2.0 +urllib3>=1.8.3 # MIT diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py index 0ba322d899..f29973d598 100644 --- a/tempest/cmd/verify_tempest_config.py +++ b/tempest/cmd/verify_tempest_config.py @@ -15,7 +15,6 @@ # under the License. import argparse -import httplib2 import os import sys import traceback @@ -29,6 +28,7 @@ from six.moves.urllib import parse as urlparse from tempest import clients from tempest.common import credentials_factory as credentials from tempest import config +import tempest.lib.common.http CONF = config.CONF @@ -91,11 +91,12 @@ def _get_api_versions(os, service): } client_dict[service].skip_path() endpoint = _get_unversioned_endpoint(client_dict[service].base_url) - dscv = CONF.identity.disable_ssl_certificate_validation - ca_certs = CONF.identity.ca_certificates_file - raw_http = httplib2.Http(disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs) - __, body = raw_http.request(endpoint, 'GET') + + http = tempest.lib.common.http.ClosingHttp( + CONF.identity.disable_ssl_certificate_validation, + CONF.identity.ca_certificates_file) + + __, body = http.request(endpoint, 'GET') client_dict[service].reset_path() try: body = json.loads(body) diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py index b3793bc8fa..dffc5f90fa 100644 --- a/tempest/lib/common/http.py +++ b/tempest/lib/common/http.py @@ -1,5 +1,4 @@ -# Copyright 2013 OpenStack Foundation -# Copyright 2013 Citrix Systems, Inc. +# Copyright 2016 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -14,12 +13,43 @@ # License for the specific language governing permissions and limitations # under the License. -import httplib2 +import urllib3 -class ClosingHttp(httplib2.Http): - def request(self, *args, **kwargs): +class ClosingHttp(urllib3.poolmanager.PoolManager): + def __init__(self, disable_ssl_certificate_validation=False, + ca_certs=None): + kwargs = {} + + if disable_ssl_certificate_validation: + urllib3.disable_warnings() + kwargs['cert_reqs'] = 'CERT_NONE' + + if ca_certs: + kwargs['cert_reqs'] = 'CERT_REQUIRED' + kwargs['ca_certs'] = ca_certs + + super(ClosingHttp, self).__init__(**kwargs) + + def request(self, url, method, *args, **kwargs): + + class Response(dict): + def __init__(self, info): + for key, value in info.getheaders().items(): + self[key.lower()] = value + self.status = info.status + self['status'] = str(self.status) + self.reason = info.reason + self.version = info.version + self['content-location'] = url + original_headers = kwargs.get('headers', {}) new_headers = dict(original_headers, connection='close') new_kwargs = dict(kwargs, headers=new_headers) - return super(ClosingHttp, self).request(*args, **new_kwargs) + + # Follow up to 5 redirections. Don't raise an exception if + # it's exceeded but return the HTTP 3XX response instead. + retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5) + r = super(ClosingHttp, self).request(method, url, retries=retry, + *args, **new_kwargs) + return Response(r), r.data diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py index 5d050d1796..9df07a160f 100644 --- a/tempest/tests/cmd/test_verify_tempest_config.py +++ b/tempest/tests/cmd/test_verify_tempest_config.py @@ -49,8 +49,9 @@ class TestDiscovery(base.TestCase): return_value='http://fake_endpoint:5000')) fake_resp = {'versions': {'values': [{'id': 'v2.0'}, {'id': 'v3.0'}]}} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + self.useFixture(mockpatch.Patch( + 'tempest.lib.common.http.ClosingHttp.request', + return_value=(None, fake_resp))) fake_os = mock.MagicMock() versions = verify_tempest_config._get_api_versions(fake_os, 'keystone') self.assertIn('v2.0', versions) @@ -62,8 +63,9 @@ class TestDiscovery(base.TestCase): return_value='http://fake_endpoint:5000')) fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + self.useFixture(mockpatch.Patch( + 'tempest.lib.common.http.ClosingHttp.request', + return_value=(None, fake_resp))) fake_os = mock.MagicMock() versions = verify_tempest_config._get_api_versions(fake_os, 'cinder') self.assertIn('v1.0', versions) @@ -75,8 +77,9 @@ class TestDiscovery(base.TestCase): return_value='http://fake_endpoint:5000')) fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + self.useFixture(mockpatch.Patch( + 'tempest.lib.common.http.ClosingHttp.request', + return_value=(None, fake_resp))) fake_os = mock.MagicMock() versions = verify_tempest_config._get_api_versions(fake_os, 'nova') self.assertIn('v2.0', versions) @@ -95,8 +98,9 @@ class TestDiscovery(base.TestCase): sample_body = ( 'Sample ResponseThis is the sample page ' 'for the web server. Why are you requesting it?') - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, sample_body))) + self.useFixture(mockpatch.Patch( + 'tempest.lib.common.http.ClosingHttp.request', + return_value=(None, sample_body))) # service value doesn't matter, just needs to match what # _get_api_versions puts in its client_dict. @@ -122,14 +126,14 @@ class TestDiscovery(base.TestCase): verify_tempest_config.verify_api_versions(fake_os, 'foo', True) self.assertFalse(verify_mock.called) - def test_verify_keystone_api_versions_no_v3(self): + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_verify_keystone_api_versions_no_v3(self, mock_request): self.useFixture(mockpatch.PatchObject( verify_tempest_config, '_get_unversioned_endpoint', return_value='http://fake_endpoint:5000')) fake_resp = {'versions': {'values': [{'id': 'v2.0'}]}} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + mock_request.return_value = (None, fake_resp) fake_os = mock.MagicMock() with mock.patch.object(verify_tempest_config, 'print_and_or_update') as print_mock: @@ -138,14 +142,14 @@ class TestDiscovery(base.TestCase): 'identity-feature-enabled', False, True) - def test_verify_keystone_api_versions_no_v2(self): + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_verify_keystone_api_versions_no_v2(self, mock_request): self.useFixture(mockpatch.PatchObject( verify_tempest_config, '_get_unversioned_endpoint', return_value='http://fake_endpoint:5000')) fake_resp = {'versions': {'values': [{'id': 'v3.0'}]}} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + mock_request.return_value = (None, fake_resp) fake_os = mock.MagicMock() with mock.patch.object(verify_tempest_config, 'print_and_or_update') as print_mock: @@ -154,14 +158,14 @@ class TestDiscovery(base.TestCase): 'identity-feature-enabled', False, True) - def test_verify_cinder_api_versions_no_v2(self): + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_verify_cinder_api_versions_no_v2(self, mock_request): self.useFixture(mockpatch.PatchObject( verify_tempest_config, '_get_unversioned_endpoint', return_value='http://fake_endpoint:5000')) fake_resp = {'versions': [{'id': 'v1.0'}]} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + mock_request.return_value = (None, fake_resp) fake_os = mock.MagicMock() with mock.patch.object(verify_tempest_config, 'print_and_or_update') as print_mock: @@ -169,14 +173,14 @@ class TestDiscovery(base.TestCase): print_mock.assert_called_once_with('api_v2', 'volume-feature-enabled', False, True) - def test_verify_cinder_api_versions_no_v1(self): + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_verify_cinder_api_versions_no_v1(self, mock_request): self.useFixture(mockpatch.PatchObject( verify_tempest_config, '_get_unversioned_endpoint', return_value='http://fake_endpoint:5000')) fake_resp = {'versions': [{'id': 'v2.0'}]} fake_resp = json.dumps(fake_resp) - self.useFixture(mockpatch.Patch('httplib2.Http.request', - return_value=(None, fake_resp))) + mock_request.return_value = (None, fake_resp) fake_os = mock.MagicMock() with mock.patch.object(verify_tempest_config, 'print_and_or_update') as print_mock: diff --git a/tempest/tests/common/test_configured_creds.py b/tempest/tests/common/test_configured_creds.py index 8c721e6bf3..3c104b2e48 100644 --- a/tempest/tests/common/test_configured_creds.py +++ b/tempest/tests/common/test_configured_creds.py @@ -22,8 +22,8 @@ from tempest.lib import exceptions as lib_exc from tempest.lib.services.identity.v2 import token_client as v2_client from tempest.lib.services.identity.v3 import token_client as v3_client from tempest.tests import fake_config -from tempest.tests import fake_identity from tempest.tests.lib import base +from tempest.tests.lib import fake_identity class ConfiguredV2CredentialsTests(base.TestCase): diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py index f2052dc74d..e1d9023b24 100644 --- a/tempest/tests/common/test_dynamic_creds.py +++ b/tempest/tests/common/test_dynamic_creds.py @@ -32,9 +32,9 @@ from tempest.services.identity.v2.json import users_client as \ json_users_client from tempest.services.network.json import routers_client from tempest.tests import fake_config -from tempest.tests import fake_http -from tempest.tests import fake_identity from tempest.tests.lib import base +from tempest.tests.lib import fake_http +from tempest.tests.lib import fake_identity class TestDynamicCredentialProvider(base.TestCase): @@ -47,7 +47,6 @@ class TestDynamicCredentialProvider(base.TestCase): super(TestDynamicCredentialProvider, self).setUp() self.useFixture(fake_config.ConfigFixture()) self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate) - self.fake_http = fake_http.fake_httplib2(return_type=200) self.stubs.Set(json_token_client.TokenClient, 'raw_request', fake_identity._fake_v2_response) cfg.CONF.set_default('operator_role', 'FakeRole', @@ -402,7 +401,7 @@ class TestDynamicCredentialProvider(base.TestCase): side_effect=side_effect) secgroup_list_mock.start() - return_values = (fake_http.fake_httplib({}, status=204), {}) + return_values = fake_http.fake_http_response({}, status=204), '' remove_secgroup_mock = self.patch( 'tempest.lib.services.network.security_groups_client.' 'SecurityGroupsClient.delete', return_value=return_values) diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py index efc5ef6770..36d6c3db4e 100644 --- a/tempest/tests/common/test_preprov_creds.py +++ b/tempest/tests/common/test_preprov_creds.py @@ -29,9 +29,8 @@ from tempest.lib import auth from tempest.lib import exceptions as lib_exc from tempest.lib.services.identity.v2 import token_client from tempest.tests import fake_config -from tempest.tests import fake_http -from tempest.tests import fake_identity from tempest.tests.lib import base +from tempest.tests.lib import fake_identity class TestPreProvisionedCredentials(base.TestCase): @@ -48,7 +47,6 @@ class TestPreProvisionedCredentials(base.TestCase): super(TestPreProvisionedCredentials, self).setUp() self.useFixture(fake_config.ConfigFixture()) self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate) - self.fake_http = fake_http.fake_httplib2(return_type=200) self.stubs.Set(token_client.TokenClient, 'raw_request', fake_identity._fake_v2_response) self.useFixture(lockutils_fixtures.ExternalLockFixture()) diff --git a/tempest/tests/fake_http.py b/tempest/tests/fake_http.py deleted file mode 100644 index d714055696..0000000000 --- a/tempest/tests/fake_http.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import httplib2 - - -class fake_httplib2(object): - - def __init__(self, return_type=None, *args, **kwargs): - self.return_type = return_type - - def request(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - if not self.return_type: - fake_headers = httplib2.Response(headers) - return_obj = { - 'uri': uri, - 'method': method, - 'body': body, - 'headers': headers - } - return (fake_headers, return_obj) - elif isinstance(self.return_type, int): - body = "fake_body" - header_info = { - 'content-type': 'text/plain', - 'status': str(self.return_type), - 'content-length': len(body) - } - resp_header = httplib2.Response(header_info) - return (resp_header, body) - else: - msg = "unsupported return type %s" % self.return_type - raise TypeError(msg) - - -class fake_httplib(object): - def __init__(self, headers, body=None, - version=1.0, status=200, reason="Ok"): - """Initialization of fake httplib - - :param headers: dict representing HTTP response headers - :param body: file-like object - :param version: HTTP Version - :param status: Response status code - :param reason: Status code related message. - """ - self.body = body - self.status = status - self.reason = reason - self.version = version - self.headers = headers - - def getheaders(self): - return copy.deepcopy(self.headers).items() - - def getheader(self, key, default): - return self.headers.get(key, default) - - def read(self, amt): - return self.body.read(amt) diff --git a/tempest/tests/fake_identity.py b/tempest/tests/fake_identity.py deleted file mode 100644 index d0de927db6..0000000000 --- a/tempest/tests/fake_identity.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import httplib2 -from oslo_serialization import jsonutils as json - -FAKE_AUTH_URL = 'http://fake_uri.com/auth' - -TOKEN = "fake_token" -ALT_TOKEN = "alt_fake_token" - -# Fake Identity v2 constants -COMPUTE_ENDPOINTS_V2 = { - "endpoints": [ - { - "adminURL": "http://fake_url/v2/first_endpoint/admin", - "region": "NoMatchRegion", - "internalURL": "http://fake_url/v2/first_endpoint/internal", - "publicURL": "http://fake_url/v2/first_endpoint/public" - }, - { - "adminURL": "http://fake_url/v2/second_endpoint/admin", - "region": "FakeRegion", - "internalURL": "http://fake_url/v2/second_endpoint/internal", - "publicURL": "http://fake_url/v2/second_endpoint/public" - }, - ], - "type": "compute", - "name": "nova" -} - -CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ] - -ALT_IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": ALT_TOKEN, - "tenant": { - "id": "fake_tenant_id" - }, - }, - "user": { - "id": "fake_user_id", - }, - "serviceCatalog": CATALOG_V2, - }, -} - -IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": TOKEN, - "tenant": { - "id": "fake_tenant_id" - }, - }, - "user": { - "id": "fake_user_id", - }, - "serviceCatalog": CATALOG_V2, - }, -} - -# Fake Identity V3 constants -COMPUTE_ENDPOINTS_V3 = { - "endpoints": [ - { - "id": "first_compute_fake_service", - "interface": "public", - "region": "NoMatchRegion", - "url": "http://fake_url/v3/first_endpoint/api" - }, - { - "id": "second_fake_service", - "interface": "public", - "region": "FakeRegion", - "url": "http://fake_url/v3/second_endpoint/api" - }, - { - "id": "third_fake_service", - "interface": "admin", - "region": "MiddleEarthRegion", - "url": "http://fake_url/v3/third_endpoint/api" - } - - ], - "type": "compute", - "id": "fake_compute_endpoint" -} - -CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ] - -IDENTITY_V3_RESPONSE = { - "token": { - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": "fake_domain_id", - "name": "fake" - }, - "id": "project_id", - "name": "project_name" - }, - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username" - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": CATALOG_V3 - } -} - -ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE - - -def _fake_v3_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - fake_headers = { - "status": "201", - "x-subject-token": TOKEN - } - return (httplib2.Response(fake_headers), - json.dumps(IDENTITY_V3_RESPONSE)) - - -def _fake_v2_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - return (httplib2.Response({"status": "200"}), - json.dumps(IDENTITY_V2_RESPONSE)) - - -def _fake_auth_failure_response(): - # the response body isn't really used in this case, but lets send it anyway - # to have a safe check in some future change on the rest client. - body = { - "unauthorized": { - "message": "Unauthorized", - "code": "401" - } - } - return httplib2.Response({"status": "401"}), json.dumps(body) diff --git a/tempest/tests/lib/fake_http.py b/tempest/tests/lib/fake_http.py index eda202d436..397c856459 100644 --- a/tempest/tests/lib/fake_http.py +++ b/tempest/tests/lib/fake_http.py @@ -14,8 +14,6 @@ import copy -import httplib2 - class fake_httplib2(object): @@ -25,7 +23,7 @@ class fake_httplib2(object): def request(self, uri, method="GET", body=None, headers=None, redirections=5, connection_type=None): if not self.return_type: - fake_headers = httplib2.Response(headers) + fake_headers = fake_http_response(headers) return_obj = { 'uri': uri, 'method': method, @@ -37,20 +35,20 @@ class fake_httplib2(object): body = body or "fake_body" header_info = { 'content-type': 'text/plain', - 'status': str(self.return_type), 'content-length': len(body) } - resp_header = httplib2.Response(header_info) + resp_header = fake_http_response(header_info, + status=self.return_type) return (resp_header, body) else: msg = "unsupported return type %s" % self.return_type raise TypeError(msg) -class fake_httplib(object): +class fake_http_response(dict): def __init__(self, headers, body=None, version=1.0, status=200, reason="Ok"): - """Fake httplib implementation + """Initialization of fake HTTP Response :param headers: dict representing HTTP response headers :param body: file-like object @@ -60,10 +58,15 @@ class fake_httplib(object): """ self.body = body self.status = status + self['status'] = str(self.status) self.reason = reason self.version = version self.headers = headers + if headers: + for key, value in headers.items(): + self[key.lower()] = value + def getheaders(self): return copy.deepcopy(self.headers).items() diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py index bac26761fd..5732065f8c 100644 --- a/tempest/tests/lib/fake_identity.py +++ b/tempest/tests/lib/fake_identity.py @@ -13,9 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. -import json +from oslo_serialization import jsonutils as json -import httplib2 +from tempest.tests.lib import fake_http FAKE_AUTH_URL = 'http://fake_uri.com/auth' @@ -139,16 +139,15 @@ ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE def _fake_v3_response(self, uri, method="GET", body=None, headers=None, redirections=5, connection_type=None): fake_headers = { - "status": "201", "x-subject-token": TOKEN } - return (httplib2.Response(fake_headers), + return (fake_http.fake_http_response(fake_headers, status=201), json.dumps(IDENTITY_V3_RESPONSE)) def _fake_v2_response(self, uri, method="GET", body=None, headers=None, redirections=5, connection_type=None): - return (httplib2.Response({"status": "200"}), + return (fake_http.fake_http_response({}, status=200), json.dumps(IDENTITY_V2_RESPONSE)) @@ -161,4 +160,4 @@ def _fake_auth_failure_response(): "code": "401" } } - return httplib2.Response({"status": "401"}), json.dumps(body) + return fake_http.fake_http_response({}, status=401), json.dumps(body) diff --git a/tempest/tests/lib/services/compute/base.py b/tempest/tests/lib/services/compute/base.py index 56020443da..c805de2e3f 100644 --- a/tempest/tests/lib/services/compute/base.py +++ b/tempest/tests/lib/services/compute/base.py @@ -12,11 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. -import httplib2 from oslo_serialization import jsonutils as json from oslotest import mockpatch from tempest.tests.lib import base +from tempest.tests.lib import fake_http class BaseComputeServiceTest(base.TestCase): @@ -26,11 +26,8 @@ class BaseComputeServiceTest(base.TestCase): json_body = json.dumps(body) if to_utf: json_body = json_body.encode('utf-8') - resp_dict = {'status': status} - if headers: - resp_dict.update(headers) - response = (httplib2.Response(resp_dict), json_body) - return response + resp = fake_http.fake_http_response(headers, status=status), json_body + return resp def check_service_client_function(self, function, function2mock, body, to_utf=False, status=200, diff --git a/tempest/tests/lib/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py index f552ef5326..49d29b37a9 100644 --- a/tempest/tests/lib/services/compute/test_base_compute_client.py +++ b/tempest/tests/lib/services/compute/test_base_compute_client.py @@ -12,14 +12,13 @@ # License for the specific language governing permissions and limitations # under the License. -import httplib2 import mock -from oslotest import mockpatch from tempest.lib.common import rest_client from tempest.lib import exceptions from tempest.lib.services.compute import base_compute_client from tempest.tests.lib import fake_auth_provider +from tempest.tests.lib import fake_http from tempest.tests.lib.services.compute import base @@ -36,28 +35,29 @@ class TestMicroversionHeaderCheck(base.BaseComputeServiceTest): super(TestMicroversionHeaderCheck, self).tearDown() base_compute_client.COMPUTE_MICROVERSION = None - def _check_microverion_header_in_response(self, fake_response): - def request(*args, **kwargs): - return (httplib2.Response(fake_response), {}) - - self.useFixture(mockpatch.PatchObject( - rest_client.RestClient, - 'request', - side_effect=request)) - - def test_correct_microverion_in_response(self): - fake_response = {self.client.api_microversion_header_name: '2.2'} - self._check_microverion_header_in_response(fake_response) + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_correct_microverion_in_response(self, mock_request): + response = fake_http.fake_http_response( + headers={self.client.api_microversion_header_name: '2.2'}, + ) + mock_request.return_value = response, '' self.client.get('fake_url') - def test_incorrect_microverion_in_response(self): - fake_response = {self.client.api_microversion_header_name: '2.3'} - self._check_microverion_header_in_response(fake_response) + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_incorrect_microverion_in_response(self, mock_request): + response = fake_http.fake_http_response( + headers={self.client.api_microversion_header_name: '2.3'}, + ) + mock_request.return_value = response, '' self.assertRaises(exceptions.InvalidHTTPResponseHeader, self.client.get, 'fake_url') - def test_no_microverion_header_in_response(self): - self._check_microverion_header_in_response({}) + @mock.patch('tempest.lib.common.http.ClosingHttp.request') + def test_no_microverion_header_in_response(self, mock_request): + response = fake_http.fake_http_response( + headers={}, + ) + mock_request.return_value = response, '' self.assertRaises(exceptions.InvalidHTTPResponseHeader, self.client.get, 'fake_url') @@ -164,7 +164,7 @@ class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest): def test_no_microverion_header_in_raw_request(self): def raw_request(*args, **kwargs): self.assertNotIn('X-OpenStack-Nova-API-Version', kwargs['headers']) - return (httplib2.Response({'status': 200}), {}) + return (fake_http.fake_http_response({}, status=200), '') with mock.patch.object(rest_client.RestClient, 'raw_request') as mock_get: @@ -196,9 +196,9 @@ class TestClientWithMicroversionHeader(base.BaseComputeServiceTest): self.assertIn('X-OpenStack-Nova-API-Version', kwargs['headers']) self.assertEqual('2.2', kwargs['headers']['X-OpenStack-Nova-API-Version']) - return (httplib2.Response( - {'status': 200, - self.client.api_microversion_header_name: '2.2'}), {}) + return (fake_http.fake_http_response( + headers={self.client.api_microversion_header_name: '2.2'}, + status=200), '') with mock.patch.object(rest_client.RestClient, 'raw_request') as mock_get: diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py index 795aff7446..e22b4fe93c 100644 --- a/tempest/tests/lib/services/compute/test_flavors_client.py +++ b/tempest/tests/lib/services/compute/test_flavors_client.py @@ -13,13 +13,13 @@ # under the License. import copy -import httplib2 from oslo_serialization import jsonutils as json from oslotest import mockpatch from tempest.lib.services.compute import flavors_client from tempest.tests.lib import fake_auth_provider +from tempest.tests.lib import fake_http from tempest.tests.lib.services.compute import base @@ -117,7 +117,7 @@ class TestFlavorsClient(base.BaseComputeServiceTest): body = json.dumps({'flavors': [TestFlavorsClient.FAKE_FLAVOR]}) if bytes_body: body = body.encode('utf-8') - response = (httplib2.Response({'status': 200}), body) + response = fake_http.fake_http_response({}, status=200), body self.useFixture(mockpatch.Patch( 'tempest.lib.common.rest_client.RestClient.get', return_value=response)) diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py index f1f29067ba..cb163a8d13 100644 --- a/tempest/tests/lib/services/compute/test_server_groups_client.py +++ b/tempest/tests/lib/services/compute/test_server_groups_client.py @@ -12,12 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. -import httplib2 - from oslotest import mockpatch from tempest.tests.lib import fake_auth_provider from tempest.lib.services.compute import server_groups_client +from tempest.tests.lib import fake_http from tempest.tests.lib.services.compute import base @@ -50,7 +49,7 @@ class TestServerGroupsClient(base.BaseComputeServiceTest): self._test_create_server_group(bytes_body=True) def test_delete_server_group(self): - response = (httplib2.Response({'status': 204}), None) + response = fake_http.fake_http_response({}, status=204), '' self.useFixture(mockpatch.Patch( 'tempest.lib.common.rest_client.RestClient.delete', return_value=response)) diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py index dd3533a4ce..d91ecdc68e 100644 --- a/tempest/tests/lib/services/identity/v2/test_token_client.py +++ b/tempest/tests/lib/services/identity/v2/test_token_client.py @@ -14,8 +14,7 @@ import json -import httplib2 -from oslotest import mockpatch +import mock from tempest.lib.common import rest_client from tempest.lib import exceptions @@ -28,7 +27,6 @@ class TestTokenClientV2(base.TestCase): def setUp(self): super(TestTokenClientV2, self).setUp() - self.fake_200_http = fake_http.fake_httplib2(return_type=200) def test_init_without_authurl(self): self.assertRaises(exceptions.IdentityError, @@ -36,10 +34,15 @@ class TestTokenClientV2(base.TestCase): def test_auth(self): token_client_v2 = token_client.TokenClient('fake_url') - post_mock = self.useFixture(mockpatch.PatchObject( - token_client_v2, 'post', return_value=self.fake_200_http.request( - 'fake_url', body={'access': {'token': 'fake_token'}}))) - resp = token_client_v2.auth('fake_user', 'fake_pass') + response = fake_http.fake_http_response( + None, status=200, + ) + body = {'access': {'token': 'fake_token'}} + + with mock.patch.object(token_client_v2, 'post') as post_mock: + post_mock.return_value = response, body + resp = token_client_v2.auth('fake_user', 'fake_pass') + self.assertIsInstance(resp, rest_client.ResponseBody) req_dict = json.dumps({ 'auth': { @@ -49,15 +52,21 @@ class TestTokenClientV2(base.TestCase): }, } }, sort_keys=True) - post_mock.mock.assert_called_once_with('fake_url/tokens', - body=req_dict) + post_mock.assert_called_once_with('fake_url/tokens', + body=req_dict) def test_auth_with_tenant(self): token_client_v2 = token_client.TokenClient('fake_url') - post_mock = self.useFixture(mockpatch.PatchObject( - token_client_v2, 'post', return_value=self.fake_200_http.request( - 'fake_url', body={'access': {'token': 'fake_token'}}))) - resp = token_client_v2.auth('fake_user', 'fake_pass', 'fake_tenant') + response = fake_http.fake_http_response( + None, status=200, + ) + body = {'access': {'token': 'fake_token'}} + + with mock.patch.object(token_client_v2, 'post') as post_mock: + post_mock.return_value = response, body + resp = token_client_v2.auth('fake_user', 'fake_pass', + 'fake_tenant') + self.assertIsInstance(resp, rest_client.ResponseBody) req_dict = json.dumps({ 'auth': { @@ -68,25 +77,31 @@ class TestTokenClientV2(base.TestCase): }, } }, sort_keys=True) - post_mock.mock.assert_called_once_with('fake_url/tokens', - body=req_dict) + post_mock.assert_called_once_with('fake_url/tokens', + body=req_dict) def test_request_with_str_body(self): token_client_v2 = token_client.TokenClient('fake_url') - self.useFixture(mockpatch.PatchObject( - token_client_v2, 'raw_request', return_value=( - httplib2.Response({'status': '200'}), - str('{"access": {"token": "fake_token"}}')))) - resp, body = token_client_v2.request('GET', 'fake_uri') - self.assertIsInstance(resp, httplib2.Response) + response = fake_http.fake_http_response( + None, status=200, + ) + body = str('{"access": {"token": "fake_token"}}') + + with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: + mock_raw_r.return_value = response, body + resp, body = token_client_v2.request('GET', 'fake_uri') self.assertIsInstance(body, dict) def test_request_with_bytes_body(self): token_client_v2 = token_client.TokenClient('fake_url') - self.useFixture(mockpatch.PatchObject( - token_client_v2, 'raw_request', return_value=( - httplib2.Response({'status': '200'}), - bytes(b'{"access": {"token": "fake_token"}}')))) - resp, body = token_client_v2.request('GET', 'fake_uri') - self.assertIsInstance(resp, httplib2.Response) + + response = fake_http.fake_http_response( + None, status=200, + ) + body = b'{"access": {"token": "fake_token"}}' + + with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: + mock_raw_r.return_value = response, body + resp, body = token_client_v2.request('GET', 'fake_uri') + self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py index bb4dae3e0f..52b8e01cd7 100644 --- a/tempest/tests/lib/services/identity/v3/test_token_client.py +++ b/tempest/tests/lib/services/identity/v3/test_token_client.py @@ -14,8 +14,7 @@ import json -import httplib2 -from oslotest import mockpatch +import mock from tempest.lib.common import rest_client from tempest.lib import exceptions @@ -24,11 +23,10 @@ from tempest.tests.lib import base from tempest.tests.lib import fake_http -class TestTokenClientV2(base.TestCase): +class TestTokenClientV3(base.TestCase): def setUp(self): - super(TestTokenClientV2, self).setUp() - self.fake_201_http = fake_http.fake_httplib2(return_type=201) + super(TestTokenClientV3, self).setUp() def test_init_without_authurl(self): self.assertRaises(exceptions.IdentityError, @@ -36,10 +34,16 @@ class TestTokenClientV2(base.TestCase): def test_auth(self): token_client_v3 = token_client.V3TokenClient('fake_url') - post_mock = self.useFixture(mockpatch.PatchObject( - token_client_v3, 'post', return_value=self.fake_201_http.request( - 'fake_url', body={'access': {'token': 'fake_token'}}))) - resp = token_client_v3.auth(username='fake_user', password='fake_pass') + response = fake_http.fake_http_response( + None, status=201, + ) + body = {'access': {'token': 'fake_token'}} + + with mock.patch.object(token_client_v3, 'post') as post_mock: + post_mock.return_value = response, body + resp = token_client_v3.auth(username='fake_user', + password='fake_pass') + self.assertIsInstance(resp, rest_client.ResponseBody) req_dict = json.dumps({ 'auth': { @@ -54,19 +58,24 @@ class TestTokenClientV2(base.TestCase): }, } }, sort_keys=True) - post_mock.mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) + post_mock.assert_called_once_with('fake_url/auth/tokens', + body=req_dict) def test_auth_with_project_id_and_domain_id(self): token_client_v3 = token_client.V3TokenClient('fake_url') - post_mock = self.useFixture(mockpatch.PatchObject( - token_client_v3, 'post', return_value=self.fake_201_http.request( - 'fake_url', body={'access': {'token': 'fake_token'}}))) - resp = token_client_v3.auth( - username='fake_user', password='fake_pass', - project_id='fcac2a055a294e4c82d0a9c21c620eb4', - user_domain_id='14f4a9a99973404d8c20ba1d2af163ff', - project_domain_id='291f63ae9ac54ee292ca09e5f72d9676') + response = fake_http.fake_http_response( + None, status=201, + ) + body = {'access': {'token': 'fake_token'}} + + with mock.patch.object(token_client_v3, 'post') as post_mock: + post_mock.return_value = response, body + resp = token_client_v3.auth( + username='fake_user', password='fake_pass', + project_id='fcac2a055a294e4c82d0a9c21c620eb4', + user_domain_id='14f4a9a99973404d8c20ba1d2af163ff', + project_domain_id='291f63ae9ac54ee292ca09e5f72d9676') + self.assertIsInstance(resp, rest_client.ResponseBody) req_dict = json.dumps({ 'auth': { @@ -92,16 +101,22 @@ class TestTokenClientV2(base.TestCase): } } }, sort_keys=True) - post_mock.mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) + post_mock.assert_called_once_with('fake_url/auth/tokens', + body=req_dict) def test_auth_with_tenant(self): - token_client_v2 = token_client.V3TokenClient('fake_url') - post_mock = self.useFixture(mockpatch.PatchObject( - token_client_v2, 'post', return_value=self.fake_201_http.request( - 'fake_url', body={'access': {'token': 'fake_token'}}))) - resp = token_client_v2.auth(username='fake_user', password='fake_pass', - project_name='fake_tenant') + token_client_v3 = token_client.V3TokenClient('fake_url') + response = fake_http.fake_http_response( + None, status=201, + ) + body = {'access': {'token': 'fake_token'}} + + with mock.patch.object(token_client_v3, 'post') as post_mock: + post_mock.return_value = response, body + resp = token_client_v3.auth(username='fake_user', + password='fake_pass', + project_name='fake_tenant') + self.assertIsInstance(resp, rest_client.ResponseBody) req_dict = json.dumps({ 'auth': { @@ -121,25 +136,32 @@ class TestTokenClientV2(base.TestCase): } }, sort_keys=True) - post_mock.mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) + post_mock.assert_called_once_with('fake_url/auth/tokens', + body=req_dict) def test_request_with_str_body(self): token_client_v3 = token_client.V3TokenClient('fake_url') - self.useFixture(mockpatch.PatchObject( - token_client_v3, 'raw_request', return_value=( - httplib2.Response({"status": "200"}), - str('{"access": {"token": "fake_token"}}')))) - resp, body = token_client_v3.request('GET', 'fake_uri') - self.assertIsInstance(resp, httplib2.Response) + response = fake_http.fake_http_response( + None, status=200, + ) + body = str('{"access": {"token": "fake_token"}}') + + with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: + mock_raw_r.return_value = response, body + resp, body = token_client_v3.request('GET', 'fake_uri') + self.assertIsInstance(body, dict) def test_request_with_bytes_body(self): token_client_v3 = token_client.V3TokenClient('fake_url') - self.useFixture(mockpatch.PatchObject( - token_client_v3, 'raw_request', return_value=( - httplib2.Response({"status": "200"}), - bytes(b'{"access": {"token": "fake_token"}}')))) - resp, body = token_client_v3.request('GET', 'fake_uri') - self.assertIsInstance(resp, httplib2.Response) + + response = fake_http.fake_http_response( + None, status=200, + ) + body = b'{"access": {"token": "fake_token"}}' + + with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: + mock_raw_r.return_value = response, body + resp, body = token_client_v3.request('GET', 'fake_uri') + self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py index 55f0c4e472..5aeb47c36d 100644 --- a/tempest/tests/lib/test_auth.py +++ b/tempest/tests/lib/test_auth.py @@ -24,7 +24,6 @@ from tempest.lib.services.identity.v2 import token_client as v2_client from tempest.lib.services.identity.v3 import token_client as v3_client from tempest.tests.lib import base from tempest.tests.lib import fake_credentials -from tempest.tests.lib import fake_http from tempest.tests.lib import fake_identity @@ -42,7 +41,6 @@ class BaseAuthTestsSetUp(base.TestCase): def setUp(self): super(BaseAuthTestsSetUp, self).setUp() - self.fake_http = fake_http.fake_httplib2(return_type=200) self.stubs.Set(auth, 'get_credentials', fake_get_credentials) self.auth_provider = self._auth(self.credentials, fake_identity.FAKE_AUTH_URL) diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py index 87af4556a3..90651b06c3 100644 --- a/tempest/tests/lib/test_rest_client.py +++ b/tempest/tests/lib/test_rest_client.py @@ -15,11 +15,11 @@ import copy import json -import httplib2 import jsonschema from oslotest import mockpatch import six +from tempest.lib.common import http from tempest.lib.common import rest_client from tempest.lib import exceptions from tempest.tests.lib import base @@ -37,7 +37,9 @@ class BaseRestClientTestClass(base.TestCase): self.fake_auth_provider = fake_auth_provider.FakeAuthProvider() self.rest_client = rest_client.RestClient( self.fake_auth_provider, None, None) - self.stubs.Set(httplib2.Http, 'request', self.fake_http.request) + self.stubs.Set(http.ClosingHttp, 'request', + self.fake_http.request) + self.useFixture(mockpatch.PatchObject(self.rest_client, '_log_request')) @@ -292,7 +294,9 @@ class TestRestClientErrorCheckerJSON(base.TestCase): if absolute_limit is False: resp_dict.update({'retry-after': 120}) resp_body.update({'overLimit': {'message': 'fake_message'}}) - resp = httplib2.Response(resp_dict) + resp = fake_http.fake_http_response(headers=resp_dict, + status=int(r_code), + body=json.dumps(resp_body)) data = { "method": "fake_method", "url": "fake_url", diff --git a/tempest/tests/test_glance_http.py b/tempest/tests/test_glance_http.py index 10f80a78de..fdbc2d2613 100644 --- a/tempest/tests/test_glance_http.py +++ b/tempest/tests/test_glance_http.py @@ -23,19 +23,14 @@ from six.moves import http_client as httplib from tempest.common import glance_http from tempest import exceptions from tempest.tests import fake_auth_provider -from tempest.tests import fake_http from tempest.tests.lib import base +from tempest.tests.lib import fake_http class TestGlanceHTTPClient(base.TestCase): def setUp(self): super(TestGlanceHTTPClient, self).setUp() - self.fake_http = fake_http.fake_httplib2(return_type=200) - # NOTE(maurosr): using http here implies that we will be using httplib - # directly. With https glance_client would use an httpS version, but - # the real backend would still be httplib anyway and since we mock it - # that there is no reason to care. self.endpoint = 'http://fake_url.com' self.fake_auth = fake_auth_provider.FakeAuthProvider() @@ -44,12 +39,12 @@ class TestGlanceHTTPClient(base.TestCase): self.useFixture(mockpatch.PatchObject( httplib.HTTPConnection, 'request', - side_effect=self.fake_http.request(self.endpoint)[1])) + side_effect=b'fake_body')) self.client = glance_http.HTTPClient(self.fake_auth, {}) def _set_response_fixture(self, header, status, resp_body): - resp = fake_http.fake_httplib(header, status=status, - body=six.StringIO(resp_body)) + resp = fake_http.fake_http_response(header, status=status, + body=six.StringIO(resp_body)) self.useFixture(mockpatch.PatchObject(httplib.HTTPConnection, 'getresponse', return_value=resp)) return resp @@ -223,7 +218,7 @@ class TestVerifiedHTTPSConnection(base.TestCase): class TestResponseBodyIterator(base.TestCase): def test_iter_default_chunk_size_64k(self): - resp = fake_http.fake_httplib({}, six.StringIO( + resp = fake_http.fake_http_response({}, six.StringIO( 'X' * (glance_http.CHUNKSIZE + 1))) iterator = glance_http.ResponseBodyIterator(resp) chunks = list(iterator) diff --git a/tempest/tests/test_negative_rest_client.py b/tempest/tests/test_negative_rest_client.py index 6a071b1630..a1b5f0ee81 100644 --- a/tempest/tests/test_negative_rest_client.py +++ b/tempest/tests/test_negative_rest_client.py @@ -15,14 +15,13 @@ # License for the specific language governing permissions and limitations # under the License. -import httplib2 +import mock from oslotest import mockpatch from tempest.common import negative_rest_client from tempest import config from tempest.tests import fake_auth_provider from tempest.tests import fake_config -from tempest.tests import fake_http from tempest.tests.lib import base @@ -31,59 +30,69 @@ class TestNegativeRestClient(base.TestCase): url = 'fake_endpoint' def setUp(self): - self.fake_http = fake_http.fake_httplib2() super(TestNegativeRestClient, self).setUp() self.useFixture(fake_config.ConfigFixture()) self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate) - self.stubs.Set(httplib2.Http, 'request', self.fake_http.request) self.negative_rest_client = negative_rest_client.NegativeRestClient( fake_auth_provider.FakeAuthProvider(), None) self.useFixture(mockpatch.PatchObject(self.negative_rest_client, '_log_request')) - def test_post(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.post', + return_value=(mock.Mock(), mock.Mock())) + def test_post(self, mock_post): __, return_dict = self.negative_rest_client.send_request('POST', self.url, [], {}) - self.assertEqual('POST', return_dict['method']) + mock_post.assert_called_once_with(self.url, {}) - def test_get(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.get', + return_value=(mock.Mock(), mock.Mock())) + def test_get(self, mock_get): __, return_dict = self.negative_rest_client.send_request('GET', self.url, []) - self.assertEqual('GET', return_dict['method']) + mock_get.assert_called_once_with(self.url) - def test_delete(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.delete', + return_value=(mock.Mock(), mock.Mock())) + def test_delete(self, mock_delete): __, return_dict = self.negative_rest_client.send_request('DELETE', self.url, []) - self.assertEqual('DELETE', return_dict['method']) + mock_delete.assert_called_once_with(self.url) - def test_patch(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.patch', + return_value=(mock.Mock(), mock.Mock())) + def test_patch(self, mock_patch): __, return_dict = self.negative_rest_client.send_request('PATCH', self.url, [], {}) - self.assertEqual('PATCH', return_dict['method']) + mock_patch.assert_called_once_with(self.url, {}) - def test_put(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.put', + return_value=(mock.Mock(), mock.Mock())) + def test_put(self, mock_put): __, return_dict = self.negative_rest_client.send_request('PUT', self.url, [], {}) - self.assertEqual('PUT', return_dict['method']) + mock_put.assert_called_once_with(self.url, {}) - def test_head(self): - self.useFixture(mockpatch.PatchObject(self.negative_rest_client, - 'response_checker')) + @mock.patch('tempest.lib.common.rest_client.RestClient.head', + return_value=(mock.Mock(), mock.Mock())) + def test_head(self, mock_head): __, return_dict = self.negative_rest_client.send_request('HEAD', self.url, []) - self.assertEqual('HEAD', return_dict['method']) + mock_head.assert_called_once_with(self.url) - def test_copy(self): + @mock.patch('tempest.lib.common.rest_client.RestClient.copy', + return_value=(mock.Mock(), mock.Mock())) + def test_copy(self, mock_copy): __, return_dict = self.negative_rest_client.send_request('COPY', self.url, []) - self.assertEqual('COPY', return_dict['method']) + mock_copy.assert_called_once_with(self.url) def test_other(self): self.assertRaises(AssertionError,