Merge "Add volume backup description parameter"
diff --git a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
index 056e199..6babd93 100644
--- a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
+++ b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
@@ -8,3 +8,5 @@
 
     * volumes_client(v1)
     * volumes_client(v2)
+    * capabilities_client(v2)
+    * scheduler_stats_client(v2)
diff --git a/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml
new file mode 100644
index 0000000..b504c78
--- /dev/null
+++ b/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - A Neutron Service Providers client is added to deal with resources
+    of the '/service-providers' route.
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index c9ba730..2dd2e89 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -31,7 +31,6 @@
         super(MigrationsAdminTest, cls).setup_clients()
         cls.client = cls.os_adm.migrations_client
         cls.flavors_admin_client = cls.os_adm.flavors_client
-        cls.admin_hosts_client = cls.os_adm.hosts_client
         cls.admin_servers_client = cls.os_adm.servers_client
 
     @test.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index efa55d5..a8a8b83 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -29,7 +29,6 @@
         super(ServersAdminTestJSON, cls).setup_clients()
         cls.client = cls.os_adm.servers_client
         cls.non_admin_client = cls.servers_client
-        cls.flavors_client = cls.os_adm.flavors_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 173ee83..d7e01f0 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -318,12 +318,7 @@
     def rebuild_server(cls, server_id, validatable=False, **kwargs):
         # Destroy an existing server and creates a new one
         if server_id:
-            try:
-                cls.servers_client.delete_server(server_id)
-                waiters.wait_for_server_termination(cls.servers_client,
-                                                    server_id)
-            except Exception:
-                LOG.exception('Failed to delete server %s' % server_id)
+            cls.delete_server(server_id)
 
         cls.password = data_utils.rand_password()
         server = cls.create_test_server(
@@ -381,18 +376,21 @@
             self.request_microversion))
 
     @classmethod
-    def create_volume(cls, image_ref=None):
+    def create_volume(cls, image_ref=None, **kwargs):
         """Create a volume and wait for it to become 'available'.
 
         :param image_ref: Specify an image id to create a bootable volume.
+        :**kwargs: other parameters to create volume.
         :returns: The available volume.
         """
-        vol_name = data_utils.rand_name(cls.__name__ + '-volume')
-        create_params = dict(size=CONF.volume.volume_size,
-                             display_name=vol_name)
+        if 'size' not in kwargs:
+            kwargs['size'] = CONF.volume.volume_size
+        if 'display_name' not in kwargs:
+            vol_name = data_utils.rand_name(cls.__name__ + '-volume')
+            kwargs['display_name'] = vol_name
         if image_ref is not None:
-            create_params['imageRef'] = image_ref
-        volume = cls.volumes_client.create_volume(**create_params)['volume']
+            kwargs['imageRef'] = image_ref
+        volume = cls.volumes_client.create_volume(**kwargs)['volume']
         cls.volumes.append(volume)
         waiters.wait_for_volume_status(cls.volumes_client,
                                        volume['id'], 'available')
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 4f53663..32b3ea3 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -35,7 +35,6 @@
     @classmethod
     def setup_clients(cls):
         super(SecurityGroupRulesNegativeTestJSON, cls).setup_clients()
-        cls.client = cls.security_groups_client
         cls.rules_client = cls.security_group_rules_client
 
     @test.attr(type=['negative'])
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 8342a3e..a21ce94 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -46,7 +46,6 @@
     @classmethod
     def setup_clients(cls):
         super(AttachInterfacesTestJSON, cls).setup_clients()
-        cls.networks_client = cls.os.networks_client
         cls.subnets_client = cls.os.subnets_client
         cls.ports_client = cls.os.ports_client
 
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 2f43157..d2e31ad 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -19,7 +19,6 @@
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
-from tempest.common import waiters
 from tempest import config
 from tempest import test
 
@@ -178,12 +177,7 @@
         # when trying to delete the subnet. The tear down in the base class
         # will try to delete the server and get a 404 but it's ignored so
         # we're OK.
-        def cleanup_server():
-            self.client.delete_server(server_multi_nics['id'])
-            waiters.wait_for_server_termination(self.client,
-                                                server_multi_nics['id'])
-
-        self.addCleanup(cleanup_server)
+        self.addCleanup(self.delete_server, server_multi_nics['id'])
 
         addresses = (self.client.list_addresses(server_multi_nics['id'])
                      ['addresses'])
@@ -215,13 +209,7 @@
 
         server_multi_nics = self.create_test_server(
             networks=networks, wait_until='ACTIVE')
-
-        def cleanup_server():
-            self.client.delete_server(server_multi_nics['id'])
-            waiters.wait_for_server_termination(self.client,
-                                                server_multi_nics['id'])
-
-        self.addCleanup(cleanup_server)
+        self.addCleanup(self.delete_server, server_multi_nics['id'])
 
         addresses = (self.client.list_addresses(server_multi_nics['id'])
                      ['addresses'])
@@ -312,7 +300,7 @@
             self.validation_resources['keypair']['private_key'],
             server=server_no_eph_disk,
             servers_client=self.client)
-        partition_num = len(linux_client.get_partitions().split('\n'))
+        disks_num = len(linux_client.get_disks().split('\n'))
 
         # Explicit server deletion necessary for Juno compatibility
         self.client.delete_server(server_no_eph_disk['id'])
@@ -332,8 +320,8 @@
             self.validation_resources['keypair']['private_key'],
             server=server_with_eph_disk,
             servers_client=self.client)
-        partition_num_emph = len(linux_client.get_partitions().split('\n'))
-        self.assertEqual(partition_num + 1, partition_num_emph)
+        disks_num_eph = len(linux_client.get_disks().split('\n'))
+        self.assertEqual(disks_num + 1, disks_num_eph)
 
 
 class ServersTestManualDisk(ServersTestJSON):
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index 7252e1b..b2d5ae7 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -52,9 +52,7 @@
         super(DeviceTaggingTest, cls).setup_clients()
         cls.networks_client = cls.os.networks_client
         cls.ports_client = cls.os.ports_client
-        cls.volumes_client = cls.os.volumes_client
         cls.subnets_client = cls.os.subnets_client
-        cls.routers_client = cls.os.routers_client
         cls.interfaces_client = cls.os.interfaces_client
 
     @classmethod
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 5a35b4e..3e408d2 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -40,14 +40,9 @@
             srv = cls.create_test_server(wait_until='ACTIVE')
             cls.existing_fixtures.append(srv)
 
-        srv = cls.create_test_server()
+        srv = cls.create_test_server(wait_until='ACTIVE')
         cls.client.delete_server(srv['id'])
