Merge "Use names containing "non-existing" as non-existing resource names"
diff --git a/releasenotes/notes/add-image-clients-af94564fb34ddca6.yaml b/releasenotes/notes/add-image-clients-af94564fb34ddca6.yaml
new file mode 100644
index 0000000..7e40fd4
--- /dev/null
+++ b/releasenotes/notes/add-image-clients-af94564fb34ddca6.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    As in the [doc]:
+    http://developer.openstack.org/api-ref/image/v2/metadefs-index.html,
+    there are some apis are not included, add them.
+
+      * namespace_properties_client(v2)
+
diff --git a/releasenotes/notes/add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
new file mode 100644
index 0000000..a1edcc5
--- /dev/null
+++ b/releasenotes/notes/add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
@@ -0,0 +1,6 @@
+---
+features:
+    - Define the identity service role_assignments_client as a library.
+      Add role_assignments_client to the library interface so the other
+      projects can use this module as a stable library without any
+      maintenance changes.
diff --git a/releasenotes/notes/new-volume-limit-client-517c17d9090f4df4.yaml b/releasenotes/notes/new-volume-limit-client-517c17d9090f4df4.yaml
new file mode 100644
index 0000000..033e147
--- /dev/null
+++ b/releasenotes/notes/new-volume-limit-client-517c17d9090f4df4.yaml
@@ -0,0 +1,3 @@
+---
+features:
+  - The volume_limits client was added to tempest.lib.
diff --git a/releasenotes/notes/remove-bootable-option-024f8944c056a3e0.yaml b/releasenotes/notes/remove-bootable-option-024f8944c056a3e0.yaml
new file mode 100644
index 0000000..e6e53af
--- /dev/null
+++ b/releasenotes/notes/remove-bootable-option-024f8944c056a3e0.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+  - The *bootable* config option in the *volume_feature_enabled* group is
+    removed because the corresponding feature os-set_bootable has been
+    implemented 2.5 years ago and all OpenStack versions which are supported
+    by Tempest should support the feature.
diff --git a/requirements.txt b/requirements.txt
index ea73180..d9a9ebb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 pbr>=1.8 # Apache-2.0
-cliff>=2.2.0 # Apache-2.0
+cliff>=2.3.0 # Apache-2.0
 jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
 testtools>=1.4.0 # MIT
 paramiko>=2.0 # LGPLv2.1+
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 609eae6..85aa301 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -177,6 +177,5 @@
     def test_aggregate_remove_nonexistent_host(self):
         aggregate = self._create_test_aggregate()
 
-        non_exist_host = data_utils.rand_name('nonexist_host')
         self.assertRaises(lib_exc.NotFound, self.client.remove_host,
-                          aggregate['id'], host=non_exist_host)
+                          aggregate['id'], host='nonexist_host')
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index b0ab9be..7eb4bbf 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -102,11 +102,10 @@
     @test.attr(type=['negative'])
     @test.idempotent_id('440b9f3f-3c7f-4293-a106-0ceda350f8de')
     def test_flavor_unset_nonexistent_key(self):
-        nonexistent_key = data_utils.rand_name('flavor_key')
         self.assertRaises(lib_exc.NotFound,
                           self.client.unset_flavor_extra_spec,
                           self.flavor['id'],
-                          nonexistent_key)
+                          'nonexistent_key')
 
     @test.attr(type=['negative'])
     @test.idempotent_id('329a7be3-54b2-48be-8052-bf2ce4afd898')
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 220ea39..0f35e14 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -122,12 +122,10 @@
     @test.attr(type=['negative'])
     @test.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa')
     def test_search_nonexistent_hypervisor(self):
-        nonexistent_hypervisor_name = data_utils.rand_name('test_hypervisor')
-
         self.assertRaises(
             lib_exc.NotFound,
             self.client.search_hypervisor,
-            nonexistent_hypervisor_name)
+            'nonexistent_hypervisor_name')
 
     @test.attr(type=['negative'])
     @test.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index f71f046..31cf39c 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -23,7 +23,6 @@
 
 
 class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest):
-    server_id = None
 
     @classmethod
     def setup_clients(cls):
@@ -38,15 +37,14 @@
         server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
         # Generating a nonexistent floatingIP id
-        cls.floating_ip_ids = []
         body = cls.client.list_floating_ips()['floating_ips']
-        for i in range(len(body)):
-            cls.floating_ip_ids.append(body[i]['id'])
+        floating_ip_ids = [floating_ip['id'] for floating_ip in body]
         while True:
-            cls.non_exist_id = data_utils.rand_int_id(start=999)
             if CONF.service_available.neutron:
                 cls.non_exist_id = data_utils.rand_uuid()
-            if cls.non_exist_id not in cls.floating_ip_ids:
+            else:
+                cls.non_exist_id = data_utils.rand_int_id(start=999)
+            if cls.non_exist_id not in floating_ip_ids:
                 break
 
     @test.attr(type=['negative'])
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 50910ec..0a94d5e 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -13,8 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import logging
-
+from oslo_log import log as logging
 from six.moves.urllib import parse as urlparse
 import testtools
 
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 5fe4cb3..c4041cb 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -66,7 +66,7 @@
 
     @test.attr(type=['negative'])
     @test.idempotent_id('131cb3a1-75cc-4d40-b4c3-1317f64719b0')
-    def test_create_volume_with_out_passing_size(self):
+    def test_create_volume_without_passing_size(self):
         # Negative: Should not be able to create volume without passing size
         # in request
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 955b6fb..c7e8411 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -168,15 +168,16 @@
             self.domain['id'], self.user['id'], src_role['id'])
 
         # List "effective" role assignments from user on the parent project
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                self.project['id'], self.user['id']))['role_assignments']
+        params = {'scope.project.id': self.project['id'],
+                  'user.id': self.user['id']}
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertNotEmpty(assignments)
 
         # List "effective" role assignments from user on the leaf project
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                leaf_project['id'], self.user['id']))['role_assignments']
+        params['scope.project.id'] = leaf_project['id']
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertNotEmpty(assignments)
 
         # Revoke role from domain
