Merge "Remove the skip for test_get_instance_action()"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index bf0b308..2ed2582 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -740,6 +740,11 @@
 # all which indicates every extension is enabled (list value)
 #api_extensions=all
 
+# Allow the execution of IPv6 subnet tests that use the
+# extended IPv6 attributes ipv6_ra_mode and ipv6_address_mode
+# (boolean value)
+#ipv6_subnet_attributes=false
+
 
 [object-storage]
 
@@ -845,6 +850,28 @@
 # queues (integer value)
 #max_queues_per_page=20
 
+# The maximum metadata size for a queue (integer value)
+#max_queue_metadata=65536
+
+# The maximum number of queue message per page when listing
+# (or) posting messages (integer value)
+#max_messages_per_page=20
+
+# The maximum size of a message body (integer value)
+#max_message_size=262144
+
+# The maximum number of messages per claim (integer value)
+#max_messages_per_claim=20
+
+# The maximum ttl for a message (integer value)
+#max_message_ttl=1209600
+
+# The maximum ttl for a claim (integer value)
+#max_claim_ttl=43200
+
+# The maximum grace period for a claim (integer value)
+#max_claim_grace=43200
+
 
 [scenario]
 
diff --git a/tempest/api/baremetal/test_nodes.py b/tempest/api/baremetal/test_nodes.py
index b6432ad..1572840 100644
--- a/tempest/api/baremetal/test_nodes.py
+++ b/tempest/api/baremetal/test_nodes.py
@@ -87,3 +87,11 @@
         resp, node = self.client.show_node(node['uuid'])
         self.assertEqual('200', resp['status'])
         self._assertExpected(new_p, node['properties'])
+
+    @test.attr(type='smoke')
+    def test_validate_driver_interface(self):
+        resp, body = self.client.validate_driver_interface(self.node['uuid'])
+        self.assertEqual('200', resp['status'])
+        core_interfaces = ['power', 'deploy']
+        for interface in core_interfaces:
+            self.assertIn(interface, body)
diff --git a/tempest/api/baremetal/test_ports.py b/tempest/api/baremetal/test_ports.py
index c2af29a..4ac7e29 100644
--- a/tempest/api/baremetal/test_ports.py
+++ b/tempest/api/baremetal/test_ports.py
@@ -145,6 +145,19 @@
             self.validate_self_link('ports', port['uuid'],
                                     port['links'][0]['href'])
 
+    def test_list_ports_details_with_address(self):
+        node_id = self.node['uuid']
+        address = data_utils.rand_mac_address()
+        self.create_port(node_id=node_id, address=address)
+        for i in range(0, 5):
+            self.create_port(node_id=node_id,
+                             address=data_utils.rand_mac_address())
+
+        resp, body = self.client.list_ports_detail(address=address)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(1, len(body['ports']))
+        self.assertEqual(address, body['ports'][0]['address'])
+
     @test.attr(type='smoke')
     def test_update_port_replace(self):
         node_id = self.node['uuid']
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index e1dc685..f147b9c 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -44,6 +44,7 @@
 
     # TODO(afazekas): Add dedicated tenant to the skiped quota tests
     # it can be moved into the setUpClass as well
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_cpu_quota_is_full(self):
         # Disallow server creation when tenant's vcpu quota is full
@@ -57,8 +58,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_memory_quota_is_full(self):
         # Disallow server creation when tenant's memory quota is full
@@ -72,8 +74,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
         # Once instances quota limit is reached, disallow server creation
@@ -86,7 +89,7 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
     @test.skip_because(bug="1186354",
                        condition=CONF.service_available.neutron)
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 8b3a0b5..cccaf13 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -54,6 +54,9 @@
             flavor_id = data_utils.rand_int_id(start=1000)
         return flavor_id
 
