Merge "Fill schema gap in flavors.py"
diff --git a/.zuul.yaml b/.zuul.yaml
index 1cf67b0..52c11c9 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -9,10 +9,10 @@
       test setup. To run a multi-node test inherit from devstack-tempest and
       set the nodeset to a multi-node one.
     required-projects:
-      - openstack/tempest
+      - git.openstack.org/openstack/tempest
     timeout: 7200
     roles:
-      - zuul: openstack-dev/devstack
+      - zuul: git.openstack.org/openstack-dev/devstack
     vars:
       devstack_services:
         tempest: true
@@ -108,6 +108,7 @@
       This job includes two nodes, controller / tempest plus a subnode, but
       it can be used with different topologies, as long as a controller node
       and a tempest one exist.
+    timeout: 10800
     vars:
       tox_envlist: full
       devstack_localrc:
@@ -143,25 +144,24 @@
     voting: false
 
 - job:
-    name: tempest-scenario-all
+    name: tempest-slow
     parent: tempest-multinode-full
     branches:
       - master
     description: |
-      This multinode integration job will run all scenario tests including slow
-      tests with lvm multibackend setup. This job will not run any API tests.
+      This multinode integration job will run all the tests tagged as slow.
+      It enables the lvm multibackend setup to cover few scenario tests.
+      This job will run only slow tests(API or Scenario) serially.
 
       Former names for this job were:
         * legacy-tempest-dsvm-neutron-scenario-multinode-lvm-multibackend
         * tempest-scenario-multinode-lvm-multibackend
     timeout: 10800
     vars:
-      # 'all' is used for applying the custom regex below.
-      tox_envlist: all
+      tox_envlist: slow-serial
       devstack_localrc:
         CINDER_ENABLED_BACKENDS: lvm:lvmdriver-1,lvm:lvmdriver-2
       tempest_concurrency: 2
-      tempest_test_regex: (^tempest\.(scenario))
 
 - job:
     name: tempest-full-queens
@@ -196,70 +196,70 @@
       - ^tempest/hacking/.*$
       - ^tempest/tests/.*$
     required-projects:
-      - openstack/almanach
-      - openstack/aodh
-      - openstack/barbican-tempest-plugin
-      - openstack/ceilometer
-      - openstack/cinder
-      - openstack/congress
-      - openstack/designate-tempest-plugin
-      - openstack/ec2-api
-      - openstack/freezer
-      - openstack/freezer-api
-      - openstack/freezer-tempest-plugin
-      - openstack/gce-api
-      - openstack/glare
-      - openstack/heat
-      - openstack/intel-nfv-ci-tests
-      - openstack/ironic
-      - openstack/ironic-inspector
-      - openstack/keystone-tempest-plugin
-      - openstack/kingbird
-      - openstack/kuryr-tempest-plugin
-      - openstack/magnum
-      - openstack/magnum-tempest-plugin
-      - openstack/manila
-      - openstack/manila-tempest-plugin
-      - openstack/mistral
-      - openstack/mogan
-      - openstack/monasca-api
-      - openstack/monasca-log-api
-      - openstack/murano
-      - openstack/networking-bgpvpn
-      - openstack/networking-cisco
-      - openstack/networking-fortinet
-      - openstack/networking-generic-switch
-      - openstack/networking-l2gw
-      - openstack/networking-midonet
-      - openstack/networking-plumgrid
-      - openstack/networking-sfc
-      - openstack/neutron
-      - openstack/neutron-dynamic-routing
-      - openstack/neutron-fwaas
-      - openstack/neutron-lbaas
-      - openstack/neutron-tempest-plugin
-      - openstack/neutron-vpnaas
-      - openstack/nova-lxd
-      - openstack/novajoin-tempest-plugin
-      - openstack/octavia-tempest-plugin
-      - openstack/oswin-tempest-plugin
-      - openstack/panko
-      - openstack/patrole
-      - openstack/qinling
-      - openstack/requirements
-      - openstack/sahara-tests
-      - openstack/senlin
-      - openstack/senlin-tempest-plugin
-      - openstack/tap-as-a-service
-      - openstack/tempest-horizon
-      - openstack/trio2o
-      - openstack/trove
-      - openstack/valet
-      - openstack/vitrage
-      - openstack/vmware-nsx-tempest-plugin
-      - openstack/watcher-tempest-plugin
-      - openstack/zaqar-tempest-plugin
-      - openstack/zun-tempest-plugin
+      - git.openstack.org/openstack/almanach
+      - git.openstack.org/openstack/aodh
+      - git.openstack.org/openstack/barbican-tempest-plugin
+      - git.openstack.org/openstack/ceilometer
+      - git.openstack.org/openstack/cinder
+      - git.openstack.org/openstack/congress
+      - git.openstack.org/openstack/designate-tempest-plugin
+      - git.openstack.org/openstack/ec2-api
+      - git.openstack.org/openstack/freezer
+      - git.openstack.org/openstack/freezer-api
+      - git.openstack.org/openstack/freezer-tempest-plugin
+      - git.openstack.org/openstack/gce-api
+      - git.openstack.org/openstack/glare
+      - git.openstack.org/openstack/heat
+      - git.openstack.org/openstack/intel-nfv-ci-tests
+      - git.openstack.org/openstack/ironic
+      - git.openstack.org/openstack/ironic-inspector
+      - git.openstack.org/openstack/keystone-tempest-plugin
+      - git.openstack.org/openstack/kingbird
+      - git.openstack.org/openstack/kuryr-tempest-plugin
+      - git.openstack.org/openstack/magnum
+      - git.openstack.org/openstack/magnum-tempest-plugin
+      - git.openstack.org/openstack/manila
+      - git.openstack.org/openstack/manila-tempest-plugin
+      - git.openstack.org/openstack/mistral
+      - git.openstack.org/openstack/mogan
+      - git.openstack.org/openstack/monasca-api
+      - git.openstack.org/openstack/monasca-log-api
+      - git.openstack.org/openstack/murano
+      - git.openstack.org/openstack/networking-bgpvpn
+      - git.openstack.org/openstack/networking-cisco
+      - git.openstack.org/openstack/networking-fortinet
+      - git.openstack.org/openstack/networking-generic-switch
+      - git.openstack.org/openstack/networking-l2gw
+      - git.openstack.org/openstack/networking-midonet
+      - git.openstack.org/openstack/networking-plumgrid
+      - git.openstack.org/openstack/networking-sfc
+      - git.openstack.org/openstack/neutron
+      - git.openstack.org/openstack/neutron-dynamic-routing
+      - git.openstack.org/openstack/neutron-fwaas
+      - git.openstack.org/openstack/neutron-lbaas
+      - git.openstack.org/openstack/neutron-tempest-plugin
+      - git.openstack.org/openstack/neutron-vpnaas
+      - git.openstack.org/openstack/nova-lxd
+      - git.openstack.org/openstack/novajoin-tempest-plugin
+      - git.openstack.org/openstack/octavia-tempest-plugin
+      - git.openstack.org/openstack/oswin-tempest-plugin
+      - git.openstack.org/openstack/panko
+      - git.openstack.org/openstack/patrole
+      - git.openstack.org/openstack/qinling
+      - git.openstack.org/openstack/requirements
+      - git.openstack.org/openstack/sahara-tests
+      - git.openstack.org/openstack/senlin
+      - git.openstack.org/openstack/senlin-tempest-plugin
+      - git.openstack.org/openstack/tap-as-a-service
+      - git.openstack.org/openstack/tempest-horizon
+      - git.openstack.org/openstack/trio2o
+      - git.openstack.org/openstack/trove
+      - git.openstack.org/openstack/valet
+      - git.openstack.org/openstack/vitrage
+      - git.openstack.org/openstack/vmware-nsx-tempest-plugin
+      - git.openstack.org/openstack/watcher-tempest-plugin
+      - git.openstack.org/openstack/zaqar-tempest-plugin
+      - git.openstack.org/openstack/zun-tempest-plugin
 
 - job:
     name: tempest-cinder-v2-api
@@ -353,7 +353,7 @@
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
         - tempest-tox-plugin-sanity-check
-        - tempest-scenario-all:
+        - tempest-slow:
             irrelevant-files:
               - ^(test-|)requirements.txt$
               - ^.*\.rst$
@@ -363,7 +363,6 @@
               - ^setup.cfg$
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
-              - ^tempest/api/.*$
         - nova-cells-v1:
             irrelevant-files:
               - ^(test-|)requirements.txt$
@@ -397,7 +396,7 @@
               - ^setup.cfg$
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
-        - tempest-scenario-all:
+        - tempest-slow:
             irrelevant-files:
               - ^(test-|)requirements.txt$
               - ^.*\.rst$
@@ -407,7 +406,6 @@
               - ^setup.cfg$
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
-              - ^tempest/api/.*$
     experimental:
       jobs:
         - tempest-cinder-v2-api:
diff --git a/HACKING.rst b/HACKING.rst
index 2a7ae1d..5b9c0f1 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -25,6 +25,8 @@
 - [T115] Check that admin tests should exist under admin path
 - [N322] Method's default argument shouldn't be mutable
 - [T116] Unsupported 'message' Exception attribute in PY3
+- [T117] Check negative tests have ``@decorators.attr(type=['negative'])``
+  applied.
 
 Test Data/Configuration
 -----------------------
@@ -146,11 +148,6 @@
 This attribute must be applied to each test that belongs to a negative test
 class, i.e. a test class name ending with "Negative.*" substring.
 
-.. todo::
-
-  Add a hacking check for ensuring that all classes that contain substring
-  "Negative" have the negative attribute decorator applied above each test.
-
 Slow Attribute
 ^^^^^^^^^^^^^^
 The ``type='slow'`` attribute is used to signify that a test takes a long time
diff --git a/doc/source/data/tempest-plugins-registry.header b/doc/source/data/tempest-plugins-registry.header
index 9821e8e..0de12b7 100644
--- a/doc/source/data/tempest-plugins-registry.header
+++ b/doc/source/data/tempest-plugins-registry.header
@@ -17,7 +17,3 @@
 The following are plugins that a script has found in the openstack/
 namespace, which includes but is not limited to official OpenStack
 projects.
-
-+----------------------------+-------------------------------------------------------------------------+
-|Plugin Name                 |URL                                                                      |
-+----------------------------+-------------------------------------------------------------------------+
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 6dd00d3..ce9bbb5 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -338,10 +338,18 @@
 
   .. _2.32: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id29
 
+  * `2.36`_
+
+  .. _2.36: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#microversion
+
   * `2.37`_
 
   .. _2.37: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id34
 
+  * `2.39`_
+
+  .. _2.39: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id35
+
   * `2.42`_
 
   .. _2.42: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-ocata
diff --git a/releasenotes/notes/cinder-use-os-endpoint-type-c11f63fd468ceb4c.yaml b/releasenotes/notes/cinder-use-os-endpoint-type-c11f63fd468ceb4c.yaml
new file mode 100644
index 0000000..1dda4e1
--- /dev/null
+++ b/releasenotes/notes/cinder-use-os-endpoint-type-c11f63fd468ceb4c.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - |
+    Cinder CLI calls have now been updated to use the ``--os-endpoint-type``
+    option instead of ``--endpoint-type``. The latter had been deprecated in
+    Cinder and has been removed in the Rocky release.
diff --git a/roles/run-tempest/README.rst b/roles/run-tempest/README.rst
index 384ca38..71b8e4f 100644
--- a/roles/run-tempest/README.rst
+++ b/roles/run-tempest/README.rst
@@ -39,3 +39,20 @@
    :default: smoke
 
    The Tempest tox environment to run.