@@ -185,16 +186,16 @@
 
         # List "effective" role assignments from user on the parent project
         # should return an empty list
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                self.project['id'], self.user['id']))['role_assignments']
+        params['scope.project.id'] = self.project['id']
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertEmpty(assignments)
 
         # List "effective" role assignments from user on the leaf project
         # should return an empty list
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                leaf_project['id'], self.user['id']))['role_assignments']
+        params['scope.project.id'] = leaf_project['id']
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertEmpty(assignments)
 
     @test.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
@@ -217,9 +218,10 @@
             self.project['id'], self.user['id'], src_role['id'])
 
         # List "effective" role assignments from user on the leaf project
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                leaf_project['id'], self.user['id']))['role_assignments']
+        params = {'scope.project.id': leaf_project['id'],
+                  'user.id': self.user['id']}
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertNotEmpty(assignments)
 
         # Revoke role from parent project
@@ -228,7 +230,6 @@
 
         # List "effective" role assignments from user on the leaf project
         # should return an empty list
-        assignments = (
-            self.role_assignments.list_user_project_effective_assignments(
-                leaf_project['id'], self.user['id']))['role_assignments']
+        assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
         self.assertEmpty(assignments)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 1cc3fa2..812c436 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -141,6 +141,7 @@
         cls.client = cls.os.image_client_v2
         cls.namespaces_client = cls.os.namespaces_client
         cls.resource_types_client = cls.os.resource_types_client
+        cls.namespace_properties_client = cls.os.namespace_properties_client
         cls.schemas_client = cls.os.schemas_client
 
     def create_namespace(cls, namespace_name=None, visibility='public',
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
new file mode 100644
index 0000000..7113db4
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
@@ -0,0 +1,57 @@
+#    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.image import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class MetadataNamespacePropertiesTest(base.BaseV2ImageTest):
+    """Test the Metadata definition namespace property basic functionality"""
+
+    @test.idempotent_id('b1a3765e-3a5d-4f6d-a3a7-3ca3476ae768')
+    def test_basic_meta_def_namespace_property(self):
+        # Get the available resource types and use one resource_type
+        body = self.resource_types_client.list_resource_types()
+        resource_name = body['resource_types'][0]['name']
+        enum = ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"]
+        # Create a namespace
+        namespace = self.create_namespace()
+        # Create resource type association
+        body = self.resource_types_client.create_resource_type_association(
+            namespace['namespace'], name=resource_name)
+        # Create a property
+        property_title = data_utils.rand_name('property')
+        body = self.namespace_properties_client.create_namespace_property(
+            namespace=namespace['namespace'], title=property_title,
+            name=resource_name, type="string", enum=enum)
+        self.assertEqual(property_title, body['title'])
+        # Show namespace property
+        body = self.namespace_properties_client.show_namespace_properties(
+            namespace['namespace'], resource_name)
+        self.assertEqual(resource_name, body['name'])
+        # Update namespace property
+        update_property_title = data_utils.rand_name('update-property')
+        body = self.namespace_properties_client.update_namespace_properties(
+            namespace['namespace'], resource_name,
+            title=update_property_title, type="string",
+            enum=enum, name=resource_name)
+        self.assertEqual(update_property_title, body['title'])
+        # Delete namespace property
+        self.namespace_properties_client.delete_namespace_property(
+            namespace['namespace'], resource_name)
+        # List namespace properties and validate deletion
+        namespace_property = [
+            namespace_property['title'] for namespace_property in
+            self.namespace_properties_client.list_namespace_properties(
+                namespace['namespace'])['properties']]
+        self.assertNotIn(update_property_title, namespace_property)
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index ed6a302..e989b69 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -49,41 +49,31 @@
     @test.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c')
     def test_create_show_list_update_delete_router(self):
         # Create a router
-        # NOTE(salv-orlando): Do not invoke self.create_router
-        # as we need to check the response code
-        name = data_utils.rand_name('router-')
-        create_body = self.routers_client.create_router(
-            name=name, external_gateway_info={
-                "network_id": CONF.network.public_network_id},
-            admin_state_up=False)
-        self.addCleanup(self._delete_router, create_body['router']['id'])
-        self.assertEqual(create_body['router']['name'], name)
+        router = self._create_router(
+            admin_state_up=False,
+            external_network_id=CONF.network.public_network_id)
+        self.assertEqual(router['admin_state_up'], False)
         self.assertEqual(
-            create_body['router']['external_gateway_info']['network_id'],
+            router['external_gateway_info']['network_id'],
             CONF.network.public_network_id)
-        self.assertEqual(create_body['router']['admin_state_up'], False)
         # Show details of the created router
-        show_body = self.routers_client.show_router(
-            create_body['router']['id'])
-        self.assertEqual(show_body['router']['name'], name)
+        router_show = self.routers_client.show_router(
+            router['id'])['router']
+        self.assertEqual(router_show['name'], router['name'])
         self.assertEqual(
-            show_body['router']['external_gateway_info']['network_id'],
+            router_show['external_gateway_info']['network_id'],
             CONF.network.public_network_id)
-        self.assertEqual(show_body['router']['admin_state_up'], False)
         # List routers and verify if created router is there in response
-        list_body = self.routers_client.list_routers()
-        routers_list = list()
-        for router in list_body['routers']:
-            routers_list.append(router['id'])
-        self.assertIn(create_body['router']['id'], routers_list)
+        routers = self.routers_client.list_routers()['routers']
+        self.assertIn(router['id'], map(lambda x: x['id'], routers))
         # Update the name of router and verify if it is updated
-        updated_name = 'updated ' + name
-        update_body = self.routers_client.update_router(
-            create_body['router']['id'], name=updated_name)
-        self.assertEqual(update_body['router']['name'], updated_name)
-        show_body = self.routers_client.show_router(
-            create_body['router']['id'])
-        self.assertEqual(show_body['router']['name'], updated_name)
+        updated_name = 'updated' + router['name']
+        router_update = self.routers_client.update_router(
+            router['id'], name=updated_name)['router']
+        self.assertEqual(router_update['name'], updated_name)
+        router_show = self.routers_client.show_router(
+            router['id'])['router']
+        self.assertEqual(router_show['name'], updated_name)
 
     @test.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
     def test_create_router_setting_project_id(self):
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index 7049db0..e6c53ec 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -92,47 +92,39 @@
     def test_get_metadata_headers_with_invalid_container_name(self):
         # Attempts to retrieve metadata headers with an invalid
         # container name.
-        invalid_name = data_utils.rand_name(name="TestInvalidContainer")
-
         self.assertRaises(exceptions.NotFound,
                           self.container_client.list_container_metadata,
-                          invalid_name)
+                          'invalid_container_name')
 
     @test.attr(type=["negative"])
     @test.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
     def test_update_metadata_with_nonexistent_container_name(self):
         # Attempts to update metadata using a nonexistent container name.
