# tempest.lib.common.api_version_utils

# Source code for tempest.lib.common.api_version_utils

    # Copyright 2015 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 testtools

    from tempest.lib.common import api_version_request
    from tempest.lib import exceptions

    LATEST_MICROVERSION = 'latest'

    class BaseMicroversionTest(object):
        """Mixin class for API microversion test class."""

        # NOTE: Basically, each microversion is small API change and we
        # can use the same tests for most microversions in most cases.
        # So it is nice to define the test class as possible to run
        # for all microversions. We need to define microversion range
        # (min_microversion, max_microversion) on each test class if necessary.
        min_microversion = None
        max_microversion = LATEST_MICROVERSION
        volume_min_microversion = None
        volume_max_microversion = LATEST_MICROVERSION
        placement_min_microversion = None
        placement_max_microversion = LATEST_MICROVERSION

    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)
        config_max_version = api_version_request.APIVersionRequest(cfg_max_version)
        if ((min_version > max_version) or
            (config_min_version > config_max_version)):
            msg = ("Test Class versions [%s - %s]. "
                   "Configuration versions [%s - %s]."
                   % (min_version.get_string(),
                      max_version.get_string(),
                      config_min_version.get_string(),
                      config_max_version.get_string()))
            raise exceptions.InvalidAPIVersionRange(msg)

        # NOTE: Select tests which are in range of configuration like
        #               config min           config max
        # ----------------+--------------------------+----------------
        # ...don't-select|
        #            ...select...  ...select...  ...select...
        #                                             |don't-select...
        # ......................select............................
        if (max_version < config_min_version or
            config_max_version < min_version):
            msg = ("The microversion range[%s - %s] of this test is out of the "
                   "configuration range[%s - %s]."
                   % (min_version.get_string(),
                      max_version.get_string(),
                      config_min_version.get_string(),
                      config_max_version.get_string()))
            raise testtools.TestCase.skipException(msg)

    def select_request_microversion(test_min_version, cfg_min_version):
        """Select microversion from test and configuration min version.

        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
        return max_version.get_string()

    def assert_version_header_matches_request(api_microversion_header_name,
                                              api_microversion,
                                              response_header):
        """Checks API microversion in response header

        Verify whether microversion is present in response header
        and with specified 'api_microversion' value.

        :param api_microversion_header_name: Microversion header name
                Example- "X-OpenStack-Nova-API-Version"
        :param api_microversion: Microversion number like "2.10", type str.
        :param response_header: Response header where microversion is
                expected to be present.
        """
        if not isinstance(api_microversion, str):
            raise TypeError('api_microversion must be a string')
        api_microversion_header_name = api_microversion_header_name.lower()
        if (api_microversion_header_name not in response_header or
            api_microversion != response_header[api_microversion_header_name]):
            msg = ("Microversion header '%s' with value '%s' does not match in "
                   "response - %s. " % (api_microversion_header_name,
                                        api_microversion,
                                        response_header))
            raise exceptions.InvalidHTTPResponseHeader(msg)

    def compare_version_header_to_response(api_microversion_header_name,
                                           api_microversion,
                                           response_header,
                                           operation='eq'):
        """Compares API microversion in response header to ``api_microversion``.

        Compare the ``api_microversion`` value in response header if microversion
        header is present in response, otherwise return false.

        To make this function work for APIs which do not return microversion
        header in response (example compute v2.0), this function does *not* raise
        InvalidHTTPResponseHeader.

        :param api_microversion_header_name: Microversion header name. Example:
            'Openstack-Api-Version'.
        :param api_microversion: Microversion number. Example:

            * '2.10' for the old-style header name, 'X-OpenStack-Nova-API-Version'
            * 'Compute 2.10' for the new-style header name, 'Openstack-Api-Version'

        :param response_header: Response header where microversion is
            expected to be present.
        :param operation: The boolean operation to use to compare the
            ``api_microversion`` to the microversion in ``response_header``.
            Can be 'lt', 'eq', 'gt', 'le', 'ne', 'ge'. Default is 'eq'. The
            operation type should be based on the order of the arguments:
            ``api_microversion`` <operation> ``response_header`` microversion.
        :returns: True if the comparison is logically true, else False if the
            comparison is logically false or if ``api_microversion_header_name`` is
            missing in the ``response_header``.
        :raises InvalidParam: If the operation is not lt, eq, gt, le, ne or ge.
        """
        api_microversion_header_name = api_microversion_header_name.lower()
        if api_microversion_header_name not in response_header:
            return False

        op = getattr(api_version_request.APIVersionRequest,
                     '__%s__' % operation, None)

        if op is None:
            msg = ("Operation %s is invalid. Valid options include: lt, eq, gt, "
                   "le, ne, ge." % operation)
            raise exceptions.InvalidParam(invalid_param=msg)

        # Remove "volume" from "volume <microversion>", for example, so that the
        # microversion can be converted to `APIVersionRequest`.
        api_version = api_microversion.split(' ')[-1]
        resp_version = response_header[api_microversion_header_name].split(' ')[-1]
        if not op(
            api_version_request.APIVersionRequest(api_version),
            api_version_request.APIVersionRequest(resp_version)):
            return False

        return True

this page last updated: 2026-03-26 22:17:27

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

found an error? report a bug