-        # We ignore errors on termination because the server may
-        # be put into ERROR status on a quick spawn, then delete,
-        # as the compute node expects the instance local status
-        # to be spawning, not deleted. See LP Bug#1061167
-        waiters.wait_for_server_termination(cls.client, srv['id'],
-                                            ignore_error=True)
+        waiters.wait_for_server_termination(cls.client, srv['id'])
         cls.deleted_fixtures.append(srv)
 
     @test.attr(type=['negative'])
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 56ec8c6..1edadef 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -111,9 +111,9 @@
                 server=server,
                 servers_client=self.servers_client)
 
-            partitions = linux_client.get_partitions()
-            device_name_to_match = ' ' + self.device + '\n'
-            self.assertIn(device_name_to_match, partitions)
+            disks = linux_client.get_disks()
+            device_name_to_match = '\n' + self.device + ' '
+            self.assertIn(device_name_to_match, disks)
 
         self._detach_volume(server['id'], attachment['volumeId'])
         self.servers_client.stop_server(server['id'])
@@ -133,8 +133,8 @@
                 server=server,
                 servers_client=self.servers_client)
 
-            partitions = linux_client.get_partitions()
-            self.assertNotIn(device_name_to_match, partitions)
+            disks = linux_client.get_disks()
+            self.assertNotIn(device_name_to_match, disks)
 
     @test.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
     def test_list_get_volume_attachments(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py
index b7fa0fe..1f18bfe 100644
--- a/tempest/api/compute/volumes/test_attach_volume_negative.py
+++ b/tempest/api/compute/volumes/test_attach_volume_negative.py
@@ -29,6 +29,7 @@
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
+    @test.related_bug('1630783', status_code=500)
     @test.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
     def test_delete_attached_volume(self):
         server = self.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 7d76731..e4e625b 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -16,8 +16,6 @@
 from oslo_log import log as logging
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest.common import waiters
 from tempest import config
 from tempest import test
 
@@ -51,34 +49,11 @@
         cls.volume_list = []
         cls.volume_id_list = []
         for i in range(3):
-            v_name = data_utils.rand_name(cls.__name__ + '-volume')
             metadata = {'Type': 'work'}
-            try:
-                volume = cls.client.create_volume(size=CONF.volume.volume_size,
-                                                  display_name=v_name,
-                                                  metadata=metadata)['volume']
-                waiters.wait_for_volume_status(cls.client,
-                                               volume['id'], 'available')
-                volume = cls.client.show_volume(volume['id'])['volume']
-                cls.volume_list.append(volume)
-                cls.volume_id_list.append(volume['id'])
-            except Exception as exc:
-                LOG.exception(exc)
-                if cls.volume_list:
-                    # We could not create all the volumes, though we were able
-                    # to create *some* of the volumes. This is typically
-                    # because the backing file size of the volume group is
-                    # too small.
-                    for volume in cls.volume_list:
-                        cls.delete_volume(volume['id'])
-                raise exc
-
-    @classmethod
-    def resource_cleanup(cls):
-        # Delete the created Volumes
-        for volume in cls.volume_list:
-            cls.delete_volume(volume['id'])
-        super(VolumesTestJSON, cls).resource_cleanup()
+            volume = cls.create_volume(metadata=metadata)
+            volume = cls.client.show_volume(volume['id'])['volume']
+            cls.volume_list.append(volume)
+            cls.volume_id_list.append(volume['id'])
 
     @test.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d')
     def test_volume_list(self):
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index 59ffc19..361ff31 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -36,7 +36,8 @@
     def test_default_project_id(self):
         # create a domain
         dom_name = data_utils.rand_name('dom')
-        domain_body = self.domains_client.create_domain(dom_name)['domain']
+        domain_body = self.domains_client.create_domain(
+            name=dom_name)['domain']
         dom_id = domain_body['id']
         self.addCleanup(self._delete_domain, dom_id)
 
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index cbf1439..e71341f 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -32,7 +32,7 @@
         cls.setup_domains = list()
         for i in range(3):
             domain = cls.domains_client.create_domain(
-                data_utils.rand_name('domain'),
+                name=data_utils.rand_name('domain'),
                 description=data_utils.rand_name('domain-desc'),
                 enabled=i < 2)['domain']
             cls.setup_domains.append(domain)
@@ -67,7 +67,7 @@
         # List domains filtering by name
         params = {'name': self.setup_domains[0]['name']}
         fetched_domains = self.domains_client.list_domains(
-            params=params)['domains']
+            **params)['domains']
         # Verify the filtered list is correct, domain names are unique
         # so exactly one domain should be found with the provided name
         self.assertEqual(1, len(fetched_domains))
@@ -79,7 +79,7 @@
         # List domains filtering by enabled domains
         params = {'enabled': True}
         fetched_domains = self.domains_client.list_domains(
-            params=params)['domains']
+            **params)['domains']
         # Verify the filtered list is correct
         self.assertIn(self.setup_domains[0], fetched_domains)
         self.assertIn(self.setup_domains[1], fetched_domains)
@@ -93,7 +93,7 @@
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
         domain = self.domains_client.create_domain(
-            d_name, description=d_desc)['domain']
+            name=d_name, description=d_desc)['domain']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self._delete_domain, domain['id'])
         self.assertIn('id', domain)
@@ -138,7 +138,7 @@
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
         domain = self.domains_client.create_domain(
-            d_name, description=d_desc, enabled=False)['domain']
+            name=d_name, description=d_desc, enabled=False)['domain']
         self.addCleanup(self.domains_client.delete_domain, domain['id'])
         self.assertEqual(d_name, domain['name'])
         self.assertFalse(domain['enabled'])
@@ -148,11 +148,15 @@
     def test_create_domain_without_description(self):
         # Create domain only with name
         d_name = data_utils.rand_name('domain')
-        domain = self.domains_client.create_domain(d_name)['domain']
+        domain = self.domains_client.create_domain(name=d_name)['domain']
         self.addCleanup(self._delete_domain, domain['id'])
         self.assertIn('id', domain)
         expected_data = {'name': d_name, 'enabled': True}
-        self.assertIsNone(domain['description'])
+        # TODO(gmann): there is bug in keystone liberty version where
+        # description is not being returned if it is not being passed in
+        # request. Bug#1649245. Once bug is fixed then we can enable the below
+        # check.
+        # self.assertEqual('', domain['description'])
         self.assertDictContainsSubset(expected_data, domain)
 
 
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 4330cab..100a121 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -28,7 +28,7 @@
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
         domain = self.domains_client.create_domain(
-            d_name,
+            name=d_name,
             description=d_desc)['domain']
         domain_id = domain['id']
 
@@ -51,7 +51,8 @@
         # Domain name length should not ne greater than 64 characters
         d_name = 'a' * 65
         self.assertRaises(lib_exc.BadRequest,
-                          self.domains_client.create_domain, d_name)
+                          self.domains_client.create_domain,
+                          name=d_name)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605')
@@ -64,9 +65,10 @@
     @test.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427')
     def test_domain_create_duplicate(self):
         domain_name = data_utils.rand_name('domain-dup')