+    @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_ram(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -67,11 +70,14 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
 
+    @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_vcpus(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -85,7 +91,7 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7c70aec..a1aaa95 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -270,7 +270,7 @@
         if not policy:
             policy = ['affinity']
         resp, body = cls.servers_client.create_server_group(name, policy)
-        cls.server_groups.append(body)
+        cls.server_groups.append(body['id'])
         return resp, body
 
     def wait_for(self, condition):
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 0e6b9d6..c1c2d05 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -89,44 +89,40 @@
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_disk(self):
         # The detailed list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_ram(self):
         # The detailed list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_disk(self):
         # The list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_ram(self):
         # The list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 448b8ff..01ff6b9 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -24,10 +24,7 @@
         super(ServerMetadataTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
-        cls.admin_client = cls._get_identity_admin_client()
-        resp, tenants = cls.admin_client.list_tenants()
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
-
         cls.server_id = server['id']
 
     def setUp(self):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 6343ead..d3297ce 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -106,6 +106,8 @@
         self.assertRaises(exceptions.BadRequest,
                           self.create_test_server, accessIPv6=IPv6)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_nonexistent_server(self):
         # Resize a non-existent server
@@ -114,6 +116,8 @@
                           self.client.resize,
                           nonexistent_server, self.flavor_ref)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_non_existent_flavor(self):
         # Resize a server with non-existent flavor
@@ -121,6 +125,8 @@
         self.assertRaises(exceptions.BadRequest, self.client.resize,
                           self.server_id, flavor_ref=nonexistent_flavor)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_null_flavor(self):
         # Resize a server with null flavor
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 375ddf8..fb8ded3 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import StringIO
+
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -27,9 +29,10 @@
 
 
 class AuthorizationTestJSON(base.BaseV2ComputeTest):
-
     @classmethod
     def setUpClass(cls):
+        if not CONF.service_available.glance:
+            raise cls.skipException('Glance is not available.')
         # No network resources required for this test
         cls.set_network_resources()
         super(AuthorizationTestJSON, cls).setUpClass()
@@ -38,6 +41,7 @@
             raise cls.skipException(msg)
         cls.client = cls.os.servers_client
         cls.images_client = cls.os.images_client
+        cls.glance_client = cls.os.image_client
         cls.keypairs_client = cls.os.keypairs_client
         cls.security_client = cls.os.security_groups_client
 
@@ -57,9 +61,14 @@
         resp, cls.server = cls.client.get_server(server['id'])
 
         name = data_utils.rand_name('image')
-        resp, body = cls.images_client.create_image(server['id'], name)
-        image_id = data_utils.parse_image_id(resp['location'])
-        cls.images_client.wait_for_image_status(image_id, 'ACTIVE')
+        resp, body = cls.glance_client.create_image(name=name,
+                                                   container_format='bare',
+                                                   disk_format='raw',
+                                                   is_public=False)
+        image_id = body['id']
+        image_file = StringIO.StringIO(('*' * 1024))
+        resp, body = cls.glance_client.update_image(image_id, data=image_file)
+        cls.glance_client.wait_for_image_status(image_id, 'active')
         resp, cls.image = cls.images_client.get_image(image_id)
 
         cls.keypairname = data_utils.rand_name('keypair')
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 8a4e3cf..09d76b8 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -294,7 +294,7 @@
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
-        ram = " 1024 "
+        ram = "1024"
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  ram, self.vcpus,
                                                  self.disk,
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index 3f8a2da..6d3308e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -57,7 +57,7 @@
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram,
                                                  self.vcpus, self.disk,
-                                                 '',
+                                                 None,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
index 307462f..7739f09 100644
--- a/tempest/api/compute/v3/admin/test_quotas_negative.py
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -34,6 +34,7 @@
 
     # TODO(afazekas): Add dedicated tenant to the skiped quota tests
     # it can be moved into the setUpClass as well
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_cpu_quota_is_full(self):
         # Disallow server creation when tenant's vcpu quota is full
@@ -47,8 +48,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_memory_quota_is_full(self):
         # Disallow server creation when tenant's memory quota is full
@@ -62,7 +64,7 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
     @test.attr(type=['negative', 'gate'])
     def test_update_quota_normal_user(self):
@@ -71,6 +73,7 @@
                           self.demo_tenant_id,
                           ram=0)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
         # Once instances quota limit is reached, disallow server creation
@@ -83,4 +86,4 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index 298cd3c..c5443ee 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -24,9 +24,7 @@
         super(ServerMetadataV3Test, cls).setUpClass()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
-        cls.tenant_id = cls.client.tenant_id
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
-
         cls.server_id = server['id']
 
     def setUp(self):
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index 0d6773c..ab0e83a 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -29,8 +29,8 @@
         if not CONF.service_available.sahara:
             raise cls.skipException('Sahara support is required')
 
-        os = cls.get_client_manager()
-        cls.client = os.data_processing_client
+        cls.os = cls.get_client_manager()
+        cls.client = cls.os.data_processing_client
 
         cls.flavor_ref = CONF.compute.flavor_ref
 
diff --git a/tempest/api/data_processing/test_job_binaries.py b/tempest/api/data_processing/test_job_binaries.py
new file mode 100644
index 0000000..689c1fe
--- /dev/null
+++ b/tempest/api/data_processing/test_job_binaries.py
@@ -0,0 +1,148 @@
+# Copyright (c) 2014 Mirantis 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.api.data_processing import base as dp_base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class JobBinaryTest(dp_base.BaseDataProcessingTest):
+    """Link to the API documentation is http://docs.openstack.org/developer/
+    sahara/restapi/rest_api_v1.1_EDP.html#job-binaries
+    """
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(JobBinaryTest, cls).setUpClass()
+        cls.swift_job_binary_with_extra = {
+            'url': 'swift://sahara-container.sahara/example.jar',
+            'description': 'Test job binary',
+            'extra': {
+                'user': cls.os.credentials.username,
+                'password': cls.os.credentials.password
+            }
+        }
+        # Create extra cls.swift_job_binary variable to use for comparison to
+        # job binary response body because response body has no 'extra' field.
+        cls.swift_job_binary = cls.swift_job_binary_with_extra.copy()
+        del cls.swift_job_binary['extra']
+
+        name = data_utils.rand_name('sahara-internal-job-binary')
+        cls.job_binary_data = 'Some script may be data'
+        job_binary_internal = cls.create_job_binary_internal(
+            name, cls.job_binary_data)[1]
+        cls.internal_db_job_binary = {
+            'url': 'internal-db://%s' % job_binary_internal['id'],
+            'description': 'Test job binary',
+        }
+
+    def _create_job_binary(self, binary_body, binary_name=None):
+        """Creates Job Binary with optional name specified.
+
+        It creates a link to data (jar, pig files, etc.) and ensures response
+        status, job binary name and response body. Returns id and name of
+        created job binary. Data may not exist when using Swift
+        as data storage. In other cases data must exist in storage.
+        """
+        if not binary_name:
+            # generate random name if it's not specified
+            binary_name = data_utils.rand_name('sahara-job-binary')
+
+        # create job binary
+        resp, body = self.create_job_binary(binary_name, **binary_body)
+
+        # ensure that binary created successfully
+        self.assertEqual(202, resp.status)
+        self.assertEqual(binary_name, body['name'])
+        if 'swift' in binary_body['url']:
+            binary_body = self.swift_job_binary
+        self.assertDictContainsSubset(binary_body, body)
+
+        return body['id'], binary_name
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_create(self):
+        self._create_job_binary(self.swift_job_binary_with_extra)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_list(self):
+        binary_info = self._create_job_binary(self.swift_job_binary_with_extra)
+
+        # check for job binary in list
+        resp, binaries = self.client.list_job_binaries()
+        self.assertEqual(200, resp.status)
+        binaries_info = [(binary['id'], binary['name']) for binary in binaries]
+        self.assertIn(binary_info, binaries_info)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_get(self):
+        binary_id, binary_name = self._create_job_binary(
+            self.swift_job_binary_with_extra)
+
+        # check job binary fetch by id
+        resp, binary = self.client.get_job_binary(binary_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(binary_name, binary['name'])
+        self.assertDictContainsSubset(self.swift_job_binary, binary)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_delete(self):
+        binary_id = self._create_job_binary(
+            self.swift_job_binary_with_extra)[0]
+
+        # delete the job binary by id
+        resp = self.client.delete_job_binary(binary_id)[0]
+        self.assertEqual(204, resp.status)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_create(self):
+        self._create_job_binary(self.internal_db_job_binary)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_list(self):
+        binary_info = self._create_job_binary(self.internal_db_job_binary)
+
+        # check for job binary in list
+        resp, binaries = self.client.list_job_binaries()
+        self.assertEqual(200, resp.status)
+        binaries_info = [(binary['id'], binary['name']) for binary in binaries]
+        self.assertIn(binary_info, binaries_info)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_get(self):
+        binary_id, binary_name = self._create_job_binary(
+            self.internal_db_job_binary)
+
+        # check job binary fetch by id
+        resp, binary = self.client.get_job_binary(binary_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(binary_name, binary['name'])
+        self.assertDictContainsSubset(self.internal_db_job_binary, binary)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_delete(self):
+        binary_id = self._create_job_binary(self.internal_db_job_binary)[0]
+
+        # delete the job binary by id
+        resp = self.client.delete_job_binary(binary_id)[0]
+        self.assertEqual(204, resp.status)
+
+    @test.attr(type='smoke')
+    def test_job_binary_get_data(self):
+        binary_id = self._create_job_binary(self.internal_db_job_binary)[0]
+
+        # get data of job binary by id
+        resp, data = self.client.get_job_binary_data(binary_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(data, self.job_binary_data)
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index dd3b576..881f69e 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -108,22 +108,22 @@
         s_name = data_utils.rand_name('service-')
         s_type = data_utils.rand_name('type--')
         s_description = data_utils.rand_name('description-')
-        resp, self.service2 =\
+        resp, service2 =\
             self.service_client.create_service(s_name, s_type,
                                                description=s_description)
-        self.service_ids.append(self.service2['id'])
+        self.service_ids.append(service2['id'])
         # Updating endpoint with new values
         region2 = data_utils.rand_name('region')
         url2 = data_utils.rand_name('url')
         interface2 = 'internal'
         resp, endpoint = \
             self.client.update_endpoint(endpoint_for_update['id'],
-                                        service_id=self.service2['id'],
+                                        service_id=service2['id'],
                                         interface=interface2, url=url2,
                                         region=region2, enabled=False)
         self.assertEqual(resp['status'], '200')
         # Asserting if the attributes of endpoint are updated
-        self.assertEqual(self.service2['id'], endpoint['service_id'])
+        self.assertEqual(service2['id'], endpoint['service_id'])
         self.assertEqual(interface2, endpoint['interface'])
         self.assertEqual(url2, endpoint['url'])
         self.assertEqual(region2, endpoint['region'])
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index cc768fd..087b87a 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -149,7 +149,8 @@
         return network
 
     @classmethod
-    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None):
+    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None,
+                      **kwargs):
         """Wrapper utility that returns a test subnet."""
         # The cidr and mask_bits depend on the ip version.
         if cls._ip_version == 4:
@@ -168,7 +169,8 @@
                     network_id=network['id'],
                     cidr=str(subnet_cidr),
                     ip_version=cls._ip_version,
-                    gateway_ip=gateway)
+                    gateway_ip=gateway,
+                    **kwargs)
                 break
             except exceptions.BadRequest as e:
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index ac0fd11..78cb221 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import netaddr
+import testtools
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
@@ -433,6 +434,29 @@
         self.assertEqual('204', resp['status'])
         self.subnets.pop()
 
+    @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+                          "IPv6 extended attributes for subnets not "
+                          "available")
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_v6_attributes(self):
+        name = data_utils.rand_name('network-')
+        resp, body = self.client.create_network(name=name)
+        self.assertEqual('201', resp['status'])
+        network = body['network']
+        net_id = network['id']
+        subnet = self.create_subnet(network,
+                                    gateway='fe80::1',
+                                    ipv6_ra_mode='slaac',
+                                    ipv6_address_mode='slaac')
+        # Verifies Subnet GW in IPv6
+        self.assertEqual(subnet['gateway_ip'], 'fe80::1')
+        self.assertEqual(subnet['ipv6_ra_mode'], 'slaac')
+        self.assertEqual(subnet['ipv6_address_mode'], 'slaac')
+        # Delete network and subnet
+        resp, body = self.client.delete_network(net_id)
+        self.assertEqual('204', resp['status'])
+        self.subnets.pop()
+
 
 class NetworksIpV6TestXML(NetworksIpV6TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 6b18182..ccc0067 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -44,9 +44,6 @@
                 cls.isolated_creds.get_admin_creds())
             # Get isolated creds for alt user
             cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
-            # Add isolated users to operator role so that they can create a
-            # container in swift.
-            cls._assign_member_role()
         else:
             cls.os = clients.Manager()
             cls.os_admin = clients.AdminManager()
@@ -80,22 +77,6 @@
         super(BaseObjectTest, cls).tearDownClass()
 
     @classmethod