-        nonexistent_name = data_utils.rand_name(
-            name="TestNonexistentContainer")
         metadata = {'animal': 'penguin'}
 
         self.assertRaises(exceptions.NotFound,
                           self.container_client.update_container_metadata,
-                          nonexistent_name, metadata)
+                          'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
     @test.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
     def test_delete_with_nonexistent_container_name(self):
         # Attempts to delete metadata using a nonexistent container name.
-        nonexistent_name = data_utils.rand_name(
-            name="TestNonexistentContainer")
         metadata = {'animal': 'penguin'}
 
         self.assertRaises(exceptions.NotFound,
                           self.container_client.delete_container_metadata,
-                          nonexistent_name, metadata)
+                          'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
     @test.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
     def test_list_all_container_objects_with_nonexistent_container(self):
         # Attempts to get a listing of all objects on a container
         # that doesn't exist.
-        nonexistent_name = data_utils.rand_name(
-            name="TestNonexistentContainer")
         params = {'limit': 9999, 'format': 'json'}
         self.assertRaises(exceptions.NotFound,
                           self.container_client.list_container_contents,
-                          nonexistent_name, params)
+                          'nonexistent_container_name', params)
 
     @test.attr(type=["negative"])
     @test.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index a3792b4..bffcb64 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -10,10 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-
-import logging
-
 import netaddr
+from oslo_log import log as logging
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index f32c84a..178b0b1 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -73,6 +73,7 @@
             cls.volumes_extension_client = cls.os.volumes_extension_client
             cls.availability_zone_client = (
                 cls.os.volume_availability_zone_client)
+            cls.volume_limits_client = cls.os.volume_limits_client
         else:
             cls.snapshots_client = cls.os.snapshots_v2_client
             cls.volumes_client = cls.os.volumes_v2_client
@@ -80,6 +81,7 @@
             cls.volumes_extension_client = cls.os.volumes_v2_extension_client
             cls.availability_zone_client = (
                 cls.os.volume_v2_availability_zone_client)
+            cls.volume_limits_client = cls.os.volume_v2_limits_client
 
     @classmethod
     def resource_setup(cls):
@@ -238,6 +240,7 @@
             cls.admin_encryption_types_client = \
                 cls.os_adm.encryption_types_client
             cls.admin_quotas_client = cls.os_adm.volume_quotas_client
+            cls.admin_volume_limits_client = cls.os_adm.volume_limits_client
         elif cls._api_version == 2:
             cls.admin_volume_qos_client = cls.os_adm.volume_qos_v2_client
             cls.admin_volume_services_client = \
@@ -250,6 +253,7 @@
             cls.admin_encryption_types_client = \
                 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
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
new file mode 100644
index 0000000..bc7694a
--- /dev/null
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -0,0 +1,49 @@
+# Copyright 2016 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 tempest.api.volume import base
+from tempest import config
+from tempest import test
+
+
+CONF = config.CONF
+
+
+class AbsoluteLimitsV2Tests(base.BaseVolumeTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(AbsoluteLimitsV2Tests, cls).resource_setup()
+        # Create a shared volume for tests
+        cls.volume = cls.create_volume()
+
+    @test.idempotent_id('8e943f53-e9d6-4272-b2e9-adcf2f7c29ad')
+    def test_get_volume_absolute_limits(self):
+        # get volume limit for a tenant
+        absolute_limits = \
+            self.volume_limits_client.show_limits(
+            )['limits']['absolute']
+
+        # verify volume limits and defaults per tenants
+        self.assertEqual(absolute_limits['totalGigabytesUsed'],
+                         CONF.volume.volume_size)
+        self.assertEqual(absolute_limits['totalVolumesUsed'], 1)
+        self.assertEqual(absolute_limits['totalSnapshotsUsed'], 0)
+        self.assertEqual(absolute_limits['totalBackupsUsed'], 0)
+        self.assertEqual(absolute_limits['totalBackupGigabytesUsed'], 0)
+
+
+class AbsoluteLimitsV1Tests(AbsoluteLimitsV2Tests):
+    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 737ce5e..38f1082 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -12,7 +12,6 @@
 #    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.volume import base
 from tempest.common.utils import data_utils
@@ -67,8 +66,6 @@
                                        self.volume['id'], 'available')
 
     @test.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599')
-    @testtools.skipUnless(CONF.volume_feature_enabled.bootable,
-                          'Update bootable status of a volume is not enabled.')
     def test_volume_bootable(self):
         # Verify that a volume bootable flag is retrieved
         for bool_bootable in [True, False]:
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index fda0dda..6ed6b9c 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -62,7 +62,7 @@
 
     @test.attr(type=['negative'])
     @test.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683')
-    def test_create_volume_with_out_passing_size(self):
+    def test_create_volume_without_passing_size(self):
         # Should not be able to create volume without passing size
         # in request
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
diff --git a/tempest/clients.py b/tempest/clients.py
index d131dc4..53f3775 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -17,7 +17,6 @@
 
 from oslo_log import log as logging
 
-from tempest.common import negative_rest_client
 from tempest import config
 from tempest.lib import auth
 from tempest.lib import exceptions as lib_exc
@@ -82,8 +81,6 @@
             build_interval=CONF.orchestration.build_interval,
             build_timeout=CONF.orchestration.build_timeout,
             **self.default_params)