+
+.. zuul:rolevar:: tempest_black_regex
+   :default: ''
+
+   A regular expression used to skip the tests.
+
+   It works only when used with some specific tox environments
+   ('all', 'all-plugin'.)
+
+   Multi-line and commented regexs can be achieved by doing this:
+
+       ::
+           vars:
+             tempest_black_regex: |
+               (?x)    # Ignore comments and whitespaces
+               # Line with only a comment.
+               (tempest.api.identity).*$
diff --git a/roles/run-tempest/defaults/main.yaml b/roles/run-tempest/defaults/main.yaml
index 85e94f2..c89eb93 100644
--- a/roles/run-tempest/defaults/main.yaml
+++ b/roles/run-tempest/defaults/main.yaml
@@ -1,3 +1,4 @@
 devstack_base_dir: /opt/stack
 tempest_test_regex: ''
 tox_envlist: smoke
+tempest_black_regex: ''
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
index b68507a..54ddc71 100644
--- a/roles/run-tempest/tasks/main.yaml
+++ b/roles/run-tempest/tasks/main.yaml
@@ -35,7 +35,9 @@
       when: blacklist_stat.stat.exists
 
 - name: Run Tempest
-  command: tox -e {{tox_envlist}} -- {{tempest_test_regex|quote}} {{blacklist_option|default('')}} --concurrency={{tempest_concurrency|default(default_concurrency)}}
+  command: tox -e {{tox_envlist}} -- {{tempest_test_regex|quote}} {{blacklist_option|default('')}} \
+            --concurrency={{tempest_concurrency|default(default_concurrency)}} \
+            --black-regex={{tempest_black_regex|quote}}
   args:
     chdir: "{{devstack_base_dir}}/tempest"
   become: true
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 57d3983..d8faa33 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -48,11 +48,11 @@
                       if (hyper['hypervisor_type'] ==
                           CONF.compute.hypervisor_type)]
 
-        hosts_available = [hyper['service']['host'] for hyper in hypers
-                           if (hyper['state'] == 'up' and
-                               hyper['status'] == 'enabled')]
-        if hosts_available:
-            cls.host = hosts_available[0]
+        cls.hosts_available = [hyper['service']['host'] for hyper in hypers
+                               if (hyper['state'] == 'up' and
+                                   hyper['status'] == 'enabled')]
+        if cls.hosts_available:
+            cls.host = cls.hosts_available[0]
         else:
             msg = "no available compute node found"
             if CONF.compute.hypervisor_type:
@@ -206,11 +206,23 @@
         az_name = data_utils.rand_name(self.az_name_prefix)
         aggregate = self._create_test_aggregate(availability_zone=az_name)
 
-        self.client.add_host(aggregate['id'], host=self.host)
-        self.addCleanup(self.client.remove_host, aggregate['id'],
-                        host=self.host)
+        # Find a host that has not been added to other zone,
+        # for one host can't be added to different zones.
+        aggregates = self.client.list_aggregates()['aggregates']
+        hosts_in_zone = []
+        for v in aggregates:
+            if v['availability_zone']:
+                hosts_in_zone.extend(v['hosts'])
+        hosts = [v for v in self.hosts_available if v not in hosts_in_zone]
+        if not hosts:
+            raise self.skipException("All hosts are already in other zones, "
+                                     "so can't add host to aggregate.")
+        host = hosts[0]
+
+        self.client.add_host(aggregate['id'], host=host)
+        self.addCleanup(self.client.remove_host, aggregate['id'], host=host)
         admin_servers_client = self.os_admin.servers_client
         server = self.create_test_server(availability_zone=az_name,
                                          wait_until='ACTIVE')
         body = admin_servers_client.show_server(server['id'])['server']
-        self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host'])
+        self.assertEqual(host, body['OS-EXT-SRV-ATTR:host'])
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index a6b71b2..e030575 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -106,7 +106,7 @@
                                        'ACTIVE')
 
         server = self.servers_client.show_server(server['id'])['server']