-    def _assign_member_role(cls):
-        primary_creds = cls.isolated_creds.get_primary_creds()
-        alt_creds = cls.isolated_creds.get_alt_creds()
-        swift_role = CONF.object_storage.operator_role
-        try:
-            resp, roles = cls.os_admin.identity_client.list_roles()
-            role = next(r for r in roles if r['name'] == swift_role)
-        except StopIteration:
-            msg = "No role named %s found" % swift_role
-            raise exceptions.NotFound(msg)
-        for creds in [primary_creds, alt_creds]:
-            cls.os_admin.identity_client.assign_user_role(creds.tenant_id,
-                                                          creds.user_id,
-                                                          role['id'])
-
-    @classmethod
     def delete_containers(cls, containers, container_client=None,
                           object_client=None):
         """Remove given containers and all objects in them.
diff --git a/tempest/api/queuing/base.py b/tempest/api/queuing/base.py
index 5649619..f4ff7f1 100644
--- a/tempest/api/queuing/base.py
+++ b/tempest/api/queuing/base.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest import test
@@ -89,3 +90,80 @@
         """Wrapper utility that sets the metadata of a queue."""
         resp, body = cls.client.set_queue_metadata(queue_name, rbody)
         return resp, body
+
+    @classmethod
+    def post_messages(cls, queue_name, rbody):
+        '''Wrapper utility that posts messages to a queue.'''
+        resp, body = cls.client.post_messages(queue_name, rbody)
+
+        return resp, body
+
+    @classmethod
+    def list_messages(cls, queue_name):
+        '''Wrapper utility that lists the messages in a queue.'''
+        resp, body = cls.client.list_messages(queue_name)
+
+        return resp, body
+
+    @classmethod
+    def get_single_message(cls, message_uri):
+        '''Wrapper utility that gets a single message.'''
+        resp, body = cls.client.get_single_message(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def get_multiple_messages(cls, message_uri):
+        '''Wrapper utility that gets multiple messages.'''
+        resp, body = cls.client.get_multiple_messages(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def delete_messages(cls, message_uri):
+        '''Wrapper utility that deletes messages.'''
+        resp, body = cls.client.delete_messages(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def post_claims(cls, queue_name, rbody, url_params=False):
+        '''Wrapper utility that claims messages.'''
+        resp, body = cls.client.post_claims(
+            queue_name, rbody, url_params=False)
+
+        return resp, body
+
+    @classmethod
+    def query_claim(cls, claim_uri):
+        '''Wrapper utility that gets a claim.'''
+        resp, body = cls.client.query_claim(claim_uri)
+
+        return resp, body
+
+    @classmethod
+    def update_claim(cls, claim_uri, rbody):
+        '''Wrapper utility that updates a claim.'''
+        resp, body = cls.client.update_claim(claim_uri, rbody)
+
+        return resp, body
+
+    @classmethod
+    def release_claim(cls, claim_uri):
+        '''Wrapper utility that deletes a claim.'''
+        resp, body = cls.client.release_claim(claim_uri)
+
+        return resp, body
+
+    @classmethod
+    def generate_message_body(cls, repeat=1):
+        '''Wrapper utility that sets the metadata of a queue.'''
+        message_ttl = data_utils.rand_int_id(start=60,
+                                             end=CONF.queuing.max_message_ttl)
+
+        key = data_utils.arbitrary_string(size=20, base_text='QueuingKey')
+        value = data_utils.arbitrary_string(size=20, base_text='QueuingValue')
+        message_body = {key: value}
+
+        rbody = ([{'body': message_body, 'ttl': message_ttl}] * repeat)
+        return rbody
diff --git a/tempest/api/queuing/test_claims.py b/tempest/api/queuing/test_claims.py
new file mode 100644
index 0000000..a306623
--- /dev/null
+++ b/tempest/api/queuing/test_claims.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2014 Rackspace, 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.
+
+import logging
+import urlparse
+
+from tempest.api.queuing import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class TestClaims(base.BaseQueuingTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestClaims, cls).setUpClass()
+        cls.queue_name = data_utils.rand_name('Queues-Test')
+        # Create Queue
+        cls.create_queue(cls.queue_name)
+
+    def _post_and_claim_messages(self, queue_name, repeat=1):
+        # Post Messages
+        message_body = self.generate_message_body(repeat=repeat)
+        self.client.post_messages(queue_name=self.queue_name,
+                                  rbody=message_body)
+
+        # Post Claim
+        claim_ttl = data_utils.rand_int_id(start=60,
+                                           end=CONF.queuing.max_claim_ttl)
+        claim_grace = data_utils.rand_int_id(start=60,
+                                             end=CONF.queuing.max_claim_grace)
+        claim_body = {"ttl": claim_ttl, "grace": claim_grace}
+        resp, body = self.client.post_claims(queue_name=self.queue_name,
+                                             rbody=claim_body)
+
+        return resp, body
+
+    @test.attr(type='smoke')
+    def test_post_claim(self):
+        _, body = self._post_and_claim_messages(queue_name=self.queue_name)
+        claimed_message_uri = body[0]['href']
+
+        # Skipping this step till bug-1331517  is fixed
+        # Get posted claim
+        # self.client.query_claim(claimed_message_uri)
+
+        # Delete Claimed message
+        self.client.delete_messages(claimed_message_uri)
+
+    @test.skip_because(bug="1331517")
+    @test.attr(type='smoke')
+    def test_query_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+
+        # Query Claim
+        claim_uri = resp['location']
+        self.client.query_claim(claim_uri)
+
+        # Delete Claimed message
+        claimed_message_uri = body[0]['href']
+        self.delete_messages(claimed_message_uri)
+
+    @test.skip_because(bug="1328111")
+    @test.attr(type='smoke')
+    def test_update_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+
+        claim_uri = resp['location']
+        claimed_message_uri = body[0]['href']
+
+        # Update Claim
+        claim_ttl = data_utils.rand_int_id(start=60,
+                                           end=CONF.queuing.max_claim_ttl)
+        update_rbody = {"ttl": claim_ttl}
+
+        self.client.update_claim(claim_uri, rbody=update_rbody)
+
+        # Verify claim ttl >= updated ttl value
+        _, body = self.client.query_claim(claim_uri)
+        updated_claim_ttl = body["ttl"]
+        self.assertTrue(updated_claim_ttl >= claim_ttl)
+
+        # Delete Claimed message
+        self.client.delete_messages(claimed_message_uri)
+
+    @test.attr(type='smoke')
+    def test_release_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+        claim_uri = resp['location']
+
+        # Release Claim
+        self.client.release_claim(claim_uri)
+
+        # Delete Claimed message
+        # This will implicitly verify that the claim is deleted.
+        message_uri = urlparse.urlparse(claim_uri).path
+        self.client.delete_messages(message_uri)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.delete_queue(cls.queue_name)
+        super(TestClaims, cls).tearDownClass()
diff --git a/tempest/api/queuing/test_messages.py b/tempest/api/queuing/test_messages.py
new file mode 100644
index 0000000..9546c91
--- /dev/null
+++ b/tempest/api/queuing/test_messages.py
@@ -0,0 +1,122 @@
+# Copyright (c) 2014 Rackspace, 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.
+
+import logging
+
+from tempest.api.queuing import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class TestMessages(base.BaseQueuingTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestMessages, cls).setUpClass()
+        cls.queue_name = data_utils.rand_name('Queues-Test')
+        # Create Queue
+        cls.client.create_queue(cls.queue_name)
+
+    def _post_messages(self, repeat=CONF.queuing.max_messages_per_page):
+        message_body = self.generate_message_body(repeat=repeat)
+        resp, body = self.post_messages(queue_name=self.queue_name,
+                                        rbody=message_body)
+        return resp, body
+
+    @test.attr(type='smoke')
+    def test_post_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+
+        # Get on the posted messages
+        message_uri = resp['location']
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_list_messages(self):
+        # Post Messages
+        self._post_messages()
+
+        # List Messages
+        resp, _ = self.list_messages(queue_name=self.queue_name)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_get_message(self):
+        # Post Messages
+        _, body = self._post_messages()
+        message_uri = body['resources'][0]
+
+        # Get posted message
+        resp, _ = self.client.get_single_message(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_get_multiple_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+        message_uri = resp['location']
+
+        # Get posted messages
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_delete_single_message(self):
+        # Post Messages
+        _, body = self._post_messages()
+        message_uri = body['resources'][0]
+
+        # Delete posted message & verify the delete operration
+        self.client.delete_messages(message_uri)
+
+        message_uri = message_uri.replace('/messages/', '/messages?ids=')
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response has to be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('204', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_delete_multiple_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+        message_uri = resp['location']
+
+        # Delete multiple messages
+        self.client.delete_messages(message_uri)
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response has to be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('204', resp['status'])
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.delete_queue(cls.queue_name)
+        super(TestMessages, cls).tearDownClass()
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/compute/v2/floating_ips.py
index 03e6aef..782f5c8 100644
--- a/tempest/api_schema/compute/v2/floating_ips.py
+++ b/tempest/api_schema/compute/v2/floating_ips.py
@@ -117,3 +117,14 @@
         'required': ['floating_ips_bulk_create']
     }
 }
+
+delete_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_delete': {'type': 'string'}
+        },
+        'required': ['floating_ips_bulk_delete']
+    }
+}
diff --git a/tempest/api_schema/queuing/v1/queues.py b/tempest/api_schema/queuing/v1/queues.py
index 4630e1c..f0b2691 100644
--- a/tempest/api_schema/queuing/v1/queues.py
+++ b/tempest/api_schema/queuing/v1/queues.py
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 list_link = {
     'type': 'object',
     'properties': {
@@ -58,6 +59,11 @@
     }
 }
 
+age = {
+    'type': 'number',
+    'minimum': 0
+}
+
 message_link = {
     'type': 'object',
     'properties': {
@@ -65,7 +71,7 @@
             'type': 'string',
             'format': 'uri'
         },
-        'age': {'type': 'number'},
+        'age': age,
         'created': {
             'type': 'string',
             'format': 'date-time'
@@ -96,3 +102,136 @@
         'required': ['messages']
     }
 }
+
+resource_schema = {
+    'type': 'array',
+    'items': 'string',
+    'minItems': 1
+}
+
+post_messages = {
+    'status_code': [201],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'resources': resource_schema,
+            'partial': {'type': 'boolean'}
+        }
+    },
+    'required': ['resources', 'partial']
+}
+
+message_ttl = {
+    'type': 'number',
+    'minimum': 1
+}
+
+list_messages_links = {
+    'type': 'array',
+    'maxItems': 1,
+    'minItems': 1,
+    'items': {
+        'type': 'object',
+        'properties': {
+            'rel': {'type': 'string'},
+            'href': {'type': 'string'}
+        },
+        'required': ['rel', 'href']
+    }
+}
+
+list_messages_response = {
+    'type': 'array',
+    'minItems': 1,
+    'items': {
+        'type': 'object',
+        'properties': {
+            'href': {'type': 'string'},
+            'ttl': message_ttl,
+            'age': age,
+            'body': {'type': 'object'}
+        },
+        'required': ['href', 'ttl', 'age', 'body']
+    }
+}
+
+list_messages = {
+    'status_code': [200, 204],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'links': list_messages_links,
+            'messages': list_messages_response
+        }
+    },
+    'required': ['links', 'messages']
+}
+
+single_message = {
+    'type': 'object',
+    'properties': {
+        'href': {'type': 'string'},
+        'ttl': message_ttl,
+        'age': age,
+        'body': {'type': 'object'}
+    },
+    'required': ['href', 'ttl', 'age', 'body']
+}
+
+get_single_message = {
+    'status_code': [200],
+    'response_body': single_message
+}
+
+get_multiple_messages = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'array',
+        'items': single_message,
+        'minItems': 1
+    }
+}
+
+messages_claimed = {
+    'type': 'object',
+    'properties': {
+        'href': {
+            'type': 'string',
+            'format': 'uri'
+        },
+        'ttl': message_ttl,
+        'age': {'type': 'number'},
+        'body': {'type': 'object'}
+    },
+    'required': ['href', 'ttl', 'age', 'body']
+}
+
+claim_messages = {
+    'status_code': [201, 204],
+    'response_body': {
+        'type': 'array',
+        'items': messages_claimed,
+        'minItems': 1
+    }
+}
+
+claim_ttl = {
+    'type': 'number',
+    'minimum': 1
+}
+
+query_claim = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'age': {'type': 'number'},
+            'ttl': claim_ttl,
+            'messages': {
+                'type': 'array',
+                'minItems': 1
+            }
+        },
+        'required': ['ttl', 'age', 'messages']
+    }
+}
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 20ee63e..1d46028 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -35,6 +35,7 @@
 from tempest.services.image.v2.json import image_client
 from tempest.services.object_storage import container_client
 from tempest.services.object_storage import object_client
+from tempest.services.volume.json import volumes_client
 
 OPTS = {}
 USERS = {}
@@ -60,6 +61,7 @@
         self.containers = container_client.ContainerClient(_auth)
         self.images = image_client.ImageClientV2JSON(_auth)
         self.flavors = flavors_client.FlavorsClientJSON(_auth)
+        self.volumes = volumes_client.VolumesClientJSON(_auth)
 
 
 def load_resources(fname):
@@ -190,6 +192,7 @@
         self.check_users()
         self.check_objects()
         self.check_servers()
+        self.check_volumes()
 
     def check_users(self):
         """Check that the users we expect to exist, do.