-        self.negative_client = negative_rest_client.NegativeRestClient(
-            self.auth_provider, service, **self.default_params)
 
     def _prepare_configuration(self):
         """Map values from CONF into Manager parameters
@@ -141,6 +138,8 @@
             self.namespaces_client = self.image_v2.NamespacesClient()
             self.resource_types_client = self.image_v2.ResourceTypesClient()
             self.schemas_client = self.image_v2.SchemasClient()
+            self.namespace_properties_client = \
+                self.image_v2.NamespacePropertiesClient()
 
     def _set_compute_clients(self):
         self.agents_client = self.compute.AgentsClient()
@@ -306,6 +305,8 @@
             self.volume_v1.AvailabilityZoneClient()
         self.volume_v2_availability_zone_client = \
             self.volume_v2.AvailabilityZoneClient()
+        self.volume_limits_client = self.volume_v1.LimitsClient()
+        self.volume_v2_limits_client = self.volume_v2.LimitsClient()
 
     def _set_object_storage_clients(self):
         # Mandatory parameters (always defined)
diff --git a/tempest/cmd/main.py b/tempest/cmd/main.py
index 641d11c..1090c41 100644
--- a/tempest/cmd/main.py
+++ b/tempest/cmd/main.py
@@ -11,11 +11,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import logging
 import sys
 
 from cliff import app
 from cliff import commandmanager
+from oslo_log import log as logging
 from pbr import version
 
 
diff --git a/tempest/common/negative_rest_client.py b/tempest/common/negative_rest_client.py
deleted file mode 100644
index 3495a24..0000000
--- a/tempest/common/negative_rest_client.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# (c) 2014 Deutsche Telekom AG
-# Copyright 2014 Red Hat, Inc.
-# Copyright 2014 NEC Corporation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib.common import rest_client
-
-CONF = config.CONF
-
-
-class NegativeRestClient(rest_client.RestClient):
-    """Version of RestClient that does not raise exceptions."""
-    def __init__(self, auth_provider, service, **kwargs):
-        region, endpoint_type = self._get_region_and_endpoint_type(service)
-        super(NegativeRestClient, self).__init__(
-            auth_provider, service, region, endpoint_type=endpoint_type,
-            **kwargs)
-
-    def _get_region_and_endpoint_type(self, service):
-        """Returns the region for a specific service"""
-        service_region = None
-        service_endpoint_type = None
-        for cfgname in dir(CONF._config):
-            # Find all config.FOO.catalog_type and assume FOO is a service.
-            cfg = getattr(CONF, cfgname)
-            catalog_type = getattr(cfg, 'catalog_type', None)
-            if catalog_type == service:
-                service_region = getattr(cfg, 'region', None)
-                service_endpoint_type = getattr(cfg, 'endpoint_type', None)
-        if not service_region:
-            service_region = CONF.identity.region
-        return service_region, service_endpoint_type
-
-    def _error_checker(self, method, url,
-                       headers, body, resp, resp_body):
-        pass
-
-    def send_request(self, method, url_template, resources, body=None):
-        url = url_template % tuple(resources)
-        if method == "GET":
-            resp, body = self.get(url)
-        elif method == "POST":
-            resp, body = self.post(url, body)
-        elif method == "PUT":
-            resp, body = self.put(url, body)
-        elif method == "PATCH":
-            resp, body = self.patch(url, body)
-        elif method == "HEAD":
-            resp, body = self.head(url)
-        elif method == "DELETE":
-            resp, body = self.delete(url)
-        elif method == "COPY":
-            resp, body = self.copy(url)
-        else:
-            assert False
-
-        return resp, body
diff --git a/tempest/config.py b/tempest/config.py
index bc9215c..70ede55 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -397,7 +397,10 @@
     cfg.BoolOpt('nova_cert',
                 default=False,
                 help='Does the test environment have the nova cert running?',
-                deprecated_for_removal=True),
+                deprecated_for_removal=True,
+                deprecated_reason="On Nova side, the nova-cert service is "
+                                  "deprecated and the service will be removed "
+                                  "as early as Ocata."),
     cfg.BoolOpt('personality',
                 default=False,
                 help='Does the test environment support server personality'),
@@ -780,11 +783,6 @@
     cfg.BoolOpt('api_v3',
                 default=False,
                 help="Is the v3 volume API enabled"),
-    cfg.BoolOpt('bootable',
-                default=True,
-                help='Update bootable status of a volume '
-                     'Not implemented on icehouse ',
-                deprecated_for_removal=True),
     # TODO(ynesenenko): Remove volume_services once liberty-eol happens.
     cfg.BoolOpt('volume_services',
                 default=False,
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index 2e5c457..9e58872 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -23,6 +23,7 @@
 from tempest.lib.common.utils import misc
 from tempest.lib import exceptions
 from tempest.lib.services import compute
+from tempest.lib.services import identity
 from tempest.lib.services import image
 from tempest.lib.services import network
 from tempest.lib.services import volume
@@ -39,6 +40,7 @@
     """
     return {
         'compute': compute,
+        'identity.v2': identity.v2,
         'image.v1': image.v1,
         'image.v2': image.v2,
         'network': network,
@@ -52,7 +54,7 @@
     # NOTE(andreaf) This list will exists only as long the remain clients
     # are migrated to tempest.lib, and it will then be deleted without
     # deprecation or advance notice
-    return set(['identity.v2', 'identity.v3', 'object-storage', 'volume.v3'])
+    return set(['identity.v3', 'object-storage', 'volume.v3'])
 
 
 def available_modules():
diff --git a/tempest/lib/services/identity/v3/role_assignments_client.py b/tempest/lib/services/identity/v3/role_assignments_client.py
new file mode 100644
index 0000000..c2dc3eb
--- /dev/null
+++ b/tempest/lib/services/identity/v3/role_assignments_client.py
@@ -0,0 +1,47 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class RoleAssignmentsClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def list_role_assignments(self, effective=False, **kwargs):
+        """List role assignments.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3/?expanded=list-effective-role-assignments-detail
+
+        :param effective: If True, returns the effective assignments, including
+                          any assignments gained by virtue of group membership.
+        """
+        url = 'role_assignments'
+        if kwargs:
+            # NOTE(rodrigods): "effective" is a key-only query parameter and
+            # is treated below.
+            if 'effective' in kwargs:
+                del kwargs['effective']
+            url += '?%s' % urllib.urlencode(kwargs)
+        if effective:
+            url += '&effective'
+
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index 32bad8b..d359d4b 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -15,10 +15,12 @@
 from tempest.lib.services.image.v2.image_members_client import \
     ImageMembersClient
 from tempest.lib.services.image.v2.images_client import ImagesClient
+from tempest.lib.services.image.v2.namespace_properties_client import \
+    NamespacePropertiesClient
 from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
 from tempest.lib.services.image.v2.resource_types_client import \
     ResourceTypesClient
 from tempest.lib.services.image.v2.schemas_client import SchemasClient
 
-__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacesClient',
-           'ResourceTypesClient', 'SchemasClient']
+__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacePropertiesClient',
+           'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
diff --git a/tempest/lib/services/image/v2/namespace_properties_client.py b/tempest/lib/services/image/v2/namespace_properties_client.py
new file mode 100644
index 0000000..1236b2b
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_properties_client.py
@@ -0,0 +1,91 @@
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class NamespacePropertiesClient(rest_client.RestClient):
+    api_version = "v2"
+
+    def list_namespace_properties(self, namespace):
+        """Lists property definitions in a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-properties
+        """
+        url = 'metadefs/namespaces/%s/properties' % namespace
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_namespace_property(self, namespace, **kwargs):
+        """Creates a property definition in a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-property
+        """
+        url = 'metadefs/namespaces/%s/properties' % namespace
+        data = json.dumps(kwargs)
+        resp, body = self.post(url, data)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_namespace_properties(self, namespace, property_name):
+        """Shows the definition for a property.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-property-definition
+        """
+        url = 'metadefs/namespaces/%s/properties/%s' % (namespace,
+                                                        property_name)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_namespace_properties(self, namespace, property_name, **kwargs):
+        """Updates a property definition.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-property-definition
+        """
+        url = 'metadefs/namespaces/%s/properties/%s' % (namespace,
+                                                        property_name)
+        data = json.dumps(kwargs)
+        resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_namespace_property(self, namespace, property_name):
+        """Removes a property definition from a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-property-definition
+        """
+        url = 'metadefs/namespaces/%s/properties/%s' % (namespace,
+                                                        property_name)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/volume/v1/__init__.py b/tempest/lib/services/volume/v1/__init__.py
index 9c98542..7b5991f 100644
--- a/tempest/lib/services/volume/v1/__init__.py
+++ b/tempest/lib/services/volume/v1/__init__.py
@@ -19,6 +19,7 @@
     EncryptionTypesClient
 from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient
 from tempest.lib.services.volume.v1.hosts_client import HostsClient
