Merge "Enable sphinx on servers_client"
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 3fd1612..f615c8a 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -50,50 +50,22 @@
         cls.swap = 1024
         cls.rxtx = 2
 
-    def flavor_clean_up(self, flavor_id):
-        self.client.delete_flavor(flavor_id)
-        self.client.wait_for_resource_deletion(flavor_id)
-
-    def _create_flavor(self, flavor_id):
-        # Create a flavor and ensure it is listed
-        # This operation requires the user to have 'admin' role
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-
-        # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id,
-                                           ephemeral=self.ephemeral,
-                                           swap=self.swap,
-                                           rxtx_factor=self.rxtx)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
-        self.assertEqual(flavor['name'], flavor_name)
-        self.assertEqual(flavor['vcpus'], self.vcpus)
-        self.assertEqual(flavor['disk'], self.disk)
-        self.assertEqual(flavor['ram'], self.ram)
-        self.assertEqual(flavor['swap'], self.swap)
-        self.assertEqual(flavor['rxtx_factor'], self.rxtx)
-        self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'],
-                         self.ephemeral)
-        self.assertEqual(flavor['os-flavor-access:is_public'], True)
-
-        # Verify flavor is retrieved
-        flavor = self.client.show_flavor(flavor['id'])['flavor']
-        self.assertEqual(flavor['name'], flavor_name)
-
-        return flavor['id']
-
     @decorators.idempotent_id('8b4330e1-12c4-4554-9390-e6639971f086')
     def test_create_flavor_with_int_id(self):
         flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, str(flavor_id))
 
     @decorators.idempotent_id('94c9bb4e-2c2a-4f3c-bb1f-5f0daf918e6d')
     def test_create_flavor_with_uuid_id(self):
         flavor_id = data_utils.rand_uuid()
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, flavor_id)
 
     @decorators.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0')
@@ -101,7 +73,10 @@
         # If nova receives a request with None as flavor_id,
         # nova generates flavor_id of uuid.
         flavor_id = None
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
 
     @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5')
@@ -109,17 +84,14 @@
         # Create a flavor and ensure it's details are listed
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           ephemeral=self.ephemeral,
-                                           swap=self.swap,
-                                           rxtx_factor=self.rxtx)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    ephemeral=self.ephemeral,
+                                    swap=self.swap,
+                                    rxtx_factor=self.rxtx)
         flag = False
         # Verify flavor is retrieved
         flavors = self.client.list_flavors(detail=True)['flavors']
@@ -144,11 +116,10 @@
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    id=new_flavor_id)
         self.assertEqual(flavor['name'], flavor_name)
         self.assertEqual(flavor['ram'], self.ram)
         self.assertEqual(flavor['vcpus'], self.vcpus)
@@ -177,15 +148,12 @@
         # tenant is not automatically added access list.
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="False")
         # Verify flavor is retrieved
         flag = False
         flavors = self.client.list_flavors(detail=True)['flavors']
@@ -205,16 +173,9 @@
     @decorators.idempotent_id('bcc418ef-799b-47cc-baa1-ce01368b8987')
     def test_create_server_with_non_public_flavor(self):
         # Create a flavor with os-flavor-access:is_public false
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="False")
 
         # Verify flavor is not used by other user
         self.assertRaises(lib_exc.BadRequest,
@@ -227,15 +188,12 @@
         # Create a Flavor with public access.
         # Try to List/Get flavor with another user
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="True")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="True")
         flag = False
         self.new_client = self.flavors_client
         # Verify flavor is retrieved with new user
@@ -247,26 +205,20 @@
 
     @decorators.idempotent_id('fb9cbde6-3a0e-41f2-a983-bdb0a823c44e')
     def test_is_public_string_variations(self):
-        flavor_id_not_public = data_utils.rand_int_id(start=1000)
         flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix)
-        flavor_id_public = data_utils.rand_int_id(start=1000)
         flavor_name_public = data_utils.rand_name(self.flavor_name_prefix)
 
         # Create a non public flavor