@@ -235,6 +238,21 @@
                              "Server %s is not pingable at %s" % (
                                  server['name'], addr))
 
+    def check_volumes(self):
+        """Check that the volumes are still there and attached."""
+        for volume in self.res['volumes']:
+            client = client_for_user(volume['owner'])
+            found = _get_volume_by_name(client, volume['name'])
+            self.assertIsNotNone(
+                found,
+                "Couldn't find expected volume %s" % volume['name'])
+
+            # Verify that a volume's attachment retrieved
+            server_id = _get_server_by_name(client, volume['server'])['id']
+            attachment = self.client.get_attachment_from_volume(volume)
+            self.assertEqual(volume['id'], attachment['volume_id'])
+            self.assertEqual(server_id, attachment['server_id'])
+
 
 #######################
 #
@@ -339,6 +357,40 @@
 
 #######################
 #
+# VOLUMES
+#
+#######################
+
+def _get_volume_by_name(client, name):
+    r, body = client.volumes.list_volumes()
+    for volume in body['volumes']:
+        if name == volume['name']:
+            return volume
+    return None
+
+
+def create_volumes(volumes):
+    for volume in volumes:
+        client = client_for_user(volume['owner'])
+
+        # only create a volume if the name isn't here
+        r, body = client.volumes.list_volumes()
+        if any(item['name'] == volume['name'] for item in body):
+            continue
+
+        client.volumes.create_volume(volume['name'], volume['size'])
+
+
+def attach_volumes(volumes):
+    for volume in volumes:
+        client = client_for_user(volume['owner'])
+
+        server_id = _get_server_by_name(client, volume['server'])['id']
+        client.volumes.attach_volume(volume['name'], server_id)
+
+
+#######################
+#
 # MAIN LOGIC
 #
 #######################
@@ -355,6 +407,8 @@
     create_objects(RES['objects'])
     create_images(RES['images'])
     create_servers(RES['servers'])
+    create_volumes(RES['volumes'])
+    attach_volumes(RES['volumes'])
 
 
 def get_options():
diff --git a/tempest/cmd/resources.yaml b/tempest/cmd/resources.yaml
index f7cb8a9..a1f567b 100644
--- a/tempest/cmd/resources.yaml
+++ b/tempest/cmd/resources.yaml
@@ -32,9 +32,14 @@
     aki: cirros-0.3.2-x86_64-vmlinuz
     ari: cirros-0.3.2-x86_64-initrd
 volumes:
-  - assegai:
-    - owner: javelin
-    - gb: 1
+  - name: assegai
+    server: peltast
+    owner: javelin
+    size: 1
+  - name: pifpouf
+    server: hoplite
+    owner: javelin
+    size: 2
 servers:
   - name: peltast
     owner: javelin
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index b4618ed..8166de5 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -106,12 +106,23 @@
             roles = self.identity_admin_client.roles.list()
         return roles
 
-    def _assign_user_role(self, tenant, user, role):
+    def _assign_user_role(self, tenant, user, role_name):
+        role = None
+        try:
+            roles = self._list_roles()
+            if self.tempest_client:
+                role = next(r for r in roles if r['name'] == role_name)
+            else:
+                role = next(r for r in roles if r.name == role_name)
+        except StopIteration:
+            msg = 'No "%s" role found' % role_name
+            raise exceptions.NotFound(msg)
         if self.tempest_client:
-            self.identity_admin_client.assign_user_role(tenant, user, role)
+            self.identity_admin_client.assign_user_role(tenant['id'],
+                                                        user['id'], role['id'])
         else:
-            self.identity_admin_client.roles.add_user_role(user,
-                                                           role, tenant=tenant)
+            self.identity_admin_client.roles.add_user_role(user.id, role.id,
+                                                           tenant.id)
 
     def _delete_user(self, user):
         if self.tempest_client:
@@ -149,22 +160,11 @@
         email = data_utils.rand_name(root) + suffix + "@example.com"
         user = self._create_user(username, self.password,
                                  tenant, email)
+        # NOTE(andrey-mp): user needs this role to create containers in swift
+        swift_operator_role = CONF.object_storage.operator_role
+        self._assign_user_role(tenant, user, swift_operator_role)
         if admin:
-            role = None
-            try:
-                roles = self._list_roles()
-                admin_role = CONF.identity.admin_role
-                if self.tempest_client:
-                    role = next(r for r in roles if r['name'] == admin_role)
-                else:
-                    role = next(r for r in roles if r.name == admin_role)
-            except StopIteration:
-                msg = "No admin role found"
-                raise exceptions.NotFound(msg)
-            if self.tempest_client:
-                self._assign_user_role(tenant['id'], user['id'], role['id'])
-            else:
-                self._assign_user_role(tenant.id, user.id, role.id)
+            self._assign_user_role(tenant, user, CONF.identity.admin_role)
         return self._get_credentials(user, tenant)
 
     def _get_credentials(self, user, tenant):
diff --git a/tempest/config.py b/tempest/config.py
index 7d871cb..6475844 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -442,6 +442,12 @@
                 default=['all'],
                 help='A list of enabled network extensions with a special '
                      'entry all which indicates every extension is enabled'),
+    cfg.BoolOpt('ipv6_subnet_attributes',
+                default=False,
+                help="Allow the execution of IPv6 subnet tests that use "
+                     "the extended IPv6 attributes ipv6_ra_mode "
+                     "and ipv6_address_mode"
+                )
 ]
 
 queuing_group = cfg.OptGroup(name='queuing',
@@ -455,6 +461,28 @@
                default=20,
                help='The maximum number of queue records per page when '
                     'listing queues'),
+    cfg.IntOpt('max_queue_metadata',
+               default=65536,
+               help='The maximum metadata size for a queue'),
+    cfg.IntOpt('max_messages_per_page',
+               default=20,
+               help='The maximum number of queue message per page when '
+                    'listing (or) posting messages'),
+    cfg.IntOpt('max_message_size',
+               default=262144,
+               help='The maximum size of a message body'),
+    cfg.IntOpt('max_messages_per_claim',
+               default=20,
+               help='The maximum number of messages per claim'),
+    cfg.IntOpt('max_message_ttl',
+               default=1209600,
+               help='The maximum ttl for a message'),
+    cfg.IntOpt('max_claim_ttl',
+               default=43200,
+               help='The maximum ttl for a claim'),
+    cfg.IntOpt('max_claim_grace',
+               default=43200,
+               help='The maximum grace period for a claim'),
 ]
 
 volume_group = cfg.OptGroup(name='volume',
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4e35aaa..93329bc 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -105,9 +105,24 @@
                             "T107: service tag should not be in path")
 
 
+def no_official_client_manager_in_api_tests(physical_line, filename):
+    """Check that the OfficialClientManager isn't used in the api tests
+
+    The api tests should not use the official clients.
+
+    T108: Can not use OfficialClientManager in the API tests
+    """
+    if 'tempest/api' in filename:
+        if 'OfficialClientManager' in physical_line:
+            return (physical_line.find('OfficialClientManager'),
+                    'T108: OfficialClientManager can not be used in the api '
+                    'tests')
+
+
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
     register(no_setupclass_for_unit_tests)
     register(no_vi_headers)
     register(service_tags_not_in_module_path)