+from tempest.lib.services.volume.v1.limits_client import LimitsClient
 from tempest.lib.services.volume.v1.qos_client import QosSpecsClient
 from tempest.lib.services.volume.v1.quotas_client import QuotasClient
 from tempest.lib.services.volume.v1.services_client import ServicesClient
@@ -28,4 +29,5 @@
 
 __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
            'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
-           'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient']
+           'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
+           'LimitsClient']
diff --git a/tempest/lib/services/volume/v1/limits_client.py b/tempest/lib/services/volume/v1/limits_client.py
new file mode 100644
index 0000000..e14b2dc
--- /dev/null
+++ b/tempest/lib/services/volume/v1/limits_client.py
@@ -0,0 +1,32 @@
+# 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 LimitsClient(rest_client.RestClient):
+    """Volume V1 limits client."""
+
+    api_version = "v1"
+
+    def show_limits(self):
+        """Returns the details of a volume absolute limits."""
+        url = "limits"
+        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/v1/snapshots_client.py b/tempest/lib/services/volume/v1/snapshots_client.py
index 2cf1555..3433e68 100644
--- a/tempest/lib/services/volume/v1/snapshots_client.py
+++ b/tempest/lib/services/volume/v1/snapshots_client.py
@@ -27,7 +27,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#listSnapshots
+        http://developer.openstack.org/api-ref/block-storage/v1/#list-snapshots-with-details-v1
         """
         url = 'snapshots'
         if detail:
@@ -45,7 +45,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#showSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-details-v1
         """
         url = "snapshots/%s" % snapshot_id
         resp, body = self.get(url)
@@ -58,7 +58,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#createSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v1/#create-snapshot-v1
         """
         post_body = json.dumps({'snapshot': kwargs})
         resp, body = self.post('snapshots', post_body)
@@ -71,7 +71,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#deleteSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v1/#delete-snapshot-v1
         """
         resp, body = self.delete("snapshots/%s" % snapshot_id)
         self.expected_success(202, resp.status)
@@ -123,7 +123,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#updateSnapshotMetadata
+        http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-v1
         """
         put_body = json.dumps({'snapshot': kwargs})
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
@@ -136,7 +136,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#showSnapshotMetadata
+        http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-metadata-v1
         """
         url = "snapshots/%s/metadata" % snapshot_id
         resp, body = self.get(url)
@@ -149,7 +149,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#updateSnapshotMetadata
+        http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-metadata-v1
         """
         put_body = json.dumps(kwargs)
         url = "snapshots/%s/metadata" % snapshot_id
diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py
index 2b696e5..4ae9935 100644
--- a/tempest/lib/services/volume/v1/types_client.py
+++ b/tempest/lib/services/volume/v1/types_client.py
@@ -40,7 +40,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#listVolumeTypes
+        http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-types-v1
         """
         url = 'types'
         if params:
@@ -56,7 +56,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#showVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v1/#show-volume-type-v1
         """
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
@@ -69,7 +69,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#createVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-type-v1
         """
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
@@ -82,7 +82,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#deleteVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v1/#delete-volume-type-v1
         """
         resp, body = self.delete("types/%s" % volume_type_id)
         self.expected_success(202, resp.status)
@@ -137,7 +137,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v1/#update-volume-type-v1
         """
         put_body = json.dumps({'volume_type': kwargs})
         resp, body = self.put('types/%s' % volume_type_id, put_body)
@@ -155,7 +155,7 @@
                      updated value.
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolumeTypeExtraSpecs
+        http://developer.openstack.org/api-ref/block-storage/v1/#update-extra-specs-for-a-volume-type-v1
         """
         url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name)
         put_body = json.dumps(extra_specs)
diff --git a/tempest/lib/services/volume/v1/volumes_client.py b/tempest/lib/services/volume/v1/volumes_client.py
index 242befc..7a25697 100644
--- a/tempest/lib/services/volume/v1/volumes_client.py
+++ b/tempest/lib/services/volume/v1/volumes_client.py
@@ -63,7 +63,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolume
+        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume
         """
         post_body = json.dumps({'volume': kwargs})
         resp, body = self.post('volumes', post_body)
