Merge "Adding a note to 'test_update_user_password' test for Keystone V2"
diff --git a/doc/source/library.rst b/doc/source/library.rst
index 8b263f2..64bd2c2 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -66,3 +66,4 @@
    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 0000000..b7a4ba8
--- /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 test those microversions 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/doc/source/plugin.rst b/doc/source/plugin.rst
index 29653a6..2622c22 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -55,6 +55,37 @@
   tempest.test_plugins =
       plugin_name = module.path:PluginClass
 
+Standalone Plugin vs In-repo Plugin
+-----------------------------------
+
+Since all that's required for a plugin to be detected by tempest is a valid
+setuptools entry point in the proper namespace there is no difference from the
+tempest perspective on either creating a separate python package to
+house the plugin or adding the code to an existing python project. However,
+there are tradeoffs to consider when deciding which approach to take when
+creating a new plugin.
+
+If you create a separate python project for your plugin this makes a lot of
+things much easier. Firstly it makes packaging and versioning much simpler, you
+can easily decouple the requirements for the plugin from the requirements for
+the other project. It lets you version the plugin independently and maintain a
+single version of the test code across project release boundaries (see the
+`Branchless Tempest Spec`_ for more details on this). It also greatly
+simplifies the install time story for external users. Instead of having to
+install the right version of a project in the same python namespace as tempest
+they simply need to pip install the plugin in that namespace. It also means
+that users don't have to worry about inadvertently installing a tempest plugin
+when they install another package.
+
+.. _Branchless Tempest Spec: http://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/branchless-tempest.html
+
+The sole advantage to integrating a plugin into an existing python project is
+that it enables you to land code changes at the same time you land test changes
+in the plugin. This reduces some of the burden on contributors by not having
+to land 2 changes to add a new API feature and then test it and doing it as a
+single combined commit.
+
+
 Plugin Class
 ============
 
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
index decc659..3dbed79 100644
--- a/etc/accounts.yaml.sample
+++ b/etc/accounts.yaml.sample
@@ -3,7 +3,25 @@
 # This is required to provide isolation between test for running in parallel
 #
 # Valid fields for credentials are defined in the descendants of
-# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES
+# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES
+#
+# The fields in KeystoneV3Credentials behave as follows:
+#
+# tenant_[id|name] also sets project_[id|name].
+#
+# project_[id|name] also sets tenant_[id|name].
+#
+# Providing distinct values for both tenant_[id|name] and project_[id|name]
+# will result in an InvalidCredentials exception.
+#
+# The value of project_domain_[id|name] is used for user_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of user_domain_[id|name] is used for project_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of domain_[id|name] is used for project_domain_[id|name] if not
+# specified and user_domain_[id|name] if not specified.
 
 - username: 'user_1'
   tenant_name: 'test_tenant_1'
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 0000000..e98671a
--- /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 bf4de3e..695af52 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 ee21284..77ed7cd 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -18,12 +18,12 @@
 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
 
@@ -47,8 +47,8 @@
         super(BaseV2ComputeTest, cls).skip_checks()
         if not CONF.service_available.nova:
             raise cls.skipException("Nova is not available")
-        cfg_min_version = CONF.compute_feature_enabled.min_microversion
-        cfg_max_version = CONF.compute_feature_enabled.max_microversion
+        cfg_min_version = CONF.compute.min_microversion
+        cfg_max_version = CONF.compute.max_microversion
         api_version_utils.check_skip_with_microversion(cls.min_microversion,
                                                        cls.max_microversion,
                                                        cfg_min_version,
@@ -105,7 +105,7 @@
         cls.request_microversion = (
             api_version_utils.select_request_microversion(
                 cls.min_microversion,
-                CONF.compute_feature_enabled.min_microversion))
+                CONF.compute.min_microversion))
         cls.build_interval = CONF.compute.build_interval
         cls.build_timeout = CONF.compute.build_timeout
         cls.image_ref = CONF.compute.image_ref
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 0b33d66..c1fbb12 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.api import utils
 from tempest.common import fixed_network
 from tempest.common.utils import data_utils
 from tempest.common import waiters
@@ -89,7 +88,7 @@
                                         wait_until='ACTIVE')
 
     @test.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
-    @utils.skip_unless_attr('multiple_images', 'Only one image found')
+    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
     def test_list_servers_filter_by_image(self):
         # Filter the list of servers by image
         params = {'image': self.image_ref}
@@ -174,7 +173,7 @@
                          len([x for x in servers['servers'] if 'id' in x]))
 
     @test.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
-    @utils.skip_unless_attr('multiple_images', 'Only one image found')
+    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
     def test_list_servers_detailed_filter_by_image(self):
         # Filter the detailed list of servers by image
         params = {'image': self.image_ref}
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index a1a881d..c1cdbf2 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -60,7 +60,7 @@
                         n2['network']['id'])
 
         # Try to create a third network while the quota is two
