Add microversion fixture to set microversion

Currently microversion is being set via set method on service clients
and stored as instance variable.
That approach is little bit complicated and provides less
flexibility on microversion control from test side.

This commit add fixture to set and reset the microversion
and during that fixture scope set microversion will be used to send API request.

Partially implements blueprint api-microversions-testing-support

Change-Id: If2bc46e36dd44dce4c4bbb53bf9024c003f78b93
This commit is contained in:
Ghanshyam 2016-02-12 17:44:48 +09:00
parent d4224b6426
commit 05049ddb0a
9 changed files with 124 additions and 184 deletions

View File

@ -0,0 +1,31 @@
# Copyright 2016 NEC Corporation. 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 fixtures
from tempest.services.compute.json import base_compute_client
class APIMicroversionFixture(fixtures.Fixture):
def __init__(self, compute_microversion):
self.compute_microversion = compute_microversion
def _setUp(self):
super(APIMicroversionFixture, self)._setUp()
base_compute_client.COMPUTE_MICROVERSION = self.compute_microversion
self.addCleanup(self._reset_compute_microversion)
def _reset_compute_microversion(self):
base_compute_client.COMPUTE_MICROVERSION = None

View File

@ -18,6 +18,7 @@ import time
from oslo_log import log as logging from oslo_log import log as logging
from tempest_lib import exceptions as lib_exc from tempest_lib import exceptions as lib_exc
from tempest.api.compute import api_microversion_fixture
from tempest.common import api_version_utils from tempest.common import api_version_utils
from tempest.common import compute from tempest.common import compute
from tempest.common.utils import data_utils from tempest.common.utils import data_utils
@ -56,13 +57,6 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
@classmethod @classmethod
def setup_credentials(cls): def setup_credentials(cls):
cls.set_network_resources() cls.set_network_resources()
cls.request_microversion = (
api_version_utils.select_request_microversion(
cls.min_microversion,
CONF.compute_feature_enabled.min_microversion))
if cls.request_microversion:
cls.services_microversion = {
CONF.compute.catalog_type: cls.request_microversion}
super(BaseV2ComputeTest, cls).setup_credentials() super(BaseV2ComputeTest, cls).setup_credentials()
@classmethod @classmethod
@ -108,6 +102,10 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
super(BaseV2ComputeTest, cls).resource_setup() super(BaseV2ComputeTest, cls).resource_setup()
cls.request_microversion = (
api_version_utils.select_request_microversion(
cls.min_microversion,
CONF.compute_feature_enabled.min_microversion))
cls.build_interval = CONF.compute.build_interval cls.build_interval = CONF.compute.build_interval
cls.build_timeout = CONF.compute.build_timeout cls.build_timeout = CONF.compute.build_timeout
cls.image_ref = CONF.compute.image_ref cls.image_ref = CONF.compute.image_ref
@ -371,6 +369,11 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
else: else:
raise exceptions.InvalidConfiguration() raise exceptions.InvalidConfiguration()
def setUp(self):
super(BaseV2ComputeTest, self).setUp()
self.useFixture(api_microversion_fixture.APIMicroversionFixture(
self.request_microversion))
class BaseV2ComputeAdminTest(BaseV2ComputeTest): class BaseV2ComputeAdminTest(BaseV2ComputeTest):
"""Base test case class for Compute Admin API tests.""" """Base test case class for Compute Admin API tests."""

View File