@@ -76,7 +76,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolume
+        http://developer.openstack.org/api-ref/block-storage/v1/#update-volume
         """
         put_body = json.dumps({'volume': kwargs})
         resp, body = self.put('volumes/%s' % volume_id, put_body)
@@ -104,7 +104,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#attachVolume
+        http://developer.openstack.org/api-ref/block-storage/v1/#attach-volume
         """
         post_body = json.dumps({'os-attach': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -161,7 +161,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#extendVolume
+        http://developer.openstack.org/api-ref/block-storage/v1/#extend-volume
         """
         post_body = json.dumps({'os-extend': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -174,7 +174,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#resetVolume
+        http://developer.openstack.org/api-ref/block-storage/v1/#reset-volume-status
         """
         post_body = json.dumps({'os-reset_status': kwargs})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
@@ -186,7 +186,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-transfer
         """
         post_body = json.dumps({'transfer': kwargs})
         resp, body = self.post('os-volume-transfer', post_body)
@@ -207,7 +207,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#listVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-transfers
         """
         url = 'os-volume-transfer'
         if params:
@@ -228,7 +228,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#acceptVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v1/#accept-volume-transfer
         """
         url = 'os-volume-transfer/%s/accept' % transfer_id
         post_body = json.dumps({'accept': kwargs})
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index f547d7d..eaaafa5 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -19,6 +19,7 @@
     EncryptionTypesClient
 from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
 from tempest.lib.services.volume.v2.hosts_client import HostsClient
+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.services_client import ServicesClient
@@ -28,4 +29,5 @@
 
 __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
            'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
-           'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient']
+           'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
+           'LimitsClient']
diff --git a/tempest/lib/services/volume/v2/limits_client.py b/tempest/lib/services/volume/v2/limits_client.py
new file mode 100644
index 0000000..ce9fba9
--- /dev/null
+++ b/tempest/lib/services/volume/v2/limits_client.py
@@ -0,0 +1,32 @@
+# 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 LimitsClient(rest_client.RestClient):
+    """Volume V2 limits client."""
+
+    api_version = "v2"
+
+    def show_limits(self):
+        """Returns the details of a volume absolute limits."""
+        url = "limits"
+        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/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index dd0f407..6f51b51 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -27,7 +27,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#listSnapshots
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-v2
         """
         url = 'snapshots'
         if detail:
@@ -45,7 +45,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#showSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-v2
         """
         url = "snapshots/%s" % snapshot_id
         resp, body = self.get(url)
@@ -58,7 +58,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot
         """
         post_body = json.dumps({'snapshot': kwargs})
         resp, body = self.post('snapshots', post_body)
@@ -71,7 +71,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-v2
         """
         put_body = json.dumps({'snapshot': kwargs})
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
@@ -84,7 +84,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#deleteSnapshot
+        http://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot-v2
         """
         resp, body = self.delete("snapshots/%s" % snapshot_id)
         self.expected_success(202, resp.status)
@@ -136,7 +136,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#showSnapshotMetadata
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata-v2
         """
         url = "snapshots/%s/metadata" % snapshot_id
         resp, body = self.get(url)
@@ -149,7 +149,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateSnapshotMetadata
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata-v2
         """
         put_body = json.dumps(kwargs)
         url = "snapshots/%s/metadata" % snapshot_id
diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py
index 7a0d6d0..31597d7 100644
--- a/tempest/lib/services/volume/v2/types_client.py
+++ b/tempest/lib/services/volume/v2/types_client.py
@@ -41,7 +41,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#showVolumeTypes
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-types-v2
         """
         url = 'types'
         if params:
@@ -57,7 +57,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#showVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-v2
         """
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
@@ -70,7 +70,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-v2
         """
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
@@ -83,7 +83,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#deleteVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type-v2
         """
         resp, body = self.delete("types/%s" % volume_type_id)
         self.expected_success(202, resp.status)
@@ -138,7 +138,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolumeType
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type-v2
         """
         put_body = json.dumps({'volume_type': kwargs})
         resp, body = self.put('types/%s' % volume_type_id, put_body)
@@ -156,7 +156,7 @@
                      updated value.
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolumeTypeExtraSpecs
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type-extra-specs-v2
         """
         url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name)
         put_body = json.dumps(extra_specs)
@@ -170,7 +170,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolumeTypeAccessExt
+        http://developer.openstack.org/api-ref/block-storage/v2/#add-type-access-v2
         """
         post_body = json.dumps({'addProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
@@ -183,7 +183,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#removeVolumeTypeAccessExt
+        http://developer.openstack.org/api-ref/block-storage/v2/#remove-type-access-v2
         """
         post_body = json.dumps({'removeProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
@@ -196,7 +196,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#listVolumeTypeAccessExt
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-type-access-v2
         """
         url = 'types/%s/os-volume-type-access' % volume_type_id
         resp, body = self.get(url)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 1fb5727..ce97adb 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -64,7 +64,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolume
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-v2
         """
         post_body = json.dumps({'volume': kwargs})
         resp, body = self.post('volumes', post_body)
@@ -77,7 +77,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateVolume
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-v2
         """
         put_body = json.dumps({'volume': kwargs})
         resp, body = self.put('volumes/%s' % volume_id, put_body)
@@ -105,7 +105,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#attachVolume
+        http://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-v2
         """
         post_body = json.dumps({'os-attach': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -162,7 +162,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#extendVolume
+        http://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-v2
         """
         post_body = json.dumps({'os-extend': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -175,7 +175,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#resetVolume
+        http://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-status-v2
         """
         post_body = json.dumps({'os-reset_status': kwargs})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
@@ -187,7 +187,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer-v2
         """
         post_body = json.dumps({'transfer': kwargs})
         resp, body = self.post('os-volume-transfer', post_body)
@@ -208,7 +208,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#listVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers-v2
         """
         url = 'os-volume-transfer'
         if params:
@@ -229,7 +229,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#acceptVolumeTransfer
+        http://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer-v2
         """
         url = 'os-volume-transfer/%s/accept' % transfer_id
         post_body = json.dumps({'accept': kwargs})
@@ -306,7 +306,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#setVolumeimagemetadata
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-image-metadata-v2
         """
         post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
         url = "volumes/%s/action" % (volume_id)
@@ -339,7 +339,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#showBackendCapabilities
+        http://developer.openstack.org/api-ref/block-storage/v2/#show_backend_capabilities-v2
         """
         url = 'capabilities/%s' % host
         resp, body = self.get(url)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index c66128d..3aab2b8 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -16,6 +16,7 @@
 import json
 import re
 
+from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common.utils import test_utils
@@ -134,3 +135,5 @@
         self.verify_metadata_on_config_drive()
         self.verify_networkdata_on_config_drive()
         self.servers_client.delete_server(self.instance['id'])
+        waiters.wait_for_server_termination(
+            self.servers_client, self.instance['id'], ignore_error=False)
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index 9b40b77..6e64a7d 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -22,14 +22,14 @@
 from tempest.lib.services.identity.v3.policies_client import PoliciesClient
 from tempest.lib.services.identity.v3.projects_client import ProjectsClient
 from tempest.lib.services.identity.v3.regions_client import RegionsClient
+from tempest.lib.services.identity.v3.role_assignments_client import \
+    RoleAssignmentsClient
 from tempest.lib.services.identity.v3.roles_client import RolesClient
 from tempest.lib.services.identity.v3.services_client import ServicesClient
 from tempest.lib.services.identity.v3.token_client import V3TokenClient
 from tempest.lib.services.identity.v3.trusts_client import TrustsClient
 from tempest.lib.services.identity.v3.users_client import UsersClient
 from tempest.services.identity.v3.json.domains_client import DomainsClient
-from tempest.services.identity.v3.json.role_assignments_client import \
-    RoleAssignmentsClient
 
 __all__ = ['CredentialsClient', 'EndPointsClient', 'GroupsClient',
            'IdentityClient', 'InheritedRolesClient', 'PoliciesClient',
diff --git a/tempest/services/identity/v3/json/role_assignments_client.py b/tempest/services/identity/v3/json/role_assignments_client.py
deleted file mode 100644
index 9fd7736..0000000
--- a/tempest/services/identity/v3/json/role_assignments_client.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2016 Red Hat, Inc.
-#
-# 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 RoleAssignmentsClient(rest_client.RestClient):
-    api_version = "v3"
-
-    def list_user_project_effective_assignments(
-            self, project_id, user_id):
-        """List the effective role assignments for a user in a project."""
-        resp, body = self.get(
-            "role_assignments?scope.project.id=%s&user.id=%s&effective" %
-            (project_id, user_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py b/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py
new file mode 100644
index 0000000..7d304c1
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py
@@ -0,0 +1,206 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.identity.v3 import role_assignments_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestRoleAssignmentsClient(base.BaseServiceTest):
+
+    FAKE_USER_ID = "313234"
+    FAKE_GROUP_ID = "101112"
+
+    FAKE_ROLE1_ID = "123456"
+    FAKE_ROLE2_ID = "123457"
+
+    FAKE_PROJECT_ID = "456789"
+    FAKE_DOMAIN_ID = "102030"
+
+    FAKE_USER_PROJECT_ASSIGNMENT = {
+        "links": {
+            "assignment": "http://example.com/identity/v3/projects/"
+                          "%s/users/%s/roles/%s" % (FAKE_PROJECT_ID,
+                                                    FAKE_USER_ID,
+                                                    FAKE_ROLE2_ID)
+        },
+        "role": {
+            "id": FAKE_ROLE2_ID
+        },
+        "scope": {
+            "project": {
+                "id": FAKE_PROJECT_ID
+            }
+        },
+        "user": {
+            "id": FAKE_USER_ID
+        }
+    }
+
+    FAKE_GROUP_PROJECT_ASSIGNMENT = {
+        "links": {
+            "assignment": "http://example.com/identity/v3/projects/"
+                          "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID,
+                                                     FAKE_GROUP_ID,
+                                                     FAKE_ROLE1_ID)
+        },
+        "role": {
+            "id": FAKE_ROLE1_ID
+        },
+        "scope": {
+            "project": {
+                "id": FAKE_PROJECT_ID
+            }
+        },
+        "group": {
+            "id": FAKE_GROUP_ID
+        }
+    }
+
+    FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT = {
+        "links": {
+            "assignment": "http://example.com/identity/v3/projects/"
+                          "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID,
+                                                     FAKE_GROUP_ID,
+                                                     FAKE_ROLE1_ID),
+            "membership": "http://example.com/identity/v3/groups/"
+                          "%s/users/%s" % (FAKE_GROUP_ID, FAKE_USER_ID)
+        },
+        "role": {
+            "id": FAKE_ROLE1_ID
+        },
+        "scope": {
+            "project": {
+                "id": FAKE_PROJECT_ID
+            }
+        },
+        "user": {
+            "id": FAKE_USER_ID
+        }
+    }
+
+    FAKE_USER_DOMAIN_ASSIGNMENT = {
+        "links": {
+            "assignment": "http://example.com/identity/v3/domains/"
+                          "%s/users/%s/roles/%s" % (FAKE_DOMAIN_ID,
+                                                    FAKE_USER_ID,
+                                                    FAKE_ROLE1_ID)
+        },
+        "role": {
+            "id": FAKE_ROLE1_ID
+        },
+        "scope": {
+            "domain": {
+                "id": FAKE_DOMAIN_ID
+            }
+        },
+        "user": {
+            "id": FAKE_USER_ID
+        }
+    }
+
+    FAKE_GROUP_PROJECT_ASSIGNMENTS = {
+        "role_assignments": [
+            FAKE_GROUP_PROJECT_ASSIGNMENT
+        ],
+        "links": {
+            "self": "http://example.com/identity/v3/role_assignments?"
+                    "scope.project.id=%s&group.id=%s&effective" % (
+                        FAKE_PROJECT_ID, FAKE_GROUP_ID),
+            "previous": None,
+            "next": None
+        }
+    }
+
+    FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS = {
+        "role_assignments": [
+            FAKE_USER_PROJECT_ASSIGNMENT,
+            FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT
+        ],
+        "links": {
+            "self": "http://example.com/identity/v3/role_assignments?"
+                    "scope.project.id=%s&user.id=%s&effective" % (
+                        FAKE_PROJECT_ID, FAKE_USER_ID),
+            "previous": None,
+            "next": None
+        }
+    }
+
+    FAKE_USER_DOMAIN_ASSIGNMENTS = {
+        "role_assignments": [
+            FAKE_USER_DOMAIN_ASSIGNMENT
+        ],
+        "links": {
+            "self": "http://example.com/identity/v3/role_assignments?"
+                    "scope.domain.id=%s&user.id=%s&effective" % (
+                        FAKE_DOMAIN_ID, FAKE_USER_ID),
+            "previous": None,
+            "next": None
+        }
+    }
+
+    def setUp(self):
+        super(TestRoleAssignmentsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = role_assignments_client.RoleAssignmentsClient(
+            fake_auth, 'identity', 'regionOne')
+
+    def _test_list_user_project_effective_assignments(self, bytes_body=False):
+        params = {'scope.project.id': self.FAKE_PROJECT_ID,
+                  'user.id': self.FAKE_USER_ID}
+        self.check_service_client_function(
+            self.client.list_role_assignments,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS,
+            bytes_body,
+            effective=True,
+            **params)
+
+    def test_list_user_project_effective_assignments_with_str_body(self):
+        self._test_list_user_project_effective_assignments()
+
+    def test_list_user_project_effective_assignments_with_bytes_body(self):
+        self._test_list_user_project_effective_assignments(bytes_body=True)
+
+    def _test_list_group_project_assignments(self, bytes_body=False):
+        params = {'scope.project.id': self.FAKE_PROJECT_ID,
+                  'group.id': self.FAKE_GROUP_ID}
+        self.check_service_client_function(
+            self.client.list_role_assignments,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_GROUP_PROJECT_ASSIGNMENTS,
+            bytes_body,
+            **params)
+
+    def test_list_group_project_assignments_with_str_body(self):
+        self._test_list_group_project_assignments()
+
+    def test_list_group_project_assignments_with_bytes_body(self):
+        self._test_list_group_project_assignments(bytes_body=True)
+
+    def _test_list_user_domain_assignments(self, bytes_body=False):
+        params = {'scope.domain.id': self.FAKE_DOMAIN_ID,
+                  'user.id': self.FAKE_USER_ID}
+        self.check_service_client_function(
+            self.client.list_role_assignments,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_GROUP_PROJECT_ASSIGNMENTS,
+            bytes_body,
+            **params)
+
+    def test_list_user_domain_assignments_with_str_body(self):
+        self._test_list_user_domain_assignments()
+
+    def test_list_user_domain_assignments_with_bytes_body(self):
+        self._test_list_user_domain_assignments(bytes_body=True)
diff --git a/tempest/tests/test_negative_rest_client.py b/tempest/tests/test_negative_rest_client.py
deleted file mode 100644
index 05f9f3e..0000000
--- a/tempest/tests/test_negative_rest_client.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# (c) 2015 Deutsche Telekom AG
-# Copyright 2015 Red Hat, Inc.
-# Copyright 2015 NEC Corporation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import mock
-from oslotest import mockpatch
-
-from tempest.common import negative_rest_client
-from tempest import config
-from tempest.tests import base
-from tempest.tests import fake_config
-from tempest.tests.lib import fake_auth_provider
-
-
-class TestNegativeRestClient(base.TestCase):
-
-    url = 'fake_endpoint'
-
-    def setUp(self):
-        super(TestNegativeRestClient, self).setUp()
-        self.useFixture(fake_config.ConfigFixture())
-        self.patchobject(config, 'TempestConfigPrivate',
-                         fake_config.FakePrivate)
-        self.negative_rest_client = negative_rest_client.NegativeRestClient(
-            fake_auth_provider.FakeAuthProvider(), None)
-        self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
-                                              '_log_request'))
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.post',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_post(self, mock_post):
-        __, return_dict = self.negative_rest_client.send_request('POST',
-                                                                 self.url,
-                                                                 [], {})
-        mock_post.assert_called_once_with(self.url, {})
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.get',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_get(self, mock_get):
-        __, return_dict = self.negative_rest_client.send_request('GET',
-                                                                 self.url,
-                                                                 [])
-        mock_get.assert_called_once_with(self.url)
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.delete',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_delete(self, mock_delete):
-        __, return_dict = self.negative_rest_client.send_request('DELETE',
-                                                                 self.url,
-                                                                 [])
-        mock_delete.assert_called_once_with(self.url)
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.patch',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_patch(self, mock_patch):
-        __, return_dict = self.negative_rest_client.send_request('PATCH',
-                                                                 self.url,
-                                                                 [], {})
-        mock_patch.assert_called_once_with(self.url, {})
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.put',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_put(self, mock_put):
-        __, return_dict = self.negative_rest_client.send_request('PUT',
-                                                                 self.url,
-                                                                 [], {})
-        mock_put.assert_called_once_with(self.url, {})
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.head',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_head(self, mock_head):
-        __, return_dict = self.negative_rest_client.send_request('HEAD',
-                                                                 self.url,
-                                                                 [])
-        mock_head.assert_called_once_with(self.url)
-
-    @mock.patch('tempest.lib.common.rest_client.RestClient.copy',
-                return_value=(mock.Mock(), mock.Mock()))
-    def test_copy(self, mock_copy):
-        __, return_dict = self.negative_rest_client.send_request('COPY',
-                                                                 self.url,
-                                                                 [])
-        mock_copy.assert_called_once_with(self.url)
-
-    def test_other(self):
-        self.assertRaises(AssertionError,
-                          self.negative_rest_client.send_request,
-                          'OTHER', self.url, [])
diff --git a/test-requirements.txt b/test-requirements.txt
index 3260915..475fb16 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,7 +1,7 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-hacking>=0.12.0,<0.13  # Apache-2.0
+hacking<0.13,>=0.12.0 # Apache-2.0
 # needed for doc build
 sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
 oslosphinx>=4.7.0 # Apache-2.0