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
diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py
new file mode 100644
index 0000000..bf4de3e
--- /dev/null
+++ b/tempest/api/compute/api_microversion_fixture.py
@@ -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
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 0856983..96f32aa 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -18,6 +18,7 @@
 from oslo_log import log as logging
 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 compute
 from tempest.common.utils import data_utils
@@ -56,13 +57,6 @@
     @classmethod
     def setup_credentials(cls):
         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()
 
     @classmethod
@@ -108,6 +102,10 @@
     @classmethod
     def resource_setup(cls):
         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_timeout = CONF.compute.build_timeout
         cls.image_ref = CONF.compute.image_ref
@@ -371,6 +369,11 @@
         else:
             raise exceptions.InvalidConfiguration()
 
+    def setUp(self):
+        super(BaseV2ComputeTest, self).setUp()
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            self.request_microversion))
+
 
 class BaseV2ComputeAdminTest(BaseV2ComputeTest):
     """Base test case class for Compute Admin API tests."""
diff --git a/tempest/clients.py b/tempest/clients.py
index 2a8a4ae..ce5f8c1 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -202,30 +202,14 @@
     }
     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.
 
         Setup all services clients and make them available for tests cases.
         :param credentials: type Credentials or TestResources
         :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)
-        self.api_microversions = api_microversions or {}
         self._set_compute_clients()
         self._set_database_clients()
         self._set_identity_clients()
@@ -390,8 +374,6 @@
         self.negative_client = negative_rest_client.NegativeRestClient(
             self.auth_provider, service, **self.default_params)
 
-        self._set_api_microversions()
-
     def _set_compute_clients(self):
         params = {
             'service': CONF.compute.catalog_type,
@@ -623,15 +605,3 @@
         self.account_client = AccountClient(self.auth_provider, **params)
         self.container_client = ContainerClient(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)
diff --git a/tempest/common/api_version_utils.py b/tempest/common/api_version_utils.py
index c3d977f..7c7e96a 100644
--- a/tempest/common/api_version_utils.py
+++ b/tempest/common/api_version_utils.py
@@ -18,6 +18,9 @@
 from tempest import exceptions
 
 
+LATEST_MICROVERSION = 'latest'
+
+
 class BaseMicroversionTest(object):
     """Mixin class for API microversion test class."""
 
@@ -27,7 +30,7 @@
     # 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'
+    max_microversion = LATEST_MICROVERSION
 
 
 def check_skip_with_microversion(test_min_version, test_max_version,
diff --git a/tempest/services/base_microversion_client.py b/tempest/services/base_microversion_client.py
deleted file mode 100644
index 4c750f5..0000000
--- a/tempest/services/base_microversion_client.py
+++ /dev/null
@@ -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
diff --git a/tempest/services/compute/json/base_compute_client.py b/tempest/services/compute/json/base_compute_client.py
index 5349af6..5ea289c 100644
--- a/tempest/services/compute/json/base_compute_client.py
+++ b/tempest/services/compute/json/base_compute_client.py
@@ -11,30 +11,38 @@
 #    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.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,
-                 api_microversion_header_name='X-OpenStack-Nova-API-Version',
                  **kwargs):
         super(BaseComputeClient, self).__init__(
-            auth_provider, service, region,
-            api_microversion_header_name, **kwargs)
+            auth_provider, service, region, **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,
                 body=None):
         resp, resp_body = super(BaseComputeClient, self).request(
             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(
                 self.api_microversion_header_name,
-                self.api_microversion,
+                COMPUTE_MICROVERSION,
                 resp)
         return resp, resp_body
 
@@ -52,7 +60,7 @@
             {'min': '2.10', 'max': None, 'schema': schemav210}]
         """
         schema = None
-        version = api_version_request.APIVersionRequest(self.api_microversion)
+        version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION)
         for items in schema_versions_info:
             min_version = api_version_request.APIVersionRequest(items['min'])
             max_version = api_version_request.APIVersionRequest(items['max'])
diff --git a/tempest/test.py b/tempest/test.py
index ee3288c..5f8ef72 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -226,7 +226,6 @@
     # Resources required to validate a server using ssh
     validation_resources = {}
     network_resources = {}
-    services_microversion = {}
 
     # NOTE(sdague): log_format is defined inline here instead of using the oslo
     # default because going through the config path recouples config to the
@@ -522,8 +521,7 @@
             else:
                 raise exceptions.InvalidCredentials(
                     "Invalid credentials type %s" % credential_type)
-        return cls.client_manager(credentials=creds, service=cls._service,
-                                  api_microversions=cls.services_microversion)
+        return cls.client_manager(credentials=creds, service=cls._service)
 
     @classmethod
     def clear_credentials(cls):
@@ -610,8 +608,7 @@
                 credentials.is_admin_available(
                     identity_version=cls.get_identity_version())):
             admin_creds = cred_provider.get_admin_creds()
-            admin_manager = clients.Manager(
-                admin_creds, api_microversions=cls.services_microversion)
+            admin_manager = clients.Manager(admin_creds)
             networks_client = admin_manager.compute_networks_client
         return fixed_network.get_tenant_network(
             cred_provider, networks_client, CONF.compute.fixed_network_name)
diff --git a/tempest/tests/services/compute/test_base_compute_client.py b/tempest/tests/services/compute/test_base_compute_client.py
index 7a55cdb..672ae33 100644
--- a/tempest/tests/services/compute/test_base_compute_client.py
+++ b/tempest/tests/services/compute/test_base_compute_client.py
@@ -13,9 +13,11 @@
 #    under the License.
 
 import httplib2
+import mock
 from oslotest import mockpatch
 from tempest_lib.common import rest_client
 
+from tempest.api.compute import api_microversion_fixture
 from tempest import exceptions
 from tempest.services.compute.json import base_compute_client
 from tempest.tests import fake_auth_provider
@@ -29,7 +31,7 @@
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = base_compute_client.BaseComputeClient(
             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 request(*args, **kwargs):
@@ -75,7 +77,8 @@
         super(TestSchemaVersionsNone, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         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):
         self.assertEqual(self.expected_schema,
@@ -129,8 +132,62 @@
         super(TestSchemaVersionsNotFound, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         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):
         self.assertRaises(exceptions.JSONSchemaNotFound,
                           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')
diff --git a/tempest/tests/services/test_base_microversion_client.py b/tempest/tests/services/test_base_microversion_client.py
deleted file mode 100644
index 11b8170..0000000
--- a/tempest/tests/services/test_base_microversion_client.py
+++ /dev/null
@@ -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')