+    register(no_official_client_manager_in_api_tests)
diff --git a/tempest/openstack/common/config/generator.py b/tempest/openstack/common/config/generator.py
index 8156cc5..664200e 100644
--- a/tempest/openstack/common/config/generator.py
+++ b/tempest/openstack/common/config/generator.py
@@ -150,7 +150,7 @@
 
 
 def _is_in_group(opt, group):
-    "Check if opt is in group."
+    """Check if opt is in group."""
     for value in group._opts.values():
         # NOTE(llu): Temporary workaround for bug #1262148, wait until
         # newly released oslo.config support '==' operator.
@@ -159,7 +159,7 @@
     return False
 
 
-def _guess_groups(opt, mod_obj):
+def _guess_groups(opt):
     # is it in the DEFAULT group?
     if _is_in_group(opt, cfg.CONF):
         return 'DEFAULT'
@@ -193,7 +193,7 @@
 
     ret = {}
     for opt in opts:
-        ret.setdefault(_guess_groups(opt, obj), []).append(opt)
+        ret.setdefault(_guess_groups(opt), []).append(opt)
     return ret.items()
 
 
@@ -223,6 +223,8 @@
 
 def _sanitize_default(name, value):
     """Set up a reasonably sensible default for pybasedir, my_ip and host."""
+    hostname = socket.gethostname()
+    fqdn = socket.getfqdn()
     if value.startswith(sys.prefix):
         # NOTE(jd) Don't use os.path.join, because it is likely to think the
         # second part is an absolute pathname and therefore drop the first
@@ -234,8 +236,13 @@
         return value.replace(BASEDIR, '')
     elif value == _get_my_ip():
         return '10.0.0.1'
-    elif value in (socket.gethostname(), socket.getfqdn()) and 'host' in name:
-        return 'tempest'
+    elif value in (hostname, fqdn):
+        if 'host' in name:
+            return 'tempest'
+    elif value.endswith(hostname):
+        return value.replace(hostname, 'tempest')
+    elif value.endswith(fqdn):
+        return value.replace(fqdn, 'tempest')
     elif value.strip() != value:
         return '"%s"' % value
     return value
@@ -246,7 +253,6 @@
     if not opt_help:
         sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
         opt_help = ""
-    opt_type = None
     try:
         opt_type = OPTION_REGEX.search(str(type(opt))).group(0)
     except (ValueError, AttributeError) as err:
diff --git a/tempest/openstack/common/gettextutils.py b/tempest/openstack/common/gettextutils.py
index 17f66f7..6102e67 100644
--- a/tempest/openstack/common/gettextutils.py
+++ b/tempest/openstack/common/gettextutils.py
@@ -32,24 +32,113 @@
 from babel import localedata
 import six
 
-_localedir = os.environ.get('tempest'.upper() + '_LOCALEDIR')
-_t = gettext.translation('tempest', localedir=_localedir, fallback=True)
-
-# We use separate translation catalogs for each log level, so set up a
-# mapping between the log level name and the translator. The domain
-# for the log level is project_name + "-log-" + log_level so messages
-# for each level end up in their own catalog.
-_t_log_levels = dict(
-    (level, gettext.translation('tempest' + '-log-' + level,
-                                localedir=_localedir,
-                                fallback=True))
-    for level in ['info', 'warning', 'error', 'critical']
-)
-
 _AVAILABLE_LANGUAGES = {}
+
+# FIXME(dhellmann): Remove this when moving to oslo.i18n.
 USE_LAZY = False
 
 
+class TranslatorFactory(object):
+    """Create translator functions
+    """
+
+    def __init__(self, domain, lazy=False, localedir=None):
+        """Establish a set of translation functions for the domain.
+
+        :param domain: Name of translation domain,
+                       specifying a message catalog.
+        :type domain: str
+        :param lazy: Delays translation until a message is emitted.
+                     Defaults to False.
+        :type lazy: Boolean
+        :param localedir: Directory with translation catalogs.
+        :type localedir: str
+        """
+        self.domain = domain
+        self.lazy = lazy
+        if localedir is None:
+            localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
+        self.localedir = localedir
+
+    def _make_translation_func(self, domain=None):
+        """Return a new translation function ready for use.
+
+        Takes into account whether or not lazy translation is being
+        done.
+
+        The domain can be specified to override the default from the
+        factory, but the localedir from the factory is always used
+        because we assume the log-level translation catalogs are
+        installed in the same directory as the main application
+        catalog.
+
+        """
+        if domain is None:
+            domain = self.domain
+        if self.lazy:
+            return functools.partial(Message, domain=domain)
+        t = gettext.translation(
+            domain,
+            localedir=self.localedir,
+            fallback=True,
+        )
+        if six.PY3:
+            return t.gettext
+        return t.ugettext
+
+    @property
+    def primary(self):
+        "The default translation function."
+        return self._make_translation_func()
+
+    def _make_log_translation_func(self, level):
+        return self._make_translation_func(self.domain + '-log-' + level)
+
+    @property
+    def log_info(self):
+        "Translate info-level log messages."
+        return self._make_log_translation_func('info')
+
+    @property
+    def log_warning(self):
+        "Translate warning-level log messages."
+        return self._make_log_translation_func('warning')
+
+    @property
+    def log_error(self):
+        "Translate error-level log messages."
+        return self._make_log_translation_func('error')
+
+    @property
+    def log_critical(self):
+        "Translate critical-level log messages."
+        return self._make_log_translation_func('critical')
+
+
+# NOTE(dhellmann): When this module moves out of the incubator into
+# oslo.i18n, these global variables can be moved to an integration
+# module within each application.
+
+# Create the global translation functions.
+_translators = TranslatorFactory('tempest')
+
+# The primary translation function using the well-known name "_"
+_ = _translators.primary
+
+# Translators for log levels.
+#
+# The abbreviated names are meant to reflect the usual use of a short
+# name like '_'. The "L" is for "log" and the other letter comes from
+# the level.
+_LI = _translators.log_info
+_LW = _translators.log_warning
+_LE = _translators.log_error
+_LC = _translators.log_critical
+
+# NOTE(dhellmann): End of globals that will move to the application's
+# integration module.
+
+
 def enable_lazy():
     """Convenience function for configuring _() to use lazy gettext
 
@@ -58,41 +147,18 @@
     your project is importing _ directly instead of using the
     gettextutils.install() way of importing the _ function.
     """
-    global USE_LAZY
+    # FIXME(dhellmann): This function will be removed in oslo.i18n,
+    # because the TranslatorFactory makes it superfluous.
+    global _, _LI, _LW, _LE, _LC, USE_LAZY
+    tf = TranslatorFactory('tempest', lazy=True)
+    _ = tf.primary
+    _LI = tf.log_info
+    _LW = tf.log_warning
+    _LE = tf.log_error
+    _LC = tf.log_critical
     USE_LAZY = True
 
 
-def _(msg):
-    if USE_LAZY:
-        return Message(msg, domain='tempest')
-    else:
-        if six.PY3:
-            return _t.gettext(msg)
-        return _t.ugettext(msg)
-
-
-def _log_translation(msg, level):
-    """Build a single translation of a log message
-    """
-    if USE_LAZY:
-        return Message(msg, domain='tempest' + '-log-' + level)
-    else:
-        translator = _t_log_levels[level]
-        if six.PY3:
-            return translator.gettext(msg)
-        return translator.ugettext(msg)
-
-# Translators for log levels.
-#
-# The abbreviated names are meant to reflect the usual use of a short
-# name like '_'. The "L" is for "log" and the other letter comes from
-# the level.
-_LI = functools.partial(_log_translation, level='info')
-_LW = functools.partial(_log_translation, level='warning')
-_LE = functools.partial(_log_translation, level='error')
-_LC = functools.partial(_log_translation, level='critical')
-
-
 def install(domain, lazy=False):
     """Install a _() function using the given translation domain.
 
@@ -112,26 +178,9 @@
                  any available locale.
     """
     if lazy:
-        # NOTE(mrodden): Lazy gettext functionality.
-        #
-        # The following introduces a deferred way to do translations on
-        # messages in OpenStack. We override the standard _() function
-        # and % (format string) operation to build Message objects that can
-        # later be translated when we have more information.
-        def _lazy_gettext(msg):
-            """Create and return a Message object.
-
-            Lazy gettext function for a given domain, it is a factory method
-            for a project/module to get a lazy gettext function for its own
-            translation domain (i.e. nova, glance, cinder, etc.)
-
-            Message encapsulates a string so that we can translate
-            it later when needed.
-            """
-            return Message(msg, domain=domain)
-
         from six import moves
-        moves.builtins.__dict__['_'] = _lazy_gettext
+        tf = TranslatorFactory(domain, lazy=True)
+        moves.builtins.__dict__['_'] = tf.primary
     else:
         localedir = '%s_LOCALEDIR' % domain.upper()
         if six.PY3:
@@ -274,13 +323,14 @@
     def __radd__(self, other):
         return self.__add__(other)
 
-    def __str__(self):
-        # NOTE(luisg): Logging in python 2.6 tries to str() log records,
-        # and it expects specifically a UnicodeError in order to proceed.
-        msg = _('Message objects do not support str() because they may '
-                'contain non-ascii characters. '
-                'Please use unicode() or translate() instead.')
-        raise UnicodeError(msg)
+    if six.PY2:
+        def __str__(self):
+            # NOTE(luisg): Logging in python 2.6 tries to str() log records,
+            # and it expects specifically a UnicodeError in order to proceed.
+            msg = _('Message objects do not support str() because they may '
+                    'contain non-ascii characters. '
+                    'Please use unicode() or translate() instead.')
+            raise UnicodeError(msg)
 
 
 def get_available_languages(domain):