-        flavor = self.client.create_flavor(name=flavor_name_not_public,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id_not_public,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        self.create_flavor(name=flavor_name_not_public,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="False")
 
         # Create a public flavor
-        flavor = self.client.create_flavor(name=flavor_name_public,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id_public,
-                                           is_public="True")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        self.create_flavor(name=flavor_name_public,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="True")
 
         def _flavor_lookup(flavors, flavor_name):
             for flavor in flavors:
@@ -290,17 +242,11 @@
 
     @decorators.idempotent_id('3b541a2e-2ac2-4b42-8b8d-ba6e22fcd4da')
     def test_create_flavor_using_string_ram(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
         ram = "1024"
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
-        self.assertEqual(flavor['name'], flavor_name)
-        self.assertEqual(flavor['vcpus'], self.vcpus)
-        self.assertEqual(flavor['disk'], self.disk)
+        flavor = self.create_flavor(ram=ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    id=new_flavor_id)
         self.assertEqual(flavor['ram'], int(ram))
         self.assertEqual(int(flavor['id']), new_flavor_id)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index c3c5460..c636894 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -467,3 +467,17 @@
         super(BaseV2ComputeAdminTest, cls).setup_clients()
         cls.availability_zone_admin_client = (
             cls.os_adm.availability_zone_client)
+        cls.admin_flavors_client = cls.os_adm.flavors_client
+
+    def create_flavor(self, ram, vcpus, disk, name=None,
+                      is_public='True', **kwargs):
+        if name is None:
+            name = data_utils.rand_name(self.__class__.__name__ + "-flavor")
+        id = kwargs.pop('id', data_utils.rand_int_id(start=1000))
+        client = self.admin_flavors_client
+        flavor = client.create_flavor(
+            ram=ram, vcpus=vcpus, disk=disk, name=name,
+            id=id, is_public=is_public, **kwargs)['flavor']
+        self.addCleanup(client.wait_for_resource_deletion, flavor['id'])
+        self.addCleanup(client.delete_flavor, flavor['id'])
+        return flavor
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index d10f370..04fe11f 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -22,7 +22,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -137,7 +137,7 @@
         # Turn the Socket into a WebSocket to do the communication
         return _WebSocket(client_socket, url)
 
-    @test.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc')
+    @decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc')
     def test_novnc(self):
         body = self.client.get_vnc_console(self.server['id'],
                                            type='novnc')['console']
@@ -151,7 +151,7 @@
         # Validate the RFB Negotiation to determine if a valid VNC session
         self._validate_rfb_negotiation()
 
-    @test.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7')
+    @decorators.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7')
     def test_novnc_bad_token(self):
         body = self.client.get_vnc_console(self.server['id'],
                                            type='novnc')['console']
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index e89be4b..445d928 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -15,7 +15,9 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -195,3 +197,112 @@
         body = self.roles_client.list_roles()['roles']
         found = [role for role in body if role in self.roles]
         self.assertEqual(len(found), len(self.roles))
+
+    def _create_implied_role(self, prior_role_id, implies_role_id,
+                             ignore_not_found=False):
+        self.roles_client.create_role_inference_rule(
+            prior_role_id, implies_role_id)
+        if ignore_not_found:
+            self.addCleanup(
+                test_utils.call_and_ignore_notfound_exc,
+                self.roles_client.delete_role_inference_rule,
+                prior_role_id,
+                implies_role_id)
+        else:
+            self.addCleanup(
+                self.roles_client.delete_role_inference_rule,
+                prior_role_id,
+                implies_role_id)
+
+    @decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69')
+    def test_implied_roles_create_delete(self):
+        prior_role_id = self.roles[0]['id']
+        implies_role_id = self.roles[1]['id']
+
+        # Create an inference rule from prior_role to implies_role
+        self._create_implied_role(prior_role_id, implies_role_id,
+                                  ignore_not_found=True)
+
+        # Check if the inference rule exists
+        self.roles_client.show_role_inference_rule(
+            prior_role_id, implies_role_id)
+
+        # Delete the inference rule
+        self.roles_client.delete_role_inference_rule(
+            prior_role_id, implies_role_id)
+        # Check if the inference rule no longer exists
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.roles_client.show_role_inference_rule,
+            prior_role_id,
+            implies_role_id)
+
+    @decorators.idempotent_id('dc6f5959-b74d-4e30-a9e5-a8255494ff00')
+    def test_roles_hierarchy(self):
+        # Create inference rule from "roles[0]" to "role[1]"
+        self._create_implied_role(
+            self.roles[0]['id'], self.roles[1]['id'])
+
+        # Create inference rule from "roles[0]" to "role[2]"
+        self._create_implied_role(
+            self.roles[0]['id'], self.roles[2]['id'])
+
+        # Create inference rule from "roles[2]" to "role"
+        self._create_implied_role(
+            self.roles[2]['id'], self.role['id'])
+
+        # Listing inferences rules from "roles[2]" should only return "role"
+        rules = self.roles_client.list_role_inferences_rules(
+            self.roles[2]['id'])['role_inference']
+        self.assertEqual(1, len(rules['implies']))
+        self.assertEqual(self.role['id'], rules['implies'][0]['id'])
+
+        # Listing inferences rules from "roles[0]" should return "roles[1]" and
+        # "roles[2]" (only direct rules are listed)
+        rules = self.roles_client.list_role_inferences_rules(
+            self.roles[0]['id'])['role_inference']
+        implies_ids = [role['id'] for role in rules['implies']]
+        self.assertEqual(2, len(implies_ids))
+        self.assertIn(self.roles[1]['id'], implies_ids)
+        self.assertIn(self.roles[2]['id'], implies_ids)
+
+    @decorators.idempotent_id('c8828027-df48-4021-95df-b65b92c7429e')
+    def test_assignments_for_implied_roles_create_delete(self):
+        # Create a grant using "roles[0]"
+        self.roles_client.create_user_role_on_project(
+            self.project['id'], self.user_body['id'], self.roles[0]['id'])
+        self.addCleanup(
+            self.roles_client.delete_role_from_user_on_project,
+            self.project['id'], self.user_body['id'], self.roles[0]['id'])
+
+        # Create an inference rule from "roles[0]" to "roles[1]"
+        self._create_implied_role(self.roles[0]['id'], self.roles[1]['id'],
+                                  ignore_not_found=True)
+
+        # In the effective list of role assignments, both prior role and
+        # implied role should be present. This means that a user can
+        # authenticate using both roles (both roles will be present
+        # in the token).
+        params = {'scope.project.id': self.project['id'],
+                  'user.id': self.user_body['id']}
+        role_assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
+        self.assertEqual(2, len(role_assignments))
+
+        roles_ids = [assignment['role']['id']
+                     for assignment in role_assignments]
+        self.assertIn(self.roles[0]['id'], roles_ids)
+        self.assertIn(self.roles[1]['id'], roles_ids)
+
+        # After deleting the implied role, only the assignment with "roles[0]"
+        # should be present.
+        self.roles_client.delete_role_inference_rule(
+            self.roles[0]['id'], self.roles[1]['id'])
+
+        role_assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
+        self.assertEqual(1, len(role_assignments))
+
+        roles_ids = [assignment['role']['id']
+                     for assignment in role_assignments]
+        self.assertIn(self.roles[0]['id'], roles_ids)
diff --git a/tempest/api/identity/v3/test_api_discovery.py b/tempest/api/identity/v3/test_api_discovery.py
index 74e9ec1..2eed3c8 100644
--- a/tempest/api/identity/v3/test_api_discovery.py
+++ b/tempest/api/identity/v3/test_api_discovery.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -21,7 +22,7 @@
     """Tests for API discovery features."""
 
     @test.attr(type='smoke')
-    @test.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
+    @decorators.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
     def test_api_version_resources(self):
         descr = self.non_admin_client.show_api_description()['version']
         expected_resources = ('id', 'links', 'media-types', 'status',
@@ -32,7 +33,7 @@
             self.assertIn(res, keys)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265')
+    @decorators.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265')
     def test_api_media_types(self):
         descr = self.non_admin_client.show_api_description()['version']
         # Get MIME type bases and descriptions
@@ -47,7 +48,7 @@
             self.assertIn(s_type, media_types)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e')
+    @decorators.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e')
     def test_api_version_statuses(self):
         descr = self.non_admin_client.show_api_description()['version']
         status = descr['status'].lower()
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index 26cb90b..570be99 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -14,15 +14,15 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class IdentityV3ProjectsTest(base.BaseIdentityV3Test):
 
     credentials = ['primary', 'alt']
 
-    @test.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d')
+    @decorators.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d')
     def test_list_projects_returns_only_authorized_projects(self):
         alt_project_name =\
             self.alt_manager.credentials.project_name
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index b410da6..1dc1df6 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -16,12 +16,12 @@
 from oslo_utils import timeutils
 import six
 from tempest.api.identity import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class TokensV3Test(base.BaseIdentityV3Test):
 
-    @test.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
+    @decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
     def test_create_token(self):
 
         creds = self.os.credentials
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 9592cb9..f263258 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -20,8 +20,8 @@
 from tempest.api.identity import base
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
-from tempest import test
 
 
 CONF = config.CONF
@@ -78,7 +78,7 @@
         time.sleep(1)
         self.non_admin_users_client.auth_provider.set_auth()
 
-    @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
+    @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
     def test_user_update_own_password(self):
         old_pass = self.creds.password
         old_token = self.non_admin_client.token
@@ -103,7 +103,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
-    @test.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
+    @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
     def test_password_history_check_self_service_api(self):
         old_pass = self.creds.password
         new_pass1 = data_utils.rand_password()
@@ -133,7 +133,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
-    @test.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
+    @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
     def test_user_account_lockout(self):
         password = self.creds.password
 
diff --git a/tempest/api/volume/v2/test_volumes_snapshots_list.py b/tempest/api/volume/v2/test_volumes_snapshots_list.py
index f389b59..3deb437 100644
--- a/tempest/api/volume/v2/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/v2/test_volumes_snapshots_list.py
@@ -15,7 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -56,33 +56,33 @@
         self.assertEqual(sorted(sorted_list, reverse=(sort_dir == 'desc')),
                          sorted_list, msg)
 
-    @test.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388')
+    @decorators.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388')
     def test_snapshot_list_param_sort_id_asc(self):
         self._list_snapshots_param_sort(sort_key='id', sort_dir='asc')
 
-    @test.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b')
+    @decorators.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b')
     def test_snapshot_list_param_sort_id_desc(self):
         self._list_snapshots_param_sort(sort_key='id', sort_dir='desc')
 
-    @test.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0')
+    @decorators.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0')
     def test_snapshot_list_param_sort_created_at_asc(self):
         self._list_snapshots_param_sort(sort_key='created_at', sort_dir='asc')
 
-    @test.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf')
+    @decorators.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf')
     def test_snapshot_list_param_sort_created_at_desc(self):
         self._list_snapshots_param_sort(sort_key='created_at', sort_dir='desc')
 
-    @test.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00')
+    @decorators.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00')
     def test_snapshot_list_param_sort_name_asc(self):
         self._list_snapshots_param_sort(sort_key='display_name',
                                         sort_dir='asc')
 
-    @test.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250')
+    @decorators.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250')
     def test_snapshot_list_param_sort_name_desc(self):
         self._list_snapshots_param_sort(sort_key='display_name',
                                         sort_dir='desc')
 
-    @test.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7')
+    @decorators.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7')
     def test_snapshot_list_param_marker(self):
         # The list of snapshots should end before the provided marker
         params = {'marker': self.snapshot_id_list[1]}
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index 2fe957b..283b10f 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -27,6 +27,7 @@
 import six.moves.urllib.parse as urlparse
 
 # TODO(oomichi): Need to remove this after switching all modules to decorators
+# on all OpenStack projects because they runs check-uuid on their own gates.
 OLD_DECORATOR_MODULE = 'test'
 
 DECORATOR_MODULE = 'decorators'
@@ -120,7 +121,7 @@
 
     @staticmethod
     def _get_idempotent_id(test_node):
-        """Return key-value dict with all metadata from @test.idempotent_id"""
+        "Return key-value dict with metadata from @decorators.idempotent_id"
         idempotent_id = None
         for decorator in test_node.decorator_list:
             if (hasattr(decorator, 'func') and
@@ -308,7 +309,8 @@
         Returns true if untagged tests exist.
         """
         def report(module_name, test_name, tests):
-            error_str = "%s:%s\nmissing @test.idempotent_id('...')\n%s\n" % (
+            error_str = ("%s:%s\nmissing @decorators.idempotent_id"
+                         "('...')\n%s\n") % (
                 tests[module_name]['source_path'],
                 tests[module_name]['tests'][test_name].lineno,
                 test_name
@@ -356,7 +358,8 @@
     else:
         errors = checker.report_untagged(untagged) or errors
     if errors:
-        sys.exit("@test.idempotent_id existence and uniqueness checks failed\n"
+        sys.exit("@decorators.idempotent_id existence and uniqueness checks "
+                 "failed\n"
                  "Run 'tox -v -euuidgen' to automatically fix tests with\n"
                  "missing @test.idempotent_id decorators.")
 
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 0c25664..cc54a39 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
-
 from oslo_log import log as logging
 import testtools
 
@@ -63,21 +61,17 @@
         snapshot_name = data_utils.rand_name('scenario-snapshot')
         snapshot = self.snapshots_client.create_snapshot(
             volume_id=volume['id'], display_name=snapshot_name)['snapshot']
-
-        def cleaner():
-            self.snapshots_client.delete_snapshot(snapshot['id'])
-            try:
-                while self.snapshots_client.show_snapshot(
-                        snapshot['id'])['snapshot']:
-                    time.sleep(1)
-            except lib_exc.NotFound:
-                pass
-        self.addCleanup(cleaner)
+        self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
+                        snapshot['id'])
+        self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
         waiters.wait_for_volume_status(self.volumes_client,
                                        volume['id'], 'available')
         waiters.wait_for_snapshot_status(self.snapshots_client,
                                          snapshot['id'], 'available')
-        self.assertEqual(snapshot_name, snapshot['display_name'])
+        if 'display_name' in snapshot:
+            self.assertEqual(snapshot_name, snapshot['display_name'])
+        else:
+            self.assertEqual(snapshot_name, snapshot['name'])
         return snapshot
 
     def _wait_for_volume_available_on_the_system(self, ip_address,
@@ -94,7 +88,6 @@
                                           CONF.compute.build_interval):
             raise lib_exc.TimeoutException
 
-    @decorators.skip_because(bug="1205344")
     @decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
@@ -109,7 +102,7 @@
         server = self.create_server(
             image_id=CONF.compute.image_ref,
             key_name=keypair['name'],
-            security_groups=security_group)
+            security_groups=[{'name': security_group['name']}])
 
         # create and add floating IP to server1
         ip_for_server = self.get_server_ip(server)
@@ -136,7 +129,7 @@
         server_from_snapshot = self.create_server(
             image_id=snapshot_image['id'],
             key_name=keypair['name'],
-            security_groups=security_group)
+            security_groups=[{'name': security_group['name']}])
 
         # create and add floating IP to server_from_snapshot
         ip_for_snapshot = self.get_server_ip(server_from_snapshot)
diff --git a/tempest/test.py b/tempest/test.py
index 039afa1..06de520 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -39,7 +39,11 @@
 
 CONF = config.CONF
 
-idempotent_id = decorators.idempotent_id
+# TODO(oomichi): This test.idempotent_id should be removed after all projects
+# switch to use decorators.idempotent_id.
+idempotent_id = debtcollector.moves.moved_function(
+    decorators.idempotent_id, 'idempotent_id', __name__,
+    version='Mitaka', removal_version='?')
 
 
 def attr(**kwargs):