-        domain = self.domains_client.create_domain(domain_name)['domain']
+        domain = self.domains_client.create_domain(name=domain_name)['domain']
         domain_id = domain['id']
         self.addCleanup(self.delete_domain, domain_id)
         # Domain name should be unique
         self.assertRaises(
-            lib_exc.Conflict, self.domains_client.create_domain, domain_name)
+            lib_exc.Conflict, self.domains_client.create_domain,
+            name=domain_name)
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index c7e8411..33fce8d 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -31,7 +31,7 @@
         u_email = '%s@testmail.tm' % u_name
         u_password = data_utils.rand_name('pass-')
         cls.domain = cls.domains_client.create_domain(
-            data_utils.rand_name('domain-'),
+            name=data_utils.rand_name('domain-'),
             description=data_utils.rand_name('domain-desc-'))['domain']
         cls.project = cls.projects_client.create_project(
             data_utils.rand_name('project-'),
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index f5bf923..670cb2f 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -34,7 +34,7 @@
         u_email = '%s@testmail.tm' % u_name
         cls.u_password = data_utils.rand_password()
         cls.domain = cls.domains_client.create_domain(
-            data_utils.rand_name('domain'),
+            name=data_utils.rand_name('domain'),
             description=data_utils.rand_name('domain-desc'))['domain']
         cls.project = cls.projects_client.create_project(
             data_utils.rand_name('project'),
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 7b037d5..c256b5b 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -38,11 +38,6 @@
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
 
-    @classmethod
-    def setup_clients(cls):
-        super(QuotasNegativeTest, cls).setup_clients()
-        cls.identity_admin_client = cls.os_adm.identity_client
-
     @test.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
     def test_network_quota_exceeding(self):
         # Set the network quota to two
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 3a264ff..978fb8f 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -43,11 +43,6 @@
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
 
-    @classmethod
-    def setup_clients(cls):
-        super(QuotasTest, cls).setup_clients()
-        cls.identity_admin_client = cls.os_adm.identity_client
-
     def _check_quotas(self, new_quotas):
         # Add a project to conduct the test
         project = data_utils.rand_name('test_project_')
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index deefbeb..c2c42bb 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -81,6 +81,7 @@
         cls.security_group_rules_client = (
             cls.os.security_group_rules_client)
         cls.network_versions_client = cls.os.network_versions_client
+        cls.service_providers_client = cls.os.service_providers_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 15d289d..5b46088 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -360,11 +360,6 @@
 class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
 
     @classmethod
-    def setup_clients(cls):
-        super(PortsAdminExtendedAttrsTestJSON, cls).setup_clients()
-        cls.identity_client = cls.os_adm.identity_client
-
-    @classmethod
     def resource_setup(cls):
         super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
         cls.network = cls.create_network()
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index e989b69..f2170ad 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -34,11 +34,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(RoutersTest, cls).setup_clients()
-        cls.identity_admin_client = cls.os_adm.identity_client
-
-    @classmethod
     def resource_setup(cls):
         super(RoutersTest, cls).resource_setup()
         cls.tenant_cidr = (CONF.network.project_network_cidr
diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py
new file mode 100644
index 0000000..be17b3e
--- /dev/null
+++ b/tempest/api/network/test_service_providers.py
@@ -0,0 +1,28 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+from tempest.api.network import base
+from tempest import test
+
+
+class ServiceProvidersTest(base.BaseNetworkTest):
+
+    @test.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
+    @testtools.skipUnless(
+        test.is_extension_enabled('service-type', 'network'),
+        'service-type extension not enabled.')
+    def test_service_providers_list(self):
+        body = self.service_providers_client.list_service_providers()
+        self.assertIn('service_providers', body)
+        self.assertIsInstance(body['service_providers'], list)
diff --git a/tempest/api/network/test_service_type_management.py b/tempest/api/network/test_service_type_management.py
deleted file mode 100644
index f49f082..0000000
--- a/tempest/api/network/test_service_type_management.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#    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.api.network import base
-from tempest.lib import decorators
-from tempest import test
-
-
-class ServiceTypeManagementTestJSON(base.BaseNetworkTest):
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServiceTypeManagementTestJSON, cls).skip_checks()
-        if not test.is_extension_enabled('service-type', 'network'):
-            msg = "Neutron Service Type Management not enabled."
-            raise cls.skipException(msg)
-
-    @decorators.skip_because(bug="1400370")
-    @test.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
-    def test_service_provider_list(self):
-        body = self.client.list_service_providers()
-        self.assertIsInstance(body['service_providers'], list)
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 52b0a9c..eb313d2 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -50,6 +50,7 @@
         cls.object_client = cls.os.object_client
         cls.container_client = cls.os.container_client
         cls.account_client = cls.os.account_client
+        cls.capabilities_client = cls.os.capabilities_client
 
     @classmethod
     def resource_setup(cls):
@@ -65,7 +66,7 @@
         cls.policies = None
 
         if CONF.object_storage_feature_enabled.discoverability:
-            _, body = cls.account_client.list_extensions()
+            _, body = cls.capabilities_client.list_capabilities()
 
             if 'swift' in body and 'policies' in body['swift']:
                 cls.policies = body['swift']['policies']
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index eda4568..59129e5 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -15,6 +15,7 @@
 
 import random
 
+import six
 import testtools
 
 from tempest.api.object_storage import base
@@ -60,8 +61,10 @@
         self.assertHeaders(resp, 'Account', 'GET')
 
         self.assertIsNotNone(container_list)
+
         for container_name in self.containers:
-            self.assertIn(container_name, container_list)
+            self.assertIn(six.text_type(container_name).encode('utf-8'),
+                          container_list)
 
     @test.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
     def test_list_no_containers(self):
@@ -132,7 +135,7 @@
         not CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
     def test_list_extensions(self):
-        resp, extensions = self.account_client.list_extensions()
+        resp, extensions = self.capabilities_client.list_capabilities()
 
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
@@ -246,7 +249,8 @@
             params=params)
         self.assertHeaders(resp, 'Account', 'GET')
         for container in container_list:
-            self.assertEqual(True, container.startswith(prefix))
+            self.assertEqual(True, container.decode(
+                'utf-8').startswith(prefix))
 
     @test.attr(type='smoke')
     @test.idempotent_id('4894c312-6056-4587-8d6f-86ffbf861f80')
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index df91325..f63c518 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -32,7 +32,7 @@
 
         if CONF.object_storage_feature_enabled.discoverability:
             # use /info to get default constraints
-            _, body = cls.account_client.list_extensions()
+            _, body = cls.capabilities_client.list_capabilities()
             cls.constraints = body['swift']
 
     @test.attr(type=["negative"])
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 261e652..4bd7637 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -22,19 +22,6 @@
 
 class VolumesActionsV2Test(base.BaseVolumeAdminTest):
 
-    @classmethod
-    def resource_setup(cls):
-        super(VolumesActionsV2Test, cls).resource_setup()
-
-        # Create a test shared volume for tests
-        cls.volume = cls.create_volume()
-
-    def tearDown(self):
-        # Set volume's status to available after test
-        self.admin_volume_client.reset_volume_status(
-            self.volume['id'], status='available')
-        super(VolumesActionsV2Test, self).tearDown()
-
     def _create_reset_and_force_delete_temp_volume(self, status=None):
         # Create volume, reset volume status, and force delete temp volume
         temp_volume = self.create_volume()
@@ -47,11 +34,13 @@
     @test.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845')
     def test_volume_reset_status(self):
         # test volume reset status : available->error->available
-        self.admin_volume_client.reset_volume_status(
-            self.volume['id'], status='error')
-        volume_get = self.admin_volume_client.show_volume(
-            self.volume['id'])['volume']
-        self.assertEqual('error', volume_get['status'])
+        volume = self.create_volume()
+        for status in ['error', 'available']:
+            self.admin_volume_client.reset_volume_status(
+                volume['id'], status=status)
+            volume_get = self.admin_volume_client.show_volume(
+                volume['id'])['volume']
+            self.assertEqual(status, volume_get['status'])
 
     @test.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
     def test_volume_force_delete_when_volume_is_creating(self):
diff --git a/tempest/api/volume/admin/test_backends_capabilities.py b/tempest/api/volume/admin/v2/test_backends_capabilities.py
similarity index 90%
rename from tempest/api/volume/admin/test_backends_capabilities.py
rename to tempest/api/volume/admin/v2/test_backends_capabilities.py
index 8a21853..fc9066c 100644
--- a/tempest/api/volume/admin/test_backends_capabilities.py
+++ b/tempest/api/volume/admin/v2/test_backends_capabilities.py
@@ -38,13 +38,13 @@
         # Get host list, formation: host@backend-name
         cls.hosts = [
             pool['name'] for pool in
-            cls.admin_volume_client.show_pools()['pools']
+            cls.admin_scheduler_stats_client.list_pools()['pools']
         ]
 
     @test.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854')
     def test_get_capabilities_backend(self):
         # Test backend properties
-        backend = self.admin_volume_client.show_backend_capabilities(
+        backend = self.admin_capabilities_client.show_backend_capabilities(
             self.hosts[0])
 
         # Verify getting capabilities parameters from a backend
@@ -62,12 +62,12 @@
         # Get list backend capabilities using show_pools
         cinder_pools = [
             pool['capabilities'] for pool in
-            self.admin_volume_client.show_pools(detail=True)['pools']
+            self.admin_scheduler_stats_client.list_pools(detail=True)['pools']
         ]
 
         # Get list backends capabilities using show_backend_capabilities
         capabilities = [
-            self.admin_volume_client.show_backend_capabilities(
+            self.admin_capabilities_client.show_backend_capabilities(
                 host=host) for host in self.hosts
         ]
 
diff --git a/tempest/api/volume/admin/v2/test_volume_pools.py b/tempest/api/volume/admin/v2/test_volume_pools.py
index c662e8c..e460278 100644
--- a/tempest/api/volume/admin/v2/test_volume_pools.py
+++ b/tempest/api/volume/admin/v2/test_volume_pools.py
@@ -29,7 +29,7 @@
     def test_get_pools_without_details(self):
         volume_info = self.admin_volume_client. \
             show_volume(self.volume['id'])['volume']
-        cinder_pools = self.admin_volume_client.show_pools()['pools']
+        cinder_pools = self.admin_scheduler_stats_client.list_pools()['pools']
         self.assertIn(volume_info['os-vol-host-attr:host'],
                       [pool['name'] for pool in cinder_pools])
 
@@ -37,7 +37,7 @@
     def test_get_pools_with_details(self):
         volume_info = self.admin_volume_client. \
             show_volume(self.volume['id'])['volume']
-        cinder_pools = self.admin_volume_client.\
-            show_pools(detail=True)['pools']
+        cinder_pools = self.admin_scheduler_stats_client.\
+            list_pools(detail=True)['pools']
         self.assertIn(volume_info['os-vol-host-attr:host'],
                       [pool['name'] for pool in cinder_pools])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 01e2c82..7cd72e1 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -266,6 +266,10 @@
                 cls.os_adm.encryption_types_v2_client
             cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
             cls.admin_volume_limits_client = cls.os_adm.volume_v2_limits_client
+            cls.admin_capabilities_client = \
+                cls.os_adm.volume_capabilities_v2_client
+            cls.admin_scheduler_stats_client = \
+                cls.os_adm.volume_scheduler_stats_v2_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/clients.py b/tempest/clients.py
index b3290ac..4a30f6f 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -127,6 +127,7 @@
             self.network.SecurityGroupRulesClient())
         self.security_groups_client = self.network.SecurityGroupsClient()
         self.network_versions_client = self.network.NetworkVersionsClient()
+        self.service_providers_client = self.network.ServiceProvidersClient()
 
     def _set_image_clients(self):
         if CONF.service_available.glance:
@@ -303,6 +304,10 @@
             self.volume_v2.AvailabilityZoneClient()
         self.volume_limits_client = self.volume_v1.LimitsClient()
         self.volume_v2_limits_client = self.volume_v2.LimitsClient()
+        self.volume_capabilities_v2_client = \
+            self.volume_v2.CapabilitiesClient()
+        self.volume_scheduler_stats_v2_client = \
+            self.volume_v2.SchedulerStatsClient()
 
     def _set_object_storage_clients(self):
         # Mandatory parameters (always defined)
@@ -310,6 +315,8 @@
 
         self.account_client = object_storage.AccountClient(self.auth_provider,
                                                            **params)
+        self.capabilities_client = object_storage.CapabilitiesClient(
+            self.auth_provider, **params)
         self.container_client = object_storage.ContainerClient(
             self.auth_provider, **params)
         self.object_client = object_storage.ObjectClient(self.auth_provider,
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 381f3df..0a1881c 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -169,7 +169,7 @@
         'nova': os.extensions_client,
         'cinder': os.volumes_extension_client,
         'neutron': os.network_extensions_client,
-        'swift': os.account_client,
+        'swift': os.capabilities_client,
     }
     # NOTE (e0ne): Use Cinder API v2 by default because v1 is deprecated
     if CONF.volume_feature_enabled.api_v2:
@@ -201,7 +201,7 @@
     if service != 'swift':
         resp = extensions_client.list_extensions()
     else:
-        __, resp = extensions_client.list_extensions()
+        __, resp = extensions_client.list_capabilities()
     # For Nova, Cinder and Neutron we use the alias name rather than the
     # 'name' field because the alias is considered to be the canonical
     # name.
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index b6ff241..8410541 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -85,7 +85,7 @@
                     return NonExistentHeader('x-account-container-count')
                 if 'x-account-object-count' not in actual:
                     return NonExistentHeader('x-account-object-count')
-                if actual['x-account-container-count'] > 0:
+                if int(actual['x-account-container-count']) > 0:
                     acct_header = "x-account-storage-policy-"
                     matched_policy_count = 0
 
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 5e23696..3f68ae8 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -304,7 +304,9 @@
         if exist_creds and not force_new:
             return exist_creds
         elif exist_creds and force_new:
-            new_index = six.text_type(roles).encode('utf-8') + '-' + \
+            # NOTE(andreaf) In py3.x encode returns bytes, and b'' is bytes
+            # In py2.7 encode returns strings, and b'' is still string
+            new_index = six.text_type(roles).encode('utf-8') + b'-' + \
                 six.text_type(len(self._creds)).encode('utf-8')
             self._creds[new_index] = exist_creds
         net_creds = self._get_creds(roles=roles)
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 9ec217f..d8993bb 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -112,11 +112,22 @@
         output = self.exec_command('grep -c ^processor /proc/cpuinfo')
         return int(output)
 
-    def get_partitions(self):
-        # Return the contents of /proc/partitions
-        command = 'cat /proc/partitions'
+    def get_disks(self):
+        # Select root disk devices as shown by lsblk
+        command = 'lsblk -lb --nodeps'
         output = self.exec_command(command)
-        return output
+        selected = []
+        pos = None
+        for l in output.splitlines():
+            if pos is None and l.find("TYPE") > 0:
+                pos = l.find("TYPE")
+                # Show header line too
+                selected.append(l)
+            # lsblk lists disk type in a column right-aligned with TYPE
+            elif pos > 0 and l[pos:pos + 4] == "disk":
+                selected.append(l)
+
+        return "\n".join(selected)
 
     def get_boot_time(self):
         cmd = 'cut -f1 -d. /proc/uptime'
diff --git a/tempest/config.py b/tempest/config.py
index 47eb427..a3d4d78 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -422,10 +422,16 @@
                 default=['all'],
                 help="A list of enabled filters that nova will accept as hints"
                      " to the scheduler when creating a server. A special "
-                     "entry 'all' indicates all filters are enabled. Empty "
-                     "list indicates all filters are disabled. The full "
-                     "available list of filters is in nova.conf: "
-                     "DEFAULT.scheduler_available_filters"),
+                     "entry 'all' indicates all filters that are included "
+                     "with nova are enabled. Empty list indicates all filters "
+                     "are disabled. The full list of available filters is in "
+                     "nova.conf: DEFAULT.scheduler_available_filters. If the "
+                     "default value is overridden in nova.conf by the test "
+                     "environment (which means that a different set of "
+                     "filters is enabled than what is included in Nova by "
+                     "default) then, this option must be configured to "
+                     "contain the same filters that Nova uses in the test "
+                     "environment."),
     cfg.BoolOpt('swap_volume',
                 default=False,
                 help='Does the test environment support in-place swapping of '
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index ad968f1..3f10dee 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -140,7 +140,7 @@
             # Domain names must be unique, in any case a list is returned,
             # selecting the first (and only) element
             self.creds_domain = self.domains_client.list_domains(
-                params={'name': domain_name})['domains'][0]
+                name=domain_name)['domains'][0]
         except lib_exc.NotFound:
             # TODO(andrea) we could probably create the domain on the fly
             msg = "Requested domain %s could not be found" % domain_name
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
index 4d1044b..a83c68b 100644
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -67,9 +67,9 @@
         API reference:
         http://developer.openstack.org/api-ref-compute-v2.1.html#createFlavor
         """
-        if kwargs.get('ephemeral'):
+        if 'ephemeral' in kwargs:
             kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral')
-        if kwargs.get('is_public'):
+        if 'is_public' in kwargs:
             kwargs['os-flavor-access:is_public'] = kwargs.pop('is_public')
 
         post_body = json.dumps({'flavor': kwargs})
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index c466f07..19e5463 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -27,6 +27,8 @@
     SecurityGroupRulesClient
 from tempest.lib.services.network.security_groups_client import \
     SecurityGroupsClient
+from tempest.lib.services.network.service_providers_client import \
+    ServiceProvidersClient
 from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
 from tempest.lib.services.network.subnets_client import SubnetsClient
 from tempest.lib.services.network.versions_client import NetworkVersionsClient
@@ -35,4 +37,5 @@
            'MeteringLabelRulesClient', 'MeteringLabelsClient',
            'NetworksClient', 'PortsClient', 'QuotasClient', 'RoutersClient',
            'SecurityGroupRulesClient', 'SecurityGroupsClient',
-           'SubnetpoolsClient', 'SubnetsClient', 'NetworkVersionsClient']
+           'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
+           'NetworkVersionsClient']
diff --git a/tempest/lib/services/network/service_providers_client.py b/tempest/lib/services/network/service_providers_client.py
new file mode 100644
index 0000000..0ee9bc3
--- /dev/null
+++ b/tempest/lib/services/network/service_providers_client.py
@@ -0,0 +1,21 @@
+#    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.network import base
+
+
+class ServiceProvidersClient(base.BaseNetworkClient):
+
+    def list_service_providers(self, **filters):
+        """Lists service providers."""
+        uri = '/service-providers'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index eaaafa5..837b4f6 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -15,6 +15,8 @@
 from tempest.lib.services.volume.v2.availability_zone_client \
     import AvailabilityZoneClient
 from tempest.lib.services.volume.v2.backups_client import BackupsClient
+from tempest.lib.services.volume.v2.capabilities_client import \
+    CapabilitiesClient
 from tempest.lib.services.volume.v2.encryption_types_client import \
     EncryptionTypesClient
 from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
@@ -22,6 +24,8 @@
 from tempest.lib.services.volume.v2.limits_client import LimitsClient
 from tempest.lib.services.volume.v2.qos_client import QosSpecsClient
 from tempest.lib.services.volume.v2.quotas_client import QuotasClient
+from tempest.lib.services.volume.v2.scheduler_stats_client import \
+    SchedulerStatsClient
 from tempest.lib.services.volume.v2.services_client import ServicesClient
 from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
 from tempest.lib.services.volume.v2.types_client import TypesClient
@@ -30,4 +34,4 @@
 __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
            'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
            'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
-           'LimitsClient']
+           'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient']
diff --git a/tempest/lib/services/volume/v2/capabilities_client.py b/tempest/lib/services/volume/v2/capabilities_client.py
new file mode 100644
index 0000000..b6de5b9
--- /dev/null
+++ b/tempest/lib/services/volume/v2/capabilities_client.py
@@ -0,0 +1,34 @@
+# Copyright 2016 Red Hat, Inc.
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class CapabilitiesClient(rest_client.RestClient):
+
+    def show_backend_capabilities(self, host):
+        """Shows capabilities for a storage back end.
+
+         Output params: see http://developer.openstack.org/
+                            api-ref-blockstorage-v2.html
+                            #showBackendCapabilities
+        """
+        url = 'capabilities/%s' % host
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/scheduler_stats_client.py b/tempest/lib/services/volume/v2/scheduler_stats_client.py
new file mode 100644
index 0000000..637254b
--- /dev/null
+++ b/tempest/lib/services/volume/v2/scheduler_stats_client.py
@@ -0,0 +1,35 @@
+# Copyright 2016 Red Hat, Inc.
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SchedulerStatsClient(rest_client.RestClient):
+
+    def list_pools(self, detail=False):
+        """List all the volumes pools (hosts).
+
+        Output params: see http://developer.openstack.org/
+                           api-ref-blockstorage-v2.html#listPools
+        """
+        url = 'scheduler-stats/get_pools'
+        if detail:
+            url += '?detail=True'
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index ce97adb..8b8e249 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from debtcollector import removals
 from oslo_serialization import jsonutils as json
 import six
 from six.moves.urllib import parse as urllib
@@ -323,6 +324,8 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    @removals.remove(message="use show_pools from tempest.lib.services."
+                             "volume.v2.scheduler_stats_client")
     def show_pools(self, detail=False):
         # List all the volumes pools (hosts)
         url = 'scheduler-stats/get_pools'
@@ -334,6 +337,8 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    @removals.remove(message="use show_backend_capabilities from tempest.lib."
+                             "services.volume.v2.capabilities_client")
     def show_backend_capabilities(self, host):
         """Shows capabilities for a storage back end.
 
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index f2f17d2..c454ae2 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -66,10 +66,10 @@
         waiters.wait_for_server_status(self.servers_client,
                                        server['id'], 'ACTIVE')
 
