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
This commit is contained in:
Ghanshyam 2016-02-25 04:57:18 +09:00 committed by Ghanshyam Mann
parent 0d560a9ce4
commit 1f47cf976b
15 changed files with 147 additions and 57 deletions

View File

@ -66,3 +66,4 @@ Current Library APIs
library/decorators
library/rest_client
library/utils
library/api_microversion_testing

View File

@ -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:

View File

@ -0,0 +1,3 @@
---
features:
- Tempest library interface addition(API Microversion testing interfaces).

View File

@ -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):

View File

@ -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

View File

@ -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__()

View File

@ -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.

View File

@ -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()

View File

@ -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.

View File

@ -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},

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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()

View File

@ -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