-        self.assertEqual(flavor['id'], server['flavor']['id'])
+        self.assert_flavor_equal(flavor['id'], server['flavor'])
 
     def _test_cold_migrate_server(self, revert=False):
         if CONF.compute.min_compute_nodes < 2:
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 87ce39d..99907a8 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -26,6 +26,7 @@
     API docs:
     https://developer.openstack.org/api-ref/compute/#networks-os-networks-deprecated
     """
+    max_microversion = '2.35'
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index cdfc44a..170b2cc 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -176,7 +176,7 @@
         self.assertEqual(self.s1_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertEqual(self.image_ref_alt, rebuilt_image_id)
-        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref, rebuilt_server['flavor'])
         waiters.wait_for_server_status(self.non_admin_client,
                                        rebuilt_server['id'], 'ACTIVE',
                                        raise_on_error=False)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d0c1973..7fbb994 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -428,21 +428,16 @@
         except Exception:
             LOG.exception('Failed to delete server %s', server_id)
 
-    @classmethod
-    def resize_server(cls, server_id, new_flavor_id, **kwargs):
+    def resize_server(self, server_id, new_flavor_id, **kwargs):
         """resize and confirm_resize an server, waits for it to be ACTIVE."""
-        cls.servers_client.resize_server(server_id, new_flavor_id, **kwargs)
-        waiters.wait_for_server_status(cls.servers_client, server_id,
+        self.servers_client.resize_server(server_id, new_flavor_id, **kwargs)
+        waiters.wait_for_server_status(self.servers_client, server_id,
                                        'VERIFY_RESIZE')
-        cls.servers_client.confirm_resize_server(server_id)
-        waiters.wait_for_server_status(cls.servers_client, server_id, 'ACTIVE')
-        server = cls.servers_client.show_server(server_id)['server']
-        # Nova API > 2.46 no longer includes flavor.id
-        if server['flavor'].get('id'):
-            if new_flavor_id != server['flavor']['id']:
-                msg = ('Flavor id of %s is not equal to new_flavor_id.'
-                       % server_id)
-                raise lib_exc.TempestException(msg)
+        self.servers_client.confirm_resize_server(server_id)
+        waiters.wait_for_server_status(
+            self.servers_client, server_id, 'ACTIVE')
+        server = self.servers_client.show_server(server_id)['server']
+        self.assert_flavor_equal(new_flavor_id, server['flavor'])
 
     @classmethod
     def delete_volume(cls, volume_id):
@@ -561,6 +556,27 @@
                                                 volume['id'], 'in-use')
         return attachment
 
+    def assert_flavor_equal(self, flavor_id, server_flavor):
+        """Check whether server_flavor equals to flavor.
+
+        :param flavor_id: flavor id
+        :param server_flavor: flavor info returned by show_server.
+        """
+        # Nova API > 2.46 no longer includes flavor.id, and schema check
+        # will cover whether 'id' should be in flavor
+        if server_flavor.get('id'):
+            msg = ('server flavor is not same as flavor!')
+            self.assertEqual(flavor_id, server_flavor['id'], msg)
+        else:
+            flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
+            self.assertEqual(flavor['name'], server_flavor['original_name'],
+                             "original_name in server flavor is not same as "
+                             "flavor name!")
+            for key in ['ram', 'vcpus', 'disk']:
+                msg = ('attribute %s in server flavor is not same as '
+                       'flavor!' % key)
+                self.assertEqual(flavor[key], server_flavor[key], msg)
+
 
 class BaseV2ComputeAdminTest(BaseV2ComputeTest):
     """Base test case class for Compute Admin API tests."""
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index a2e58c9..bebc6ca 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -33,8 +33,11 @@
 
     def tearDown(self):
         """Terminate test instances created after a test is executed."""
-        self.server_check_teardown()
         super(ImagesOneServerNegativeTestJSON, self).tearDown()
+        # NOTE(zhufl): Because server_check_teardown will raise Exception
+        # which will prevent other cleanup steps from being executed, so
+        # server_check_teardown should be called after super's tearDown.
+        self.server_check_teardown()
 
     def setUp(self):
         # NOTE(afazekas): Normally we use the same server with all test cases,
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 0585fec..8c2202e 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -18,6 +18,7 @@
 
 
 class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest):
+    max_microversion = '2.56'
 
     @classmethod
     def setup_clients(cls):
@@ -26,22 +27,14 @@
 
     @decorators.idempotent_id('b54c66af-6ab6-4cf0-a9e5-a0cb58d75e0b')
     def test_absLimits_get(self):
-        # To check if all limits are present in the response
-        limits = self.client.show_limits()['limits']
-        absolute_limits = limits['absolute']
-        expected_elements = ['maxImageMeta', 'maxPersonality',
-                             'maxPersonalitySize',
-                             'maxServerMeta', 'maxTotalCores',
-                             'maxTotalFloatingIps', 'maxSecurityGroups',
-                             'maxSecurityGroupRules', 'maxTotalInstances',
-                             'maxTotalKeypairs', 'maxTotalRAMSize',
-                             'maxServerGroups', 'maxServerGroupMembers',
-                             'totalCoresUsed', 'totalFloatingIpsUsed',
-                             'totalSecurityGroupsUsed', 'totalInstancesUsed',
-                             'totalRAMUsed', 'totalServerGroupsUsed']
-        # check whether all expected elements exist
-        missing_elements =\
-            [ele for ele in expected_elements if ele not in absolute_limits]
-        self.assertEmpty(missing_elements,
-                         "Failed to find element %s in absolute limits list"
-                         % ', '.join(ele for ele in missing_elements))
+        # To check if all limits are present in the response (will be checked
+        # by schema)
+        self.client.show_limits()
+
+
+class AbsoluteLimitsV257TestJSON(base.BaseV2ComputeTest):
+    min_microversion = '2.57'
+    max_microversion = 'latest'
+
+    # NOTE(felipemonteiro): This class tests the Absolute Limits APIs
+    # response schema for the 2.57 microversion.
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index bef4eb5..500638a 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -33,15 +33,15 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8')
-    def test_max_image_meta_exceed_limit(self):
-        # We should not create vm with image meta over maxImageMeta limit
+    def test_max_metadata_exceed_limit(self):
+        # We should not create vm with metadata over maxServerMeta limit
         # Get max limit value
         limits = self.client.show_limits()['limits']
-        max_meta = limits['absolute']['maxImageMeta']
+        max_meta = limits['absolute']['maxServerMeta']
 
         # No point in running this test if there is no limit.
         if max_meta == -1:
-            raise self.skipException('no limit for maxImageMeta')
+            raise self.skipException('no limit for maxServerMeta')
 
         # Create server should fail, since we are passing > metadata Limit!
         max_meta_data = max_meta + 1
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 122c4f5..4f0dbad 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -80,7 +80,7 @@
             self.assertEqual("", self.server['image'])
         else:
             self.assertEqual(self.image_ref, self.server['image']['id'])
-        self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref, self.server['flavor'])
         self.assertEqual(self.meta, self.server['metadata'])
 
     @decorators.attr(type='smoke')
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index 5d9bf48..40681cb 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -382,5 +382,8 @@
         waiters.wait_for_interface_detach(self.interfaces_client,
                                           server['id'],
                                           interface['port_id'])
-        self.verify_metadata_from_api(server, ssh_client,
-                                      self.verify_empty_devices)
+        # FIXME(mriedem): The assertion that the tagged devices are removed
+        # from the metadata for the server is being skipped until bug 1775947
+        # is fixed.
+        # self.verify_metadata_from_api(server, ssh_client,
+        #                               self.verify_empty_devices)
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 3e44b56..5801db1 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -44,10 +44,13 @@
         self._websocket = None
 
     def tearDown(self):
-        self.server_check_teardown()
         super(NoVNCConsoleTestJSON, self).tearDown()
         if self._websocket is not None:
             self._websocket.close()
+        # NOTE(zhufl): Because server_check_teardown will raise Exception
+        # which will prevent other cleanup steps from being executed, so
+        # server_check_teardown should be called after super's tearDown.
+        self.server_check_teardown()
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 961b2b7..f6494b5 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -59,8 +59,11 @@
                 self.server_id, validatable=True)
 
     def tearDown(self):
-        self.server_check_teardown()
         super(ServerActionsTestJSON, self).tearDown()
+        # NOTE(zhufl): Because server_check_teardown will raise Exception
+        # which will prevent other cleanup steps from being executed, so
+        # server_check_teardown should be called after super's tearDown.
+        self.server_check_teardown()
 
     @classmethod
     def setup_credentials(cls):
@@ -197,7 +200,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref, rebuilt_server['flavor'])
 
         # Verify the server properties after the rebuild completes
         waiters.wait_for_server_status(self.client,
@@ -251,7 +254,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertEqual(new_image, rebuilt_image_id)
-        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref, rebuilt_server['flavor'])
 
         # Verify the server properties after the rebuild completes
         waiters.wait_for_server_status(self.client,
@@ -303,7 +306,7 @@
                                        expected_status)
 
         server = self.client.show_server(server_id)['server']
-        self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref_alt, server['flavor'])
 
         if stop:
             # NOTE(mriedem): tearDown requires the server to be started.
@@ -367,7 +370,7 @@
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
         server = self.client.show_server(self.server_id)['server']
-        self.assertEqual(self.flavor_ref, server['flavor']['id'])
+        self.assert_flavor_equal(self.flavor_ref, server['flavor'])
 
     @decorators.idempotent_id('fbbf075f-a812-4022-bc5c-ccb8047eef12')
     @decorators.related_bug('1737599')
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index 5286c8f..1b7cb96 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -47,8 +47,16 @@
         super(ServerGroupTestJSON, cls).resource_setup()
         cls.policy = ['affinity']
 
-        cls.created_server_group = cls.create_test_server_group(
-            policy=cls.policy)
+    def setUp(self):
+        super(ServerGroupTestJSON, self).setUp()
+        # TODO(zhufl): After microversion 2.13 project_id and user_id are
+        # added to the body of server_group, and microversion is not used
+        # in resource_setup for now, so we should create server group in setUp
+        # in order to use the same microversion as in testcases till
+        # microversion support in resource_setup is fulfilled.
+        if not hasattr(self, 'created_server_group'):
+            self.__class__.created_server_group = \
+                self.create_test_server_group(policy=self.policy)
 
     def _create_server_group(self, name, policy):
         # create the test server-group with given policy
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index e944c28..0c1c05c 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -40,8 +40,11 @@
             self.__class__.server_id = self.recreate_server(self.server_id)
 
     def tearDown(self):
-        self.server_check_teardown()
         super(ServersNegativeTestJSON, self).tearDown()
+        # NOTE(zhufl): Because server_check_teardown will raise Exception
+        # which will prevent other cleanup steps from being executed, so
+        # server_check_teardown should be called after super's tearDown.
+        self.server_check_teardown()
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py
index b8c79d7..76131e2 100644
--- a/tempest/api/compute/test_networks.py
+++ b/tempest/api/compute/test_networks.py
@@ -20,6 +20,8 @@
 
 
 class ComputeNetworksTest(base.BaseV2ComputeTest):
+    max_microversion = '2.35'
+
     @classmethod
     def skip_checks(cls):
         super(ComputeNetworksTest, cls).skip_checks()
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index 82664e8..148b368 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -18,7 +18,19 @@
 from tempest.lib import decorators
 
 
-class ListProjectsTestJSON(base.BaseIdentityV3AdminTest):
+class BaseListProjectsTestJSON(base.BaseIdentityV3AdminTest):
+
+    def _list_projects_with_params(self, included, excluded, params, key):
+        # Validate that projects in ``included`` belongs to the projects
+        # returned that match ``params`` but not projects in ``excluded``
+        body = self.projects_client.list_projects(params)['projects']
+        for p in included:
+            self.assertIn(p[key], map(lambda x: x[key], body))
+        for p in excluded:
+            self.assertNotIn(p[key], map(lambda x: x[key], body))
+
+
+class ListProjectsTestJSON(BaseListProjectsTestJSON):
 
     @classmethod
     def resource_setup(cls):
@@ -61,17 +73,20 @@
     def test_list_projects_with_domains(self):
         # List projects with domain
         self._list_projects_with_params(
-            {'domain_id': self.domain['id']}, 'domain_id')
+            [self.p1], [self.p2, self.p3], {'domain_id': self.domain['id']},
+            'domain_id')
 
     @decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8')
     def test_list_projects_with_enabled(self):
         # List the projects with enabled
-        self._list_projects_with_params({'enabled': False}, 'enabled')
+        self._list_projects_with_params(
+            [self.p1], [self.p2, self.p3], {'enabled': False}, 'enabled')
 
     @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
     def test_list_projects_with_name(self):
         # List projects with name
-        self._list_projects_with_params({'name': self.p1_name}, 'name')
+        self._list_projects_with_params(
+            [self.p1], [self.p2, self.p3], {'name': self.p1_name}, 'name')
 
     @decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac')
     def test_list_projects_with_parent(self):
@@ -82,8 +97,3 @@
         self.assertNotEmpty(fetched_projects)
         for project in fetched_projects:
             self.assertEqual(self.p3['parent_id'], project['parent_id'])
-
-    def _list_projects_with_params(self, params, key):
-        body = self.projects_client.list_projects(params)['projects']
-        self.assertIn(self.p1[key], map(lambda x: x[key], body))
-        self.assertNotIn(self.p2[key], map(lambda x: x[key], body))
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 39d03e7..7e8cc8e 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -13,6 +13,7 @@
 import testtools
 
 from tempest.api.network import base
+from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
@@ -95,7 +96,6 @@
         self.assertEqual(self.network['id'], show_net['id'])
         self.assertFalse(show_net['router:external'])
 
-    @decorators.skip_because(bug="1749820")
     @decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb')
     @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
                           'Floating ips are not availabled')
@@ -118,8 +118,15 @@
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.admin_floating_ips_client.delete_floatingip,
                         created_floating_ip['id'])
-        floatingip_list = self.admin_floating_ips_client.list_floatingips(
-            network=external_network['id'])
+        if utils.is_extension_enabled('filter-validation', 'network'):
+            floatingip_list = self.admin_floating_ips_client.list_floatingips(
+                floating_network_id=external_network['id'])
+        else:
+            # NOTE(hongbin): This is for testing the backward-compatibility
+            # of neutron API although the parameter is a wrong filter
+            # for listing floating IPs.
+            floatingip_list = self.admin_floating_ips_client.list_floatingips(
+                invalid_filter=external_network['id'])
         self.assertIn(created_floating_ip['id'],
                       (f['id'] for f in floatingip_list['floatingips']))
         self.admin_networks_client.delete_network(external_network['id'])
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index e546bff..61a6df4 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -38,8 +38,8 @@
     @classmethod
     def setup_clients(cls):
         super(BaseVolumeQuotasAdminTestJSON, cls).setup_clients()
-        cls.transfer_client = cls.os_primary.volume_transfers_v2_client
-        cls.alt_transfer_client = cls.os_alt.volume_transfers_v2_client
+        cls.transfer_client = cls.os_primary.volume_transfers_client_latest
+        cls.alt_transfer_client = cls.os_alt.volume_transfers_client_latest
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 81fd6e6..64fe29a 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -74,24 +74,19 @@
         if CONF.service_available.glance:
             cls.images_client = cls.os_primary.image_client_v2
 
-        if cls._api_version == 3:
-            cls.backups_client = cls.os_primary.backups_v3_client
-            cls.volumes_client = cls.os_primary.volumes_v3_client
-            cls.messages_client = cls.os_primary.volume_v3_messages_client
-            cls.versions_client = cls.os_primary.volume_v3_versions_client
-            cls.groups_client = cls.os_primary.groups_v3_client
-            cls.group_snapshots_client = (
-                cls.os_primary.group_snapshots_v3_client)
-        else:
-            cls.backups_client = cls.os_primary.backups_v2_client
-            cls.volumes_client = cls.os_primary.volumes_v2_client
-
-        cls.snapshots_client = cls.os_primary.snapshots_v2_client
+        cls.backups_client = cls.os_primary.backups_client_latest
+        cls.volumes_client = cls.os_primary.volumes_client_latest
+        cls.messages_client = cls.os_primary.volume_messages_client_latest
+        cls.versions_client = cls.os_primary.volume_versions_client_latest
+        cls.groups_client = cls.os_primary.groups_client_latest
+        cls.group_snapshots_client = (
+            cls.os_primary.group_snapshots_client_latest)
+        cls.snapshots_client = cls.os_primary.snapshots_client_latest
         cls.volumes_extension_client =\
-            cls.os_primary.volumes_v2_extension_client
+            cls.os_primary.volumes_extension_client_latest
         cls.availability_zone_client = (
-            cls.os_primary.volume_v2_availability_zone_client)
-        cls.volume_limits_client = cls.os_primary.volume_v2_limits_client
+            cls.os_primary.volume_availability_zone_client_latest)
+        cls.volume_limits_client = cls.os_primary.volume_limits_client_latest
 
     def setUp(self):
         super(BaseVolumeTest, self).setUp()
@@ -247,34 +242,34 @@
     def setup_clients(cls):
         super(BaseVolumeAdminTest, cls).setup_clients()
 
-        cls.admin_volume_qos_client = cls.os_admin.volume_qos_v2_client
+        cls.admin_volume_qos_client = cls.os_admin.volume_qos_client_latest
         cls.admin_volume_services_client = \
-            cls.os_admin.volume_services_v2_client
-        cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
-        cls.admin_volume_manage_client = cls.os_admin.volume_manage_v2_client
-        cls.admin_volume_client = cls.os_admin.volumes_v2_client
-        if cls._api_version == 3:
-            cls.admin_volume_client = cls.os_admin.volumes_v3_client
-            cls.admin_groups_client = cls.os_admin.groups_v3_client
-            cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
-            cls.admin_group_snapshots_client = \
-                cls.os_admin.group_snapshots_v3_client
-            cls.admin_group_types_client = cls.os_admin.group_types_v3_client
-        cls.admin_hosts_client = cls.os_admin.volume_hosts_v2_client
+            cls.os_admin.volume_services_client_latest
+        cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
+        cls.admin_volume_manage_client = (
+            cls.os_admin.volume_manage_client_latest)
+        cls.admin_volume_client = cls.os_admin.volumes_client_latest
+        cls.admin_groups_client = cls.os_admin.groups_client_latest
+        cls.admin_messages_client = cls.os_admin.volume_messages_client_latest
+        cls.admin_group_snapshots_client = \
+            cls.os_admin.group_snapshots_client_latest
+        cls.admin_group_types_client = cls.os_admin.group_types_client_latest
+        cls.admin_hosts_client = cls.os_admin.volume_hosts_client_latest
         cls.admin_snapshot_manage_client = \
-            cls.os_admin.snapshot_manage_v2_client
-        cls.admin_snapshots_client = cls.os_admin.snapshots_v2_client
-        cls.admin_backups_client = cls.os_admin.backups_v2_client
+            cls.os_admin.snapshot_manage_client_latest
+        cls.admin_snapshots_client = cls.os_admin.snapshots_client_latest
+        cls.admin_backups_client = cls.os_admin.backups_client_latest
         cls.admin_encryption_types_client = \
-            cls.os_admin.encryption_types_v2_client
+            cls.os_admin.encryption_types_client_latest
         cls.admin_quota_classes_client = \
-            cls.os_admin.volume_quota_classes_v2_client
-        cls.admin_quotas_client = cls.os_admin.volume_quotas_v2_client
-        cls.admin_volume_limits_client = cls.os_admin.volume_v2_limits_client
+            cls.os_admin.volume_quota_classes_client_latest
+        cls.admin_quotas_client = cls.os_admin.volume_quotas_client_latest
+        cls.admin_volume_limits_client = (
+            cls.os_admin.volume_limits_client_latest)
         cls.admin_capabilities_client = \
-            cls.os_admin.volume_capabilities_v2_client
+            cls.os_admin.volume_capabilities_client_latest
         cls.admin_scheduler_stats_client = \
-            cls.os_admin.volume_scheduler_stats_v2_client
+            cls.os_admin.volume_scheduler_stats_client_latest
 
     @classmethod
     def create_test_qos_specs(cls, name=None, consumer=None, **kwargs):
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 75e81b7..c85e0bc 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -27,10 +27,10 @@
     def setup_clients(cls):
         super(VolumesTransfersTest, cls).setup_clients()
 
-        cls.client = cls.os_primary.volume_transfers_v2_client
-        cls.alt_client = cls.os_alt.volume_transfers_v2_client
-        cls.alt_volumes_client = cls.os_alt.volumes_v2_client
-        cls.adm_volumes_client = cls.os_admin.volumes_v2_client
+        cls.client = cls.os_primary.volume_transfers_client_latest
+        cls.alt_client = cls.os_alt.volume_transfers_client_latest
+        cls.alt_volumes_client = cls.os_alt.volumes_client_latest
+        cls.adm_volumes_client = cls.os_admin.volumes_client_latest
 
     @decorators.idempotent_id('4d75b645-a478-48b1-97c8-503f64242f1a')
     def test_create_get_list_accept_volume_transfer(self):
diff --git a/tempest/clients.py b/tempest/clients.py
index 2a07be9..4f2846e 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -241,6 +241,47 @@
         # if only api_v3 is enabled, all these clients should be available
         if (CONF.volume_feature_enabled.api_v2 or
             CONF.volume_feature_enabled.api_v3):
+            self.backups_client_latest = self.volume_v3.BackupsClient()
+            self.encryption_types_client_latest = \
+                self.volume_v3.EncryptionTypesClient()
+            self.snapshot_manage_client_latest = \
+                self.volume_v3.SnapshotManageClient()
+            self.snapshots_client_latest = self.volume_v3.SnapshotsClient()
+            self.volume_capabilities_client_latest = \
+                self.volume_v3.CapabilitiesClient()
+            self.volume_manage_client_latest = (
+                self.volume_v3.VolumeManageClient())
+            self.volume_qos_client_latest = self.volume_v3.QosSpecsClient()
+            self.volume_services_client_latest = (
+                self.volume_v3.ServicesClient())
+            self.volume_types_client_latest = self.volume_v3.TypesClient()
+            self.volume_hosts_client_latest = self.volume_v3.HostsClient()
+            self.volume_quotas_client_latest = self.volume_v3.QuotasClient()
+            self.volume_quota_classes_client_latest = \
+                self.volume_v3.QuotaClassesClient()
+            self.volume_scheduler_stats_client_latest = \
+                self.volume_v3.SchedulerStatsClient()
+            self.volume_transfers_client_latest = \
+                self.volume_v3.TransfersClient()
+            self.volume_availability_zone_client_latest = \
+                self.volume_v3.AvailabilityZoneClient()
+            self.volume_limits_client_latest = self.volume_v3.LimitsClient()
+            self.volumes_client_latest = self.volume_v3.VolumesClient()
+            self.volumes_extension_client_latest = \
+                self.volume_v3.ExtensionsClient()
+            self.group_types_client_latest = self.volume_v3.GroupTypesClient()
+            self.groups_client_latest = self.volume_v3.GroupsClient()
+            self.group_snapshots_client_latest = \
+                self.volume_v3.GroupSnapshotsClient()
+            self.volume_messages_client_latest = (
+                self.volume_v3.MessagesClient())
+            self.volume_versions_client_latest = (
+                self.volume_v3.VersionsClient())
+
+            # TODO(gmann): Below alias for service clients have been
+            # deprecated and will be removed in future. Start using the alias
+            # defined above with suffix _latest.
+            # ****************Deprecated alias start from here***************
             self.backups_v2_client = self.volume_v3.BackupsClient()
             self.encryption_types_v2_client = \
                 self.volume_v3.EncryptionTypesClient()
@@ -268,11 +309,6 @@
             self.volumes_v2_extension_client = \
                 self.volume_v3.ExtensionsClient()
 
-            # Set default client for users that don't need explicit version
-            self.volumes_client_latest = self.volumes_v2_client
-            self.snapshots_client_latest = self.snapshots_v2_client
-            self.backups_client_latest = self.backups_v2_client
-
         if CONF.volume_feature_enabled.api_v3:
             self.backups_v3_client = self.volume_v3.BackupsClient()
             self.group_types_v3_client = self.volume_v3.GroupTypesClient()
@@ -283,11 +319,7 @@
             self.volume_v3_messages_client = self.volume_v3.MessagesClient()
             self.volume_v3_versions_client = self.volume_v3.VersionsClient()
             self.volumes_v3_client = self.volume_v3.VolumesClient()
-
-            # Set default client for users that don't need explicit version
-            self.volumes_client_latest = self.volumes_v3_client
-            self.snapshots_client_latest = self.snapshots_v3_client
-            self.backups_client_latest = self.backups_v3_client
+            # ****************Deprecated alias end here***********************
 
     def _set_object_storage_clients(self):
         self.account_client = self.object_storage.AccountClient()
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 27e1bc1..83cf42c 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -315,7 +315,7 @@
 class VolumeQuotaService(BaseService):
     def __init__(self, manager, **kwargs):
         super(VolumeQuotaService, self).__init__(kwargs)
-        self.client = manager.volume_quotas_v2_client
+        self.client = manager.volume_quotas_client_latest
 
     def delete(self):
         client = self.client
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 68c4a10..f2730b3 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -165,7 +165,7 @@
 
     if volume_backed:
         volume_name = data_utils.rand_name(__name__ + '-volume')
-        volumes_client = clients.volumes_v2_client
+        volumes_client = clients.volumes_client_latest
         params = {'name': volume_name,
                   'imageRef': image_id,
                   'size': CONF.volume.volume_size}
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index a57a360..a72675e 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -34,6 +34,9 @@
 METHOD_DELETE_RESOURCE = re.compile(r"^\s*def delete_.+")
 CLASS = re.compile(r"^class .+")
 EX_ATTRIBUTE = re.compile(r'(\s+|\()(e|ex|exc|exception).message(\s+|\))')
+NEGATIVE_TEST_DECORATOR = re.compile(
+    r'\s*@decorators\.attr\(type=.*negative.*\)')
+_HAVE_NEGATIVE_DECORATOR = False
 
 
 def import_no_clients_in_api_and_scenario_tests(physical_line, filename):
@@ -306,6 +309,29 @@
         yield(0, msg)
 
 
+def negative_test_attribute_always_applied_to_negative_tests(physical_line,
+                                                             filename):
+    """Check ``@decorators.attr(type=['negative'])`` applied to negative tests.
+
+    T117
+    """
+    global _HAVE_NEGATIVE_DECORATOR
+
+    if re.match(r'.\/tempest\/api\/.*_negative.*', filename):
+
+        if NEGATIVE_TEST_DECORATOR.match(physical_line):
+            _HAVE_NEGATIVE_DECORATOR = True
+            return
+
+        if TEST_DEFINITION.match(physical_line):
+            if not _HAVE_NEGATIVE_DECORATOR:
+                return (
+                    0, "T117: Must apply `@decorators.attr(type=['negative'])`"
+                       " to all negative API tests"
+                )
+            _HAVE_NEGATIVE_DECORATOR = False
+
+
 def factory(register):
     register(import_no_clients_in_api_and_scenario_tests)
     register(scenario_tests_need_service_tags)
@@ -322,3 +348,4 @@
     register(use_rand_uuid_instead_of_uuid4)
     register(dont_put_admin_tests_on_nonadmin_path)
     register(unsupported_exception_attribute_PY3)
+    register(negative_test_attribute_always_applied_to_negative_tests)
diff --git a/tempest/lib/api_schema/response/compute/v2_1/server_groups.py b/tempest/lib/api_schema/response/compute/v2_1/server_groups.py
new file mode 100644
index 0000000..01db20b
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/server_groups.py
@@ -0,0 +1,65 @@
+# Copyright 2017 NTT 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.
+
+common_server_group = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'name': {'type': 'string'},
+        'policies': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        # 'members' attribute contains the array of instance's UUID of
+        # instances present in server group
+        'members': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        'metadata': {'type': 'object'}
+    },
+    'additionalProperties': False,
+    'required': ['id', 'name', 'policies', 'members', 'metadata']
+}
+
+create_show_server_group = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_group': common_server_group
+        },
+        'additionalProperties': False,
+        'required': ['server_group']
+    }
+}
+
+delete_server_group = {
+    'status_code': [204]
+}
+
+list_server_groups = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_groups': {
+                'type': 'array',
+                'items': common_server_group
+            }
+        },
+        'additionalProperties': False,
+        'required': ['server_groups']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 2954de0..3300298 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -345,58 +345,6 @@
     }
 }
 
-common_server_group = {
-    'type': 'object',
-    'properties': {
-        'id': {'type': 'string'},
-        'name': {'type': 'string'},
-        'policies': {
-            'type': 'array',
-            'items': {'type': 'string'}
-        },
-        # 'members' attribute contains the array of instance's UUID of
-        # instances present in server group
-        'members': {
-            'type': 'array',
-            'items': {'type': 'string'}
-        },
-        'metadata': {'type': 'object'}
-    },
-    'additionalProperties': False,
-    'required': ['id', 'name', 'policies', 'members', 'metadata']
-}
-
-create_show_server_group = {
-    'status_code': [200],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'server_group': common_server_group
-        },
-        'additionalProperties': False,
-        'required': ['server_group']
-    }
-}
-
-delete_server_group = {
-    'status_code': [204]
-}
-
-list_server_groups = {
-    'status_code': [200],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'server_groups': {
-                'type': 'array',
-                'items': common_server_group
-            }
-        },
-        'additionalProperties': False,
-        'required': ['server_groups']
-    }
-}
-
 instance_actions = {
     'type': 'object',
     'properties': {
@@ -430,8 +378,9 @@
             'traceback': {'type': ['string', 'null']}
         },
         'additionalProperties': False,
-        'required': ['event', 'start_time', 'finish_time', 'result',
-                     'traceback']
+        # NOTE(zhufl): events.traceback can only be seen by admin users
+        # with default policy.json, so it shouldn't be a required field.
+        'required': ['event', 'start_time', 'finish_time', 'result']
     }
 }
 
diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/server_groups.py
similarity index 74%
rename from tempest/lib/api_schema/response/compute/v2_13/servers.py
rename to tempest/lib/api_schema/response/compute/v2_13/server_groups.py
index a90f3e4..2b59e38 100644
--- a/tempest/lib/api_schema/response/compute/v2_13/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_13/server_groups.py
@@ -14,21 +14,22 @@
 
 import copy
 
-from tempest.lib.api_schema.response.compute.v2_1 import servers
+from tempest.lib.api_schema.response.compute.v2_1 import server_groups
 
 
-common_server_group = copy.deepcopy(servers.common_server_group)
+common_server_group = copy.deepcopy(server_groups.common_server_group)
 common_server_group['properties']['project_id'] = {'type': 'string'}
 common_server_group['properties']['user_id'] = {'type': 'string'}
 common_server_group['required'].append('project_id')
 common_server_group['required'].append('user_id')
 
-create_show_server_group = copy.deepcopy(servers.create_show_server_group)
+create_show_server_group = copy.deepcopy(
+    server_groups.create_show_server_group)
 create_show_server_group['response_body']['properties'][
     'server_group'] = common_server_group
 
-delete_server_group = copy.deepcopy(servers.delete_server_group)
+delete_server_group = copy.deepcopy(server_groups.delete_server_group)
 
-list_server_groups = copy.deepcopy(servers.list_server_groups)
+list_server_groups = copy.deepcopy(server_groups.list_server_groups)
 list_server_groups['response_body']['properties']['server_groups'][
     'items'] = common_server_group
diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py
index 3eb658f..fb1a2fc 100644
--- a/tempest/lib/api_schema/response/compute/v2_16/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_16/servers.py
@@ -157,4 +157,14 @@
     }
 }
 
+# NOTE(gmann): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.9 ******
 list_servers = copy.deepcopy(servers.list_servers)
+update_server = copy.deepcopy(servers.update_server)
+rebuild_server = copy.deepcopy(servers.rebuild_server)
+rebuild_server_with_admin_pass = copy.deepcopy(
+    servers.rebuild_server_with_admin_pass)
+show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(servers.get_remote_consoles)
diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py
index fd9e933..e3e8ad1 100644
--- a/tempest/lib/api_schema/response/compute/v2_19/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_19/servers.py
@@ -16,10 +16,10 @@
 
 from tempest.lib.api_schema.response.compute.v2_16 import servers \
     as serversv216
-from tempest.lib.api_schema.response.compute.v2_9 import servers as serversv29
 
-list_servers = copy.deepcopy(serversv216.list_servers)
-
+# Compute microversion 2.19:
+# 1. New attributes in 'server' dict.
+#      'description'
 get_server = copy.deepcopy(serversv216.get_server)
 get_server['response_body']['properties']['server'][
     'properties'].update({'description': {'type': ['string', 'null']}})
@@ -32,21 +32,29 @@
 list_servers_detail['response_body']['properties']['servers']['items'][
     'required'].append('description')
 
-update_server = copy.deepcopy(serversv29.update_server)
+update_server = copy.deepcopy(serversv216.update_server)
 update_server['response_body']['properties']['server'][
     'properties'].update({'description': {'type': ['string', 'null']}})
 update_server['response_body']['properties']['server'][
     'required'].append('description')
 
-rebuild_server = copy.deepcopy(serversv29.rebuild_server)
+rebuild_server = copy.deepcopy(serversv216.rebuild_server)
 rebuild_server['response_body']['properties']['server'][
     'properties'].update({'description': {'type': ['string', 'null']}})
 rebuild_server['response_body']['properties']['server'][
     'required'].append('description')
 
 rebuild_server_with_admin_pass = copy.deepcopy(
-    serversv29.rebuild_server_with_admin_pass)
+    serversv216.rebuild_server_with_admin_pass)
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'properties'].update({'description': {'type': ['string', 'null']}})
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'required'].append('description')
+
+# NOTE(gmann): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.16 ******
+list_servers = copy.deepcopy(serversv216.list_servers)
+show_server_diagnostics = copy.deepcopy(serversv216.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(serversv216.get_remote_consoles)
diff --git a/tempest/lib/api_schema/response/compute/v2_26/servers.py b/tempest/lib/api_schema/response/compute/v2_26/servers.py
index 5c35eab..8e62dc3 100644
--- a/tempest/lib/api_schema/response/compute/v2_26/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_26/servers.py
@@ -15,7 +15,6 @@
 
 import copy
 
-from tempest.lib.api_schema.response.compute.v2_1 import servers as servers21
 from tempest.lib.api_schema.response.compute.v2_19 import servers as servers219
 
 # The 2.26 microversion changes the server GET and (detailed) LIST responses to
@@ -62,10 +61,6 @@
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'required'].append('tags')
 
-# list response schema wasn't changed for v2.26 so use v2.1
-
-list_servers = copy.deepcopy(servers21.list_servers)
-
 list_tags = {
     'status_code': [200],
     'response_body': {
@@ -98,3 +93,11 @@
 }
 
 delete_tag = {'status_code': [204]}
+
+# NOTE(gmann): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.19 ******
+list_servers = copy.deepcopy(servers219.list_servers)
+show_server_diagnostics = copy.deepcopy(servers219.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(servers219.get_remote_consoles)
diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py
index f24103e..969df3b 100644
--- a/tempest/lib/api_schema/response/compute/v2_3/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_3/servers.py
@@ -163,4 +163,13 @@
     }
 }
 
+# NOTE: Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.1 ***
 list_servers = copy.deepcopy(servers.list_servers)
+update_server = copy.deepcopy(servers.update_server)
+rebuild_server = copy.deepcopy(servers.rebuild_server)
+rebuild_server_with_admin_pass = copy.deepcopy(
+    servers.rebuild_server_with_admin_pass)
+show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
diff --git a/tempest/tests/lib/services/volume/v2/__init__.py b/tempest/lib/api_schema/response/compute/v2_36/__init__.py
similarity index 100%
rename from tempest/tests/lib/services/volume/v2/__init__.py
rename to tempest/lib/api_schema/response/compute/v2_36/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_36/limits.py b/tempest/lib/api_schema/response/compute/v2_36/limits.py
new file mode 100644
index 0000000..8e94690
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_36/limits.py
@@ -0,0 +1,35 @@
+# Copyright 2018 ZTE 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import limits as limitv21
+
+# Compute microversion 2.36:
+# remove attributes in get_limit:
+#    'maxSecurityGroupRules',
+#    'maxSecurityGroups',
+#    'maxTotalFloatingIps',
+#    'totalFloatingIpsUsed',
+#    'totalSecurityGroupsUsed'
+
+get_limit = copy.deepcopy(limitv21.get_limit)
+
+for item in ['maxSecurityGroupRules', 'maxSecurityGroups',
+             'maxTotalFloatingIps', 'totalFloatingIpsUsed',
+             'totalSecurityGroupsUsed']:
+    get_limit['response_body']['properties']['limits']['properties'][
+        'absolute']['properties'].pop(item)
+    get_limit['response_body']['properties']['limits']['properties'][
+        'absolute']['required'].remove(item)
diff --git a/tempest/tests/lib/services/volume/v2/__init__.py b/tempest/lib/api_schema/response/compute/v2_39/__init__.py
similarity index 100%
copy from tempest/tests/lib/services/volume/v2/__init__.py
copy to tempest/lib/api_schema/response/compute/v2_39/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_39/limits.py b/tempest/lib/api_schema/response/compute/v2_39/limits.py
new file mode 100644
index 0000000..3df6616
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_39/limits.py
@@ -0,0 +1,29 @@
+# Copyright 2018 ZTE 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_36 import limits as limitv236
+
+# Compute microversion 2.39:
+# remove attributes in get_limit:
+#    'maxImageMeta'
+
+get_limit = copy.deepcopy(limitv236.get_limit)
+
+get_limit['response_body']['properties']['limits']['properties']['absolute'][
+    'properties'].pop('maxImageMeta')
+
+get_limit['response_body']['properties']['limits']['properties']['absolute'][
+    'required'].remove('maxImageMeta')
diff --git a/tempest/lib/api_schema/response/compute/v2_47/servers.py b/tempest/lib/api_schema/response/compute/v2_47/servers.py
index 5d6d4c3..5922f76 100644
--- a/tempest/lib/api_schema/response/compute/v2_47/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_47/servers.py
@@ -53,3 +53,14 @@
     servers226.rebuild_server_with_admin_pass)
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'properties'].update({'flavor': flavor})
+
+# NOTE(zhufl): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.26 ***
+list_tags = copy.deepcopy(servers226.list_tags)
+update_all_tags = copy.deepcopy(servers226.update_all_tags)
+delete_all_tags = copy.deepcopy(servers226.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers226.check_tag_existence)
+update_tag = copy.deepcopy(servers226.update_tag)
+delete_tag = copy.deepcopy(servers226.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_48/servers.py b/tempest/lib/api_schema/response/compute/v2_48/servers.py
index 5904758..02b00d6 100644
--- a/tempest/lib/api_schema/response/compute/v2_48/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_48/servers.py
@@ -113,3 +113,14 @@
 }
 
 get_server = copy.deepcopy(servers247.get_server)
+
+# NOTE(zhufl): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.26 ***
+list_tags = copy.deepcopy(servers247.list_tags)
+update_all_tags = copy.deepcopy(servers247.update_all_tags)
+delete_all_tags = copy.deepcopy(servers247.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers247.check_tag_existence)
+update_tag = copy.deepcopy(servers247.update_tag)
+delete_tag = copy.deepcopy(servers247.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_54/servers.py b/tempest/lib/api_schema/response/compute/v2_54/servers.py
index c084696..e264186 100644
--- a/tempest/lib/api_schema/response/compute/v2_54/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_54/servers.py
@@ -39,11 +39,18 @@
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'required'].append('key_name')
 
-# ****** Schemas unchanged in microversion 2.54 since microversion 2.47 ***
-
 # NOTE(gmann): Below are the unchanged schema in this microversion. We need
 # to keep this schema in this file to have the generic way to select the
 # right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged in microversion 2.54 since microversion 2.47 ***
 get_server = copy.deepcopy(servers247.get_server)
 list_servers_detail = copy.deepcopy(servers247.list_servers_detail)
 update_server = copy.deepcopy(servers247.update_server)
+
+# ****** Schemas unchanged since microversion 2.26 ***
+list_tags = copy.deepcopy(servers247.list_tags)
+update_all_tags = copy.deepcopy(servers247.update_all_tags)
+delete_all_tags = copy.deepcopy(servers247.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers247.check_tag_existence)
+update_tag = copy.deepcopy(servers247.update_tag)
+delete_tag = copy.deepcopy(servers247.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_57/limits.py b/tempest/lib/api_schema/response/compute/v2_57/limits.py
new file mode 100644
index 0000000..dcb8b3d
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_57/limits.py
@@ -0,0 +1,30 @@
+# Copyright 2018 ZTE 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_39 import limits as limitv239
+
+# Compute microversion 2.57:
+# remove attributes in get_limit:
+#    'maxPersonality',
+#    'maxPersonalitySize'
+
+get_limit = copy.deepcopy(limitv239.get_limit)
+
+for item in ['maxPersonality', 'maxPersonalitySize']:
+    get_limit['response_body']['properties']['limits']['properties'][
+        'absolute']['properties'].pop(item)
+    get_limit['response_body']['properties']['limits']['properties'][
+        'absolute']['required'].remove(item)
diff --git a/tempest/lib/api_schema/response/compute/v2_57/servers.py b/tempest/lib/api_schema/response/compute/v2_57/servers.py
index ed1ca7d..d7de5fd 100644
--- a/tempest/lib/api_schema/response/compute/v2_57/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_57/servers.py
@@ -43,11 +43,18 @@
 rebuild_server_with_admin_pass['response_body']['properties']['server'][
     'required'].append('user_data')
 
-# ****** Schemas unchanged in microversion 2.57 since microversion 2.54 ***
-
 # NOTE(gmann): Below are the unchanged schema in this microversion. We need
-# to keeo this schema in this file to have the generic way to select the
+# to keep this schema in this file to have the generic way to select the
 # right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged in microversion 2.57 since microversion 2.54 ***
 get_server = copy.deepcopy(servers254.get_server)
 list_servers_detail = copy.deepcopy(servers254.list_servers_detail)
 update_server = copy.deepcopy(servers254.update_server)
+
+# ****** Schemas unchanged since microversion 2.26 ***
+list_tags = copy.deepcopy(servers254.list_tags)
+update_all_tags = copy.deepcopy(servers254.update_all_tags)
+delete_all_tags = copy.deepcopy(servers254.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers254.check_tag_existence)
+update_tag = copy.deepcopy(servers254.update_tag)
+delete_tag = copy.deepcopy(servers254.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_6/servers.py b/tempest/lib/api_schema/response/compute/v2_6/servers.py
index 29b3e86..d5774de 100644
--- a/tempest/lib/api_schema/response/compute/v2_6/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_6/servers.py
@@ -16,9 +16,18 @@
 
 from tempest.lib.api_schema.response.compute.v2_3 import servers
 
+# NOTE: Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.3 ******
 list_servers = copy.deepcopy(servers.list_servers)
 get_server = copy.deepcopy(servers.get_server)
 list_servers_detail = copy.deepcopy(servers.list_servers_detail)
+update_server = copy.deepcopy(servers.update_server)
+rebuild_server = copy.deepcopy(servers.rebuild_server)
+rebuild_server_with_admin_pass = copy.deepcopy(
+    servers.rebuild_server_with_admin_pass)
+show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
 
 # NOTE: The consolidated remote console API got introduced with v2.6
 # with bp/consolidate-console-api. See Nova commit 578bafeda
@@ -31,7 +40,7 @@
                 'type': 'object',
                 'properties': {
                     'protocol': {'enum': ['vnc', 'rdp', 'serial', 'spice']},
-                    'type': {'enum': ['novnc', 'xpvnc', 'rdp-html5',
+                    'type': {'enum': ['novnc', 'xvpvnc', 'rdp-html5',
                                       'spice-html5', 'serial']},
                     'url': {
                         'type': 'string',
diff --git a/tempest/lib/api_schema/response/compute/v2_63/servers.py b/tempest/lib/api_schema/response/compute/v2_63/servers.py
index 5cdaf54..6a20890 100644
--- a/tempest/lib/api_schema/response/compute/v2_63/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_63/servers.py
@@ -63,3 +63,14 @@
     'properties'].update({'trusted_image_certificates': trusted_certs})
 get_server['response_body']['properties']['server'][
     'required'].append('trusted_image_certificates')
+
+# NOTE(zhufl): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.26 ***
+list_tags = copy.deepcopy(servers257.list_tags)
+update_all_tags = copy.deepcopy(servers257.update_all_tags)
+delete_all_tags = copy.deepcopy(servers257.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers257.check_tag_existence)
+update_tag = copy.deepcopy(servers257.update_tag)
+delete_tag = copy.deepcopy(servers257.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py
index 7df02d5..f412839 100644
--- a/tempest/lib/api_schema/response/compute/v2_9/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_9/servers.py
@@ -17,7 +17,13 @@
 from tempest.lib.api_schema.response.compute.v2_1 import servers as servers_21
 from tempest.lib.api_schema.response.compute.v2_6 import servers
 
+# NOTE: Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.6 ******
 list_servers = copy.deepcopy(servers.list_servers)
+show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(servers.get_remote_consoles)
 
 get_server = copy.deepcopy(servers.get_server)
 get_server['response_body']['properties']['server'][
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 3fb56ec..d8c776b 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -269,7 +269,7 @@
         :param merge_stderr: if True the stderr buffer is merged into stdout
         :type merge_stderr: boolean
         """