@ -202,30 +202,14 @@ class Manager(manager.Manager):
} }
default_params_with_timeout_values.update(default_params) default_params_with_timeout_values.update(default_params)
def __init__(self, credentials, service=None, api_microversions=None): def __init__(self, credentials, service=None):
"""Initialization of Manager class. """Initialization of Manager class.
Setup all services clients and make them available for tests cases. Setup all services clients and make them available for tests cases.
:param credentials: type Credentials or TestResources :param credentials: type Credentials or TestResources
:param service: Service name :param service: Service name
:param api_microversions: This is dict of services catalog type
and their microversion which will be set on respective
services clients.
{<service catalog type>: request_microversion}
Example :
{'compute': request_microversion}
- request_microversion will be set on all compute
service clients.
OR
{'compute': request_microversion,
'volume': request_microversion}
- request_microversion of compute will be set on all
compute service clients.
- request_microversion of volume will be set on all
volume service clients.
""" """
super(Manager, self).__init__(credentials=credentials) super(Manager, self).__init__(credentials=credentials)
self.api_microversions = api_microversions or {}
self._set_compute_clients() self._set_compute_clients()
self._set_database_clients() self._set_database_clients()
self._set_identity_clients() self._set_identity_clients()
@ -390,8 +374,6 @@ class Manager(manager.Manager):
self.negative_client = negative_rest_client.NegativeRestClient( self.negative_client = negative_rest_client.NegativeRestClient(
self.auth_provider, service, **self.default_params) self.auth_provider, service, **self.default_params)
self._set_api_microversions()
def _set_compute_clients(self): def _set_compute_clients(self):
params = { params = {
'service': CONF.compute.catalog_type, 'service': CONF.compute.catalog_type,
@ -623,15 +605,3 @@ class Manager(manager.Manager):
self.account_client = AccountClient(self.auth_provider, **params) self.account_client = AccountClient(self.auth_provider, **params)
self.container_client = ContainerClient(self.auth_provider, **params) self.container_client = ContainerClient(self.auth_provider, **params)
self.object_client = ObjectClient(self.auth_provider, **params) self.object_client = ObjectClient(self.auth_provider, **params)
def _set_api_microversions(self):
service_clients = [x for x in self.__dict__ if x.endswith('_client')]
for client in service_clients:
client_obj = getattr(self, client)
microversion = self.api_microversions.get(client_obj.service)
if microversion:
if hasattr(client_obj, 'set_api_microversion'):
client_obj.set_api_microversion(microversion)
else:
LOG.debug("Need to implement set_api_microversion on %s"
% client)

View File

@ -18,6 +18,9 @@ from tempest.common import api_version_request
from tempest import exceptions from tempest import exceptions
LATEST_MICROVERSION = 'latest'
class BaseMicroversionTest(object): class BaseMicroversionTest(object):
"""Mixin class for API microversion test class.""" """Mixin class for API microversion test class."""
@ -27,7 +30,7 @@ class BaseMicroversionTest(object):
# for all microversions. We need to define microversion range # for all microversions. We need to define microversion range
# (min_microversion, max_microversion) on each test class if necessary. # (min_microversion, max_microversion) on each test class if necessary.
min_microversion = None min_microversion = None
max_microversion = 'latest' max_microversion = LATEST_MICROVERSION
def check_skip_with_microversion(test_min_version, test_max_version, def check_skip_with_microversion(test_min_version, test_max_version,

View File

@ -1,54 +0,0 @@
# Copyright 2016 NEC Corporation. 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.
from tempest_lib.common import rest_client
class BaseMicroversionClient(rest_client.RestClient):
"""Base class to support microversion in service clients
This class is used to support microversion in service clients.
This provides feature to make API request with microversion.
Service clients derived from this class will be able to send API
request to server with or without microversion.
If api_microversion is not set on service client then API request will be
normal request without microversion.
"""
def __init__(self, auth_provider, service, region,
api_microversion_header_name, **kwargs):
"""Base Microversion Client __init__
:param auth_provider: an auth provider object used to wrap requests in
auth
:param str service: The service name to use for the catalog lookup
:param str region: The region to use for the catalog lookup
:param str api_microversion_header_name: The microversion header name
to use for sending API
request with microversion
:param kwargs: kwargs required by rest_client.RestClient
"""
super(BaseMicroversionClient, self).__init__(
auth_provider, service, region, **kwargs)
self.api_microversion_header_name = api_microversion_header_name
self.api_microversion = None
def get_headers(self):
headers = super(BaseMicroversionClient, self).get_headers()
if self.api_microversion:
headers[self.api_microversion_header_name] = self.api_microversion
return headers
def set_api_microversion(self, microversion):
self.api_microversion = microversion

View File

@ -11,30 +11,38 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from tempest_lib.common import rest_client
from tempest.common import api_version_request from tempest.common import api_version_request
from tempest.common import api_version_utils from tempest.common import api_version_utils
from tempest import exceptions from tempest import exceptions
from tempest.services import base_microversion_client
COMPUTE_MICROVERSION = None
class BaseComputeClient(base_microversion_client.BaseMicroversionClient): class BaseComputeClient(rest_client.RestClient):
api_microversion_header_name = 'X-OpenStack-Nova-API-Version'
def __init__(self, auth_provider, service, region, def __init__(self, auth_provider, service, region,
api_microversion_header_name='X-OpenStack-Nova-API-Version',
**kwargs): **kwargs):
super(BaseComputeClient, self).__init__( super(BaseComputeClient, self).__init__(
auth_provider, service, region, auth_provider, service, region, **kwargs)
api_microversion_header_name, **kwargs)
def get_headers(self):
headers = super(BaseComputeClient, self).get_headers()
if COMPUTE_MICROVERSION:
headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION
return headers
def request(self, method, url, extra_headers=False, headers=None, def request(self, method, url, extra_headers=False, headers=None,
body=None): body=None):
resp, resp_body = super(BaseComputeClient, self).request( resp, resp_body = super(BaseComputeClient, self).request(
method, url, extra_headers, headers, body) method, url, extra_headers, headers, body)
if self.api_microversion and self.api_microversion != 'latest': if (COMPUTE_MICROVERSION and
COMPUTE_MICROVERSION != api_version_utils.LATEST_MICROVERSION):
api_version_utils.assert_version_header_matches_request( api_version_utils.assert_version_header_matches_request(
self.api_microversion_header_name, self.api_microversion_header_name,
self.api_microversion, COMPUTE_MICROVERSION,
resp) resp)
return resp, resp_body return resp, resp_body
@ -52,7 +60,7 @@ class BaseComputeClient(base_microversion_client.BaseMicroversionClient):
{'min': '2.10', 'max': None, 'schema': schemav210}] {'min': '2.10', 'max': None, 'schema': schemav210}]
""" """
schema = None schema = None
version = api_version_request.APIVersionRequest(self.api_microversion) version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION)
for items in schema_versions_info: for items in schema_versions_info:
min_version = api_version_request.APIVersionRequest(items['min']) min_version = api_version_request.APIVersionRequest(items['min'])
max_version = api_version_request.APIVersionRequest(items['max']) max_version = api_version_request.APIVersionRequest(items['max'])

View File

@ -226,7 +226,6 @@ class BaseTestCase(testtools.testcase.WithAttributes,
# Resources required to validate a server using ssh # Resources required to validate a server using ssh
validation_resources = {} validation_resources = {}
network_resources = {} network_resources = {}
services_microversion = {}
# NOTE(sdague): log_format is defined inline here instead of using the oslo # NOTE(sdague): log_format is defined inline here instead of using the oslo
# default because going through the config path recouples config to the # default because going through the config path recouples config to the
@ -522,8 +521,7 @@ class BaseTestCase(testtools.testcase.WithAttributes,
else: else:
raise exceptions.InvalidCredentials( raise exceptions.InvalidCredentials(
"Invalid credentials type %s" % credential_type) "Invalid credentials type %s" % credential_type)
return cls.client_manager(credentials=creds, service=cls._service, return cls.client_manager(credentials=creds, service=cls._service)
api_microversions=cls.services_microversion)
@classmethod @classmethod
def clear_credentials(cls): def clear_credentials(cls):
@ -610,8 +608,7 @@ class BaseTestCase(testtools.testcase.WithAttributes,
credentials.is_admin_available( credentials.is_admin_available(
identity_version=cls.get_identity_version())): identity_version=cls.get_identity_version())):
admin_creds = cred_provider.get_admin_creds() admin_creds = cred_provider.get_admin_creds()
admin_manager = clients.Manager( admin_manager = clients.Manager(admin_creds)
admin_creds, api_microversions=cls.services_microversion)
networks_client = admin_manager.compute_networks_client networks_client = admin_manager.compute_networks_client
return fixed_network.get_tenant_network( return fixed_network.get_tenant_network(
cred_provider, networks_client, CONF.compute.fixed_network_name) cred_provider, networks_client, CONF.compute.fixed_network_name)

View File

@ -13,9 +13,11 @@
# under the License. # under the License.
import httplib2 import httplib2
import mock
from oslotest import mockpatch from oslotest import mockpatch
from tempest_lib.common import rest_client from tempest_lib.common import rest_client
from tempest.api.compute import api_microversion_fixture
from tempest import exceptions from tempest import exceptions
from tempest.services.compute.json import base_compute_client from tempest.services.compute.json import base_compute_client
from tempest.tests import fake_auth_provider from tempest.tests import fake_auth_provider
@ -29,7 +31,7 @@ class TestMicroversionHeaderCheck(base.BaseComputeServiceTest):
fake_auth = fake_auth_provider.FakeAuthProvider() fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = base_compute_client.BaseComputeClient( self.client = base_compute_client.BaseComputeClient(
fake_auth, 'compute', 'regionOne') fake_auth, 'compute', 'regionOne')
self.client.set_api_microversion('2.2') self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
def _check_microverion_header_in_response(self, fake_response): def _check_microverion_header_in_response(self, fake_response):
def request(*args, **kwargs): def request(*args, **kwargs):
@ -75,7 +77,8 @@ class TestSchemaVersionsNone(base.BaseComputeServiceTest):
super(TestSchemaVersionsNone, self).setUp() super(TestSchemaVersionsNone, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider() fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne') self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne')
self.client.api_microversion = self.api_microversion self.useFixture(api_microversion_fixture.APIMicroversionFixture(
self.api_microversion))
def test_schema(self): def test_schema(self):
self.assertEqual(self.expected_schema, self.assertEqual(self.expected_schema,
@ -129,8 +132,62 @@ class TestSchemaVersionsNotFound(base.BaseComputeServiceTest):
super(TestSchemaVersionsNotFound, self).setUp() super(TestSchemaVersionsNotFound, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider() fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne') self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne')
self.client.api_microversion = self.api_microversion self.useFixture(api_microversion_fixture.APIMicroversionFixture(
self.api_microversion))
def test_schema(self): def test_schema(self):
self.assertRaises(exceptions.JSONSchemaNotFound, self.assertRaises(exceptions.JSONSchemaNotFound,
self.client.return_selected_schema) self.client.return_selected_schema)
class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest):
def setUp(self):
super(TestClientWithoutMicroversionHeader, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = base_compute_client.BaseComputeClient(
fake_auth, 'compute', 'regionOne')
def test_no_microverion_header(self):
header = self.client.get_headers()
self.assertNotIn('X-OpenStack-Nova-API-Version', header)
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}), {})
with mock.patch.object(rest_client.RestClient,
'raw_request') as mock_get:
mock_get.side_effect = raw_request
self.client.get('fake_url')
class TestClientWithMicroversionHeader(base.BaseComputeServiceTest):
def setUp(self):
super(TestClientWithMicroversionHeader, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = base_compute_client.BaseComputeClient(
fake_auth, 'compute', 'regionOne')
self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
def test_microverion_header(self):
header = self.client.get_headers()
self.assertIn('X-OpenStack-Nova-API-Version', header)
self.assertEqual('2.2',
header['X-OpenStack-Nova-API-Version'])
def test_microverion_header_in_raw_request(self):
def raw_request(*args, **kwargs):
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'}), {})
with mock.patch.object(rest_client.RestClient,
'raw_request') as mock_get:
mock_get.side_effect = raw_request
self.client.get('fake_url')

View File

@ -1,75 +0,0 @@
# Copyright 2016 NEC Corporation. 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
import mock
from tempest_lib.common import rest_client
from tempest.services import base_microversion_client
from tempest.tests import fake_auth_provider
from tempest.tests.services.compute import base
class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest):
def setUp(self):
super(TestClientWithoutMicroversionHeader, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = base_microversion_client.BaseMicroversionClient(
fake_auth, 'compute', 'regionOne', 'X-OpenStack-Nova-API-Version')
def test_no_microverion_header(self):
header = self.client.get_headers()
self.assertNotIn(self.client.api_microversion_header_name, header)
def test_no_microverion_header_in_raw_request(self):
def raw_request(*args, **kwargs):
self.assertNotIn(self.client.api_microversion_header_name,
kwargs['headers'])
return (httplib2.Response({'status': 200}), {})
with mock.patch.object(rest_client.RestClient,
'raw_request') as mock_get:
mock_get.side_effect = raw_request
self.client.get('fake_url')
class TestClientWithMicroversionHeader(base.BaseComputeServiceTest):
def setUp(self):
super(TestClientWithMicroversionHeader, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = base_microversion_client.BaseMicroversionClient(
fake_auth, 'compute', 'regionOne', 'X-OpenStack-Nova-API-Version')
self.client.set_api_microversion('2.2')
def test_microverion_header(self):
header = self.client.get_headers()
self.assertIn(self.client.api_microversion_header_name, header)
self.assertEqual(self.client.api_microversion,
header[self.client.api_microversion_header_name])
def test_microverion_header_in_raw_request(self):
def raw_request(*args, **kwargs):
self.assertIn(self.client.api_microversion_header_name,
kwargs['headers'])
self.assertEqual(
self.client.api_microversion,
kwargs['headers'][self.client.api_microversion_header_name])
return (httplib2.Response({'status': 200}), {})
with mock.patch.object(rest_client.RestClient,
'raw_request') as mock_get:
mock_get.side_effect = raw_request
self.client.get('fake_url')