From 1f47cf976b6e57deb2aa6fb24ed249bf05c331e9 Mon Sep 17 00:00:00 2001 From: Ghanshyam Date: Thu, 25 Feb 2016 04:57:18 +0900 Subject: [PATCH] Migrated microversion testing framework to tempest/lib Tempest implements the microversion testing support and that framework and interfaces have been tested by implementing the Compute 2.2 microversion as well as by their unit tests. Those should be stable interfaces so that can be consumed by other projects microversion testing either in tempest or outside tempest. To make them as stable interface, this commit moving that framework and its interfaces to tempest/lib folder. Adding release notes and library doc for those interface. Partially implements blueprint api-microversions-testing-support Change-Id: Icbdcfb4cd5b7fb1029eec035b9e0024be59c8d1f --- doc/source/library.rst | 1 + .../library/api_microversion_testing.rst | 29 +++++++++++++++ ...sion-testing-support-2ceddd2255670932.yaml | 3 ++ .../api/compute/api_microversion_fixture.py | 2 +- tempest/api/compute/base.py | 2 +- tempest/exceptions.py | 14 -------- .../{ => lib}/common/api_version_request.py | 27 ++++++++------ tempest/{ => lib}/common/api_version_utils.py | 34 +++++++++++++++--- tempest/lib/exceptions.py | 14 ++++++++ .../services/compute}/base_compute_client.py | 27 ++++++++++---- .../services/compute/json/keypairs_client.py | 2 +- .../common/test_api_version_request.py | 6 ++-- .../common/test_api_version_utils.py | 6 ++-- .../compute/test_base_compute_client.py | 35 +++++++++++++------ tempest/tests/test_microversions.py | 2 +- 15 files changed, 147 insertions(+), 57 deletions(-) create mode 100644 doc/source/library/api_microversion_testing.rst create mode 100644 releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml rename tempest/{ => lib}/common/api_version_request.py (92%) rename tempest/{ => lib}/common/api_version_utils.py (78%) rename tempest/{services/compute/json => lib/services/compute}/base_compute_client.py (79%) rename tempest/tests/{ => lib}/common/test_api_version_request.py (98%) rename tempest/tests/{ => lib}/common/test_api_version_utils.py (97%) rename tempest/tests/{ => lib}/services/compute/test_base_compute_client.py (86%) diff --git a/doc/source/library.rst b/doc/source/library.rst index 8b263f2bf2..64bd2c28f1 100644 --- a/doc/source/library.rst +++ b/doc/source/library.rst @@ -66,3 +66,4 @@ Current Library APIs library/decorators library/rest_client library/utils + library/api_microversion_testing diff --git a/doc/source/library/api_microversion_testing.rst b/doc/source/library/api_microversion_testing.rst new file mode 100644 index 0000000000..0d0b595072 --- /dev/null +++ b/doc/source/library/api_microversion_testing.rst @@ -0,0 +1,29 @@ +.. _api_microversion_testing: + +API Microversion Testing Support in Temepst +=========================================== + +--------------------------------------------- +Framework to support API Microversion testing +--------------------------------------------- + +Many of the OpenStack components have implemented API microversions. +It is important to tests those microversion in Tempest or external plugins. +Tempest now provides stable interfaces to support to test the API microversions. +Based on the microversion range coming from the combination of both configuration +and each test case, APIs request will be made with selected microversion. + +This document explains the interfaces needed for microversion testing. + + +The api_version_request module +"""""""""""""""""""""""""""""" + +.. automodule:: tempest.lib.common.api_version_request + :members: + +The api_version_utils module +"""""""""""""""""""""""""""" + +.. automodule:: tempest.lib.common.api_version_utils + :members: diff --git a/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml new file mode 100644 index 0000000000..e98671a521 --- /dev/null +++ b/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml @@ -0,0 +1,3 @@ +--- +features: + - Tempest library interface addition(API Microversion testing interfaces). \ No newline at end of file diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py index bf4de3ef4a..695af52003 100644 --- a/tempest/api/compute/api_microversion_fixture.py +++ b/tempest/api/compute/api_microversion_fixture.py @@ -14,7 +14,7 @@ import fixtures -from tempest.services.compute.json import base_compute_client +from tempest.lib.services.compute import base_compute_client class APIMicroversionFixture(fixtures.Fixture): diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py index ee21284279..f61d2fbb35 100644 --- a/tempest/api/compute/base.py +++ b/tempest/api/compute/base.py @@ -18,12 +18,12 @@ import time from oslo_log import log as logging from tempest.api.compute import api_microversion_fixture -from tempest.common import api_version_utils from tempest.common import compute from tempest.common.utils import data_utils from tempest.common import waiters from tempest import config from tempest import exceptions +from tempest.lib.common import api_version_utils from tempest.lib import exceptions as lib_exc import tempest.test diff --git a/tempest/exceptions.py b/tempest/exceptions.py index 86e8460a28..031df7fe7c 100644 --- a/tempest/exceptions.py +++ b/tempest/exceptions.py @@ -176,20 +176,6 @@ class InvalidStructure(TempestException): message = "Invalid structure of table with details" -class InvalidAPIVersionString(TempestException): - message = ("API Version String %(version)s is of invalid format. Must " - "be of format MajorNum.MinorNum or string 'latest'.") - - -class JSONSchemaNotFound(TempestException): - message = ("JSON Schema for %(version)s is not found in \n" - " %(schema_versions_info)s") - - -class InvalidAPIVersionRange(TempestException): - message = ("API Min Version is greater than Max version") - - class CommandFailed(Exception): def __init__(self, returncode, cmd, output, stderr): super(CommandFailed, self).__init__() diff --git a/tempest/common/api_version_request.py b/tempest/lib/common/api_version_request.py similarity index 92% rename from tempest/common/api_version_request.py rename to tempest/lib/common/api_version_request.py index d8a5b563a6..b2b68a6b27 100644 --- a/tempest/common/api_version_request.py +++ b/tempest/lib/common/api_version_request.py @@ -14,7 +14,7 @@ import re -from tempest import exceptions +from tempest.lib import exceptions # Define the minimum and maximum version of the API across all of the @@ -39,6 +39,11 @@ class APIVersionRequest(object): This class provides convenience methods for manipulation and comparison of version numbers that we need to do to implement microversions. + + :param version_string: String representation of APIVersionRequest. + Correct format is 'X.Y', where 'X' and 'Y' are int values. + None value should be used to create Null APIVersionRequest, + which is equal to 0.0 """ # NOTE: This 'latest' version is a magic number, we assume any @@ -47,13 +52,7 @@ class APIVersionRequest(object): latest_ver_minor = 99999 def __init__(self, version_string=None): - """Create an API version request object. - - :param version_string: String representation of APIVersionRequest. - Correct format is 'X.Y', where 'X' and 'Y' are int values. - None value should be used to create Null APIVersionRequest, - which is equal to 0.0 - """ + """Create an API version request object.""" # NOTE(gmann): 'version_string' as String "None" will be considered as # invalid version string. self.ver_major = 0 @@ -77,6 +76,12 @@ class APIVersionRequest(object): return ("API Version Request: %s" % self.get_string()) def is_null(self): + """Checks whether version is null. + + Return True if version object is null otherwise False. + + :returns: boolean + """ return self.ver_major == 0 and self.ver_minor == 0 def _format_type_error(self, other): @@ -120,9 +125,9 @@ class APIVersionRequest(object): greater than or equal to the minimum version and less than or equal to the maximum version. - @param min_version: Minimum acceptable version. - @param max_version: Maximum acceptable version. - @returns: boolean + :param min_version: Minimum acceptable version. + :param max_version: Maximum acceptable version. + :returns: boolean If min_version is null then there is no minimum limit. If max_version is null then there is no maximum limit. diff --git a/tempest/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py similarity index 78% rename from tempest/common/api_version_utils.py rename to tempest/lib/common/api_version_utils.py index 7c7e96ab22..73cd280020 100644 --- a/tempest/common/api_version_utils.py +++ b/tempest/lib/common/api_version_utils.py @@ -14,8 +14,8 @@ import testtools -from tempest.common import api_version_request -from tempest import exceptions +from tempest.lib.common import api_version_request +from tempest.lib import exceptions LATEST_MICROVERSION = 'latest' @@ -35,6 +35,20 @@ class BaseMicroversionTest(object): def check_skip_with_microversion(test_min_version, test_max_version, cfg_min_version, cfg_max_version): + """Checks API microversions range and returns whether test needs to be skip + + Compare the test and configured microversion range and returns + whether test microversion range is out of configured one. + This method can be used to skip the test based on configured and test + microversion range. + + :param test_min_version: Test Minimum Microversion + :param test_max_version: Test Maximum Microversion + :param cfg_min_version: Configured Minimum Microversion + :param cfg_max_version: Configured Maximum Microversion + :returns: boolean + """ + min_version = api_version_request.APIVersionRequest(test_min_version) max_version = api_version_request.APIVersionRequest(test_max_version) config_min_version = api_version_request.APIVersionRequest(cfg_min_version) @@ -68,6 +82,16 @@ def check_skip_with_microversion(test_min_version, test_max_version, def select_request_microversion(test_min_version, cfg_min_version): + """Select microversion from test and configuration. + + Compare requested microversion and return the maximum + microversion out of those. + + :param test_min_version: Test Minimum Microversion + :param cfg_min_version: Configured Minimum Microversion + :returns: Selected microversion string + """ + test_version = api_version_request.APIVersionRequest(test_min_version) cfg_version = api_version_request.APIVersionRequest(cfg_min_version) max_version = cfg_version if cfg_version >= test_version else test_version @@ -82,10 +106,10 @@ def assert_version_header_matches_request(api_microversion_header_name, Verify whether microversion is present in response header and with specified 'api_microversion' value. - @param: api_microversion_header_name: Microversion header name + :param api_microversion_header_name: Microversion header name Example- "X-OpenStack-Nova-API-Version" - @param: api_microversion: Microversion number like "2.10" - @param: response_header: Response header where microversion is + :param api_microversion: Microversion number like "2.10" + :param response_header: Response header where microversion is expected to be present. """ api_microversion_header_name = api_microversion_header_name.lower() diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py index 2bf7cdd324..b9b2ae9539 100644 --- a/tempest/lib/exceptions.py +++ b/tempest/lib/exceptions.py @@ -153,6 +153,20 @@ class InvalidStructure(TempestException): message = "Invalid structure of table with details" +class InvalidAPIVersionString(TempestException): + message = ("API Version String %(version)s is of invalid format. Must " + "be of format MajorNum.MinorNum or string 'latest'.") + + +class JSONSchemaNotFound(TempestException): + message = ("JSON Schema for %(version)s is not found in\n" + " %(schema_versions_info)s") + + +class InvalidAPIVersionRange(TempestException): + message = ("The API version range is invalid.") + + class BadAltAuth(TempestException): """Used when trying and failing to change to alt creds. diff --git a/tempest/services/compute/json/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py similarity index 79% rename from tempest/services/compute/json/base_compute_client.py rename to tempest/lib/services/compute/base_compute_client.py index 8cfde4b34e..bbadc8fb32 100644 --- a/tempest/services/compute/json/base_compute_client.py +++ b/tempest/lib/services/compute/base_compute_client.py @@ -11,16 +11,30 @@ # 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 -from tempest.common import api_version_request -from tempest.common import api_version_utils -from tempest import exceptions +from tempest.lib.common import api_version_request +from tempest.lib.common import api_version_utils +from tempest.lib.common import rest_client +from tempest.lib import exceptions COMPUTE_MICROVERSION = None class BaseComputeClient(rest_client.RestClient): + """Base compute service clients class to support microversion. + + This class adds microversion to API request header if same is set + and provide interface to select appropriate JSON schema file for + response validation. + + :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 + request with microversion + :param kwargs: kwargs required by rest_client.RestClient + """ + api_microversion_header_name = 'X-OpenStack-Nova-API-Version' def __init__(self, auth_provider, service, region, @@ -50,9 +64,10 @@ class BaseComputeClient(rest_client.RestClient): """Get JSON schema This method provides the matching schema for requested - microversion (self.api_microversion). + microversion. + :param schema_versions_info: List of dict which provides schema - information with range of valid versions. + information with range of valid versions. Example - schema_versions_info = [ {'min': None, 'max': '2.1', 'schema': schemav21}, diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py index 045f03c3b6..2af55b2235 100644 --- a/tempest/services/compute/json/keypairs_client.py +++ b/tempest/services/compute/json/keypairs_client.py @@ -18,7 +18,7 @@ from oslo_serialization import jsonutils as json from tempest.api_schema.response.compute.v2_1 import keypairs as schemav21 from tempest.api_schema.response.compute.v2_2 import keypairs as schemav22 from tempest.lib.common import rest_client -from tempest.services.compute.json import base_compute_client +from tempest.lib.services.compute import base_compute_client class KeyPairsClient(base_compute_client.BaseComputeClient): diff --git a/tempest/tests/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py similarity index 98% rename from tempest/tests/common/test_api_version_request.py rename to tempest/tests/lib/common/test_api_version_request.py index 38fbfc1415..bdaa936511 100644 --- a/tempest/tests/common/test_api_version_request.py +++ b/tempest/tests/lib/common/test_api_version_request.py @@ -12,9 +12,9 @@ # License for the specific language governing permissions and limitations # under the License. -from tempest.common import api_version_request -from tempest import exceptions -from tempest.tests import base +from tempest.lib.common import api_version_request +from tempest.lib import exceptions +from tempest.tests.lib import base class APIVersionRequestTests(base.TestCase): diff --git a/tempest/tests/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py similarity index 97% rename from tempest/tests/common/test_api_version_utils.py rename to tempest/tests/lib/common/test_api_version_utils.py index 501f954d09..591b87ed42 100644 --- a/tempest/tests/common/test_api_version_utils.py +++ b/tempest/tests/lib/common/test_api_version_utils.py @@ -14,9 +14,9 @@ import testtools -from tempest.common import api_version_utils -from tempest import exceptions -from tempest.tests import base +from tempest.lib.common import api_version_utils +from tempest.lib import exceptions +from tempest.tests.lib import base class TestVersionSkipLogic(base.TestCase): diff --git a/tempest/tests/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py similarity index 86% rename from tempest/tests/services/compute/test_base_compute_client.py rename to tempest/tests/lib/services/compute/test_base_compute_client.py index 1a782471ba..f552ef5326 100644 --- a/tempest/tests/services/compute/test_base_compute_client.py +++ b/tempest/tests/lib/services/compute/test_base_compute_client.py @@ -16,12 +16,11 @@ import httplib2 import mock from oslotest import mockpatch -from tempest.api.compute import api_microversion_fixture -from tempest import exceptions from tempest.lib.common import rest_client -from tempest.services.compute.json import base_compute_client -from tempest.tests import fake_auth_provider -from tempest.tests.services.compute import base +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.services.compute import base class TestMicroversionHeaderCheck(base.BaseComputeServiceTest): @@ -31,7 +30,11 @@ class TestMicroversionHeaderCheck(base.BaseComputeServiceTest): fake_auth = fake_auth_provider.FakeAuthProvider() self.client = base_compute_client.BaseComputeClient( fake_auth, 'compute', 'regionOne') - self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2')) + base_compute_client.COMPUTE_MICROVERSION = '2.2' + + def tearDown(self): + super(TestMicroversionHeaderCheck, self).tearDown() + base_compute_client.COMPUTE_MICROVERSION = None def _check_microverion_header_in_response(self, fake_response): def request(*args, **kwargs): @@ -77,8 +80,11 @@ class TestSchemaVersionsNone(base.BaseComputeServiceTest): super(TestSchemaVersionsNone, self).setUp() fake_auth = fake_auth_provider.FakeAuthProvider() self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne') - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.api_microversion)) + base_compute_client.COMPUTE_MICROVERSION = self.api_microversion + + def tearDown(self): + super(TestSchemaVersionsNone, self).tearDown() + base_compute_client.COMPUTE_MICROVERSION = None def test_schema(self): self.assertEqual(self.expected_schema, @@ -132,8 +138,11 @@ class TestSchemaVersionsNotFound(base.BaseComputeServiceTest): super(TestSchemaVersionsNotFound, self).setUp() fake_auth = fake_auth_provider.FakeAuthProvider() self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne') - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.api_microversion)) + base_compute_client.COMPUTE_MICROVERSION = self.api_microversion + + def tearDown(self): + super(TestSchemaVersionsNotFound, self).tearDown() + base_compute_client.COMPUTE_MICROVERSION = None def test_schema(self): self.assertRaises(exceptions.JSONSchemaNotFound, @@ -170,7 +179,11 @@ class TestClientWithMicroversionHeader(base.BaseComputeServiceTest): fake_auth = fake_auth_provider.FakeAuthProvider() self.client = base_compute_client.BaseComputeClient( fake_auth, 'compute', 'regionOne') - self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2')) + base_compute_client.COMPUTE_MICROVERSION = '2.2' + + def tearDown(self): + super(TestClientWithMicroversionHeader, self).tearDown() + base_compute_client.COMPUTE_MICROVERSION = None def test_microverion_header(self): header = self.client.get_headers() diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py index 673864160a..f19ee49ef2 100644 --- a/tempest/tests/test_microversions.py +++ b/tempest/tests/test_microversions.py @@ -17,7 +17,7 @@ import testtools from tempest.api.compute import base as compute_base from tempest import config -from tempest import exceptions +from tempest.lib import exceptions from tempest.tests import base from tempest.tests import fake_config