-        flags += ' --endpoint-type %s' % endpoint_type
+        flags += ' --os-endpoint-type %s' % endpoint_type
         return self.cmd_with_auth(
             'cinder', action, flags, params, fail_ok, merge_stderr)
 
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index 8918a8c..833cfd6 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -331,7 +331,7 @@
         self.region = region
         # Check if passed or default credentials are valid
         if not self.credentials.is_valid():
-            raise exceptions.InvalidCredentials()
+            raise exceptions.InvalidCredentials(credentials)
         # Get the identity classes matching the provided credentials
         # TODO(andreaf) Define a new interface in Credentials to get
         # the API version from an instance
@@ -340,7 +340,9 @@
                     isinstance(self.credentials, auth.IDENTITY_VERSION[k][0])]
         # Zero matches or more than one are both not valid.
         if len(identity) != 1:
-            raise exceptions.InvalidCredentials()
+            msg = "Zero or %d ambiguous auth provider found. identity: %s, " \
+                "credentials: %s" % (len(identity), identity, credentials)
+            raise exceptions.InvalidCredentials(msg)
         self.auth_version, auth_provider_class = identity[0]
         self.dscv = disable_ssl_certificate_validation
         self.ca_certs = ca_certs
diff --git a/tempest/lib/services/compute/limits_client.py b/tempest/lib/services/compute/limits_client.py
index efe9889..9af80c4 100644
--- a/tempest/lib/services/compute/limits_client.py
+++ b/tempest/lib/services/compute/limits_client.py
@@ -15,15 +15,25 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.lib.api_schema.response.compute.v2_1 import limits as schema
+from tempest.lib.api_schema.response.compute.v2_1 import limits as schemav21
+from tempest.lib.api_schema.response.compute.v2_36 import limits as schemav236
+from tempest.lib.api_schema.response.compute.v2_39 import limits as schemav239
+from tempest.lib.api_schema.response.compute.v2_57 import limits as schemav257
 from tempest.lib.common import rest_client
 from tempest.lib.services.compute import base_compute_client
 
 
 class LimitsClient(base_compute_client.BaseComputeClient):
 