-    def check_partitions(self):
+    def check_disks(self):
         # NOTE(andreaf) The device name may be different on different guest OS
-        partitions = self.linux_client.get_partitions()
-        self.assertEqual(1, partitions.count(CONF.compute.volume_device_name))
+        disks = self.linux_client.get_disks()
+        self.assertEqual(1, disks.count(CONF.compute.volume_device_name))
 
     def create_and_add_security_group_to_server(self, server):
         secgroup = self._create_security_group()
@@ -145,7 +145,7 @@
         self.linux_client = self.get_remote_client(
             floating_ip['ip'], private_key=keypair['private_key'])
 
-        self.check_partitions()
+        self.check_disks()
 
         # delete the floating IP, this should refresh the server addresses
         self.compute_floating_ips_client.delete_floating_ip(floating_ip['id'])
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 32f5d9f..1360b09 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -15,7 +15,6 @@
 from oslo_log import log
 import testtools
 
-from tempest import clients
 from tempest.common.utils import data_utils
 from tempest.common.utils import net_info
 from tempest import config
@@ -113,9 +112,9 @@
             access point
         """
 
-        def __init__(self, credentials):
-            self.manager = clients.Manager(credentials)
+        def __init__(self, clients):
             # Credentials from manager are filled with both names and IDs
+            self.manager = clients
             self.creds = self.manager.credentials
             self.network = None
             self.subnet = None
@@ -152,11 +151,6 @@
         # Create no network resources for these tests.
         cls.set_network_resources()
         super(TestSecurityGroupsBasicOps, cls).setup_credentials()
-        # TODO(mnewby) Consider looking up entities as needed instead
-        # of storing them as collections on the class.
-
-        # Credentials from the manager are filled with both IDs and Names
-        cls.alt_creds = cls.alt_manager.credentials
 
     @classmethod
     def resource_setup(cls):
@@ -171,9 +165,8 @@
 
         cls.floating_ips = {}
         cls.tenants = {}
-        creds = cls.manager.credentials
-        cls.primary_tenant = cls.TenantProperties(creds)
-        cls.alt_tenant = cls.TenantProperties(cls.alt_creds)
+        cls.primary_tenant = cls.TenantProperties(cls.os)
+        cls.alt_tenant = cls.TenantProperties(cls.os_alt)
         for tenant in [cls.primary_tenant, cls.alt_tenant]:
             cls.tenants[tenant.creds.tenant_id] = tenant
 
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 0f2c78c..dff00e7 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -85,9 +85,9 @@
         ssh = self.get_remote_client(ip_address, private_key=private_key)
 
         def _func():
-            part = ssh.get_partitions()
-            LOG.debug("Partitions:%s" % part)
-            return CONF.compute.volume_device_name in part
+            disks = ssh.get_disks()
+            LOG.debug("Disks: %s" % disks)
+            return CONF.compute.volume_device_name in disks
 
         if not test_utils.call_until_true(_func,
                                           CONF.compute.build_timeout,
diff --git a/tempest/services/identity/v3/json/domains_client.py b/tempest/services/identity/v3/json/domains_client.py
index fe929a5..43cb62c 100644
--- a/tempest/services/identity/v3/json/domains_client.py
+++ b/tempest/services/identity/v3/json/domains_client.py
@@ -21,29 +21,36 @@
 class DomainsClient(rest_client.RestClient):
     api_version = "v3"
 
-    def create_domain(self, name, **kwargs):
-        """Creates a domain."""
-        description = kwargs.get('description', None)
-        en = kwargs.get('enabled', True)
-        post_body = {
-            'description': description,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'domain': post_body})
+    def create_domain(self, **kwargs):
+        """Creates a domain.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain
+        """
+        post_body = json.dumps({'domain': kwargs})
         resp, body = self.post('domains', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def delete_domain(self, domain_id):
-        """Deletes a domain."""
+        """Deletes a domain.
+
+        For APi details, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain
+        """
         resp, body = self.delete('domains/%s' % domain_id)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def list_domains(self, params=None):
-        """List Domains."""
+    def list_domains(self, **params):
+        """List Domains.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#list-domains
+        """
         url = 'domains'
         if params:
             url += '?%s' % urllib.urlencode(params)
@@ -53,24 +60,24 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_domain(self, domain_id, **kwargs):
-        """Updates a domain."""
-        body = self.show_domain(domain_id)['domain']
-        description = kwargs.get('description', body['description'])
-        en = kwargs.get('enabled', body['enabled'])
-        name = kwargs.get('name', body['name'])
-        post_body = {
-            'description': description,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'domain': post_body})
+        """Updates a domain.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain
+        """
+        post_body = json.dumps({'domain': kwargs})
         resp, body = self.patch('domains/%s' % domain_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def show_domain(self, domain_id):
-        """Get Domain details."""
+        """Get Domain details.
+
+        For API details, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-details
+        """
         resp, body = self.get('domains/%s' % domain_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
diff --git a/tempest/services/object_storage/__init__.py b/tempest/services/object_storage/__init__.py
index 96fe4a3..d1a61d6 100644
--- a/tempest/services/object_storage/__init__.py
+++ b/tempest/services/object_storage/__init__.py
@@ -13,7 +13,10 @@
 # the License.
 
 from tempest.services.object_storage.account_client import AccountClient
+from tempest.services.object_storage.capabilities_client import \
+    CapabilitiesClient
 from tempest.services.object_storage.container_client import ContainerClient
 from tempest.services.object_storage.object_client import ObjectClient
 
-__all__ = ['AccountClient', 'ContainerClient', 'ObjectClient']
+__all__ = ['AccountClient', 'CapabilitiesClient', 'ContainerClient',
+           'ObjectClient']
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 6012a92..9932b4a 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -144,13 +144,3 @@
             body = body.strip().splitlines()
         self.expected_success([200, 204], resp.status)
         return resp, body
-
-    def list_extensions(self):
-        self.skip_path()
-        try:
-            resp, body = self.get('info')
-        finally:
-            self.reset_path()
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return resp, body
diff --git a/tempest/services/object_storage/capabilities_client.py b/tempest/services/object_storage/capabilities_client.py
new file mode 100644
index 0000000..0fe437f
--- /dev/null
+++ b/tempest/services/object_storage/capabilities_client.py
@@ -0,0 +1,31 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class CapabilitiesClient(rest_client.RestClient):
+
+    def list_capabilities(self):
+        self.skip_path()
+        try:
+            resp, body = self.get('info')
+        finally:
+            self.reset_path()
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return resp, body
diff --git a/tempest/test.py b/tempest/test.py
index 93fbed3..af97932 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -141,8 +141,38 @@
     return False
 
 
+def related_bug(bug, status_code=None):
+    """A decorator useful to know solutions from launchpad bug reports
+
+    @param bug: The launchpad bug number causing the test
+    @param status_code: The status code related to the bug report
+    """
+    def decorator(f):
+        @functools.wraps(f)
+        def wrapper(self, *func_args, **func_kwargs):
+            try:
+                return f(self, *func_args, **func_kwargs)
+            except Exception as exc:
+                exc_status_code = getattr(exc, 'status_code', None)
+                if status_code is None or status_code == exc_status_code:
+                    LOG.error('Hints: This test was made for the bug %s. '
+                              'The failure could be related to '
+                              'https://launchpad.net/bugs/%s' % (bug, bug))
+                raise exc
+        return wrapper
+    return decorator
+
+
 def is_scheduler_filter_enabled(filter_name):
-    """Check the list of enabled compute scheduler filters from config. """
+    """Check the list of enabled compute scheduler filters from config.
+
+    This function checks whether the given compute scheduler filter is
+    available and configured in the config file. If the
+    scheduler_available_filters option is set to 'all' (Default value. which
+    means default filters are configured in nova) in tempest.conf then, this
+    function returns True with assumption that requested filter 'filter_name'
+    is one of available filter in nova ("nova.scheduler.filters.all_filters").
+    """
 
     filters = CONF.compute_feature_enabled.scheduler_available_filters
     if len(filters) == 0:
@@ -504,8 +534,12 @@
             else:
                 raise lib_exc.InvalidCredentials(
                     "Invalid credentials type %s" % credential_type)
-        return cls.client_manager(credentials=creds.credentials,
-                                  service=cls._service)
+        manager = cls.client_manager(credentials=creds.credentials,
+                                     service=cls._service)
+        # NOTE(andreaf) Ensure credentials have user and project id fields.
+        # It may not be the case when using pre-provisioned credentials.
+        manager.auth_provider.set_auth()
+        return manager
 
     @classmethod
     def clear_credentials(cls):
@@ -532,18 +566,17 @@
         """
         if not CONF.validation.run_validation:
             return