diff --git a/tempest/openstack/common/importutils.py b/tempest/openstack/common/importutils.py
index 6c0d3b2..d5dd22f 100644
--- a/tempest/openstack/common/importutils.py
+++ b/tempest/openstack/common/importutils.py
@@ -24,10 +24,10 @@
 def import_class(import_str):
     """Returns a class from a string including module and class."""
     mod_str, _sep, class_str = import_str.rpartition('.')
+    __import__(mod_str)
     try:
-        __import__(mod_str)
         return getattr(sys.modules[mod_str], class_str)
-    except (ValueError, AttributeError):
+    except AttributeError:
         raise ImportError('Class %s cannot be found (%s)' %
                           (class_str,
                            traceback.format_exception(*sys.exc_info())))
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 07d8828..e6593db 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -21,6 +21,7 @@
 import subprocess
 import time
 
+from cinderclient import exceptions as cinder_exceptions
 from heatclient import exc as heat_exceptions
 import netaddr
 from neutronclient.common import exceptions as exc
@@ -354,7 +355,7 @@
         return server
 
     def create_volume(self, client=None, size=1, name=None,
-                      snapshot_id=None, imageRef=None):
+                      snapshot_id=None, imageRef=None, volume_type=None):
         if client is None:
             client = self.volume_client
         if name is None:
@@ -362,7 +363,8 @@
         LOG.debug("Creating a volume (size: %s, name: %s)", size, name)
         volume = client.volumes.create(size=size, display_name=name,
                                        snapshot_id=snapshot_id,
-                                       imageRef=imageRef)
+                                       imageRef=imageRef,
+                                       volume_type=volume_type)
         self.set_resource(name, volume)
         self.assertEqual(name, volume.display_name)
         self.status_timeout(client.volumes, volume.id, 'available')
@@ -623,6 +625,84 @@
             timeout=CONF.baremetal.unprovision_timeout)
 
 
+class EncryptionScenarioTest(OfficialClientTest):
+    """
+    Base class for encryption scenario tests
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(EncryptionScenarioTest, cls).setUpClass()
+
+        # use admin credentials to create encrypted volume types
+        admin_creds = cls.admin_credentials()
+        manager = clients.OfficialClientManager(credentials=admin_creds)
+        cls.admin_volume_client = manager.volume_client
+
+    def _wait_for_volume_status(self, status):
+        self.status_timeout(
+            self.volume_client.volumes, self.volume.id, status)
+
+    def _wait_for_volume_deletion(self):
+        self.delete_timeout(
+            self.volume_client.volumes, self.volume.id,
+            not_found_exception=cinder_exceptions.NotFound)
+
+    def nova_boot(self):
+        self.keypair = self.create_keypair()
+        create_kwargs = {'key_name': self.keypair.name}
+        self.server = self.create_server(self.compute_client,
+                                         image=self.image,
+                                         create_kwargs=create_kwargs)
+
+    def create_volume_type(self, client=None, name=None):
+        if not client:
+            client = self.admin_volume_client
+        if not name:
+            name = 'generic'
+        randomized_name = data_utils.rand_name('scenario-type-' + name + '-')
+        LOG.debug("Creating a volume type: %s", randomized_name)
+        volume_type = client.volume_types.create(randomized_name)
+        self.addCleanup(client.volume_types.delete, volume_type.id)
+        return volume_type
+
+    def create_encryption_type(self, client=None, type_id=None, provider=None,
+                               key_size=None, cipher=None,
+                               control_location=None):
+        if not client:
+            client = self.admin_volume_client
+        if not type_id:
+            volume_type = self.create_volume_type()
+            type_id = volume_type.id
+        LOG.debug("Creating an encryption type for volume type: %s", type_id)
+        client.volume_encryption_types.create(type_id,
+                                              {'provider': provider,
+                                               'key_size': key_size,
+                                               'cipher': cipher,
+                                               'control_location':
+                                               control_location})
+
+    def nova_volume_attach(self):
+        attach_volume_client = self.compute_client.volumes.create_server_volume
+        volume = attach_volume_client(self.server.id,
+                                      self.volume.id,
+                                      '/dev/vdb')
+        self.assertEqual(self.volume.id, volume.id)
+        self._wait_for_volume_status('in-use')
+
+    def nova_volume_detach(self):
+        detach_volume_client = self.compute_client.volumes.delete_server_volume
+        detach_volume_client(self.server.id, self.volume.id)
+        self._wait_for_volume_status('available')
+
+        volume = self.volume_client.volumes.get(self.volume.id)
+        self.assertEqual('available', volume.status)
+
+    def cinder_delete_encrypted(self):
+        self.volume_client.volumes.delete(self.volume.id)
+        self._wait_for_volume_deletion()
+
+
 class NetworkScenarioTest(OfficialClientTest):
     """
     Base class for network scenario tests
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
new file mode 100644
index 0000000..f223cbf
--- /dev/null
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory
+# 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.scenario import manager
+from tempest import test
+
+
+class TestEncryptedCinderVolumes(manager.EncryptionScenarioTest):
+
+    """
+    This test is for verifying the functionality of encrypted cinder volumes.
+
+    For both LUKS and cryptsetup encryption types, this test performs
+    the following:
+        * Creates an image in Glance
+        * Boots an instance from the image
+        * Creates an encryption type (as admin)
+        * Creates a volume of that encryption type (as a regular user)
+        * Attaches and detaches the encrypted volume to the instance
+        * Deletes the encrypted volume
+    """
+
+    def launch_instance(self):
+        self.glance_image_create()
+        self.nova_boot()
+
+    def create_encrypted_volume(self, encryption_provider):
+        volume_type = self.create_volume_type(name='luks')
+        self.create_encryption_type(type_id=volume_type.id,
+                                    provider=encryption_provider,
+                                    key_size=512,
+                                    cipher='aes-xts-plain64',
+                                    control_location='front-end')
+        self.volume = self.create_volume(volume_type=volume_type.name)
+
+    def attach_detach_volume(self):
+        self.nova_volume_attach()
+        self.nova_volume_detach()
+
+    def delete_volume(self):
+        self.cinder_delete_encrypted()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_luks(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'luks.LuksEncryptor')
+        self.attach_detach_volume()
+        self.delete_volume()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_cryptsetup(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'cryptsetup.CryptsetupEncryptor')
+        self.attach_detach_volume()
+        self.delete_volume()
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 03cfef5..826da48 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 
-import httplib
 import tempfile
 import time
 import urllib2
@@ -150,7 +149,10 @@
                 private_key=private_key)
 
             # Write a backend's responce into a file
-            resp = """HTTP/1.0 200 OK\r\nContent-Length: 8\r\n\r\n%s"""
+            resp = """echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n""" \
+                   """Connection: close\r\nContent-Type: text/html; """ \
+                   """charset=UTF-8\r\n\r\n%s"; cat >/dev/null"""
+
             with tempfile.NamedTemporaryFile() as script:
                 script.write(resp % server_name)
                 script.flush()
@@ -158,15 +160,17 @@
                     key.write(private_key)
                     key.flush()
                     commands.copy_file_to_host(script.name,
-                                               "~/script1",
+                                               "/tmp/script1",
                                                ip,
                                                username, key.name)
+
             # Start netcat
-            start_server = """sudo nc -ll -p %(port)s -e cat """ \
-                           """~/%(script)s &"""
+            start_server = """sudo nc -ll -p %(port)s -e sh """ \
+                           """/tmp/%(script)s &"""
             cmd = start_server % {'port': self.port1,
                                   'script': 'script1'}
             ssh_client.exec_command(cmd)
+
             if len(self.server_ips) == 1:
                 with tempfile.NamedTemporaryFile() as script:
                     script.write(resp % 'server2')
@@ -175,7 +179,7 @@
                         key.write(private_key)
                         key.flush()
                         commands.copy_file_to_host(script.name,
-                                                   "~/script2", ip,
+                                                   "/tmp/script2", ip,
                                                    username, key.name)
                 cmd = start_server % {'port': self.port2,
                                       'script': 'script2'}
@@ -281,19 +285,14 @@
     def _send_requests(self, vip_ip, expected, num_req=10):
         count = 0
         while count < num_req:
-            try:
-                resp = []
-                for i in range(len(self.members)):
-                    resp.append(
-                        urllib2.urlopen(
-                            "http://{0}/".format(vip_ip)).read())
-                count += 1
-                self.assertEqual(expected,
-                                 set(resp))
-            # NOTE: There always is a slim chance of getting this exception
-            #       due to special aspects of haproxy internal behavior.
-            except httplib.BadStatusLine:
-                pass
+            resp = []
+            for i in range(len(self.members)):
+                resp.append(
+                    urllib2.urlopen(
+                        "http://{0}/".format(vip_ip)).read())
+            count += 1
+            self.assertEqual(expected,
+                             set(resp))
 
     @test.attr(type='smoke')
     @test.services('compute', 'network')
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 321b08b..f98ecff 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -122,7 +122,7 @@
 
         return resp, self.deserialize(body)
 