+    schema_versions_info = [
+        {'min': None, 'max': '2.35', 'schema': schemav21},
+        {'min': '2.36', 'max': '2.38', 'schema': schemav236},
+        {'min': '2.39', 'max': '2.56', 'schema': schemav239},
+        {'min': '2.57', 'max': None, 'schema': schemav257}]
+
     def show_limits(self):
         resp, body = self.get("limits")
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.get_limit, resp, body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index 03cd645..0d440d5 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -16,8 +16,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
-from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213
+from tempest.lib.api_schema.response.compute.v2_1 import server_groups \
+    as schema
+from tempest.lib.api_schema.response.compute.v2_13 import server_groups \
+    as schemav213
 from tempest.lib.common import rest_client
 from tempest.lib.services.compute import base_compute_client
 
diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py
index ed6df47..3c38dba 100644
--- a/tempest/lib/services/image/v2/images_client.py
+++ b/tempest/lib/services/image/v2/images_client.py
@@ -32,7 +32,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/index.html#update-an-image
+        https://developer.openstack.org/api-ref/image/v2/#update-image
         """
         data = json.dumps(patch)
         headers = {"Content-Type": "application/openstack-images-v2.0"
@@ -47,7 +47,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/index.html#create-an-image
+        https://developer.openstack.org/api-ref/image/v2/#create-image
         """
         data = json.dumps(kwargs)
         resp, body = self.post('images', data)