+
         if keypair is None:
-            if CONF.validation.auth_method.lower() == "keypair":
-                keypair = True
-            else:
-                keypair = False
+            keypair = (CONF.validation.auth_method.lower() == "keypair")
+
         if floating_ip is None:
-            if CONF.validation.connect_method.lower() == "floating":
-                floating_ip = True
-            else:
-                floating_ip = False
+            floating_ip = (CONF.validation.connect_method.lower() ==
+                           "floating")
+
         if security_group is None:
             security_group = CONF.validation.security_group
+
         if security_group_rules is None:
             security_group_rules = CONF.validation.security_group_rules
 
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 00b4542..1af0d95 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -401,7 +401,7 @@
                            'not_fake': 'metadata',
                            'swift': 'metadata'})
         fake_os = mock.MagicMock()
-        fake_os.account_client.list_extensions = fake_list_extensions
+        fake_os.capabilities_client.list_capabilities = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
@@ -423,7 +423,7 @@
                            'not_fake': 'metadata',
                            'swift': 'metadata'})
         fake_os = mock.MagicMock()
-        fake_os.account_client.list_extensions = fake_list_extensions
+        fake_os.capabilities_client.list_capabilities = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index e59e08f..e4f4c04 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -107,13 +107,20 @@
         self.assertEqual(self.conn.get_number_of_vcpus(), 16)
         self._assert_exec_called_with('grep -c ^processor /proc/cpuinfo')
 