-    def _show_request(self, resource, uuid, permanent=False):
+    def _show_request(self, resource, uuid, permanent=False, **kwargs):
         """
         Gets a specific object of the specified type.
 
@@ -130,7 +130,10 @@
         :return: Serialized object as a dictionary.
 
         """
-        uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
+        if 'uri' in kwargs:
+            uri = kwargs['uri']
+        else:
+            uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
         resp, body = self.get(uri)
 
         return resp, self.deserialize(body)
diff --git a/tempest/services/baremetal/v1/base_v1.py b/tempest/services/baremetal/v1/base_v1.py
index 52479b5..61342eb 100644
--- a/tempest/services/baremetal/v1/base_v1.py
+++ b/tempest/services/baremetal/v1/base_v1.py
@@ -47,9 +47,9 @@
         return self._list_request('/nodes/%s/states' % uuid)
 
     @base.handle_errors
-    def list_ports_detail(self):
+    def list_ports_detail(self, **kwargs):
         """Details list all existing ports."""
-        return self._list_request('/ports/detail')
+        return self._list_request('/ports/detail', **kwargs)
 
     @base.handle_errors
     def list_drivers(self):
@@ -239,3 +239,19 @@
         target = {'target': state}
         return self._put_request('nodes/%s/states/power' % node_uuid,
                                  target)
+
+    @base.handle_errors
+    def validate_driver_interface(self, node_uuid):
+        """
+        Get all driver interfaces of a specific node.
+
+        :param uuid: Unique identifier of the node in UUID format.
+
+        """
+
+        uri = '{pref}/{res}/{uuid}/{postf}'.format(pref=self.uri_prefix,
+                                                   res='nodes',
+                                                   uuid=node_uuid,
+                                                   postf='validate')
+
+        return self._show_request('nodes', node_uuid, uri=uri)
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 7616a99..7af904b 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -37,13 +37,16 @@
                  *args, **kwargs):
         # FIXME(andreaf) replace credentials and auth_url with auth_provider
 
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
+
         self.connection_timeout = str(CONF.boto.http_socket_timeout)
         self.num_retries = str(CONF.boto.num_retries)
         self.build_timeout = CONF.boto.build_timeout
         self.ks_cred = {"username": username,
                         "password": password,
                         "auth_url": auth_url,
-                        "tenant_name": tenant_name}
+                        "tenant_name": tenant_name,
+                        "insecure": insecure_ssl}
 
     def _keystone_aws_get(self):
         # FIXME(andreaf) Move EC2 credentials to AuthProvider
@@ -90,7 +93,10 @@
         self._config_boto_timeout(self.connection_timeout, self.num_retries)
         if not all((self.connection_data["aws_access_key_id"],
                    self.connection_data["aws_secret_access_key"])):
-            if all(self.ks_cred.itervalues()):
+            if all([self.ks_cred.get('auth_url'),
+                    self.ks_cred.get('username'),
+                    self.ks_cred.get('tenant_name'),
+                    self.ks_cred.get('password')]):
                 ec2_cred = self._keystone_aws_get()
                 self.connection_data["aws_access_key_id"] = \
                     ec2_cred.access
@@ -109,6 +115,7 @@
 
     def __init__(self, *args, **kwargs):
         super(APIClientEC2, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.ec2_url)
@@ -129,6 +136,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "region": region,
                                 "host": purl.hostname,
                                 "port": port,
@@ -187,6 +195,7 @@
 
     def __init__(self, *args, **kwargs):
         super(ObjectClientS3, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.s3_url)
@@ -201,6 +210,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "host": purl.hostname,
                                 "port": port,
                                 "calling_format": boto.s3.connection.
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 92b4ddf..0028eea 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -137,4 +137,5 @@
         post_body = json.dumps({'ip_range': ip_range})
         resp, body = self.put('os-floating-ips-bulk/delete', post_body)
         body = json.loads(body)
+        self.validate_response(schema.delete_floating_ips_bulk, resp, body)
         return resp, body['floating_ips_bulk_delete']
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index 2353908..4a7c163 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -22,6 +22,7 @@
 
 from tempest.common import glance_http
 from tempest.common import rest_client
+from tempest.common.utils import misc as misc_utils
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
@@ -297,6 +298,9 @@
                            'while waiting for %s, '
                            'but we got %s.' %
                            (self.build_timeout, status, value))
+                caller = misc_utils.find_test_caller()
+                if caller:
+                    message = '(%s) %s' % (caller, message)
                 raise exceptions.TimeoutException(message)
             time.sleep(self.build_interval)
             old_value = value
diff --git a/tempest/services/queuing/json/queuing_client.py b/tempest/services/queuing/json/queuing_client.py
index e5978f5..031c9c6 100644
--- a/tempest/services/queuing/json/queuing_client.py
+++ b/tempest/services/queuing/json/queuing_client.py
@@ -14,11 +14,14 @@
 # limitations under the License.
 
 import json
+import urllib
 
 from tempest.api_schema.queuing.v1 import queues as queues_schema
 from tempest.common import rest_client
+from tempest.common.utils import data_utils
 from tempest import config
 
+
 CONF = config.CONF
 
 
@@ -30,11 +33,16 @@
         self.version = '1'
         self.uri_prefix = 'v{0}'.format(self.version)
 
+        client_id = data_utils.rand_uuid_hex()
+        self.headers = {'Client-ID': client_id}
+
     def list_queues(self):
         uri = '{0}/queues'.format(self.uri_prefix)
         resp, body = self.get(uri)
-        body = json.loads(body)
-        self.validate_response(queues_schema.list_queues, resp, body)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.list_queues, resp, body)
         return resp, body
 
     def create_queue(self, queue_name):
@@ -74,3 +82,80 @@
         uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
         resp, body = self.put(uri, body=json.dumps(rbody))
         return resp, body
+
+    def post_messages(self, queue_name, rbody):
+        uri = '{0}/queues/{1}/messages'.format(self.uri_prefix, queue_name)
+        resp, body = self.post(uri, body=json.dumps(rbody),
+                               extra_headers=True,
+                               headers=self.headers)
+
+        body = json.loads(body)
+        return resp, body
+
+    def list_messages(self, queue_name):
+        uri = '{0}/queues/{1}/messages?echo=True'.format(self.uri_prefix,
+                                                         queue_name)
+        resp, body = self.get(uri, extra_headers=True, headers=self.headers)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.list_messages, resp, body)
+
+        return resp, body
+
+    def get_single_message(self, message_uri):
+        resp, body = self.get(message_uri, extra_headers=True,
+                              headers=self.headers)
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.get_single_message, resp,
+                                   body)
+        return resp, body
+
+    def get_multiple_messages(self, message_uri):
+        resp, body = self.get(message_uri, extra_headers=True,
+                              headers=self.headers)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.get_multiple_messages,
+                                   resp,
+                                   body)
+
+        return resp, body
+
+    def delete_messages(self, message_uri):
+        resp, body = self.delete(message_uri)
+        assert(resp['status'] == '204')
+        return resp, body
+
+    def post_claims(self, queue_name, rbody, url_params=False):
+        uri = '{0}/queues/{1}/claims'.format(self.uri_prefix, queue_name)
+        if url_params:
+            uri += '?%s' % urllib.urlencode(url_params)
+
+        resp, body = self.post(uri, body=json.dumps(rbody),
+                               extra_headers=True,
+                               headers=self.headers)
+
+        body = json.loads(body)
+        self.validate_response(queues_schema.claim_messages, resp, body)
+        return resp, body
+
+    def query_claim(self, claim_uri):
+        resp, body = self.get(claim_uri)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.query_claim, resp, body)
+        return resp, body
+
+    def update_claim(self, claim_uri, rbody):
+        resp, body = self.patch(claim_uri, body=json.dumps(rbody))
+        assert(resp['status'] == '204')
+        return resp, body
+
+    def release_claim(self, claim_uri):
+        resp, body = self.delete(claim_uri)
+        assert(resp['status'] == '204')
+        return resp, body
diff --git a/tempest/test.py b/tempest/test.py
index 650fad7..afe7a96 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -108,6 +108,7 @@
         'object_storage': CONF.service_available.swift,
         'dashboard': CONF.service_available.horizon,
         'ceilometer': CONF.service_available.ceilometer,
+        'data_processing': CONF.service_available.sahara
     }
 
     def decorator(f):
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 91c3274..52fdf7e 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -99,3 +99,11 @@
             './tempest/scenario/compute/fake_test.py'))
         self.assertFalse(checks.service_tags_not_in_module_path(
             "@test.services('compute')", './tempest/api/image/fake_test.py'))
+
+    def test_no_official_client_manager_in_api_tests(self):
+        self.assertTrue(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/api/compute/base.py"))
+        self.assertFalse(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/scenario/fake_test.py"))
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
index bf1f553..27cd6b5 100644
--- a/tempest/tests/test_ssh.py
+++ b/tempest/tests/test_ssh.py
@@ -36,13 +36,13 @@
             rsa_mock.assert_called_once_with(mock.sentinel.csio)
             cs_mock.assert_called_once_with('mykey')
             rsa_mock.reset_mock()
-            cs_mock.rest_mock()
+            cs_mock.reset_mock()
             pkey = mock.sentinel.pkey
             # Shouldn't call out to load a file from RSAKey, since
             # a sentinel isn't a basestring...
             ssh.Client('localhost', 'root', pkey=pkey)
-            rsa_mock.assert_not_called()
-            cs_mock.assert_not_called()
+            self.assertEqual(0, rsa_mock.call_count)
+            self.assertEqual(0, cs_mock.call_count)
 
     def _set_ssh_connection_mocks(self):
         client_mock = mock.MagicMock()
@@ -75,7 +75,7 @@
             password=None
         )]
         self.assertEqual(expected_connect, client_mock.connect.mock_calls)