-        with self.assertRaisesRegexp(
+        with self.assertRaisesRegex(
                 lib_exc.Conflict,
                 "An object with that identifier already exists\\n" +
                 "Details.*Quota exceeded for resources: \['network'\].*"):
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 2bc86ad..36cb15f 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -34,7 +34,7 @@
         # has a distributed attribute.
         super(RoutersTestDVR, cls).resource_setup()
         name = data_utils.rand_name('pretest-check')
-        router = cls.admin_routers_client.create_router(name)
+        router = cls.admin_routers_client.create_router(name=name)
         cls.admin_routers_client.delete_router(router['router']['id'])
         if 'distributed' not in router['router']:
             msg = "'distributed' flag not found. DVR Possibly not enabled"
@@ -53,7 +53,7 @@
         set to True
         """
         name = data_utils.rand_name('router')
-        router = self.admin_routers_client.create_router(name,
+        router = self.admin_routers_client.create_router(name=name,
                                                          distributed=True)
         self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
@@ -73,7 +73,7 @@
         as opposed to a "Distributed Virtual Router"
         """
         name = data_utils.rand_name('router')
-        router = self.admin_routers_client.create_router(name,
+        router = self.admin_routers_client.create_router(name=name,
                                                          distributed=False)
         self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
@@ -95,7 +95,7 @@
         """
         name = data_utils.rand_name('router')
         # router needs to be in admin state down in order to be upgraded to DVR
-        router = self.admin_routers_client.create_router(name,
+        router = self.admin_routers_client.create_router(name=name,
                                                          distributed=False,
                                                          admin_state_up=False)
         self.addCleanup(self.admin_routers_client.delete_router,
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 8e0c361..d78fc04 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -233,7 +233,7 @@
         if enable_snat is not None:
             ext_gw_info['enable_snat'] = enable_snat
         body = cls.routers_client.create_router(
-            router_name, external_gateway_info=ext_gw_info,
+            name=router_name, external_gateway_info=ext_gw_info,
             admin_state_up=admin_state_up, **kwargs)
         router = body['router']
         cls.routers.append(router)
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index fbed5e8..77008ab 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -338,12 +338,12 @@
                          fixed_ips=[
                              {'subnet_id': subnet['id'],
                               'ip_address': ip}])
-        self.assertRaisesRegexp(lib_exc.Conflict,
-                                "object with that identifier already exists",
-                                self.create_port,
-                                self.network,
-                                fixed_ips=[{'subnet_id': subnet['id'],
-                                            'ip_address': ip}])
+        self.assertRaisesRegex(lib_exc.Conflict,
+                               "object with that identifier already exists",
+                               self.create_port,
+                               self.network,
+                               fixed_ips=[{'subnet_id': subnet['id'],
+                                           'ip_address': ip}])
 
     def _create_subnet_router(self, kwargs):
         subnet = self.create_subnet(self.network, **kwargs)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index a31a4f0..fa1ed6a 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -12,10 +12,9 @@
 #    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 itertools
-
 import netaddr
 import six
+import testtools
 
 from tempest.api.network import base
 from tempest.common import custom_matchers
@@ -376,6 +375,9 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec')
+    @test.requires_ext(extension='external-net', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_external_network_visibility(self):
         """Verifies user can see external networks but not subnets."""
         body = self.networks_client.list_networks(**{'router:external': True})
@@ -387,17 +389,12 @@
         self.assertEmpty(nonexternal, "Found non-external networks"
                                       " in filtered list (%s)." % nonexternal)
         self.assertIn(CONF.network.public_network_id, networks)
-
-        subnets_iter = (network['subnets']
-                        for network in body['networks']
-                        if not network['shared'])
-        # subnets_iter is a list (iterator) of lists. This flattens it to a
-        # list of UUIDs
-        public_subnets_iter = itertools.chain(*subnets_iter)
-        body = self.subnets_client.list_subnets()
-        subnets = [sub['id'] for sub in body['subnets']
-                   if sub['id'] in public_subnets_iter]
-        self.assertEmpty(subnets, "Public subnets visible")
+        # only check the public network ID because the other networks may
+        # belong to other tests and their state may have changed during this
+        # test
+        body = self.subnets_client.list_subnets(
+            network_id=CONF.network.public_network_id)
+        self.assertEmpty(body['subnets'], "Public subnets visible")
 
 
 class BulkNetworkOpsTestJSON(base.BaseNetworkTest):
@@ -621,7 +618,7 @@
         subnet_ids = [subnet['id'] for subnet in subnets['subnets']]
         self.assertNotIn(subnet_slaac['id'], subnet_ids,
                          "Subnet wasn't deleted")
-        self.assertRaisesRegexp(
+        self.assertRaisesRegex(
             lib_exc.Conflict,
             "There are one or more ports still in use on the network",
             self.networks_client.delete_network,
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 01afc51..11f7fc6 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -53,7 +53,7 @@
         # as we need to check the response code
         name = data_utils.rand_name('router-')
         create_body = self.routers_client.create_router(
-            name, external_gateway_info={
+            name=name, external_gateway_info={
                 "network_id": CONF.network.public_network_id},
             admin_state_up=False)
         self.addCleanup(self._delete_router, create_body['router']['id'])
@@ -97,7 +97,7 @@
 
         name = data_utils.rand_name('router-')
         create_body = self.admin_routers_client.create_router(
-            name, tenant_id=project_id)
+            name=name, tenant_id=project_id)
         self.addCleanup(self.admin_routers_client.delete_router,
                         create_body['router']['id'])
         self.assertEqual(project_id, create_body['router']['tenant_id'])
@@ -124,7 +124,7 @@
                 'network_id': CONF.network.public_network_id,
                 'enable_snat': enable_snat}
             create_body = self.admin_routers_client.create_router(
-                name, external_gateway_info=external_gateway_info)
+                name=name, external_gateway_info=external_gateway_info)
             self.addCleanup(self.admin_routers_client.delete_router,
                             create_body['router']['id'])
             # Verify snat attributes after router creation
@@ -389,7 +389,7 @@
     def test_create_distributed_router(self):
         name = data_utils.rand_name('router')
         create_body = self.admin_routers_client.create_router(
-            name, distributed=True)
+            name=name, distributed=True)
         self.addCleanup(self._delete_router,
                         create_body['router']['id'],
                         self.admin_routers_client)
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 5213c18..401fa3b 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -227,7 +227,7 @@
                  {'ethertype': 'IPv4',
                   'ip_prefix': CONF.network.tenant_network_v6_cidr})
         for pair in pairs:
-            self.assertRaisesRegexp(
+            self.assertRaisesRegex(
                 lib_exc.BadRequest,
                 "Conflicting value ethertype",
                 self.security_group_rules_client.create_security_group_rule,
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
index ffff580..61c271c 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
@@ -1,10 +1,15 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
index b660c19..0bc6d69 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
@@ -1,11 +1,16 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         deletion_policy: 'Retain'
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index 37e68ef..a5aaf6e 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -32,8 +32,7 @@
         self.assertIsNotNone(volume_id)
         volume = self.volumes_client.show_volume(volume_id)['volume']
         self.assertEqual('available', volume.get('status'))
-        self.assertEqual(template['resources']['volume']['properties'][
-            'size'], volume.get('size'))
+        self.assertEqual(CONF.volume.volume_size, volume.get('size'))
 
         # Some volume properties have been renamed with Cinder v2
         if CONF.volume_feature_enabled.api_v2:
@@ -51,8 +50,8 @@
     def _outputs_verify(self, stack_identifier, template):
         self.assertEqual('available',
                          self.get_stack_output(stack_identifier, 'status'))
-        self.assertEqual(str(template['resources']['volume']['properties'][
-            'size']), self.get_stack_output(stack_identifier, 'size'))
+        self.assertEqual(str(CONF.volume.volume_size),
+                         self.get_stack_output(stack_identifier, 'size'))
         self.assertEqual(template['resources']['volume']['properties'][
             'description'], self.get_stack_output(stack_identifier,
                                                   'display_description'))
@@ -65,7 +64,12 @@
         """Create and delete a volume via OS::Cinder::Volume."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
@@ -94,7 +98,12 @@
         """Ensure the 'Retain' deletion policy is respected."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic_delete_retain')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
diff --git a/tempest/api/utils.py b/tempest/api/utils.py
deleted file mode 100644
index 00c93b7..0000000
--- a/tempest/api/utils.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# 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.
-
-"""Common utilities used in testing."""
-
-from tempest import test
-
-
-class skip_unless_attr(object):
-    """Decorator that skips a test if a specified attr exists and is True."""
-    def __init__(self, attr, msg=None):
-        self.attr = attr
-        self.message = msg or ("Test case attribute %s not found "
-                               "or False") % attr
-
-    def __call__(self, func):
-        def _skipper(*args, **kw):
-            """Wrapped skipper function."""
-            testobj = args[0]
-            if not getattr(testobj, self.attr, False):
-                raise test.BaseTestCase.skipException(self.message)
-            func(*args, **kw)
-        _skipper.__name__ = func.__name__
-        _skipper.__doc__ = func.__doc__
-        return _skipper
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 03dfd7b..6124676 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -316,7 +316,7 @@
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
         resp_body = routers_admin_client.create_router(
-            router_name,
+            name=router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 5a52043..3706b54 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -117,7 +117,6 @@
 
         if is_dry_run:
             self.dry_run_data["_tenants_to_clean"] = {}
-            f = open(DRY_RUN_JSON, 'w+')
 
         admin_mgr = self.admin_mgr
         # Always cleanup tempest and alt tempest tenants unless
@@ -146,9 +145,9 @@
             svc.run()
 
         if is_dry_run:
-            f.write(json.dumps(self.dry_run_data, sort_keys=True,
-                               indent=2, separators=(',', ': ')))
-            f.close()
+            with open(DRY_RUN_JSON, 'w+') as f:
+                f.write(json.dumps(self.dry_run_data, sort_keys=True,
+                                   indent=2, separators=(',', ': ')))
 
         self._remove_admin_user_roles()
 
@@ -281,16 +280,15 @@
             svc = service(admin_mgr, **kwargs)
             svc.run()
 
-        f = open(SAVED_STATE_JSON, 'w+')
-        f.write(json.dumps(data,
-                           sort_keys=True, indent=2, separators=(',', ': ')))
-        f.close()
+        with open(SAVED_STATE_JSON, 'w+') as f:
+            f.write(json.dumps(data,
+                    sort_keys=True, indent=2, separators=(',', ': ')))
 
     def _load_json(self):
         try:
-            json_file = open(SAVED_STATE_JSON)
-            self.json_data = json.load(json_file)
-            json_file.close()
+            with open(SAVED_STATE_JSON) as json_file:
+                self.json_data = json.load(json_file)
+
         except IOError as ex:
             LOG.exception("Failed loading saved state, please be sure you"
                           " have first run cleanup with --init-saved-state "
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 28ffb56..a0676b6 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -390,6 +390,7 @@
         self.metering_labels_client = manager.metering_labels_client
         self.metering_label_rules_client = manager.metering_label_rules_client
         self.security_groups_client = manager.security_groups_client
+        self.routers_client = manager.routers_client
 
     def _filter_by_conf_networks(self, item_list):
         if not item_list or not all(('network_id' in i for i in item_list)):
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 48c06ff..057c227 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -838,7 +838,7 @@
             LOG.warning("Duplicated router name: %s" % router['name'])
             continue
 
-        client.networks.create_router(router['name'])
+        client.networks.create_router(name=router['name'])
 
 
 def destroy_routers(routers):
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 5e5e127..9049886 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -354,8 +354,6 @@
     outfile = sys.stdout
     if update:
         conf_file = _get_config_file()
-        if opts.output:
-            outfile = open(opts.output, 'w+')
         CONF_PARSER = moves.configparser.SafeConfigParser()
         CONF_PARSER.optionxform = str
         CONF_PARSER.readfp(conf_file)
@@ -378,8 +376,9 @@
         display_results(results, update, replace)
         if update:
             conf_file.close()
-            CONF_PARSER.write(outfile)
-        outfile.close()
+            if opts.output:
+                with open(opts.output, 'w+') as outfile:
+                    CONF_PARSER.write(outfile)
     finally:
         icreds.clear_creds()
 
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 2fbd1b2..2d2909a 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -49,10 +49,6 @@
 
     # TODO(jlanoux) add support of wait_until PINGABLE/SSHABLE
 
-    name = name
-    flavor = flavor
-    image_id = image_id
-
     if name is None:
         name = data_utils.rand_name(__name__ + "-instance")
     if flavor is None:
@@ -152,14 +148,12 @@
 
             except Exception:
                 with excutils.save_and_reraise_exception():
-                    if ('preserve_server_on_error' not in kwargs
-                        or kwargs['preserve_server_on_error'] is False):
-                        for server in servers:
-                            try:
-                                clients.servers_client.delete_server(
-                                    server['id'])
-                            except Exception:
-                                LOG.exception('Deleting server %s failed'
-                                              % server['id'])
+                    for server in servers:
+                        try:
+                            clients.servers_client.delete_server(
+                                server['id'])
+                        except Exception:
+                            LOG.exception('Deleting server %s failed'
+                                          % server['id'])
 
     return body, servers
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 2ffc92d..5f6c8b8 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -240,7 +240,7 @@
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
         resp_body = self.routers_admin_client.create_router(
-            router_name,
+            name=router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index cfd9df6..36e3e3a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -102,7 +102,12 @@
         cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
         return self.exec_command(cmd).strip().lower()
 
-    def get_nic_name(self, address):
+    def get_nic_name_by_mac(self, address):
+        cmd = "ip -o link | awk '/%s/ {print $2}'" % address
+        nic = self.exec_command(cmd)
+        return nic.strip().strip(":").lower()
+
+    def get_nic_name_by_ip(self, address):
         cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
         nic = self.exec_command(cmd)
         return nic.strip().strip(":").lower()
@@ -142,7 +147,7 @@
     def _renew_lease_udhcpc(self, fixed_ip=None):
         """Renews DHCP lease via udhcpc client. """
         file_path = '/var/run/udhcpc.'
-        nic_name = self.get_nic_name(fixed_ip)
+        nic_name = self.get_nic_name_by_ip(fixed_ip)
         pid = self.exec_command('cat {path}{nic}.pid'.
                                 format(path=file_path, nic=nic_name))
         pid = pid.strip()
diff --git a/tempest/config.py b/tempest/config.py
index ea151ae..4c3b04b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -281,13 +281,7 @@
                help=('The minimum number of compute nodes expected. This will '
                      'be utilized by some multinode specific tests to ensure '
                      'that requests match the expected size of the cluster '
-                     'you are testing with.'))
-]
-
-compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
-                                      title="Enabled Compute Service Features")
-
-ComputeFeaturesGroup = [
+                     'you are testing with.')),
     cfg.StrOpt('min_microversion',
                default=None,
                help="Lower version of the test target microversion range. "
@@ -296,7 +290,8 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'"),
+                    "with format 'X.Y' or string 'latest'",
+                    deprecated_group='compute-feature-enabled'),
     cfg.StrOpt('max_microversion',
                default=None,
                help="Upper version of the test target microversion range. "
@@ -305,7 +300,14 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'"),
+                    "with format 'X.Y' or string 'latest'",
+                    deprecated_group='compute-feature-enabled'),
+]
+
+compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
+                                      title="Enabled Compute Service Features")
+
+ComputeFeaturesGroup = [
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 86e8460..031df7f 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -176,20 +176,6 @@
     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/lib/auth.py b/tempest/lib/auth.py
index 2d20a0b..71c4f4f 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -622,6 +622,9 @@
         return None not in (self.username, self.password)
 
 
+COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
+
+
 class KeystoneV3Credentials(Credentials):
     """Credentials suitable for the Keystone Identity V3 API"""
 
@@ -630,6 +633,16 @@
                   'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
                   'user_domain_name', 'user_id']
 
+    def _apply_credentials(self, attr):
+        for (key1, key2) in COLLISIONS:
+            val1 = attr.get(key1)
+            val2 = attr.get(key2)
+            if val1 and val2 and val1 != val2:
+                msg = ('Cannot have conflicting values for %s and %s' %
+                       (key1, key2))
+                raise exceptions.InvalidCredentials(msg)
+        super(KeystoneV3Credentials, self)._apply_credentials(attr)
+
     def __setattr__(self, key, value):
         parent = super(KeystoneV3Credentials, self)
         # for tenant_* set both project and tenant
@@ -657,8 +670,10 @@
                 parent.__setattr__('user_domain_name', value)
         # support domain_name coming from config
         if key == 'domain_name':
-            parent.__setattr__('user_domain_name', value)
-            parent.__setattr__('project_domain_name', value)
+            if self.user_domain_name is None:
+                parent.__setattr__('user_domain_name', value)
+            if self.project_domain_name is None:
+                parent.__setattr__('project_domain_name', value)
         # finally trigger default behaviour for all attributes
         parent.__setattr__(key, value)
 
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index b5c9b95..b7d6a24 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -81,21 +81,23 @@
     DEF_RE = re.compile(r'\s*def (\w+)\(')
     bug_found = False
     results = []
-    lines = open(path, 'rb').readlines()
-    for x, line in enumerate(lines):
-        if not bug_found:
-            res = BUG_RE.match(line)
-            if res:
-                bug_no = int(res.group(1))
-                debug("Found bug skip %s on line %d", bug_no, x + 1)
-                bug_found = True
-        else:
-            res = DEF_RE.match(line)
-            if res:
-                method = res.group(1)
-                debug("Found test method %s skips for bug %d", method, bug_no)
-                results.append((method, bug_no))
-                bug_found = False
+    with open(path, 'rb') as content:
+        lines = content.readlines()
+        for x, line in enumerate(lines):
+            if not bug_found:
+                res = BUG_RE.match(line)
+                if res:
+                    bug_no = int(res.group(1))
+                    debug("Found bug skip %s on line %d", bug_no, x + 1)
+                    bug_found = True
+            else:
+                res = DEF_RE.match(line)
+                if res:
+                    method = res.group(1)
+                    debug("Found test method %s skips for bug %d",
+                          method, bug_no)
+                    results.append((method, bug_no))
+                    bug_found = False
     return results
 
 
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 d8a5b56..b2b68a6 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 @@
     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 @@
     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 @@
         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 @@
         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 77%
rename from tempest/common/api_version_utils.py
rename to tempest/lib/common/api_version_utils.py
index 7c7e96a..1371b3c 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 @@
 
 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 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
@@ -77,15 +101,15 @@
 def assert_version_header_matches_request(api_microversion_header_name,
                                           api_microversion,
                                           response_header):
-    """Checks API microversion in resposne 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
+    :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 2bf7cdd..b9b2ae9 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -153,6 +153,20 @@
     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 76%
rename from tempest/services/compute/json/base_compute_client.py
rename to tempest/lib/services/compute/base_compute_client.py
index 8cfde4b..9161abb 100644
--- a/tempest/services/compute/json/base_compute_client.py
+++ b/tempest/lib/services/compute/base_compute_client.py
@@ -11,16 +11,29 @@
 #    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 that is set
+    and provides 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
+    :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 +63,10 @@
         """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},
@@ -64,12 +78,12 @@
         for items in schema_versions_info:
             min_version = api_version_request.APIVersionRequest(items['min'])
             max_version = api_version_request.APIVersionRequest(items['max'])
-            # This is case where self.api_microversion is None, which means
+            # This is case where COMPUTE_MICROVERSION is None, which means
             # request without microversion So select base v2.1 schema.
             if version.is_null() and items['min'] is None:
                 schema = items['schema']
                 break
-            # else select appropriate schema as per self.api_microversion
+            # else select appropriate schema as per COMPUTE_MICROVERSION
             elif version.matches(min_version, max_version):
                 schema = items['schema']
                 break
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 0c16056..8ba5f9a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -262,7 +262,7 @@
         return server
 
     def create_volume(self, size=None, name=None, snapshot_id=None,
-                      imageRef=None, volume_type=None, wait_on_delete=True):
+                      imageRef=None, volume_type=None):
         if name is None:
             name = data_utils.rand_name(self.__class__.__name__)
         kwargs = {'display_name': name,
@@ -273,17 +273,10 @@
             kwargs.update({'size': size})
         volume = self.volumes_client.create_volume(**kwargs)['volume']
 
-        if wait_on_delete:
-            self.addCleanup(self.volumes_client.wait_for_resource_deletion,
-                            volume['id'])
-            self.addCleanup(self.delete_wrapper,
-                            self.volumes_client.delete_volume, volume['id'])
-        else:
-            self.addCleanup_with_wait(
-                waiter_callable=self.volumes_client.wait_for_resource_deletion,
-                thing_id=volume['id'], thing_id_param='id',
-                cleanup_callable=self.delete_wrapper,
-                cleanup_args=[self.volumes_client.delete_volume, volume['id']])
+        self.addCleanup(self.volumes_client.wait_for_resource_deletion,
+                        volume['id'])
+        self.addCleanup(self.delete_wrapper,
+                        self.volumes_client.delete_volume, volume['id'])
 
         # NOTE(e0ne): Cinder API v2 uses name instead of display_name
         if 'display_name' in volume:
@@ -394,8 +387,6 @@
         if properties is None:
             properties = {}
         name = data_utils.rand_name('%s-' % name)
-        image_file = open(path, 'rb')
-        self.addCleanup(image_file.close)
         params = {
             'name': name,
             'container_format': fmt,
@@ -406,7 +397,8 @@
         image = self.image_client.create_image(**params)['image']
         self.addCleanup(self.image_client.delete_image, image['id'])
         self.assertEqual("queued", image['status'])
-        self.image_client.update_image(image['id'], data=image_file)
+        with open(path, 'rb') as image_file:
+            self.image_client.update_image(image['id'], data=image_file)
         return image['id']
 
     def glance_image_create(self):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 2e9abe1..9e2477e 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -776,7 +776,7 @@
         private_key = self._get_server_key(server)
         ssh_client = self.get_remote_client(fip.floating_ip_address,
                                             private_key=private_key)
-        spoof_nic = ssh_client.get_nic_name(spoof_port["mac_address"])
+        spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
         dhcp_ports = self._list_ports(device_owner="network:dhcp",
                                       network_id=self.new_net["id"])
         new_net_dhcp = dhcp_ports[0]["fixed_ips"][0]["ip_address"]
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index fc33dd9..66c8ade 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -145,7 +145,7 @@
                                   "ports: %s")
                          % (self.network_v6, ports))
         mac6 = ports[0]
-        ssh.set_nic_state(ssh.get_nic_name(mac6))
+        ssh.set_nic_state(ssh.get_nic_name_by_mac(mac6))
 
     def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False):
         net_list = self.prepare_network(address6_mode=address6_mode,
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 045f03c..2af55b2 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -18,7 +18,7 @@
 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/services/network/json/routers_client.py b/tempest/services/network/json/routers_client.py
index 18442cf..725dd76 100644
--- a/tempest/services/network/json/routers_client.py
+++ b/tempest/services/network/json/routers_client.py
@@ -15,10 +15,13 @@
 
 class RoutersClient(base.BaseNetworkClient):
 
-    def create_router(self, name, admin_state_up=True, **kwargs):
+    def create_router(self, **kwargs):
+        """Create a router.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#createRouter
+        """
         post_body = {'router': kwargs}
-        post_body['router']['name'] = name
-        post_body['router']['admin_state_up'] = admin_state_up
         uri = '/routers'
         return self.create_resource(uri, post_body)
 
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index dc7b434..57cfe97 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -257,7 +257,7 @@
         javelin.create_routers([self.fake_object])
 
         mocked_function = self.fake_client.networks.create_router
-        mocked_function.assert_called_once_with(self.fake_object['name'])
+        mocked_function.assert_called_once_with(name=self.fake_object['name'])
 
     def test_create_router_existing(self):
         self.fake_client.routers.list_routers.return_value = {
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 1048a52..685a0b3 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -36,9 +36,8 @@
         testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path)
 
         conf_path = conf_dir.join('.testr.conf')
-        conf_file = open(conf_path, 'r')
-        self.addCleanup(conf_file.close)
-        self.assertEqual(conf_file.read(), testr_conf_file)
+        with open(conf_path, 'r') as conf_file:
+            self.assertEqual(conf_file.read(), testr_conf_file)
 
     def test_generate_sample_config(self):
         local_dir = self.useFixture(fixtures.TempDir())
diff --git a/tempest/tests/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py
similarity index 97%
rename from tempest/tests/common/test_api_version_request.py
rename to tempest/tests/lib/common/test_api_version_request.py
index 38fbfc1..bdaa936 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 501f954..591b87e 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/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 07502d0..493df89 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -24,15 +24,15 @@
     def test_rand_uuid(self):
         actual = data_utils.rand_uuid()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
-                                         "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
+        self.assertRegex(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
+                         "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
         actual2 = data_utils.rand_uuid()
         self.assertNotEqual(actual, actual2)
 
     def test_rand_uuid_hex(self):
         actual = data_utils.rand_uuid_hex()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[0-9a-f]{32}$")
+        self.assertRegex(actual, "^[0-9a-f]{32}$")
 
         actual2 = data_utils.rand_uuid_hex()
         self.assertNotEqual(actual, actual2)
@@ -52,14 +52,14 @@
     def test_rand_name_with_prefix(self):
         actual = data_utils.rand_name(prefix='prefix-str')
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^prefix-str-")
+        self.assertRegex(actual, "^prefix-str-")
         actual2 = data_utils.rand_name(prefix='prefix-str')
         self.assertNotEqual(actual, actual2)
 
     def test_rand_password(self):
         actual = data_utils.rand_password()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
         actual2 = data_utils.rand_password()
         self.assertNotEqual(actual, actual2)
 
@@ -67,7 +67,7 @@
         actual = data_utils.rand_password(8)
         self.assertIsInstance(actual, str)
         self.assertEqual(len(actual), 8)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
         actual2 = data_utils.rand_password(8)
         self.assertNotEqual(actual, actual2)
 
@@ -75,14 +75,14 @@
         actual = data_utils.rand_password(2)
         self.assertIsInstance(actual, str)
         self.assertEqual(len(actual), 3)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
         actual2 = data_utils.rand_password(2)
         self.assertNotEqual(actual, actual2)
 
     def test_rand_url(self):
         actual = data_utils.rand_url()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^https://url-[0-9]*\.com$")
+        self.assertRegex(actual, "^https://url-[0-9]*\.com$")
         actual2 = data_utils.rand_url()
         self.assertNotEqual(actual, actual2)
 
@@ -96,8 +96,8 @@
     def test_rand_mac_address(self):
         actual = data_utils.rand_mac_address()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^([0-9a-f][0-9a-f]:){5}"
-                                         "[0-9a-f][0-9a-f]$")
+        self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){5}"
+                         "[0-9a-f][0-9a-f]$")
 
         actual2 = data_utils.rand_mac_address()
         self.assertNotEqual(actual, actual2)
@@ -117,12 +117,12 @@
     def test_random_bytes(self):
         actual = data_utils.random_bytes()  # default size=1024
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[\x00-\xFF]{1024}")
+        self.assertRegex(actual, "^[\x00-\xFF]{1024}")
         actual2 = data_utils.random_bytes()
         self.assertNotEqual(actual, actual2)
 
         actual = data_utils.random_bytes(size=2048)
-        self.assertRegexpMatches(actual, "^[\x00-\xFF]{2048}")
+        self.assertRegex(actual, "^[\x00-\xFF]{2048}")
 
     def test_get_ipv6_addr_by_EUI64(self):
         actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::',
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 1a78247..f552ef5 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 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 @@
         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 @@
         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 @@
         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 @@
         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/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index ebcfe82..6a01490 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -530,3 +530,43 @@
 
         expected = 'http://fake_url/v3'
         self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+
+class TestKeystoneV3Credentials(base.TestCase):
+    def testSetAttrUserDomain(self):
+        creds = auth.KeystoneV3Credentials()
+        creds.user_domain_name = 'user_domain'
+        creds.domain_name = 'domain'
+        self.assertEqual('user_domain', creds.user_domain_name)
+        creds = auth.KeystoneV3Credentials()
+        creds.domain_name = 'domain'
+        creds.user_domain_name = 'user_domain'
+        self.assertEqual('user_domain', creds.user_domain_name)
+
+    def testSetAttrProjectDomain(self):
+        creds = auth.KeystoneV3Credentials()
+        creds.project_domain_name = 'project_domain'
+        creds.domain_name = 'domain'
+        self.assertEqual('project_domain', creds.user_domain_name)
+        creds = auth.KeystoneV3Credentials()
+        creds.domain_name = 'domain'
+        creds.project_domain_name = 'project_domain'
+        self.assertEqual('project_domain', creds.project_domain_name)
+
+    def testProjectTenantNoCollision(self):
+        creds = auth.KeystoneV3Credentials(tenant_id='tenant')
+        self.assertEqual('tenant', creds.project_id)
+        creds = auth.KeystoneV3Credentials(project_id='project')
+        self.assertEqual('project', creds.tenant_id)
+        creds = auth.KeystoneV3Credentials(tenant_name='tenant')
+        self.assertEqual('tenant', creds.project_name)
+        creds = auth.KeystoneV3Credentials(project_name='project')
+        self.assertEqual('project', creds.tenant_name)
+
+    def testProjectTenantCollision(self):
+        attrs = {'tenant_id': 'tenant', 'project_id': 'project'}
+        self.assertRaises(
+            exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
+        attrs = {'tenant_name': 'tenant', 'project_name': 'project'}
+        self.assertRaises(
+            exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index 558445d..07b577c 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -109,7 +109,7 @@
         t = TestFoo('test_foo')
         if expected_to_skip:
             self.assertRaises(testtools.TestCase.skipException,
-                              t.test_foo())
+                              t.test_foo)
         else:
             try:
                 t.test_foo()
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index 6738641..cef7975 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -17,7 +17,7 @@
 
 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
 
@@ -64,9 +64,9 @@
                       expected_pass_tests,
                       expected_skip_tests):
         cfg.CONF.set_default('min_microversion',
-                             cfg_min, group='compute-feature-enabled')
+                             cfg_min, group='compute')
         cfg.CONF.set_default('max_microversion',
-                             cfg_max, group='compute-feature-enabled')
+                             cfg_max, group='compute')
         try:
             for test_class in expected_pass_tests:
                 test_class.skip_checks()
@@ -138,16 +138,16 @@
 
     def test_config_invalid_version(self):
         cfg.CONF.set_default('min_microversion',
-                             '2.5', group='compute-feature-enabled')
+                             '2.5', group='compute')
         cfg.CONF.set_default('max_microversion',
-                             '2.1', group='compute-feature-enabled')
+                             '2.1', group='compute')
         self.assertRaises(exceptions.InvalidAPIVersionRange,
                           VersionTestNoneTolatest.skip_checks)
 
     def test_config_version_invalid_test_version(self):
         cfg.CONF.set_default('min_microversion',
-                             None, group='compute-feature-enabled')
+                             None, group='compute')
         cfg.CONF.set_default('max_microversion',
-                             '2.13', group='compute-feature-enabled')
+                             '2.13', group='compute')
         self.assertRaises(exceptions.InvalidAPIVersionRange,
                           InvalidVersionTest.skip_checks)
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index a47e217..b554514 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -73,21 +73,23 @@
     DEF_RE = re.compile(r'\s*def (\w+)\(')
     bug_found = False
     results = []
-    lines = open(path, 'rb').readlines()
-    for x, line in enumerate(lines):
-        if not bug_found:
-            res = BUG_RE.match(line)
-            if res:
-                bug_no = int(res.group(1))
-                debug("Found bug skip %s on line %d", bug_no, x + 1)
-                bug_found = True
-        else:
-            res = DEF_RE.match(line)
-            if res:
-                method = res.group(1)
-                debug("Found test method %s skips for bug %d", method, bug_no)
-                results.append((method, bug_no))
-                bug_found = False
+    with open(path, 'rb') as content:
+        lines = content.readlines()
+        for x, line in enumerate(lines):
+            if not bug_found:
+                res = BUG_RE.match(line)
+                if res:
+                    bug_no = int(res.group(1))
+                    debug("Found bug skip %s on line %d", bug_no, x + 1)
+                    bug_found = True
+            else:
+                res = DEF_RE.match(line)
+                if res:
+                    method = res.group(1)
+                    debug("Found test method %s skips for bug %d",
+                          method, bug_no)
+                    results.append((method, bug_no))
+                    bug_found = False
     return results