-    def test_get_partitions(self):
-        proc_partitions = """major minor  #blocks  name
+    def test_get_disks(self):
+        output_lsblk = """\
+NAME       MAJ:MIN    RM          SIZE RO TYPE MOUNTPOINT
+sda          8:0       0  128035676160  0 disk
+sdb          8:16      0 1000204886016  0 disk
+sr0         11:0       1    1073741312  0 rom"""
+        result = """\
+NAME       MAJ:MIN    RM          SIZE RO TYPE MOUNTPOINT
+sda          8:0       0  128035676160  0 disk
+sdb          8:16      0 1000204886016  0 disk"""
 
-8        0  1048576 vda"""
-        self.ssh_mock.mock.exec_command.return_value = proc_partitions
-        self.assertEqual(self.conn.get_partitions(), proc_partitions)
-        self._assert_exec_called_with('cat /proc/partitions')
+        self.ssh_mock.mock.exec_command.return_value = output_lsblk
+        self.assertEqual(self.conn.get_disks(), result)
+        self._assert_exec_called_with('lsblk -lb --nodeps')
 
     def test_get_boot_time(self):
         booted_at = 10000
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py b/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py
new file mode 100644
index 0000000..1d56db6
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py
@@ -0,0 +1,191 @@
+# Copyright 2016 EasyStack.  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.image.v2 import namespace_properties_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespacePropertiesClient(base.BaseServiceTest):
+    FAKE_CREATE_SHOW_NAMESPACE_PROPERTY = {
+        "description": "property",
+        "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"],
+        "name": "OS::Glance::Image",
+        "title": "Hypervisor Type",
+        "type": "string"
+    }
+
+    FAKE_LIST_NAMESPACE_PROPERTY = {
+        "properties": {
+            "hw_disk_bus": {
+                "description": "property.",
+                "enum": ["scsi", "virtio", "uml", "xen", "ide", "usb"],
+                "title": "Disk Bus",
+                "type": "string"
+            },
+            "hw_machine_type": {
+                "description": "desc.",
+                "title": "Machine Type",
+                "type": "string"
+            },
+            "hw_qemu_guest_agent": {
+                "description": "desc.",
+                "enum": [
+                    "yes",
+                    "no"
+                ],
+                "title": "QEMU Guest Agent",
+                "type": "string"
+            },
+            "hw_rng_model": {
+                "default": "virtio",
+                "description": "desc",
+                "title": "Random Number Generator Device",
+                "type": "string"
+            },
+            "hw_scsi_model": {
+                "default": "virtio-scsi",
+                "description": "desc.",
+                "title": "SCSI Model",
+                "type": "string"
+            },
+            "hw_video_model": {
+                "description": "The video image driver used.",
+                "enum": [
+                    "vga",
+                    "cirrus",
+                    "vmvga",
+                    "xen",
+                    "qxl"
+                ],
+                "title": "Video Model",
+                "type": "string"
+            },
+            "hw_video_ram": {
+                "description": "desc.",
+                "title": "Max Video Ram",
+                "type": "integer"
+            },
+            "hw_vif_model": {
+                "description": "desc.",
+                "enum": ["e1000",
+                         "ne2k_pci",
+                         "pcnet",
+                         "rtl8139",
+                         "virtio",
+                         "e1000",
+                         "e1000e",
+                         "VirtualE1000",
+                         "VirtualE1000e",
+                         "VirtualPCNet32",
+                         "VirtualSriovEthernetCard",
+                         "VirtualVmxnet",
+                         "netfront",
+                         "ne2k_pci"
+                         ],
+                "title": "Virtual Network Interface",
+                "type": "string"
+            },
+            "os_command_line": {
+                "description": "desc.",
+                "title": "Kernel Command Line",
+                "type": "string"
+            }
+        }
+    }
+
+    FAKE_UPDATE_NAMESPACE_PROPERTY = {
+        "description": "property",
+        "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"],
+        "name": "OS::Glance::Image",
+        "title": "update Hypervisor Type",
+        "type": "string"
+    }
+
+    def setUp(self):
+        super(TestNamespacePropertiesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = namespace_properties_client.NamespacePropertiesClient(
+            fake_auth, 'image', 'regionOne')
+
+    def _test_create_namespace_property(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_namespace_property,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY,
+            bytes_body, status=201,
+            namespace="OS::Compute::Hypervisor",
+            title="Hypervisor Type", name="OS::Glance::Image",
+            type="string",
+            enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"])
+
+    def _test_list_namespace_property(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_namespace_properties,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_NAMESPACE_PROPERTY,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor")
+
+    def _test_show_namespace_property(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_namespace_properties,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            property_name="OS::Glance::Image")
+
+    def _test_update_namespace_property(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_namespace_properties,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_NAMESPACE_PROPERTY,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            property_name="OS::Glance::Image",
+            title="update Hypervisor Type", type="string",
+            enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"],
+            name="OS::Glance::Image")
+
+    def test_create_namespace_property_with_str_body(self):
+        self._test_create_namespace_property()
+
+    def test_create_namespace_property_with_bytes_body(self):
+        self._test_create_namespace_property(bytes_body=True)
+
+    def test_list_namespace_property_with_str_body(self):
+        self._test_list_namespace_property()
+
+    def test_list_namespace_property_with_bytes_body(self):
+        self._test_list_namespace_property(bytes_body=True)
+
+    def test_show_namespace_property_with_str_body(self):
+        self._test_show_namespace_property()
+
+    def test_show_namespace_property_with_bytes_body(self):
+        self._test_show_namespace_property(bytes_body=True)
+
+    def test_update_namespace_property_with_str_body(self):
+        self._test_update_namespace_property()
+
+    def test_update_namespace_property_with_bytes_body(self):
+        self._test_update_namespace_property(bytes_body=True)
+
+    def test_delete_namespace(self):
+        self.check_service_client_function(
+            self.client.delete_namespace_property,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, namespace="OS::Compute::Hypervisor",
+            property_name="OS::Glance::Image", status=204)
diff --git a/tempest/tests/lib/services/network/test_service_providers_client.py b/tempest/tests/lib/services/network/test_service_providers_client.py
new file mode 100644
index 0000000..ae11ef0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_service_providers_client.py
@@ -0,0 +1,37 @@
+#    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.network import service_providers_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestServiceProvidersClient(base.BaseServiceTest):
+    def setUp(self):
+        super(TestServiceProvidersClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = service_providers_client.ServiceProvidersClient(
+            fake_auth, 'network', 'regionOne')
+
+    def _test_list_service_providers(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_service_providers,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"service_providers": []},
+            bytes_body)
+
+    def test_list_service_providers_with_str_body(self):
+        self._test_list_service_providers()
+
+    def test_list_service_providers_with_bytes_body(self):
+        self._test_list_service_providers(bytes_body=True)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index 6da7e41..2f975d2 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -458,6 +458,56 @@
         expected = 'http://fake_url/v2.0'
         self._test_base_url_helper(expected, filters, ('token', auth_data))
 
+    def test_base_url_with_extra_path_endpoint(self):
+        auth_data = {
+            'serviceCatalog': [
+                {
+                    'type': 'compute',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'publicURL': 'http://fake_url/some_path/v2.0'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/some_path/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+    def test_base_url_with_unversioned_extra_path_endpoint(self):
+        auth_data = {
+            'serviceCatalog': [
+                {
+                    'type': 'compute',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'publicURL': 'http://fake_url/some_path'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/some_path/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
     def test_token_not_expired(self):
         expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
         self._verify_expiry(expiry_data=expiry_data, should_be_expired=False)
@@ -592,6 +642,58 @@
         expected = 'http://fake_url/v3'
         self._test_base_url_helper(expected, filters, ('token', auth_data))
 
+    def test_base_url_with_extra_path_endpoint(self):
+        auth_data = {
+            'catalog': [
+                {
+                    'type': 'compute',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'url': 'http://fake_url/some_path/v2.0',
+                            'interface': 'public'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/some_path/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+    def test_base_url_with_unversioned_extra_path_endpoint(self):
+        auth_data = {
+            'catalog': [
+                {
+                    'type': 'compute',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'url': 'http://fake_url/some_path',
+                            'interface': 'public'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/some_path/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
     # Base URL test with scope only for V3
     def test_base_url_scope_project(self):
         self.auth_provider.scope = 'project'