@@ -84,7 +84,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/#delete-an-image
+        https://developer.openstack.org/api-ref/image/v2/#delete-image
          """
         url = 'images/%s' % image_id
         resp, _ = self.delete(url)
@@ -96,7 +96,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/#show-images
+        https://developer.openstack.org/api-ref/image/v2/#list-images
         """
         url = 'images'
 
@@ -113,7 +113,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/#show-image-details
+        https://developer.openstack.org/api-ref/image/v2/#show-image
         """
         url = 'images/%s' % image_id
         resp, body = self.get(url)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 9db7f92..cdc30b9 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -94,6 +94,10 @@
         if not client:
             client = self.ports_client
         name = data_utils.rand_name(self.__class__.__name__)
+        if CONF.network.port_vnic_type and 'binding:vnic_type' not in kwargs:
+            kwargs['binding:vnic_type'] = CONF.network.port_vnic_type
+        if CONF.network.port_profile and 'binding:profile' not in kwargs:
+            kwargs['binding:profile'] = CONF.network.port_profile
         result = client.create_port(
             name=name,
             network_id=network_id,
@@ -297,7 +301,7 @@
 
     def create_volume_type(self, client=None, name=None, backend_name=None):
         if not client:
-            client = self.os_admin.volume_types_v2_client
+            client = self.os_admin.volume_types_client_latest
         randomized_name = name or data_utils.rand_name(
             'volume-type-' + self.__class__.__name__)
 
@@ -642,9 +646,10 @@
         return floating_ip
 
     def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
-                         private_key=None):
+                         private_key=None, server=None):
         ssh_client = self.get_remote_client(ip_address,
-                                            private_key=private_key)
+                                            private_key=private_key,
+                                            server=server)
         if dev_name is not None:
             ssh_client.make_fs(dev_name)
             ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
@@ -658,9 +663,10 @@
         return timestamp
 
     def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
-                      private_key=None):
+                      private_key=None, server=None):
         ssh_client = self.get_remote_client(ip_address,
-                                            private_key=private_key)
+                                            private_key=private_key,
+                                            server=server)
         if dev_name is not None:
             ssh_client.mount(dev_name, mount_path)
         timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
@@ -1202,9 +1208,9 @@
     @classmethod
     def setup_clients(cls):
         super(EncryptionScenarioTest, cls).setup_clients()
-        cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
+        cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
         cls.admin_encryption_types_client =\
-            cls.os_admin.encryption_types_v2_client
+            cls.os_admin.encryption_types_client_latest
 
     def create_encryption_type(self, client=None, type_id=None, provider=None,
                                key_size=None, cipher=None,
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index b0e4669..7452ee6 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -197,7 +197,14 @@
                                        'VERIFY_RESIZE')
         self.servers_client.confirm_resize_server(server['id'])
         server = self.servers_client.show_server(server['id'])['server']
-        self.assertEqual(resize_flavor, server['flavor']['id'])
+        # Nova API > 2.46 no longer includes flavor.id, and schema check
+        # will cover whether 'id' should be in flavor
+        if server['flavor'].get('id'):
+            self.assertEqual(resize_flavor, server['flavor']['id'])
+        else:
+            flavor = self.flavors_client.show_flavor(resize_flavor)['flavor']
+            for key in ['original_name', 'ram', 'vcpus', 'disk']:
+                self.assertEqual(flavor[key], server['flavor'][key])
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index e39afe0..f5805ef 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -369,7 +369,8 @@
             self.floating_ips[tenant.access_point['id']]['floating_ip_address']
         private_key = tenant.keypair['private_key']
         access_point_ssh = self.get_remote_client(
-            access_point_ssh, private_key=private_key)
+            access_point_ssh, private_key=private_key,
+            server=tenant.access_point)
         return access_point_ssh
 
     def _test_in_tenant_block(self, tenant):
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 68f18d1..d6b6d14 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -63,7 +63,8 @@
 
         instance_ip = self.get_server_ip(server)
         timestamp = self.create_timestamp(instance_ip,
-                                          private_key=keypair['private_key'])
+                                          private_key=keypair['private_key'],
+                                          server=server)
 
         # Prevent bug #1257594 from coming back
         # Unshelve used to boot the instance with the original image, not
@@ -71,7 +72,8 @@
         self._shelve_then_unshelve_server(server)
 
         timestamp2 = self.get_timestamp(instance_ip,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=server)
         self.assertEqual(timestamp, timestamp2)
 
     @decorators.attr(type='slow')
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index b51a781..a33d4d4 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -57,7 +57,8 @@
 
         instance_ip = self.get_server_ip(server)
         timestamp = self.create_timestamp(instance_ip,
-                                          private_key=keypair['private_key'])
+                                          private_key=keypair['private_key'],
+                                          server=server)
 
         # snapshot the instance
         snapshot_image = self.create_server_snapshot(server=server)
@@ -71,5 +72,6 @@
         # check the existence of the timestamp file in the second instance
         server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
         timestamp2 = self.get_timestamp(server_from_snapshot_ip,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=server_from_snapshot)
         self.assertEqual(timestamp, timestamp2)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index ef369d6..2782119 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -96,7 +96,8 @@
                                                       keypair['private_key'])
         timestamp = self.create_timestamp(ip_for_server,
                                           CONF.compute.volume_device_name,
-                                          private_key=keypair['private_key'])
+                                          private_key=keypair['private_key'],
+                                          server=server)
         self.nova_volume_detach(server, volume)
 
         # snapshot the volume
@@ -126,5 +127,6 @@
         # check the existence of the timestamp file in the volume2
         timestamp2 = self.get_timestamp(ip_for_snapshot,
                                         CONF.compute.volume_device_name,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=server_from_snapshot)
         self.assertEqual(timestamp, timestamp2)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 1564f25..79c2d14 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -108,7 +108,8 @@
         LOG.info("Setting timestamp in instance %s", instance_1st)
         ip_instance_1st = self.get_server_ip(instance_1st)
         timestamp = self.create_timestamp(ip_instance_1st,
-                                          private_key=keypair['private_key'])
+                                          private_key=keypair['private_key'],
+                                          server=instance_1st)
 
         # delete instance
         LOG.info("Deleting first instance: %s", instance_1st)
@@ -126,7 +127,8 @@
         LOG.info("Getting timestamp in instance %s", instance_2nd)
         ip_instance_2nd = self.get_server_ip(instance_2nd)
         timestamp2 = self.get_timestamp(ip_instance_2nd,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=instance_2nd)
         self.assertEqual(timestamp, timestamp2)
 
         # snapshot a volume
@@ -150,7 +152,8 @@
                  server_from_snapshot)
         server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
         timestamp3 = self.get_timestamp(server_from_snapshot_ip,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=server_from_snapshot)
         self.assertEqual(timestamp, timestamp3)
 
     @decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index ff7996a..c54bb38 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -40,7 +40,7 @@
     @classmethod
     def setup_clients(cls):
         super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
-        cls.admin_volumes_client = cls.os_admin.volumes_v2_client
+        cls.admin_volumes_client = cls.os_admin.volumes_client_latest
 
     @classmethod
     def skip_checks(cls):
@@ -114,7 +114,8 @@
         LOG.info("Setting timestamp in instance %s", instance['id'])
         ip_instance = self.get_server_ip(instance)
         timestamp = self.create_timestamp(ip_instance,
-                                          private_key=keypair['private_key'])
+                                          private_key=keypair['private_key'],
+                                          server=instance)
 
         # retype volume with migration from backend #1 to backend #2
         LOG.info("Retyping Volume %s to new type %s", volume_origin['id'],
@@ -125,5 +126,6 @@
         LOG.info("Getting timestamp in postmigrated instance %s",
                  instance['id'])
         timestamp2 = self.get_timestamp(ip_instance,
-                                        private_key=keypair['private_key'])
+                                        private_key=keypair['private_key'],
+                                        server=instance)
         self.assertEqual(timestamp, timestamp2)
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 8641b63..32d6224 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -225,7 +225,7 @@
         # This test verifies that wrong config api_v2 = True is detected
         class FakeClient(object):
             def get_versions(self):
-                return (None, ['v1.0'])
+                return (None, ['v1.1'])
 
         fake_os = mock.MagicMock()
         fake_module = mock.MagicMock()
diff --git a/tempest/tests/lib/services/volume/v2/test_backups_client.py b/tempest/tests/lib/services/volume/v2/test_backups_client.py
deleted file mode 100644
index 14e5fb0..0000000
--- a/tempest/tests/lib/services/volume/v2/test_backups_client.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
-# 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.services.volume.v2 import backups_client
-from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services import base
-
-
-class TestBackupsClient(base.BaseServiceTest):
-
-    FAKE_BACKUP_LIST = {
-        "backups": [
-            {
-                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
-                "links": [
-                    {
-                        "href": "fake-url-1",
-                        "rel": "self"
-                    },
-                    {
-                        "href": "fake-url-2",
-                        "rel": "bookmark"
-                    }
-                ],
-                "name": "backup001"
-            }
-        ]
-    }
-
-    FAKE_BACKUP_LIST_WITH_DETAIL = {
-        "backups": [
-            {
-                "availability_zone": "az1",
-                "container": "volumebackups",
-                "created_at": "2013-04-02T10:35:27.000000",
-                "description": None,
-                "fail_reason": None,
-                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
-                "links": [
-                    {
-                        "href": "fake-url-1",
-                        "rel": "self"
-                    },
-                    {
-                        "href": "fake-url-2",
-                        "rel": "bookmark"
-                    }
-                ],
-                "name": "backup001",
-                "object_count": 22,
-                "size": 1,
-                "status": "available",
-                "volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6",
-                "is_incremental": True,
-                "has_dependent_backups": False
-            }
-        ]
-    }
-
-    def setUp(self):
-        super(TestBackupsClient, self).setUp()
-        fake_auth = fake_auth_provider.FakeAuthProvider()
-        self.client = backups_client.BackupsClient(fake_auth,
-                                                   'volume',
-                                                   'regionOne')
-
-    def _test_list_backups(self, detail=False, mock_args='backups',
-                           bytes_body=False, **params):
-        if detail:
-            resp_body = self.FAKE_BACKUP_LIST_WITH_DETAIL
-        else:
-            resp_body = self.FAKE_BACKUP_LIST
-        self.check_service_client_function(
-            self.client.list_backups,
-            'tempest.lib.common.rest_client.RestClient.get',
-            resp_body,
-            to_utf=bytes_body,
-            mock_args=[mock_args],
-            detail=detail,
-            **params)
-
-    def test_list_backups_with_str_body(self):
-        self._test_list_backups()
-
-    def test_list_backups_with_bytes_body(self):
-        self._test_list_backups(bytes_body=True)
-
-    def test_list_backups_with_detail_with_str_body(self):
-        mock_args = "backups/detail"
-        self._test_list_backups(detail=True, mock_args=mock_args)
-
-    def test_list_backups_with_detail_with_bytes_body(self):
-        mock_args = "backups/detail"
-        self._test_list_backups(detail=True, mock_args=mock_args,
-                                bytes_body=True)
-
-    def test_list_backups_with_params(self):
-        # Run the test separately for each param, to avoid assertion error
-        # resulting from randomized params order.
-        mock_args = 'backups?sort_key=name'
-        self._test_list_backups(mock_args=mock_args, sort_key='name')
-
-        mock_args = 'backups/detail?limit=10'
-        self._test_list_backups(detail=True, mock_args=mock_args,
-                                bytes_body=True, limit=10)
diff --git a/tempest/tests/lib/services/volume/v2/test_availability_zone_client.py b/tempest/tests/lib/services/volume/v3/test_availability_zone_client.py
similarity index 96%
rename from tempest/tests/lib/services/volume/v2/test_availability_zone_client.py
rename to tempest/tests/lib/services/volume/v3/test_availability_zone_client.py
index 770565c..4827326 100644
--- a/tempest/tests/lib/services/volume/v2/test_availability_zone_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_availability_zone_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import availability_zone_client
+from tempest.lib.services.volume.v3 import availability_zone_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v3/test_backups_client.py b/tempest/tests/lib/services/volume/v3/test_backups_client.py
index f1ce987..5412064 100644
--- a/tempest/tests/lib/services/volume/v3/test_backups_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_backups_client.py
@@ -20,6 +20,55 @@
 
 class TestBackupsClient(base.BaseServiceTest):
 
+    FAKE_BACKUP_LIST = {
+        "backups": [
+            {
+                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
+                "links": [
+                    {
+                        "href": "fake-url-1",
+                        "rel": "self"
+                    },
+                    {
+                        "href": "fake-url-2",
+                        "rel": "bookmark"
+                    }
+                ],
+                "name": "backup001"
+            }
+        ]
+    }
+
+    FAKE_BACKUP_LIST_WITH_DETAIL = {
+        "backups": [
+            {
+                "availability_zone": "az1",
+                "container": "volumebackups",
+                "created_at": "2013-04-02T10:35:27.000000",
+                "description": None,
+                "fail_reason": None,
+                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
+                "links": [
+                    {
+                        "href": "fake-url-1",
+                        "rel": "self"
+                    },
+                    {
+                        "href": "fake-url-2",
+                        "rel": "bookmark"
+                    }
+                ],
+                "name": "backup001",
+                "object_count": 22,
+                "size": 1,
+                "status": "available",
+                "volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6",
+                "is_incremental": True,
+                "has_dependent_backups": False
+            }
+        ]
+    }
+
     FAKE_BACKUP_UPDATE = {
         "backup": {
             "id": "4c65c15f-a5c5-464b-b92a-90e4c04636a7",
@@ -35,6 +84,46 @@
                                                    'volume',
                                                    'regionOne')
 
+    def _test_list_backups(self, detail=False, mock_args='backups',
+                           bytes_body=False, **params):
+        if detail:
+            resp_body = self.FAKE_BACKUP_LIST_WITH_DETAIL
+        else:
+            resp_body = self.FAKE_BACKUP_LIST
+        self.check_service_client_function(
+            self.client.list_backups,
+            'tempest.lib.common.rest_client.RestClient.get',
+            resp_body,
+            to_utf=bytes_body,
+            mock_args=[mock_args],
+            detail=detail,
+            **params)
+
+    def test_list_backups_with_str_body(self):
+        self._test_list_backups()
+
+    def test_list_backups_with_bytes_body(self):
+        self._test_list_backups(bytes_body=True)
+
+    def test_list_backups_with_detail_with_str_body(self):
+        mock_args = "backups/detail"
+        self._test_list_backups(detail=True, mock_args=mock_args)
+
+    def test_list_backups_with_detail_with_bytes_body(self):
+        mock_args = "backups/detail"
+        self._test_list_backups(detail=True, mock_args=mock_args,
+                                bytes_body=True)
+
+    def test_list_backups_with_params(self):
+        # Run the test separately for each param, to avoid assertion error
+        # resulting from randomized params order.
+        mock_args = 'backups?sort_key=name'
+        self._test_list_backups(mock_args=mock_args, sort_key='name')
+
+        mock_args = 'backups/detail?limit=10'
+        self._test_list_backups(detail=True, mock_args=mock_args,
+                                bytes_body=True, limit=10)
+
     def _test_update_backup(self, bytes_body=False):
         self.check_service_client_function(
             self.client.update_backup,
diff --git a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py b/tempest/tests/lib/services/volume/v3/test_capabilities_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_capabilities_client.py
rename to tempest/tests/lib/services/volume/v3/test_capabilities_client.py
index 3d3f1e1..7efe1ff 100644
--- a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_capabilities_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import capabilities_client
+from tempest.lib.services.volume.v3 import capabilities_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v3/test_encryption_types_client.py
similarity index 98%
rename from tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
rename to tempest/tests/lib/services/volume/v3/test_encryption_types_client.py
index 8de9fb4..c788181 100644
--- a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_encryption_types_client.py
@@ -12,7 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from tempest.lib.services.volume.v2 import encryption_types_client
+from tempest.lib.services.volume.v3 import encryption_types_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_extensions_client.py b/tempest/tests/lib/services/volume/v3/test_extensions_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_extensions_client.py
rename to tempest/tests/lib/services/volume/v3/test_extensions_client.py
index c0ee421..a8bbffd 100644
--- a/tempest/tests/lib/services/volume/v2/test_extensions_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_extensions_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import extensions_client
+from tempest.lib.services.volume.v3 import extensions_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v3/test_hosts_client.py
similarity index 98%
rename from tempest/tests/lib/services/volume/v2/test_hosts_client.py
rename to tempest/tests/lib/services/volume/v3/test_hosts_client.py
index e107910..67ae4fd 100644
--- a/tempest/tests/lib/services/volume/v2/test_hosts_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_hosts_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import hosts_client
+from tempest.lib.services.volume.v3 import hosts_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_limits_client.py b/tempest/tests/lib/services/volume/v3/test_limits_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_limits_client.py
rename to tempest/tests/lib/services/volume/v3/test_limits_client.py
index 202054c..f94fbe1 100644
--- a/tempest/tests/lib/services/volume/v2/test_limits_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_limits_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import limits_client
+from tempest.lib.services.volume.v3 import limits_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py b/tempest/tests/lib/services/volume/v3/test_quota_classes_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_quota_classes_client.py
rename to tempest/tests/lib/services/volume/v3/test_quota_classes_client.py
index e715fcc..6190733 100644
--- a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_quota_classes_client.py
@@ -15,7 +15,7 @@
 
 import copy
 
-from tempest.lib.services.volume.v2 import quota_classes_client
+from tempest.lib.services.volume.v3 import quota_classes_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_quotas_client.py b/tempest/tests/lib/services/volume/v3/test_quotas_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_quotas_client.py
rename to tempest/tests/lib/services/volume/v3/test_quotas_client.py
index 6384350..aa5d251 100644
--- a/tempest/tests/lib/services/volume/v2/test_quotas_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_quotas_client.py
@@ -12,7 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from tempest.lib.services.volume.v2 import quotas_client
+from tempest.lib.services.volume.v3 import quotas_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py b/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
similarity index 97%
rename from tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py
rename to tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
index 8a5f25f..e0f5566 100644
--- a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.services.volume.v2 import scheduler_stats_client
+from tempest.lib.services.volume.v3 import scheduler_stats_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py b/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
similarity index 94%
rename from tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py
rename to tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
index e03a8eb..1b88020 100644
--- a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
@@ -17,9 +17,7 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.lib.services.volume.v2 import snapshot_manage_client
-from tempest.lib.services.volume.v3 import snapshot_manage_client \
-    as snapshot_manage_clientv3
+from tempest.lib.services.volume.v3 import snapshot_manage_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
@@ -65,7 +63,7 @@
 
         # NOTE: Use sort_keys for json.dumps so that the expected and actual
         # payloads are guaranteed to be identical for mock_args assert check.
-        with mock.patch.object(snapshot_manage_clientv3.json,
+        with mock.patch.object(snapshot_manage_client.json,
                                'dumps') as mock_dumps:
             mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
 
diff --git a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py b/tempest/tests/lib/services/volume/v3/test_snapshots_client.py
similarity index 99%
rename from tempest/tests/lib/services/volume/v2/test_snapshots_client.py
rename to tempest/tests/lib/services/volume/v3/test_snapshots_client.py
index c9f57a0..2efd2e6 100644
--- a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_snapshots_client.py
@@ -12,7 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from tempest.lib.services.volume.v2 import snapshots_client
+from tempest.lib.services.volume.v3 import snapshots_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
diff --git a/tempest/tests/lib/services/volume/v2/test_transfers_client.py b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
similarity index 95%
rename from tempest/tests/lib/services/volume/v2/test_transfers_client.py
rename to tempest/tests/lib/services/volume/v3/test_transfers_client.py
index 8e7c6f4..d631fe7 100644
--- a/tempest/tests/lib/services/volume/v2/test_transfers_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
@@ -18,9 +18,7 @@
 import mock
 from oslo_serialization import jsonutils as json
 
-from tempest.lib.services.volume.v2 import transfers_client
-from tempest.lib.services.volume.v3 import transfers_client \
-    as transfers_clientv3
+from tempest.lib.services.volume.v3 import transfers_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
@@ -65,7 +63,7 @@
 
         # NOTE: Use sort_keys for json.dumps so that the expected and actual
         # payloads are guaranteed to be identical for mock_args assert check.
-        with mock.patch.object(transfers_clientv3.json, 'dumps') as mock_dumps:
+        with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps:
             mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
 
             self.check_service_client_function(
@@ -86,7 +84,7 @@
 
         # NOTE: Use sort_keys for json.dumps so that the expected and actual
         # payloads are guaranteed to be identical for mock_args assert check.
-        with mock.patch.object(transfers_clientv3.json, 'dumps') as mock_dumps:
+        with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps:
             mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
 
             self.check_service_client_function(
diff --git a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py b/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
similarity index 94%
rename from tempest/tests/lib/services/volume/v2/test_volume_manage_client.py
rename to tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
index 0fb66bb..902f027 100644
--- a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
@@ -17,9 +17,7 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.lib.services.volume.v2 import volume_manage_client
-from tempest.lib.services.volume.v3 import volume_manage_client \
-    as volume_manage_clientv3
+from tempest.lib.services.volume.v3 import volume_manage_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
 
@@ -93,7 +91,7 @@
 
         # NOTE: Use sort_keys for json.dumps so that the expected and actual
         # payloads are guaranteed to be identical for mock_args assert check.
-        with mock.patch.object(volume_manage_clientv3.json,
+        with mock.patch.object(volume_manage_client.json,
                                'dumps') as mock_dumps:
             mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
 
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index bc3a753..9534ce8 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -193,3 +193,60 @@
             "raise TestCase.failureException(exception.message)"))), 1)
         self.assertEqual(len(list(checks.unsupported_exception_attribute_PY3(
             "raise TestCase.failureException(ee.message)"))), 0)
+
+    def _test_no_negatve_test_attribute_applied_to_negative_test(
+            self, filename, with_other_decorators=False,
+            with_negative_decorator=True, expected_success=True):
+        check = checks.negative_test_attribute_always_applied_to_negative_tests
+        other_decorators = [
+            "@decorators.idempotent_id(123)",
+            "@utils.requires_ext(extension='ext', service='svc')"
+        ]
+
+        if with_other_decorators:
+            # Include multiple decorators to verify that this check works with
+            # arbitrarily many decorators. These insert decorators above the
+            # @decorators.attr(type=['negative']) decorator.
+            for decorator in other_decorators:
+                self.assertIsNone(check(" %s" % decorator, filename))
+        if with_negative_decorator:
+            self.assertIsNone(
+                check("@decorators.attr(type=['negative'])", filename))
+        if with_other_decorators:
+            # Include multiple decorators to verify that this check works with
+            # arbitrarily many decorators. These insert decorators between
+            # the test and the @decorators.attr(type=['negative']) decorator.
+            for decorator in other_decorators:
+                self.assertIsNone(check(" %s" % decorator, filename))
+        final_result = check(" def test_some_negative_case", filename)
+        if expected_success:
+            self.assertIsNone(final_result)
+        else:
+            self.assertIsInstance(final_result, tuple)
+            self.assertFalse(final_result[0])
+
+    def test_no_negatve_test_attribute_applied_to_negative_test(self):
+        # Check negative filename, negative decorator passes
+        self._test_no_negatve_test_attribute_applied_to_negative_test(
+            "./tempest/api/test_something_negative.py")
+        # Check negative filename, negative decorator, other decorators passes
+        self._test_no_negatve_test_attribute_applied_to_negative_test(
+            "./tempest/api/test_something_negative.py",
+            with_other_decorators=True)
+
+        # Check non-negative filename skips check, causing pass
+        self._test_no_negatve_test_attribute_applied_to_negative_test(
+            "./tempest/api/test_something.py")
+
+        # Check negative filename, no negative decorator fails
+        self._test_no_negatve_test_attribute_applied_to_negative_test(
+            "./tempest/api/test_something_negative.py",
+            with_negative_decorator=False,
+            expected_success=False)
+        # Check negative filename, no negative decorator, other decorators
+        # fails
+        self._test_no_negatve_test_attribute_applied_to_negative_test(
+            "./tempest/api/test_something_negative.py",
+            with_other_decorators=True,
+            with_negative_decorator=False,
+            expected_success=False)
diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh
index 20c99b2..d2fd2aa 100755
--- a/tools/generate-tempest-plugins-list.sh
+++ b/tools/generate-tempest-plugins-list.sh
@@ -49,13 +49,37 @@
 
 sorted_plugins=$(python tools/generate-tempest-plugins-list.py)
 
+name_col_len=$(echo "${sorted_plugins}" | wc -L)
+name_col_len=$(( name_col_len + 2 ))
+
+# Print the title underline for a RST table.
+function title_underline {
+    printf "== "
+    local len=$1
+    while [[ $len -gt 0 ]]; do
+        printf "="
+        len=$(( len - 1))
+    done
+    printf " ===\n"
+}
+
+printf "\n\n"
+title_underline ${name_col_len}
+printf "%-3s %-${name_col_len}s %s\n" "SR" "Plugin Name" "URL"
+title_underline ${name_col_len}
+
+i=0
 for k in ${sorted_plugins}; do
+    i=$((i+1))
     project=${k:0:28}
     giturl="git://git.openstack.org/openstack/${k:0:26}"
-    printf "|%-28s|%-73s|\n" "${project}" "${giturl}"
-    printf "+----------------------------+-------------------------------------------------------------------------+\n"
+    printf "%-3s %-${name_col_len}s %s\n" "$i" "${project}" "${giturl}"
 done
 
+title_underline ${name_col_len}
+
+printf "\n\n"
+
 if [[ -r doc/source/data/tempest-plugins-registry.footer ]]; then
     cat doc/source/data/tempest-plugins-registry.footer
 fi
diff --git a/tox.ini b/tox.ini
index de4f1b7..befa991 100644
--- a/tox.ini
+++ b/tox.ini
@@ -135,6 +135,16 @@
     find . -type f -name "*.pyc" -delete
     tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs}
 
+[testenv:slow-serial]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+# The regex below is used to select the slow tagged tests to run serially:
+commands =
+    find . -type f -name "*.pyc" -delete
+    tempest run --serial --regex '\[.*\bslow\b.*\]' {posargs}
+
 [testenv:venv]
 deps =
   -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}