-        s_mock.assert_not_called()
+        self.assertEqual(0, s_mock.call_count)
 
     def test_get_ssh_connection_two_attemps(self):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 485beff..bbc3d15 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -42,6 +42,8 @@
         self.fake_http = fake_http.fake_httplib2(return_type=200)
         self.stubs.Set(http.ClosingHttp, 'request',
                        fake_identity._fake_v2_response)
+        cfg.CONF.set_default('operator_role', 'FakeRole',
+                             group='object-storage')
 
     def test_tempest_client(self):
         iso_creds = isolated_creds.IsolatedCreds('test class')
@@ -92,6 +94,31 @@
                           {'id': id, 'name': name})))
         return tenant_fix
 
+    def _mock_list_roles(self, id, name):
+        roles_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'list_roles',
+            return_value=({'status': 200},
+                          [{'id': id, 'name': name},
+                           {'id': '1', 'name': 'FakeRole'}])))
+        return roles_fix
+
+    def _mock_assign_user_role(self):
+        tenant_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'assign_user_role',
+            return_value=({'status': 200},
+                          {})))
+        return tenant_fix
+
+    def _mock_list_role(self):
+        roles_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'list_roles',
+            return_value=({'status': 200},
+                          [{'id': '1', 'name': 'FakeRole'}])))
+        return roles_fix
+
     def _mock_network_create(self, iso_creds, id, name):
         net_fix = self.useFixture(mockpatch.PatchObject(
             iso_creds.network_admin_client,
@@ -121,6 +148,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self._mock_user_create('1234', 'fake_prim_user')
         primary_creds = iso_creds.get_primary_creds()
@@ -135,13 +164,9 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_list_roles('1234', 'admin')
         self._mock_user_create('1234', 'fake_admin_user')
         self._mock_tenant_create('1234', 'fake_admin_tenant')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '1234', 'name': 'admin'}])))
 
         user_mock = mock.patch.object(json_iden_client.IdentityClientJSON,
                                       'assign_user_role')
@@ -150,7 +175,9 @@
         with mock.patch.object(json_iden_client.IdentityClientJSON,
                                'assign_user_role') as user_mock:
             admin_creds = iso_creds.get_admin_creds()
-        user_mock.assert_called_once_with('1234', '1234', '1234')
+        user_mock.assert_has_calls([
+            mock.call('1234', '1234', '1'),
+            mock.call('1234', '1234', '1234')])
         self.assertEqual(admin_creds.username, 'fake_admin_user')
         self.assertEqual(admin_creds.tenant_name, 'fake_admin_tenant')
         # Verify IDs
@@ -162,6 +189,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        roles_fix = self._mock_list_role()
         tenant_fix = self._mock_tenant_create('1234', 'fake_prim_tenant')
         user_fix = self._mock_user_create('1234', 'fake_prim_user')
         iso_creds.get_primary_creds()
@@ -172,16 +201,11 @@
         iso_creds.get_alt_creds()
         tenant_fix.cleanUp()
         user_fix.cleanUp()
+        roles_fix.cleanUp()
         tenant_fix = self._mock_tenant_create('123456', 'fake_admin_tenant')
         user_fix = self._mock_user_create('123456', 'fake_admin_user')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         user_mock = self.patch(
             'tempest.services.identity.json.identity_client.'
             'IdentityClientJSON.delete_user')
@@ -209,6 +233,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_alt_user')
         self._mock_tenant_create('1234', 'fake_alt_tenant')
         alt_creds = iso_creds.get_alt_creds()
@@ -222,6 +248,8 @@
     def test_network_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_net')
@@ -247,6 +275,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
         # Create primary tenant and network
+        self._mock_assign_user_role()
+        roles_fix = self._mock_list_role()
         user_fix = self._mock_user_create('1234', 'fake_prim_user')
         tenant_fix = self._mock_tenant_create('1234', 'fake_prim_tenant')
         net_fix = self._mock_network_create(iso_creds, '1234', 'fake_net')
@@ -278,6 +308,7 @@
         net_fix.cleanUp()
         subnet_fix.cleanUp()
         router_fix.cleanUp()
+        roles_fix.cleanUp()
         # Create admin tenant and networks
         user_fix = self._mock_user_create('123456', 'fake_admin_user')
         tenant_fix = self._mock_tenant_create('123456', 'fake_admin_tenant')
@@ -286,14 +317,8 @@
         subnet_fix = self._mock_subnet_create(iso_creds, '123456',
                                               'fake_admin_subnet')
         router_fix = self._mock_router_create('123456', 'fake_admin_router')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         self.patch('tempest.services.identity.json.identity_client.'
                    'IdentityClientJSON.delete_user')
         self.patch('tempest.services.identity.json.identity_client.'
@@ -348,6 +373,8 @@
     def test_network_alt_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_alt_user')
         self._mock_tenant_create('1234', 'fake_alt_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_alt_net')
@@ -372,6 +399,7 @@
     def test_network_admin_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
         self._mock_user_create('1234', 'fake_admin_user')
         self._mock_tenant_create('1234', 'fake_admin_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_admin_net')
@@ -380,14 +408,8 @@
         router_interface_mock = self.patch(
             'tempest.services.network.json.network_client.NetworkClientJSON.'
             'add_router_interface_with_subnet_id')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         router_interface_mock.called_once_with('1234', '1234')
         network = iso_creds.get_admin_network()
         subnet = iso_creds.get_admin_subnet()
@@ -410,6 +432,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         net = mock.patch.object(iso_creds.network_admin_client,
@@ -444,6 +468,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
@@ -460,6 +486,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
@@ -476,6 +504,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
diff --git a/test-requirements.txt b/test-requirements.txt
index 215f28b..13ef291 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -8,3 +8,4 @@
 mock>=1.0
 coverage>=3.6
 oslotest
+stevedore>=0.14
diff --git a/tools/config/check_uptodate.sh b/tools/config/check_uptodate.sh
index 528bd5b..0f0d77e 100755
--- a/tools/config/check_uptodate.sh
+++ b/tools/config/check_uptodate.sh
@@ -16,6 +16,10 @@
 trap "rm -rf $TEMPDIR" EXIT
 
 tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
+if [ $? != 0 ]
+then
+    exit 1
+fi
 
 if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}
 then
diff --git a/tools/config/generate_sample.sh b/tools/config/generate_sample.sh
index 20ddfbb..d22b2f0 100755
--- a/tools/config/generate_sample.sh
+++ b/tools/config/generate_sample.sh
@@ -1,5 +1,15 @@
 #!/usr/bin/env bash
 
+# Generate sample configuration for your project.
+#
+# Aside from the command line flags, it also respects a config file which
+# should be named oslo.config.generator.rc and be placed in the same directory.
+#
+# You can then export the following variables:
+# TEMPEST_CONFIG_GENERATOR_EXTRA_MODULES: list of modules to interrogate for options.
+# TEMPEST_CONFIG_GENERATOR_EXTRA_LIBRARIES: list of libraries to discover.
+# TEMPEST_CONFIG_GENERATOR_EXCLUDED_FILES: list of files to remove from automatic listing.
+
 print_hint() {
     echo "Try \`${0##*/} --help' for more information." >&2
 }
@@ -95,6 +105,10 @@
     source "$RC_FILE"
 fi
 
+for filename in ${TEMPEST_CONFIG_GENERATOR_EXCLUDED_FILES}; do
+    FILES="${FILES[@]/$filename/}"
+done
+
 for mod in ${TEMPEST_CONFIG_GENERATOR_EXTRA_MODULES}; do
     MODULES="$MODULES -m $mod"
 done
@@ -111,6 +125,11 @@
 MODULEPATH=${MODULEPATH:-$DEFAULT_MODULEPATH}
 OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
 python -m $MODULEPATH $MODULES $LIBRARIES $FILES > $OUTPUTFILE
+if [ $? != 0 ]
+then
+    echo "Can not generate $OUTPUTFILE"
+    exit 1
+fi
 
 # Hook to allow projects to append custom config file snippets
 CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)
diff --git a/tools/config/oslo.config.generator.rc b/tools/config/oslo.config.generator.rc
new file mode 100644
index 0000000..303e156
--- /dev/null
+++ b/tools/config/oslo.config.generator.rc
@@ -0,0 +1 @@
+MODULEPATH=tempest.common.generate_sample_tempest
diff --git a/tools/generate_sample.sh b/tools/generate_sample.sh
deleted file mode 100755
index 9b312c9..0000000
--- a/tools/generate_sample.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-MODULEPATH=tempest.common.generate_sample_tempest tools/config/generate_sample.sh $@
diff --git a/tox.ini b/tox.ini
index c1acde9..7f69fad 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = pep8
+envlist = pep8,py27
 minversion = 1.6
 skipsdist = True
 
@@ -85,7 +85,6 @@
        -r{toxinidir}/test-requirements.txt
 
 [testenv:pep8]
-setenv = MODULEPATH=tempest.common.generate_sample_tempest
 commands =
    flake8 {posargs}
    {toxinidir}/tools/config/check_uptodate.sh