Merge "Remove skip mark to test_create_image_when_server_is_rebooting"
diff --git a/HACKING.rst b/HACKING.rst
index eafa81b..1db1e26 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -1,3 +1,7 @@
+Tempest Coding Guide
+====================
+
+
 Test Data/Configuration
 -----------------------
 - Assume nothing about existing test data
diff --git a/doc/source/HACKING.rst b/doc/source/HACKING.rst
new file mode 120000
index 0000000..a2f06b7
--- /dev/null
+++ b/doc/source/HACKING.rst
@@ -0,0 +1 @@
+../../HACKING.rst
\ No newline at end of file
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1ca7344..e8fdf2c 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -3,9 +3,9 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-===================================
+=======================
 Tempest Testing Project
-===================================
+=======================
 
 Contents:
 
@@ -13,11 +13,11 @@
    :maxdepth: 2
 
    overview
+   HACKING
 
-
--------------------------------
+------------
 Field Guides
--------------------------------
+------------
 Tempest contains tests of many different types, the field guides
 attempt to explain these in a way that makes it easy to understand
 where your test contributions should go.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 3147859..915e2fa 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -12,6 +12,8 @@
 disable_ssl_certificate_validation = False
 # URL for where to find the OpenStack Identity API endpoint (Keystone)
 uri = http://127.0.0.1:5000/v2.0/
+# URL for where to find the OpenStack V3 Identity API endpoint (Keystone)
+uri_v3 = http://127.0.0.1:5000/v3/
 # Should typically be left as keystone unless you have a non-Keystone
 # authentication API service
 strategy = keystone
@@ -63,6 +65,10 @@
 flavor_ref = 1
 flavor_ref_alt = 2
 
+# User names used to authenticate to an instance for a given image.
+image_ssh_user = root
+image_alt_ssh_user = root
+
 # Number of seconds to wait while looping to check the status of an
 # instance that is building.
 build_interval = 10
@@ -220,12 +226,12 @@
 # Number of seconds to time out on waiting for a volume
 # to be available or reach an expected status
 build_timeout = 300
-# Runs Cinder multi-backend tests (requires 2 backend declared in cinder.conf)
+# Runs Cinder multi-backend tests (requires 2 backends declared in cinder.conf)
 # They must have different volume_backend_name (backend1_name and backend2_name
 # have to be different)
 multi_backend_enabled = false
-backend1_name = LVM_iSCSI
-backend2_name = LVM_iSCSI_1
+backend1_name = BACKEND_1
+backend2_name = BACKEND_2
 
 [object-storage]
 # This section contains configuration options used when executing tests
@@ -303,7 +309,7 @@
 
 # Instance type for tests. Needs to be big enough for a
 # full OS plus the test workload
-instance_type = m1.tiny
+instance_type = m1.micro
 
 # Name of heat-cfntools enabled image to use when launching test instances
 # If not specified, tests that spawn instances will not run
@@ -312,3 +318,19 @@
 # Name of existing keypair to launch servers with. The default is not to specify
 # any key, which will generate a keypair for each test class
 #keypair_name = heat_key
+
+[scenario]
+# Directory containing image files
+img_dir = /opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+
+# AMI image file name
+ami_img_file = cirros-0.3.1-x86_64-blank.img
+
+# ARI image file name
+ari_img_file = cirros-0.3.1-x86_64-initrd
+
+# AKI image file name
+aki_img_file = cirros-0.3.1-x86_64-vmlinuz
+
+# ssh username for the image file
+ssh_user = cirros
diff --git a/tools/pip-requires b/requirements.txt
similarity index 90%
rename from tools/pip-requires
rename to requirements.txt
index 4873d75..19d6e0b 100644
--- a/tools/pip-requires
+++ b/requirements.txt
@@ -12,6 +12,7 @@
 python-keystoneclient>=0.2.0
 python-novaclient>=2.10.0
 python-quantumclient>=2.1
+python-cinderclient>=1.0.4,<2
 testresources
 keyring
 testrepository
diff --git a/run_tests.sh b/run_tests.sh
index d5b2494..366564e 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -166,11 +166,14 @@
 fi
 
 run_tests
+retval=$?
 
 if [ $nova_coverage -eq 1 ]; then
     run_coverage_report
 fi
 
 if [ -z "$noseargs" ]; then
-  run_pep8
+    run_pep8
 fi
+
+exit $retval
diff --git a/tempest/README.rst b/tempest/README.rst
index fa29fe2..892b0f8 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -75,8 +75,8 @@
 ------------
 
 Many openstack components include 3rdparty API support. It is
-completely legitmate for Tempest to include tests of 3rdparty APIs,
-but those should be kept seperate from the normal OpenStack
+completely legitimate for Tempest to include tests of 3rdparty APIs,
+but those should be kept separate from the normal OpenStack
 validation.
 
 
@@ -84,5 +84,5 @@
 ----------
 
 Whitebox tests are tests which require access to the database of the
-target OpenStack machine to verify internal state after opperations
+target OpenStack machine to verify internal state after operations
 are made. White box tests are allowed to use the python clients.
diff --git a/tempest/api/README.rst b/tempest/api/README.rst
index cf0aac7..617fda4 100644
--- a/tempest/api/README.rst
+++ b/tempest/api/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to API tests
-========
+==========================
 
 
 What are these tests?
---------
+---------------------
 
 One of Tempest's prime function is to ensure that your OpenStack cloud
 works with the OpenStack API as documented. The current largest
@@ -21,7 +21,7 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 
 This is one of the core missions for the Tempest project, and where it
 started. Many people use this bit of function in Tempest to ensure
@@ -34,7 +34,7 @@
 
 
 Scope of these tests
---------
+--------------------
 
 API tests should always use the Tempest implementation of the
 OpenStack API, as we want to ensure that bugs aren't hidden by the
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index acdfb74..b66bd7e 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -43,7 +43,7 @@
                     filter(lambda y: y['service'] == 'compute', hosts_all))
         cls.host = hosts[0]
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_create_delete(self):
         # Create and delete an aggregate.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -56,7 +56,7 @@
         self.assertEquals(200, resp.status)
         self.client.wait_for_resource_deletion(aggregate['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_create_delete_with_az(self):
         # Create and delete an aggregate.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -70,7 +70,7 @@
         self.assertEquals(200, resp.status)
         self.client.wait_for_resource_deletion(aggregate['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_create_verify_entry_in_list(self):
         # Create an aggregate and ensure it is listed.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -83,7 +83,7 @@
                       map(lambda x: (x['id'], x['availability_zone']),
                           aggregates))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_create_get_details(self):
         # Create an aggregate and ensure its details are returned.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -144,7 +144,7 @@
         self.assertRaises(exceptions.NotFound,
                           self.client.get_aggregate, -1)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_add_remove_host(self):
         # Add an host to the given aggregate and remove.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -165,7 +165,7 @@
                           body['availability_zone'])
         self.assertNotIn(self.host, body['hosts'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_add_host_list(self):
         # Add an host to the given aggregate and list.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -182,7 +182,7 @@
         self.assertEquals(None, agg['availability_zone'])
         self.assertIn(self.host, agg['hosts'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_add_host_get_details(self):
         # Add an host to the given aggregate and get details.
         aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -196,7 +196,7 @@
         self.assertEquals(None, body['availability_zone'])
         self.assertIn(self.host, body['hosts'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_aggregate_add_host_create_server_with_az(self):
         # Add an host to the given aggregate and create a server.
         aggregate_name = rand_name(self.aggregate_name_prefix)
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index ab2f2d9..8a56b89 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -34,14 +34,14 @@
         cls.client = cls.os_adm.availability_zone_client
         cls.non_adm_client = cls.availability_zone_client
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_availability_zone_list(self):
         # List of availability zone
         resp, availability_zone = self.client.get_availability_zone_list()
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_availability_zone_list_detail(self):
         # List of availability zones and available services
         resp, availability_zone = \
@@ -49,7 +49,7 @@
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_availability_zone_list_with_non_admin_user(self):
         # List of availability zone with non admin user
         resp, availability_zone = \
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 8424709..f201cf7 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -51,7 +51,7 @@
 class FixedIPsTestJson(FixedIPsBase):
     _interface = 'json'
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_fixed_ip_details(self):
         resp, fixed_ip = self.client.get_fixed_ip_details(self.ip)
         self.assertEqual(fixed_ip['address'], self.ip)
@@ -61,13 +61,13 @@
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.get_fixed_ip_details, self.ip)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_set_reserve(self):
         body = {"reserve": "None"}
         resp, body = self.client.reserve_fixed_ip(self.ip, body)
         self.assertEqual(resp.status, 202)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_set_unreserve(self):
         body = {"unreserve": "None"}
         resp, body = self.client.reserve_fixed_ip(self.ip, body)
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 47097ed..6db20f9 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -53,7 +53,7 @@
         self.assertEqual(resp.status, 202)
         self.client.wait_for_resource_deletion(flavor_id)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_create_flavor(self):
         # Create a flavor and ensure it is listed
         # This operation requires the user to have 'admin' role
@@ -92,7 +92,7 @@
         self.assertEqual(resp.status, 200)
         self.assertEqual(flavor['name'], flavor_name)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_create_flavor_verify_entry_in_list_details(self):
         # Create a flavor and ensure it's details are listed
         # This operation requires the user to have 'admin' role
@@ -193,7 +193,7 @@
                 flag = True
         self.assertTrue(flag)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_flavor_not_public_verify_entry_not_in_list_details(self):
         #Create a flavor with os-flavor-access:is_public false should not
         #be present in list_details.
@@ -241,7 +241,7 @@
                 flag = True
         self.assertTrue(flag)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_is_public_string_variations(self):
         flavor_id_not_public = rand_int_id(start=1000)
         flavor_name_not_public = rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index f4b969d..63d5025 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -50,7 +50,7 @@
         cls.vcpus = 1
         cls.disk = 10
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_flavor_access_add_remove(self):
         #Test to add and remove flavor access to a given tenant.
         flavor_name = rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
new file mode 100644
index 0000000..00a5955
--- /dev/null
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -0,0 +1,112 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class HypervisorAdminTestJSON(base.BaseComputeAdminTest):
+
+    """
+    Tests Hypervisors API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(HypervisorAdminTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.hypervisor_client
+        cls.non_adm_client = cls.hypervisor_client
+
+    def _list_hypervisors(self):
+        # List of hypervisors
+        resp, hypers = self.client.get_hypervisor_list()
+        self.assertEqual(200, resp.status)
+        return hypers
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_list(self):
+        # List of hypervisor and available hypervisors hostname
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_list_details(self):
+        # Display the details of the all hypervisor
+        resp, hypers = self.client.get_hypervisor_list_details()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypers) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_show_details(self):
+        # Display the details of the specified hypervisor
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        resp, details = (self.client.
+                         get_hypervisor_show_details(hypers[0]['id']))
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(details) > 0)
+        self.assertEqual(details['hypervisor_hostname'],
+                         hypers[0]['hypervisor_hostname'])
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_show_servers(self):
+        # Show instances about the specific hypervisors
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        hostname = hypers[0]['hypervisor_hostname']
+        resp, hypervisors = self.client.get_hypervisor_servers(hostname)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypervisors) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_stats(self):
+        # Verify the stats of the all hypervisor
+        resp, stats = self.client.get_hypervisor_stats()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(stats) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_uptime(self):
+        # Verify that GET shows the specified hypervisor uptime
+        hypers = self._list_hypervisors()
+
+        resp, uptime = self.client.get_hypervisor_uptime(hypers[0]['id'])
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(uptime) > 0)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_list_with_non_admin_user(self):
+        # List of hypervisor and available services with non admin user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_list)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_list_details_with_non_admin_user(self):
+        # List of hypervisor details and available services with non admin user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_list_details)
+
+
+class HypervisorAdminTestXML(HypervisorAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 1266405..a6b4e31 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -19,6 +19,7 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
+import testtools
 
 
 class QuotasAdminTestJSON(base.BaseComputeAdminTest):
@@ -70,12 +71,9 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(expected_quota_set, quota_set)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_update_all_quota_resources_for_tenant(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Admin can update all the resource quota limits for a tenant
         new_quota_set = {'force': True,
                          'injected_file_content_bytes': 20480,
@@ -125,12 +123,9 @@
             self.assertEqual(200, resp.status, "Failed to reset quota "
                              "defaults")
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_create_server_when_cpu_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's vcpu quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_vcpu_quota = quota_set['cores']
@@ -144,12 +139,9 @@
                         cores=default_vcpu_quota)
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_create_server_when_memory_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's memory quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_mem_quota = quota_set['ram']
@@ -165,12 +157,9 @@
 
 #TODO(afazekas): Add test that tried to update the quota_set as a regular user
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         #Once instances quota limit is reached, disallow server creation
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_instances_quota = quota_set['instances']
@@ -183,6 +172,7 @@
                         instances=default_instances_quota)
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_security_groups_exceed_limit(self):
         # Negative test: Creation Security Groups over limit should FAIL
@@ -204,6 +194,7 @@
                           self.sg_client.create_security_group,
                           "sg-overlimit", "sg-desc")
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_security_groups_rules_exceed_limit(self):
         # Negative test: Creation of Security Group Rules should FAIL
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index db7928a..78dac21 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -34,7 +34,7 @@
         cls.client = cls.os_adm.services_client
         cls.non_admin_client = cls.services_client
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_services(self):
         # List Compute services
         resp, services = self.client.list_services()
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index 9c4c4b9..ce05899 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -51,7 +51,7 @@
         # Returns formatted datetime
         return at.strftime('%Y-%m-%dT%H:%M:%S.%f')
 
-    @attr('positive')
+    @attr(type='gate')
     def test_list_usage_all_tenants(self):
         # Get usage for all tenants
         params = {'start': self.start,
@@ -61,7 +61,7 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(len(tenant_usage), 8)
 
-    @attr('positive')
+    @attr(type='gate')
     def test_get_usage_tenant(self):
         # Get usage for a specific tenant
         params = {'start': self.start,
@@ -72,7 +72,7 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(len(tenant_usage), 8)
 
-    @attr('positive')
+    @attr(type='gate')
     def test_get_usage_tenant_with_non_admin_user(self):
         # Get usage for a specific tenant with non admin user
         params = {'start': self.start,
@@ -83,7 +83,7 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(len(tenant_usage), 8)
 
-    @attr('negative')
+    @attr(type=['negative', 'gate'])
     def test_get_usage_tenant_with_empty_tenant_id(self):
         # Get usage for a specific tenant empty
         params = {'start': self.start,
@@ -92,7 +92,7 @@
                           self.adm_client.get_tenant_usage,
                           '', params)
 
-    @attr('negative')
+    @attr(type=['negative', 'gate'])
     def test_get_usage_tenant_with_invalid_date(self):
         # Get usage for tenant with invalid date
         params = {'start': self.end,
@@ -101,7 +101,7 @@
                           self.adm_client.get_tenant_usage,
                           self.tenant_id, params)
 
-    @attr('negative')
+    @attr(type=['negative', 'gate'])
     def test_list_usage_all_tenants_with_non_admin_user(self):
         # Get usage for all tenants with non admin user
         params = {'start': self.start,
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index b19b9d9..0fa5a84 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -64,6 +64,7 @@
         cls.availability_zone_client = os.availability_zone_client
         cls.aggregates_client = os.aggregates_client
         cls.services_client = os.services_client
+        cls.hypervisor_client = os.hypervisor_client
         cls.build_interval = cls.config.compute.build_interval
         cls.build_timeout = cls.config.compute.build_timeout
         cls.ssh_user = cls.config.compute.ssh_user
@@ -73,6 +74,8 @@
         cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
         cls.servers = []
 
+        cls.servers_client_v3_auth = os.servers_client_v3_auth
+
     @classmethod
     def _get_identity_admin_client(cls):
         """
@@ -184,15 +187,24 @@
         flavor = kwargs.get('flavor', cls.flavor_ref)
         image_id = kwargs.get('image_id', cls.image_ref)
 
-        resp, server = cls.servers_client.create_server(
+        resp, body = cls.servers_client.create_server(
             name, image_id, flavor, **kwargs)
-        cls.servers.append(server)
+
+        # handle the case of multiple servers
+        servers = [body]
+        if 'min_count' in kwargs or 'max_count' in kwargs:
+            # Get servers created which name match with name param.
+            r, b = cls.servers_client.list_servers()
+            servers = [s for s in b['servers'] if s['name'].startswith(name)]
+
+        cls.servers.extend(servers)
 
         if 'wait_until' in kwargs:
-            cls.servers_client.wait_for_server_status(
-                server['id'], kwargs['wait_until'])
+            for server in servers:
+                cls.servers_client.wait_for_server_status(
+                    server['id'], kwargs['wait_until'])
 
-        return resp, server
+        return resp, body
 
     def wait_for(self, condition):
         """Repeatedly calls condition() until a timeout."""
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index a60cbe9..27526eb 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -56,21 +56,21 @@
         self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
                           999)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_flavors_limit_results(self):
         # Only the expected number of flavors should be returned
         params = {'limit': 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertEqual(1, len(flavors))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_flavors_detailed_limit_results(self):
         # Only the expected number of flavors (detailed) should be returned
         params = {'limit': 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertEqual(1, len(flavors))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_flavors_using_marker(self):
         # The list of flavors should start from the provided marker
         resp, flavors = self.client.list_flavors()
@@ -81,7 +81,7 @@
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
                          'The list of flavors did not start after the marker.')
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_flavors_detailed_using_marker(self):
         # The list of flavors should start from the provided marker
         resp, flavors = self.client.list_flavors_with_detail()
@@ -92,7 +92,7 @@
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
                          'The list of flavors did not start after the marker.')
 
-    @attr(type=['positive', 'gate'])
+    @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()
@@ -103,7 +103,7 @@
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @attr(type=['positive', 'gate'])
+    @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()
@@ -114,7 +114,7 @@
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @attr(type=['positive', 'gate'])
+    @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()
@@ -125,7 +125,7 @@
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @attr(type=['positive', 'gate'])
+    @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()
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index c2e6bd0..0d7f26d 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -56,7 +56,7 @@
         resp, body = cls.client.delete_floating_ip(cls.floating_ip_id)
         super(FloatingIPsTestJSON, cls).tearDownClass()
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_allocate_floating_ip(self):
         # Positive test:Allocation of a new floating IP to a project
         # should be successful
@@ -81,7 +81,7 @@
                           self.client.create_floating_ip,
                           "non_exist_pool")
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
         # should be successful
@@ -96,7 +96,7 @@
         # Check it was really deleted.
         self.client.wait_for_resource_deletion(floating_ip_body['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_associate_disassociate_floating_ip(self):
         # Positive test:Associate and disassociate the provided floating IP
         # to a specific server should be successful
@@ -138,7 +138,7 @@
                           self.client.disassociate_floating_ip_from_server,
                           "0.0.0.0", self.server_id)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_associate_already_associated_floating_ip(self):
         # positive test:Association of an already associated floating IP
         # to specific server should change the association of the Floating IP
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index d77b0a5..3e1aa82 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -42,7 +42,7 @@
             cls.client.delete_floating_ip(cls.floating_ip_id[i])
         super(FloatingIPDetailsTestJSON, cls).tearDownClass()
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_floating_ips(self):
         # Positive test:Should return the list of floating IPs
         resp, body = self.client.list_floating_ips()
@@ -53,7 +53,7 @@
         for i in range(3):
             self.assertTrue(self.floating_ip[i] in floating_ips)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_floating_ip_details(self):
         # Positive test:Should be able to GET the details of floatingIP
         #Creating a floating IP for which details are to be checked
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index c7f0b23..4163245 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -131,7 +131,7 @@
         # Verify the image was deleted correctly
         resp, body = self.client.delete_image(image_id)
         self.assertEqual('204', resp['status'])
-        self.assertRaises(exceptions.NotFound, self.client.get_image, image_id)
+        self.client.wait_for_resource_deletion(image_id)
 
     @testtools.skipUnless(compute.MULTI_USER,
                           'Need multiple users for this test.')
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 471a75a..9db28ad 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -84,7 +84,7 @@
         self.assertRaises(exceptions.NotFound, self.client.get_image,
                           "nonexistingimageid")
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_status(self):
         # The list of images should contain only images with the
         # provided status
@@ -95,7 +95,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_name(self):
         # List of all images should contain the expected images filtered
         # by name
@@ -106,7 +106,7 @@
         self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_server_id(self):
         # The images should contain images filtered by server id
         params = {'server': self.server1['id']}
@@ -118,7 +118,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_server_ref(self):
         # The list of servers should be filtered by server ref
         server_links = self.server2['links']
@@ -135,7 +135,7 @@
             self.assertTrue(any([i for i in images
                                  if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_type(self):
         # The list of servers should be filtered by image type
         params = {'type': 'snapshot'}
@@ -146,7 +146,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_limit_results(self):
         # Verify only the expected number of results are returned
         params = {'limit': '1'}
@@ -155,7 +155,7 @@
         #ref: Question #224349
         self.assertEqual(1, len([x for x in images if 'id' in x]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_filter_by_changes_since(self):
         # Verify only updated images are returned in the detailed list
 
@@ -166,7 +166,7 @@
         found = any([i for i in images if i['id'] == self.image3_id])
         self.assertTrue(found)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_filter_by_status(self):
         # Detailed list of all images should only contain images
         # with the provided status
@@ -177,7 +177,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_filter_by_name(self):
         # Detailed list of all images should contain the expected
         # images filtered by name
@@ -188,7 +188,7 @@
         self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_limit_results(self):
         # Verify only the expected number of results (with full details)
         # are returned
@@ -196,7 +196,7 @@
         resp, images = self.client.list_images_with_detail(params)
         self.assertEqual(1, len(images))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_filter_by_server_ref(self):
         # Detailed list of servers should be filtered by server ref
         server_links = self.server2['links']
@@ -213,7 +213,7 @@
             self.assertTrue(any([i for i in images
                                  if i['id'] == self.image3_id]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_filter_by_type(self):
         # The detailed list of servers should be filtered by image type
         params = {'type': 'snapshot'}
@@ -225,7 +225,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_images_with_detail_filter_by_changes_since(self):
         # Verify an update image is returned
 
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 4c0398e..6abca3f 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -29,7 +29,7 @@
         super(KeyPairsTestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_keypairs_create_list_delete(self):
         # Keypairs created should be available in the response list
         #Create 3 keypairs
@@ -63,7 +63,7 @@
             resp, _ = self.client.delete_keypair(keypair['name'])
             self.assertEqual(202, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_keypair_create_delete(self):
         # Keypair should be created, verified and deleted
         k_name = rand_name('keypair-')
@@ -79,7 +79,7 @@
         resp, _ = self.client.delete_keypair(k_name)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_keypair_detail(self):
         # Keypair should be created, Got details by name and deleted
         k_name = rand_name('keypair-')
@@ -102,7 +102,7 @@
             resp, _ = self.client.delete_keypair(k_name)
             self.assertEqual(202, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_keypair_create_with_pub_key(self):
         # Keypair should be created with a given public key
         k_name = rand_name('keypair-')
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 15af0f2..6a32b64 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -29,7 +29,7 @@
         super(SecurityGroupRulesTestJSON, cls).setUpClass()
         cls.client = cls.security_groups_client
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_group_rules_create(self):
         # Positive test: Creation of Security Group rule
         # should be successfull
@@ -52,7 +52,7 @@
         self.addCleanup(self.client.delete_security_group_rule, rule['id'])
         self.assertEqual(200, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_group_rules_create_with_optional_arguments(self):
         # Positive test: Creation of Security Group rule
         # with optional arguments
@@ -189,7 +189,7 @@
                           self.client.delete_security_group_rule,
                           rand_name('999'))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_group_rules_list(self):
         # Positive test: Created Security Group rules should be
         # in the list of all rules
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 5f3a37e..f960ca4 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -33,7 +33,7 @@
         resp, _ = self.client.delete_security_group(securitygroup_id)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_groups_create_list_delete(self):
         # Positive test:Should return the list of Security Groups
         #Create 3 Security Groups
@@ -61,7 +61,7 @@
 
     #TODO(afazekas): scheduled for delete,
     #test_security_group_create_get_delete covers it
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_group_create_delete(self):
         # Security Group should be created, verified and deleted
         s_name = rand_name('securitygroup-')
@@ -80,7 +80,7 @@
                          "The created Security Group name is "
                          "not equal to the requested name")
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_security_group_create_get_delete(self):
         # Security Group should be created, fetched and deleted
         s_name = rand_name('securitygroup-')
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index f605485..e5fee4d 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -92,14 +92,14 @@
         self.assertTrue(found)
 
     @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_can_log_into_created_server(self):
         # Check that the user can authenticate with the generated password
         linux_client = RemoteClient(self.server, self.ssh_user, self.password)
         self.assertTrue(linux_client.can_authenticate())
 
     @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_verify_created_server_vcpus(self):
         # Verify that the number of vcpus reported by the instance matches
         # the amount stated by the flavor
@@ -108,7 +108,7 @@
         self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
 
     @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_host_name_is_same_as_server_name(self):
         # Verify the instance host name is the same as the server name
         linux_client = RemoteClient(self.server, self.ssh_user, self.password)
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index a0ed009..e9385b5 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -33,7 +33,7 @@
         super(ServerDiskConfigTestJSON, cls).setUpClass()
         cls.client = cls.os.servers_client
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_rebuild_server_with_manual_disk_config(self):
         # A server should be rebuilt using the manual disk config option
         resp, server = self.create_server(disk_config='AUTO',
@@ -57,7 +57,7 @@
         #Delete the server
         resp, body = self.client.delete_server(server['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_rebuild_server_with_auto_disk_config(self):
         # A server should be rebuilt using the auto disk config option
         resp, server = self.create_server(disk_config='MANUAL',
@@ -82,7 +82,7 @@
         resp, body = self.client.delete_server(server['id'])
 
     @testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_resize_server_from_manual_to_auto(self):
         # A server should be resized from manual to auto disk config
         resp, server = self.create_server(disk_config='MANUAL',
@@ -102,7 +102,7 @@
         resp, body = self.client.delete_server(server['id'])
 
     @testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_resize_server_from_auto_to_manual(self):
         # A server should be resized from auto to manual disk config
         resp, server = self.create_server(disk_config='AUTO',
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index e5da0a2..f13e51e 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -31,7 +31,7 @@
         cls.request_id = resp['x-compute-request-id']
         cls.server_id = server['id']
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_instance_actions(self):
         # List actions of the provided server
         resp, body = self.client.reboot(self.server_id, 'HARD')
@@ -43,7 +43,7 @@
         self.assertTrue(any([i for i in body if i['action'] == 'create']))
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_instance_action(self):
         # Get the action details of the provided server
         resp, body = self.client.get_instance_action(self.server_id,
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index dbebf5e..31b44f7 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -84,7 +84,7 @@
         super(ListServerFiltersTestJSON, cls).tearDownClass()
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filter_by_image(self):
         # Filter the list of servers by image
         params = {'image': self.image_ref}
@@ -95,7 +95,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filter_by_flavor(self):
         # Filter the list of servers by flavor
         params = {'flavor': self.flavor_ref_alt}
@@ -106,7 +106,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filter_by_server_name(self):
         # Filter the list of servers by server name
         params = {'name': self.s1_name}
@@ -117,7 +117,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filter_by_server_status(self):
         # Filter the list of servers by server status
         params = {'status': 'active'}
@@ -128,7 +128,7 @@
         self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filter_by_limit(self):
         # Verify only the expected number of servers are returned
         params = {'limit': 1}
@@ -137,7 +137,7 @@
         self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_detailed_filter_by_image(self):
         # Filter the detailed list of servers by image
         params = {'image': self.image_ref}
@@ -148,7 +148,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_detailed_filter_by_flavor(self):
         # Filter the detailed list of servers by flavor
         params = {'flavor': self.flavor_ref_alt}
@@ -159,7 +159,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_detailed_filter_by_server_name(self):
         # Filter the detailed list of servers by server name
         params = {'name': self.s1_name}
@@ -170,7 +170,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_detailed_filter_by_server_status(self):
         # Filter the detailed list of servers by server status
         params = {'status': 'active'}
@@ -182,7 +182,7 @@
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
         self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filtered_by_name_wildcard(self):
         # List all servers that contains 'server' in name
         params = {'name': 'server'}
@@ -205,7 +205,7 @@
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
     @testtools.skip('Until Bug #1170718 is resolved.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
         # Here should be listed 1 server
@@ -218,7 +218,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_filtered_by_ip_regex(self):
         # Filter servers by regex ip
         # List all servers filtered by part of ip address.
@@ -232,7 +232,7 @@
         self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_servers_detailed_limit_results(self):
         # Verify only the expected number of detailed results are returned
         params = {'limit': 1}
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 0f35ee5..db9bdc1 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,6 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import datetime
 
 from tempest.api import compute
 from tempest.api.compute import base
@@ -170,7 +171,8 @@
     @attr(type='gate')
     def test_list_servers_by_changes_since(self):
         # Servers are listed by specifying changes-since date
-        changes_since = {'changes-since': '2011-01-01T12:34:00Z'}
+        since = datetime.datetime.utcnow() - datetime.timedelta(minutes=2)
+        changes_since = {'changes-since': since.isoformat()}
         resp, body = self.client.list_servers(changes_since)
         self.assertEqual('200', resp['status'])
         # changes-since returns all instances, including deleted.
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index a705dd3..9fde618 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -25,16 +25,6 @@
     _interface = 'json'
     _name = 'multiple-create-test'
 
-    def _get_created_servers(self, name):
-        """Get servers created which name match with name param."""
-        resp, body = self.servers_client.list_servers()
-        servers = body['servers']
-        servers_created = []
-        for server in servers:
-            if server['name'].startswith(name):
-                servers_created.append(server)
-        return servers_created
-
     def _generate_name(self):
         return rand_name(self._name)
 
@@ -45,22 +35,10 @@
         """
         kwargs['name'] = kwargs.get('name', self._generate_name())
         resp, body = self.create_server(**kwargs)
-        created_servers = self._get_created_servers(kwargs['name'])
-        # NOTE(maurosr): append it to cls.servers list from base.BaseCompute
-        # class.
-        self.servers.extend(created_servers)
-        # NOTE(maurosr): get a server list, check status of the ones with names
-        # that match and wait for them become active. At a first look, since
-        # they are building in parallel, wait inside the for doesn't seem be
-        # harmful to the performance
-        if wait_until is not None:
-            for server in created_servers:
-                self.servers_client.wait_for_server_status(server['id'],
-                                                           wait_until)
 
         return resp, body
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_multiple_create(self):
         resp, body = self._create_multiple_servers(wait_until='ACTIVE',
                                                    min_count=1,
@@ -103,7 +81,7 @@
                           min_count=min_count,
                           max_count=max_count)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_multiple_create_with_reservation_return(self):
         resp, body = self._create_multiple_servers(wait_until='ACTIVE',
                                                    min_count=1,
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 228dc45..9f97f4f 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -167,7 +167,7 @@
         self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_resize_server_revert(self):
         # The server's RAM and disk space should return to its original
         # values after a resize is reverted
@@ -217,7 +217,7 @@
                           personality=personality,
                           adminPass='rebuild')
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_console_output(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id and number of lines
@@ -239,7 +239,7 @@
                           '!@#$%^&*()', 10)
 
     @testtools.skip('Until tempest Bug #1014683 is fixed.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_console_output_server_id_in_reboot_status(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id in reboot status
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 4744bf5..a3ec423 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -46,7 +46,7 @@
         self.assertRaises(exceptions.OverLimit, self.create_server,
                           personality=personality)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_can_create_server_with_max_number_personality_files(self):
         # Server should be created successfully if maximum allowed number of
         # files is injected into the server during creation.
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 7e0ac85..8225a4c 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -169,7 +169,7 @@
                           self.server_id,
                           self.volume_to_detach['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_rescued_vm_associate_dissociate_floating_ip(self):
         # Rescue the server
         self.servers_client.rescue_server(
@@ -189,7 +189,7 @@
                                                         self.server_id)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_rescued_vm_add_remove_security_group(self):
         # Rescue the server
         self.servers_client.rescue_server(
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 57baae6..3ff2538 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -32,7 +32,7 @@
         self.clear_servers()
         super(ServersTestJSON, self).tearDown()
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_create_server_with_admin_password(self):
         # If an admin password is provided on server creation, the server's
         # root password should be set to that password.
@@ -60,7 +60,7 @@
         name2 = server['name']
         self.assertEqual(name1, name2)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_create_specify_keypair(self):
         # Specify a keypair while creating a server
 
@@ -73,7 +73,7 @@
         resp, server = self.client.get_server(server['id'])
         self.assertEqual(key_name, server['key_name'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_update_server_name(self):
         # The server name should be changed to the the provided value
         resp, server = self.create_server(wait_until='ACTIVE')
@@ -88,7 +88,7 @@
         resp, server = self.client.get_server(server['id'])
         self.assertEqual('newname', server['name'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_update_access_server_address(self):
         # The server's access addresses should reflect the provided values
         resp, server = self.create_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 5f53080..bbe489c 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -236,7 +236,11 @@
         # Create a server with a nonexistent security group
 
         security_groups = [{'name': 'does_not_exist'}]
-        self.assertRaises(exceptions.BadRequest,
+        if self.config.network.quantum_available:
+            expected_exception = exceptions.NotFound
+        else:
+            expected_exception = exceptions.BadRequest
+        self.assertRaises(expected_exception,
                           self.create_server,
                           security_groups=security_groups)
 
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 47d6169..3119643 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -33,7 +33,7 @@
         resp, server = cls.create_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_virtual_interfaces(self):
         # Positive test:Should be able to GET the virtual interfaces list
         # for a given server_id
diff --git a/tempest/api/compute/test_auth_token.py b/tempest/api/compute/test_auth_token.py
new file mode 100644
index 0000000..bbe92ef
--- /dev/null
+++ b/tempest/api/compute/test_auth_token.py
@@ -0,0 +1,52 @@
+# Copyright 2013 IBM Corp
+#
+#   Licensed under the Apache License, Version 2.0 (the "License"); you may
+#   not use this file except in compliance with the License. You may obtain
+#   a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#   License for the specific language governing permissions and limitations
+#   under the License.
+
+
+import testtools
+
+from tempest.api.compute import base
+import tempest.config as config
+
+
+class AuthTokenTestJSON(base.BaseComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AuthTokenTestJSON, cls).setUpClass()
+
+        cls.servers_v2 = cls.os.servers_client
+        cls.servers_v3 = cls.os.servers_client_v3_auth
+
+    def test_v2_token(self):
+        # Can get a token using v2 of the identity API and use that to perform
+        # an operation on the compute service.
+
+        # Doesn't matter which compute API is used,
+        # picking list_servers because it's easy.
+        self.servers_v2.list_servers()
+
+    @testtools.skipIf(not config.TempestConfig().identity.uri_v3,
+                      'v3 auth client not configured')
+    def test_v3_token(self):
+        # Can get a token using v3 of the identity API and use that to perform
+        # an operation on the compute service.
+
+        # Doesn't matter which compute API is used,
+        # picking list_servers because it's easy.
+        self.servers_v3.list_servers()
+
+
+class AuthTokenTestXML(AuthTokenTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 4893e3d..291c8e4 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -23,7 +23,7 @@
 class ExtensionsTestJSON(base.BaseComputeTest):
     _interface = 'json'
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_extensions(self):
         # List of all extensions
         resp, extensions = self.extensions_client.list_extensions()
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 5d45251..b507e03 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -70,7 +70,7 @@
         self.attached = True
 
     @testtools.skipIf(not run_ssh, 'SSH required for this test')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_attach_detach_volume(self):
         # Stop and Start a server with an attached volume, ensuring that
         # the volume remains attached.
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 7d3c075..a6302e6 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -75,7 +75,7 @@
                 #Checking if the deleted Volume still exists
                 self.client.wait_for_resource_deletion(volume['id'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_volume_get_metadata_none(self):
         # CREATE, GET empty metadata dict
         try:
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index bbfadba..bcc49aa 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -33,7 +33,7 @@
     alt_tenant = rand_name('test_tenant_')
     alt_description = rand_name('desc_')
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_create_user(self):
         # Create a user
         self.data.setup_test_tenant()
@@ -125,7 +125,7 @@
         # Unset the token to allow further tests to generate a new token
         self.client.clear_auth()
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_delete_user(self):
         # Delete a user
         self.data.setup_test_tenant()
@@ -150,7 +150,7 @@
         self.assertRaises(exceptions.NotFound, self.client.delete_user,
                           'junk12345123')
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_user_authentication(self):
         # Valid user's token is authenticated
         self.data.setup_test_user()
@@ -225,7 +225,7 @@
         self.assertEqual('200', resp['status'])
         self.client.clear_auth()
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_get_users(self):
         # Get a list of users and find the test user
         self.data.setup_test_user()
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
new file mode 100644
index 0000000..8d019fe
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -0,0 +1,54 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.identity import base
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class DomainsTestJSON(base.BaseIdentityAdminTest):
+    _interface = 'json'
+
+    def _delete_domain(self, domain_id):
+        # It is necessary to disable the domian before deleting,
+        # or else it would result in unauthorized error
+        _, body = self.v3_client.update_domain(domain_id, enabled=False)
+        resp, _ = self.v3_client.delete_domain(domain_id)
+        self.assertEqual(204, resp.status)
+
+    @attr(type='smoke')
+    def test_list_domains(self):
+        #Test to list domains
+        domain_ids = list()
+        fetched_ids = list()
+        for _ in range(3):
+            _, domain = self.v3_client.create_domain(
+                rand_name('domain-'), description=rand_name('domain-desc-'))
+            # Delete the domian at the end of this method
+            self.addCleanup(self._delete_domain, domain['id'])
+            domain_ids.append(domain['id'])
+        # List and Verify Domains
+        resp, body = self.v3_client.list_domains()
+        self.assertEqual(resp['status'], '200')
+        for d in body:
+            fetched_ids.append(d['id'])
+        missing_doms = [d for d in domain_ids if d not in fetched_ids]
+        self.assertEqual(0, len(missing_doms))
+
+
+class DomainsTestXML(DomainsTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index c5d3f93..640daa5 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -47,7 +47,6 @@
                                        properties=properties)
         self.assertTrue('id' in body)
         image_id = body.get('id')
-        self.created_images.append(image_id)
         self.assertEqual('New Name', body.get('name'))
         self.assertTrue(body.get('is_public'))
         self.assertEqual('queued', body.get('status'))
@@ -71,8 +70,6 @@
                                        properties={'key1': 'value1',
                                                    'key2': 'value2'})
         self.assertTrue('id' in body)
-        image_id = body.get('id')
-        self.created_images.append(image_id)
         self.assertEqual('New Remote Image', body.get('name'))
         self.assertTrue(body.get('is_public'))
         self.assertEqual('active', body.get('status'))
@@ -88,7 +85,6 @@
                                        copy_from=self.config.images.http_image)
         self.assertTrue('id' in body)
         image_id = body.get('id')
-        self.created_images.append(image_id)
         self.assertEqual('New Http Image', body.get('name'))
         self.assertTrue(body.get('is_public'))
         self.client.wait_for_image_status(image_id, 'active')
@@ -106,8 +102,6 @@
                                        min_ram=40,
                                        properties=properties)
         self.assertTrue('id' in body)
-        image_id = body.get('id')
-        self.created_images.append(image_id)
         self.assertEqual('New_image_with_min_ram', body.get('name'))
         self.assertTrue(body.get('is_public'))
         self.assertEqual('queued', body.get('status'))
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 966adc3..34db6e3 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -50,7 +50,6 @@
                                        visibility='public')
         self.assertTrue('id' in body)
         image_id = body.get('id')
-        self.created_images.append(image_id)
         self.assertTrue('name' in body)
         self.assertEqual('New Name', body.get('name'))
         self.assertTrue('visibility' in body)
@@ -79,7 +78,7 @@
         # We add a few images here to test the listing functionality of
         # the images API
         for x in xrange(0, 10):
-            cls.created_images.append(cls._create_standard_image(x))
+            cls._create_standard_image(x)
 
     @classmethod
     def _create_standard_image(cls, number):
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index e0e40cb..8068284 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -73,6 +73,7 @@
         cidr = netaddr.IPNetwork(cls.network_cfg.tenant_network_cidr)
         mask_bits = cls.network_cfg.tenant_network_mask_bits
         # Find a cidr that is not in use yet and create a subnet with it
+        failure = None
         for subnet_cidr in cidr.subnet(mask_bits):
             try:
                 resp, body = cls.client.create_subnet(network['id'],
@@ -82,6 +83,12 @@
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
                 if not is_overlapping_cidr:
                     raise
+                # save the failure in case all of the CIDRs are overlapping
+                failure = e
+
+        if not body and failure:
+            raise failure
+
         subnet = body['subnet']
         cls.subnets.append(subnet)
         return subnet
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 78c09e0..1f45f92 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -54,7 +54,7 @@
         cls.subnet = cls.create_subnet(cls.network)
         cls.cidr = cls.subnet['cidr']
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_create_delete_network_subnet(self):
         # Creates a network
         name = rand_name('network-')
@@ -83,7 +83,7 @@
         resp, body = self.client.delete_network(network['id'])
         self.assertEqual('204', resp['status'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_show_network(self):
         # Verifies the details of a network
         resp, body = self.client.show_network(self.network['id'])
@@ -92,7 +92,7 @@
         self.assertEqual(self.network['id'], network['id'])
         self.assertEqual(self.name, network['name'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_networks(self):
         # Verify the network exists in the list of all networks
         resp, body = self.client.list_networks()
@@ -100,7 +100,7 @@
         found = any(n for n in networks if n['id'] == self.network['id'])
         self.assertTrue(found)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_show_subnet(self):
         # Verifies the details of a subnet
         resp, body = self.client.show_subnet(self.subnet['id'])
@@ -109,7 +109,7 @@
         self.assertEqual(self.subnet['id'], subnet['id'])
         self.assertEqual(self.cidr, subnet['cidr'])
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_list_subnets(self):
         # Verify the subnet exists in the list of all subnets
         resp, body = self.client.list_subnets()
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index d7b87d1..b40774e 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -53,27 +53,25 @@
         self.assertIn('x-account-bytes-used', resp)
 
     @attr(type='smoke')
-    def test_create_account_metadata(self):
+    def test_create_and_delete_account_metadata(self):
+        header = 'test-account-meta'
+        data = 'Meta!'
         # add metadata to account
-        metadata = {'test-account-meta': 'Meta!'}
-        resp, _ = \
-            self.account_client.create_account_metadata(metadata=metadata)
+        resp, _ = self.account_client.create_account_metadata(
+            metadata={header: data})
         self.assertEqual(resp['status'], '204')
 
-        resp, metadata = self.account_client.list_account_metadata()
-        self.assertIn('x-account-meta-test-account-meta', resp)
-        self.assertEqual(resp['x-account-meta-test-account-meta'], 'Meta!')
+        resp, _ = self.account_client.list_account_metadata()
+        self.assertIn('x-account-meta-' + header, resp)
+        self.assertEqual(resp['x-account-meta-' + header], data)
 
-    @attr(type='smoke')
-    def test_delete_account_metadata(self):
         # delete metadata from account
-        metadata = ['test-account-meta']
         resp, _ = \
-            self.account_client.delete_account_metadata(metadata=metadata)
+            self.account_client.delete_account_metadata(metadata=[header])
         self.assertEqual(resp['status'], '204')
 
-        resp, metadata = self.account_client.list_account_metadata()
-        self.assertNotIn('x-account-meta-test-account-meta', resp)
+        resp, _ = self.account_client.list_account_metadata()
+        self.assertNotIn('x-account-meta-' + header, resp)
 
     @attr(type=['negative', 'gate'])
     def test_list_containers_with_non_authorized_user(self):
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index a1c1c06..ea8637c 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -52,7 +52,7 @@
             cls.delete_containers(cls.containers, client[0], client[1])
 
     @testtools.skip('Until Bug #1093743 is resolved.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_container_synchronization(self):
         # container to container synchronization
         # to allow/accept sync requests to/from other accounts
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 72a1d51..a83e92c 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -15,10 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import hashlib
 import time
 
-import testtools
-
 from tempest.api.object_storage import base
 from tempest.common.utils.data_utils import arbitrary_string
 from tempest.common.utils.data_utils import rand_name
@@ -298,8 +297,7 @@
                           self.container_name, object_name,
                           metadata=self.custom_headers)
 
-    @testtools.skip('Until Bug #1097137 is resolved.')
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_get_object_using_temp_url(self):
         # access object using temporary URL within expiration time
 
@@ -337,7 +335,7 @@
                 resp, _ = self.account_client.list_account_metadata()
                 self.assertNotIn('x-account-meta-temp-url-key', resp)
 
-    @attr(type=['positive', 'gate'])
+    @attr(type='gate')
     def test_object_upload_in_segments(self):
         # create object
         object_name = rand_name(name='LObject')
@@ -366,6 +364,30 @@
             self.container_name, object_name)
         self.assertEqual(data * segments, body)
 
+    @attr(type='gate')
+    def test_get_object_if_different(self):
+        # http://en.wikipedia.org/wiki/HTTP_ETag
+        # Make a conditional request for an object using the If-None-Match
+        # header, it should get downloaded only if the local file is different,
+        # otherwise the response code should be 304 Not Modified
+        object_name = rand_name(name='TestObject')
+        data = arbitrary_string()
+        self.object_client.create_object(self.container_name,
+                                         object_name, data)
+        # local copy is identical, no download
+        md5 = hashlib.md5(data).hexdigest()
+        headers = {'If-None-Match': md5}
+        url = "%s/%s" % (self.container_name, object_name)
+        resp, _ = self.object_client.get(url, headers=headers)
+        self.assertEqual(resp['status'], '304')
+
+        # local copy is different, download
+        local_data = "something different"
+        md5 = hashlib.md5(local_data).hexdigest()
+        headers = {'If-None-Match': md5}
+        resp, body = self.object_client.get(url, headers=headers)
+        self.assertEqual(resp['status'], '200')
+
 
 class PublicObjectTest(base.BaseObjectTest):
     def setUp(self):
@@ -444,71 +466,3 @@
         except Exception as e:
             self.fail("Failed to get public readable object with another"
                       " user creds raised exception is %s" % e)
-
-    @testtools.skip('Until Bug #1020722 is resolved.')
-    @attr(type='smoke')
-    def test_write_public_object_without_using_creds(self):
-        # make container public-writable, and create object anonymously, e.g.
-        # without using credentials
-        try:
-            # update container metadata to make publicly writable
-            cont_headers = {'X-Container-Write': '-*'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers, metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-            # list container metadata
-            resp, _ = self.container_client.list_container_metadata(
-                self.container_name)
-            self.assertEqual(resp['status'], '204')
-            self.assertIn('x-container-write', resp)
-            self.assertEqual(resp['x-container-write'], '-*')
-
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name),
-                                    base_text=object_name)
-            headers = {'Content-Type': 'application/json',
-                       'Accept': 'application/json'}
-            # create object as anonymous user
-            resp, body = self.custom_object_client.create_object(
-                self.container_name, object_name, data, metadata=headers)
-            self.assertEqual(resp['status'], '201')
-
-        except Exception as e:
-            self.fail("Failed to create public writable object without using"
-                      " creds raised exception is %s" % e)
-
-    @testtools.skip('Until Bug #1020722 is resolved.')
-    @attr(type='smoke')
-    def test_write_public_with_another_user_creds(self):
-        # make container public-writable, and create object with another user's
-        # credentials
-        try:
-            # update container metadata to make it publicly writable
-            cont_headers = {'X-Container-Write': '-*'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers,
-                metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-            # list container metadata
-            resp, _ = self.container_client.list_container_metadata(
-                self.container_name)
-            self.assertEqual(resp['status'], '204')
-            self.assertIn('x-container-write', resp)
-            self.assertEqual(resp['x-container-write'], '-*')
-
-            # trying to get auth token of alternative user
-            token = self.identity_client_alt.get_auth()
-            headers = {'Content-Type': 'application/json',
-                       'Accept': 'application/json',
-                       'X-Auth-Token': token}
-
-            # trying to create an object with another user's creds
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name),
-                                    base_text=object_name)
-            resp, body = self.custom_object_client.create_object(
-                self.container_name, object_name, data, metadata=headers)
-            self.assertEqual(resp['status'], '201')
-        except Exception as e:
-            self.fail("Failed to create public writable object with another"
-                      " user creds raised exception is %s" % e)
diff --git a/tempest/api/orchestration/stacks/test_instance_cfn_init.py b/tempest/api/orchestration/stacks/test_instance_cfn_init.py
new file mode 100644
index 0000000..2349830
--- /dev/null
+++ b/tempest/api/orchestration/stacks/test_instance_cfn_init.py
@@ -0,0 +1,152 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    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 json
+import logging
+
+from tempest.api.orchestration import base
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+LOG = logging.getLogger(__name__)
+
+
+class InstanceCfnInitTestJSON(base.BaseOrchestrationTest):
+    _interface = 'json'
+
+    template = """
+HeatTemplateFormatVersion: '2012-12-12'
+Description: |
+  Template which uses a wait condition to confirm that a minimal
+  cfn-init and cfn-signal has worked
+Parameters:
+  KeyName:
+    Type: String
+  InstanceType:
+    Type: String
+  ImageId:
+    Type: String
+Resources:
+  CfnUser:
+    Type: AWS::IAM::User
+  SmokeKeys:
+    Type: AWS::IAM::AccessKey
+    Properties:
+      UserName: {Ref: CfnUser}
+  SmokeServer:
+    Type: AWS::EC2::Instance
+    Metadata:
+      AWS::CloudFormation::Init:
+        config:
+          files:
+            /tmp/smoke-status:
+              content: smoke test complete
+            /etc/cfn/cfn-credentials:
+              content:
+                Fn::Join:
+                - ''
+                - - AWSAccessKeyId=
+                  - {Ref: SmokeKeys}
+                  - '
+
+                    '
+                  - AWSSecretKey=
+                  - Fn::GetAtt: [SmokeKeys, SecretAccessKey]
+                  - '
+
+                    '
+              mode: '000400'
+              owner: root
+              group: root
+    Properties:
+      ImageId: {Ref: ImageId}
+      InstanceType: {Ref: InstanceType}
+      KeyName: {Ref: KeyName}
+      UserData:
+        Fn::Base64:
+          Fn::Join:
+          - ''
+          - - |-
+                #!/bin/bash -v
+                /opt/aws/bin/cfn-init
+            - |-
+                || error_exit ''Failed to run cfn-init''
+                /opt/aws/bin/cfn-signal -e 0 --data "`cat /tmp/smoke-status`" '
+            - {Ref: WaitHandle}
+            - '''
+
+              '
+  WaitHandle:
+    Type: AWS::CloudFormation::WaitConditionHandle
+  WaitCondition:
+    Type: AWS::CloudFormation::WaitCondition
+    DependsOn: SmokeServer
+    Properties:
+      Handle: {Ref: WaitHandle}
+      Timeout: '600'
+Outputs:
+  WaitConditionStatus:
+    Description: Contents of /tmp/smoke-status on SmokeServer
+    Value:
+      Fn::GetAtt: [WaitCondition, Data]
+"""
+
+    @classmethod
+    def setUpClass(cls):
+        super(InstanceCfnInitTestJSON, cls).setUpClass()
+        if not cls.orchestration_cfg.image_ref:
+            raise cls.skipException("No image available to test")
+        cls.client = cls.orchestration_client
+
+    def setUp(self):
+        super(InstanceCfnInitTestJSON, self).setUp()
+        stack_name = rand_name('heat')
+        keypair_name = (self.orchestration_cfg.keypair_name or
+                        self._create_keypair()['name'])
+
+        # create the stack
+        self.stack_identifier = self.create_stack(
+            stack_name,
+            self.template,
+            parameters={
+                'KeyName': keypair_name,
+                'InstanceType': self.orchestration_cfg.instance_type,
+                'ImageId': self.orchestration_cfg.image_ref
+            })
+
+    @attr(type='gate')
+    def test_stack_wait_condition_data(self):
+
+        sid = self.stack_identifier
+
+        # wait for create to complete.
+        self.client.wait_for_stack_status(sid, 'CREATE_COMPLETE')
+
+        # fetch the stack
+        resp, body = self.client.get_stack(sid)
+        self.assertEqual('CREATE_COMPLETE', body['stack_status'])
+
+        # fetch the stack
+        resp, body = self.client.get_stack(sid)
+        self.assertEqual('CREATE_COMPLETE', body['stack_status'])
+
+        # This is an assert of great significance, as it means the following
+        # has happened:
+        # - cfn-init read the provided metadata and wrote out a file
+        # - a user was created and credentials written to the instance
+        # - a cfn-signal was built which was signed with provided credentials
+        # - the wait condition was fulfilled and the stack has changed state
+        wait_status = json.loads(body['outputs'][0]['output_value'])
+        self.assertEqual('smoke test complete', wait_status['00000'])
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 2b2b1a1..086b981 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -1,8 +1,5 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
 #    a copy of the License at
@@ -15,12 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.volume import base
 from tempest.common import log as logging
 from tempest.common.utils.data_utils import rand_name
-from tempest import config
 from tempest.services.volume.json.admin import volume_types_client
 from tempest.services.volume.json import volumes_client
 from tempest.test import attr
@@ -31,66 +25,62 @@
 class VolumeMultiBackendTest(base.BaseVolumeAdminTest):
     _interface = "json"
 
-    multi_backend_enabled = config.TempestConfig().volume.multi_backend_enabled
-    backend1_name = config.TempestConfig().volume.backend1_name
-    backend2_name = config.TempestConfig().volume.backend2_name
-    backend_names_equal = False
-    if (backend1_name == backend2_name):
-        backend_names_equal = True
-
     @classmethod
-    @testtools.skipIf(not multi_backend_enabled,
-                      "Cinder multi-backend feature is not available")
     def setUpClass(cls):
         super(VolumeMultiBackendTest, cls).setUpClass()
+        if not cls.config.volume.multi_backend_enabled:
+            raise cls.skipException("Cinder multi-backend feature disabled")
+
+        cls.backend1_name = cls.config.volume.backend1_name
+        cls.backend2_name = cls.config.volume.backend2_name
 
         adm_user = cls.config.identity.admin_username
         adm_pass = cls.config.identity.admin_password
         adm_tenant = cls.config.identity.admin_tenant_name
         auth_url = cls.config.identity.uri
 
-        cls.client = volumes_client.VolumesClientJSON(cls.config,
-                                                      adm_user,
-                                                      adm_pass,
-                                                      auth_url,
-                                                      adm_tenant)
-        cls.client2 = volume_types_client.VolumeTypesClientJSON(cls.config,
-                                                                adm_user,
-                                                                adm_pass,
-                                                                auth_url,
-                                                                adm_tenant)
+        cls.volume_client = volumes_client.VolumesClientJSON(cls.config,
+                                                             adm_user,
+                                                             adm_pass,
+                                                             auth_url,
+                                                             adm_tenant)
+        cls.type_client = volume_types_client.VolumeTypesClientJSON(cls.config,
+                                                                    adm_user,
+                                                                    adm_pass,
+                                                                    auth_url,
+                                                                    adm_tenant)
 
-        ## variables initialization
-        type_name1 = rand_name('type-')
-        type_name2 = rand_name('type-')
-        cls.volume_type_list = []
-
-        vol_name1 = rand_name('Volume-')
-        vol_name2 = rand_name('Volume-')
+        cls.volume_type_id_list = []
         cls.volume_id_list = []
-
         try:
-            ## Volume types creation
+            # Volume/Type creation (uses backend1_name)
+            type1_name = rand_name('Type-')
+            vol1_name = rand_name('Volume-')
             extra_specs1 = {"volume_backend_name": cls.backend1_name}
-            resp, cls.body1 = cls.client2.create_volume_type(
-                type_name1, extra_specs=extra_specs1)
-            cls.volume_type_list.append(cls.body1)
+            resp, cls.type1 = cls.type_client.create_volume_type(
+                type1_name, extra_specs=extra_specs1)
+            cls.volume_type_id_list.append(cls.type1['id'])
 
-            extra_specs2 = {"volume_backend_name": cls.backend2_name}
-            resp, cls.body2 = cls.client2.create_volume_type(
-                type_name2, extra_specs=extra_specs2)
-            cls.volume_type_list.append(cls.body2)
-
-            ## Volumes creation
-            resp, cls.volume1 = cls.client.create_volume(
-                size=1, display_name=vol_name1, volume_type=type_name1)
-            cls.client.wait_for_volume_status(cls.volume1['id'], 'available')
+            resp, cls.volume1 = cls.volume_client.create_volume(
+                size=1, display_name=vol1_name, volume_type=type1_name)
             cls.volume_id_list.append(cls.volume1['id'])
+            cls.volume_client.wait_for_volume_status(cls.volume1['id'],
+                                                     'available')
 
-            resp, cls.volume2 = cls.client.create_volume(
-                size=1, display_name=vol_name2, volume_type=type_name2)
-            cls.client.wait_for_volume_status(cls.volume2['id'], 'available')
-            cls.volume_id_list.append(cls.volume2['id'])
+            if cls.backend1_name != cls.backend2_name:
+                # Volume/Type creation (uses backend2_name)
+                type2_name = rand_name('Type-')
+                vol2_name = rand_name('Volume-')
+                extra_specs2 = {"volume_backend_name": cls.backend2_name}
+                resp, cls.type2 = cls.type_client.create_volume_type(
+                    type2_name, extra_specs=extra_specs2)
+                cls.volume_type_id_list.append(cls.type2['id'])
+
+                resp, cls.volume2 = cls.volume_client.create_volume(
+                    size=1, display_name=vol2_name, volume_type=type2_name)
+                cls.volume_id_list.append(cls.volume2['id'])
+                cls.volume_client.wait_for_volume_status(cls.volume2['id'],
+                                                         'available')
         except Exception:
             LOG.exception("setup failed")
             cls.tearDownClass()
@@ -100,60 +90,43 @@
     def tearDownClass(cls):
         ## volumes deletion
         for volume_id in cls.volume_id_list:
-            cls.client.delete_volume(volume_id)
-            cls.client.wait_for_resource_deletion(volume_id)
+            cls.volume_client.delete_volume(volume_id)
+            cls.volume_client.wait_for_resource_deletion(volume_id)
 
         ## volume types deletion
-        for volume_type in cls.volume_type_list:
-            cls.client2.delete_volume_type(volume_type)
+        for volume_type_id in cls.volume_type_id_list:
+            cls.type_client.delete_volume_type(volume_type_id)
 
         super(VolumeMultiBackendTest, cls).tearDownClass()
 
-    @attr(type=['smoke'])
-    def test_multi_backend_enabled(self):
-        # this test checks that multi backend is enabled for at least the
-        # computes where the volumes created in setUp were made
+    @attr(type='smoke')
+    def test_backend_name_reporting(self):
+        # this test checks if os-vol-attr:host is populated correctly after
+        # the multi backend feature has been enabled
         # if multi-backend is enabled: os-vol-attr:host should be like:
         # host@backend_name
-        # this test fails if:
-        # - multi backend is not enabled
-        resp, fetched_volume = self.client.get_volume(self.volume1['id'])
+        resp, volume = self.volume_client.get_volume(self.volume1['id'])
         self.assertEqual(200, resp.status)
 
-        volume_host1 = fetched_volume['os-vol-host-attr:host']
-        msg = ("Multi-backend is not available for at least host "
-               "%(volume_host1)s") % locals()
-        self.assertTrue(len(volume_host1.split("@")) > 1, msg)
-
-        resp, fetched_volume = self.client.get_volume(self.volume2['id'])
-        self.assertEqual(200, resp.status)
-
-        volume_host2 = fetched_volume['os-vol-host-attr:host']
-        msg = ("Multi-backend is not available for at least host "
-               "%(volume_host2)s") % locals()
-        self.assertTrue(len(volume_host2.split("@")) > 1, msg)
+        volume1_host = volume['os-vol-host-attr:host']
+        msg = ("multi-backend reporting incorrect values for volume %s" %
+               self.volume1['id'])
+        self.assertTrue(len(volume1_host.split("@")) > 1, msg)
 
     @attr(type='gate')
     def test_backend_name_distinction(self):
-        # this test checks that the two volumes created at setUp doesn't
-        # belong to the same backend (if they are in the same backend, that
-        # means, volume_backend_name distinction is not working properly)
-        # this test fails if:
-        # - tempest.conf is not well configured
-        # - the two volumes belongs to the same backend
+        # this test checks that the two volumes created at setUp don't
+        # belong to the same backend (if they are, than the
+        # volume backend distinction is not working properly)
+        if self.backend1_name == self.backend2_name:
+            raise self.skipException("backends configured with same name")
 
-        # checks tempest.conf
-        msg = ("tempest.conf is not well configured, "
-               "backend1_name and backend2_name are equal")
-        self.assertEqual(self.backend_names_equal, False, msg)
+        resp, volume = self.volume_client.get_volume(self.volume1['id'])
+        volume1_host = volume['os-vol-host-attr:host']
 
-        # checks the two volumes belongs to different backend
-        resp, fetched_volume = self.client.get_volume(self.volume1['id'])
-        volume_host1 = fetched_volume['os-vol-host-attr:host']
+        resp, volume = self.volume_client.get_volume(self.volume2['id'])
+        volume2_host = volume['os-vol-host-attr:host']
 
-        resp, fetched_volume = self.client.get_volume(self.volume2['id'])
-        volume_host2 = fetched_volume['os-vol-host-attr:host']
-
-        msg = ("volume2 was created in the same backend as volume1: "
-               "%(volume_host2)s.") % locals()
-        self.assertNotEqual(volume_host2, volume_host1, msg)
+        msg = ("volumes %s and %s were created in the same backend" %
+               (self.volume1['id'], self.volume2['id']))
+        self.assertNotEqual(volume1_host, volume2_host, msg)
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 74a62cb..4131d3e 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -38,7 +38,7 @@
                                                                auth_url,
                                                                adm_tenant)
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_type_list(self):
         # List Volume types.
         try:
@@ -48,7 +48,7 @@
         except Exception:
             self.fail("Could not list volume types")
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_create_get_delete_volume_with_volume_type_and_extra_specs(self):
         # Create/get/delete volume with volume_type and extra spec.
         try:
@@ -100,7 +100,7 @@
                 resp, _ = self.client.delete_volume_type(body['id'])
                 self.assertEqual(202, resp.status)
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_type_create_delete(self):
         # Create/Delete volume type.
         try:
@@ -123,7 +123,7 @@
         except Exception:
             self.fail("Could not create a volume_type")
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_type_create_get(self):
         # Create/get volume type.
         try:
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index 20c5cc4..417f296 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -34,7 +34,7 @@
         cls.client.delete_volume_type(cls.volume_type['id'])
         super(VolumeTypesExtraSpecsTest, cls).tearDownClass()
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_type_extra_specs_list(self):
         # List Volume types extra specs.
         try:
@@ -53,7 +53,7 @@
         except Exception:
             self.fail("Could not list volume types extra specs")
 
-    @attr(type=['gate'])
+    @attr(type='gate')
     def test_volume_type_extra_specs_update(self):
         # Update volume type extra specs
         try:
@@ -77,7 +77,7 @@
         except Exception:
             self.fail("Couldnt update volume type extra spec")
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_type_extra_spec_create_get_delete(self):
         # Create/Get/Delete volume type extra spec.
         try:
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 41fd930..cd5ab34 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -52,7 +52,7 @@
 
         super(VolumesActionsTest, cls).tearDownClass()
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_attach_detach_volume_to_instance(self):
         # Volume is attached and detached successfully from an instance
         try:
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 0148183..68ab745 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -105,11 +105,11 @@
                 self.assertEqual(202, resp.status)
                 self.client.wait_for_resource_deletion(volume['id'])
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_create_get_delete(self):
         self._volume_create_get_delete(image_ref=None)
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_from_image(self):
         self._volume_create_get_delete(image_ref=self.config.compute.image_ref)
 
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 3202662..5d5fd7e 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -76,7 +76,7 @@
             cls.client.wait_for_resource_deletion(volid)
         super(VolumesListTest, cls).tearDownClass()
 
-    @attr(type=['smoke'])
+    @attr(type='smoke')
     def test_volume_list(self):
         # Get a list of Volumes
         # Fetch all volumes
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 3a0c802..602209a 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -12,8 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.volume import base
 from tempest.common import log as logging
 from tempest.common.utils.data_utils import rand_name
@@ -82,6 +80,5 @@
         self.clear_snapshots()
 
 
-@testtools.skip("Until Bug #1177610 is resolved.")
 class VolumesSnapshotTestXML(VolumesSnapshotTest):
     _interface = "xml"
diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst
index 4742d4a..76b05a3 100644
--- a/tempest/cli/README.rst
+++ b/tempest/cli/README.rst
@@ -1,16 +1,16 @@
 Tempest Guide to CLI tests
-========
+==========================
 
 
 What are these tests?
----------
+---------------------
 The cli tests test the various OpenStack command line interface tools
 to ensure that they minimally function. The current scope is read only
 operations on a cloud that are hard to test via unit tests.
 
 
 Why are these tests in tempest?
----------
+-------------------------------
 These tests exist here because it is extremely difficult to build a
 functional enough environment in the python-*client unit tests to
 provide this kind of testing. Because we already put up a cloud in the
@@ -20,14 +20,14 @@
 
 
 Scope of these tests
----------
+--------------------
 This should stay limited to the scope of testing the cli. Functional
 testing of the cloud should be elsewhere, this is about exercising the
 cli code.
 
 
 Example of a good test
----------
+----------------------
 Tests should be isolated to a single command in one of the python
 clients.
 
diff --git a/tempest/cli/simple_read_only/test_keystone.py b/tempest/cli/simple_read_only/test_keystone.py
index 067f58c..45d519b 100644
--- a/tempest/cli/simple_read_only/test_keystone.py
+++ b/tempest/cli/simple_read_only/test_keystone.py
@@ -107,3 +107,14 @@
 
     def test_admin_bashcompletion(self):
         self.keystone('bash-completion')
+
+    # Optional arguments:
+
+    def test_admin_version(self):
+        self.keystone('', flags='--version')
+
+    def test_admin_debug_list(self):
+        self.keystone('catalog', flags='--debug')
+
+    def test_admin_timeout(self):
+        self.keystone('catalog', flags='--timeout 15')
diff --git a/tempest/clients.py b/tempest/clients.py
index d78ce61..e778dc1 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -30,6 +30,8 @@
 from tempest.services.compute.json.floating_ips_client import \
     FloatingIPsClientJSON
 from tempest.services.compute.json.hosts_client import HostsClientJSON
+from tempest.services.compute.json.hypervisor_client import \
+    HypervisorClientJSON
 from tempest.services.compute.json.images_client import ImagesClientJSON
 from tempest.services.compute.json.interfaces_client import \
     InterfacesClientJSON
@@ -52,6 +54,7 @@
 from tempest.services.compute.xml.flavors_client import FlavorsClientXML
 from tempest.services.compute.xml.floating_ips_client import \
     FloatingIPsClientXML
+from tempest.services.compute.xml.hypervisor_client import HypervisorClientXML
 from tempest.services.compute.xml.images_client import ImagesClientXML
 from tempest.services.compute.xml.interfaces_client import \
     InterfacesClientXML
@@ -231,6 +234,11 @@
     "xml": PolicyClientXML,
 }
 
+HYPERVISOR_CLIENT = {
+    "json": HypervisorClientJSON,
+    "xml": HypervisorClientXML,
+}
+
 
 class Manager(object):
 
@@ -264,14 +272,26 @@
             raise exceptions.InvalidConfiguration(msg)
 
         self.auth_url = self.config.identity.uri
+        self.auth_url_v3 = self.config.identity.uri_v3
 
         if self.config.identity.strategy == 'keystone':
             client_args = (self.config, self.username, self.password,
                            self.auth_url, self.tenant_name)
+
+            if self.auth_url_v3:
+                auth_version = 'v3'
+                client_args_v3_auth = (self.config, self.username,
+                                       self.password, self.auth_url_v3,
+                                       self.tenant_name, auth_version)
+            else:
+                client_args_v3_auth = None
+
         else:
             client_args = (self.config, self.username, self.password,
                            self.auth_url)
 
+            client_args_v3_auth = None
+
         try:
             self.servers_client = SERVERS_CLIENTS[interface](*client_args)
             self.limits_client = LIMITS_CLIENTS[interface](*client_args)
@@ -305,6 +325,14 @@
             self.tenant_usages_client = \
                 TENANT_USAGES_CLIENT[interface](*client_args)
             self.policy_client = POLICY_CLIENT[interface](*client_args)
+            self.hypervisor_client = HYPERVISOR_CLIENT[interface](*client_args)
+
+            if client_args_v3_auth:
+                self.servers_client_v3_auth = SERVERS_CLIENTS[interface](
+                    *client_args_v3_auth)
+            else:
+                self.servers_client_v3_auth = None
+
         except KeyError:
             msg = "Unsupported interface type `%s'" % interface
             raise exceptions.InvalidConfiguration(msg)
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index d81af83..baa3c03 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -1,6 +1,7 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
 # Copyright 2012 OpenStack, LLC
+# Copyright 2013 IBM Corp.
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -36,12 +37,14 @@
     TYPE = "json"
     LOG = logging.getLogger(__name__)
 
-    def __init__(self, config, user, password, auth_url, tenant_name=None):
+    def __init__(self, config, user, password, auth_url, tenant_name=None,
+                 auth_version='v2'):
         self.config = config
         self.user = user
         self.password = password
         self.auth_url = auth_url
         self.tenant_name = tenant_name
+        self.auth_version = auth_version
 
         self.service = None
         self.token = None
@@ -70,11 +73,16 @@
         """
 
         if self.strategy == 'keystone':
-            self.token, self.base_url = self.keystone_auth(self.user,
-                                                           self.password,
-                                                           self.auth_url,
-                                                           self.service,
-                                                           self.tenant_name)
+
+            if self.auth_version == 'v3':
+                auth_func = self.identity_auth_v3
+            else:
+                auth_func = self.keystone_auth
+
+            self.token, self.base_url = (
+                auth_func(self.user, self.password, self.auth_url,
+                          self.service, self.tenant_name))
+
         else:
             self.token, self.base_url = self.basic_auth(self.user,
                                                         self.password,
@@ -116,7 +124,7 @@
 
     def keystone_auth(self, user, password, auth_url, service, tenant_name):
         """
-        Provides authentication via Keystone.
+        Provides authentication via Keystone using v2 identity API.
         """
 
         # Normalize URI to ensure /tokens is in it.
@@ -170,6 +178,90 @@
         raise exceptions.IdentityError('Unexpected status code {0}'.format(
             resp.status))
 
+    def identity_auth_v3(self, user, password, auth_url, service,
+                         project_name, domain_id='default'):
+        """Provides authentication using Identity API v3."""
+
+        req_url = auth_url.rstrip('/') + '/auth/tokens'
+
+        creds = {
+            "auth": {
+                "identity": {
+                    "methods": ["password"],
+                    "password": {
+                        "user": {
+                            "name": user, "password": password,
+                            "domain": {"id": domain_id}
+                        }
+                    }
+                },
+                "scope": {
+                    "project": {
+                        "domain": {"id": domain_id},
+                        "name": project_name
+                    }
+                }
+            }
+        }
+
+        headers = {'Content-Type': 'application/json'}
+        body = json.dumps(creds)
+        resp, body = self.http_obj.request(req_url, 'POST',
+                                           headers=headers, body=body)
+
+        if resp.status == 201:
+            try:
+                token = resp['x-subject-token']
+            except Exception:
+                self.LOG.exception("Failed to obtain token using V3"
+                                   " authentication (auth URL is '%s')" %
+                                   req_url)
+                raise
+
+            catalog = json.loads(body)['token']['catalog']
+
+            mgmt_url = None
+            for service_info in catalog:
+                if service_info['type'] != service:
+                    continue  # this isn't the entry for us.
+
+                endpoints = service_info['endpoints']
+
+                # Look for an endpoint in the region if configured.
+                if service in self.region:
+                    region = self.region[service]
+
+                    for ep in endpoints:
+                        if ep['region'] != region:
+                            continue
+
+                        mgmt_url = ep['url']
+                        # FIXME(blk-u): this isn't handling endpoint type
+                        # (public, internal, admin).
+                        break
+
+                if not mgmt_url:
+                    # Didn't find endpoint for region, use the first.
+
+                    ep = endpoints[0]
+                    mgmt_url = ep['url']
+                    # FIXME(blk-u): this isn't handling endpoint type
+                    # (public, internal, admin).
+
+                break
+
+            return token, mgmt_url
+
+        elif resp.status == 401:
+            raise exceptions.AuthenticationFailure(user=user,
+                                                   password=password)
+        else:
+            self.LOG.error("Failed to obtain token using V3 authentication"
+                           " (auth URL is '%s'), the response status is %s" %
+                           (req_url, resp.status))
+            raise exceptions.AuthenticationFailure(user=user,
+                                                   password=password)
+
     def post(self, url, body, headers):
         return self.request('POST', url, headers, body)
 
diff --git a/tempest/config.py b/tempest/config.py
index 8f3e574..85be7a6 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -37,7 +37,9 @@
                 help="Set to True if using self-signed SSL certificates."),
     cfg.StrOpt('uri',
                default=None,
-               help="Full URI of the OpenStack Identity API (Keystone)"),
+               help="Full URI of the OpenStack Identity API (Keystone), v2"),
+    cfg.StrOpt('uri_v3',
+               help='Full URI of the OpenStack Identity API (Keystone), v3'),
     cfg.StrOpt('strategy',
                default='keystone',
                help="Which auth method does the environment use? "
@@ -118,6 +120,13 @@
     cfg.IntOpt('flavor_ref_alt',
                default=2,
                help='Valid secondary flavor to be used in tests.'),
+    cfg.StrOpt('image_ssh_user',
+               default="root",
+               help="User name used to authenticate to an instance."),
+    cfg.StrOpt('image_alt_ssh_user',
+               default="root",
+               help="User name used to authenticate to an instance using "
+                    "the alternate image."),
     cfg.BoolOpt('resize_available',
                 default=False,
                 help="Does the test environment support resizing?"),
@@ -316,12 +325,12 @@
                help="Catalog type of the Volume Service"),
     cfg.BoolOpt('multi_backend_enabled',
                 default=False,
-                help="Runs Cinder multi-backend test (requires 2 backend)"),
+                help="Runs Cinder multi-backend test (requires 2 backends)"),
     cfg.StrOpt('backend1_name',
-               default='LVM_iSCSI',
+               default='BACKEND_1',
                help="Name of the backend1 (must be declared in cinder.conf)"),
     cfg.StrOpt('backend2_name',
-               default='LVM_iSCSI_1',
+               default='BACKEND_2',
                help="Name of the backend2 (must be declared in cinder.conf)"),
 ]
 
@@ -379,7 +388,7 @@
                 default=False,
                 help="Whether or not Heat is expected to be available"),
     cfg.StrOpt('instance_type',
-               default='m1.tiny',
+               default='m1.micro',
                help="Instance type for tests. Needs to be big enough for a "
                     "full OS plus the test workload"),
     cfg.StrOpt('image_ref',
@@ -486,6 +495,34 @@
         conf.register_opt(opt, group='stress')
 
 
+scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options')
+
+ScenarioGroup = [
+    cfg.StrOpt('img_dir',
+               default='/opt/stack/new/devstack/files/images/'
+               'cirros-0.3.1-x86_64-uec',
+               help='Directory containing image files'),
+    cfg.StrOpt('ami_img_file',
+               default='cirros-0.3.1-x86_64-blank.img',
+               help='AMI image file name'),
+    cfg.StrOpt('ari_img_file',
+               default='cirros-0.3.1-x86_64-initrd',
+               help='ARI image file name'),
+    cfg.StrOpt('aki_img_file',
+               default='cirros-0.3.1-x86_64-vmlinuz',
+               help='AKI image file name'),
+    cfg.StrOpt('ssh_user',
+               default='cirros',
+               help='ssh username for the image file')
+]
+
+
+def register_scenario_opts(conf):
+    conf.register_group(scenario_group)
+    for opt in ScenarioGroup:
+        conf.register_opt(opt, group='scenario')
+
+
 @singleton
 class TempestConfig:
     """Provides OpenStack configuration information."""
@@ -535,6 +572,7 @@
         register_boto_opts(cfg.CONF)
         register_compute_admin_opts(cfg.CONF)
         register_stress_opts(cfg.CONF)
+        register_scenario_opts(cfg.CONF)
         self.compute = cfg.CONF.compute
         self.whitebox = cfg.CONF.whitebox
         self.identity = cfg.CONF.identity
@@ -546,6 +584,7 @@
         self.boto = cfg.CONF.boto
         self.compute_admin = cfg.CONF['compute-admin']
         self.stress = cfg.CONF.stress
+        self.scenario = cfg.CONF.scenario
         if not self.compute_admin.username:
             self.compute_admin.username = self.identity.admin_username
             self.compute_admin.password = self.identity.admin_password
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 353a9ac..5e941da 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -53,6 +53,17 @@
                      " in tempest/api/* tests"))
 
 
+def import_no_files_in_tests(physical_line, filename):
+    """Check for merges that try to land into tempest/tests
+
+    T103: tempest/tests directory is deprecated
+    """
+
+    if "tempest/tests" in filename:
+        return (0, ("T103: tempest/tests is deprecated"))
+
+
 def factory(register):
     register(skip_bugs)
     register(import_no_clients_in_api)
+    register(import_no_files_in_tests)
diff --git a/tempest/manager.py b/tempest/manager.py
index 25e80ad..762bc18 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -22,6 +22,7 @@
 from tempest.services.compute.json import extensions_client
 from tempest.services.compute.json import flavors_client
 from tempest.services.compute.json import floating_ips_client
+from tempest.services.compute.json import hypervisor_client
 from tempest.services.compute.json import images_client
 from tempest.services.compute.json import keypairs_client
 from tempest.services.compute.json import limits_client
@@ -46,6 +47,7 @@
 VolumesClient = volumes_client.VolumesClientJSON
 SnapshotsClient = snapshots_client.SnapshotsClientJSON
 QuotasClient = quotas_client.QuotasClientJSON
+HypervisorClient = hypervisor_client.HypervisorClientJSON
 
 LOG = logging.getLogger(__name__)
 
@@ -132,6 +134,7 @@
         self.snapshots_client = SnapshotsClient(*client_args)
         self.quotas_client = QuotasClient(*client_args)
         self.network_client = NetworkClient(*client_args)
+        self.hypervisor_client = HypervisorClient(*client_args)
 
 
 class ComputeFuzzClientAltManager(Manager):
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
index c5fa0d3..98b74e4 100644
--- a/tempest/scenario/README.rst
+++ b/tempest/scenario/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to Scenario tests
-========
+===============================
 
 
 What are these tests?
---------
+---------------------
 
 Scenario tests are "through path" tests of OpenStack
 function. Complicated setups where one part might depend on completion
@@ -17,13 +17,13 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 This is one of tempests core purposes, testing the integration between
 projects.
 
 
 Scope of these tests
---------
+--------------------
 Scenario tests should always test at least 2 services in
 interaction. They should use the official python client libraries for
 OpenStack, as they provide a more realistic approach in how people
@@ -34,7 +34,7 @@
 
 
 Example of a good test
---------
+----------------------
 While we are looking for interaction of 2 or more services, be
 specific in your interactions. A giant "this is my data center" smoke
 test is hard to debug when it goes wrong.
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index a358f20..366ff43 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -20,19 +20,17 @@
 import subprocess
 
 # Default client libs
+import cinderclient.client
 import glanceclient
 import keystoneclient.v2_0.client
 import netaddr
 import novaclient.client
-try:
-    # TODO(sdague): is there are reason this is still optional
-    from quantumclient.common import exceptions as exc
-    import quantumclient.v2_0.client
+from quantumclient.common import exceptions as exc
+import quantumclient.v2_0.client
 
-except ImportError:
-    pass
 
 from tempest.api.network import common as net_common
+from tempest.common import ssh
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 import tempest.manager
@@ -49,6 +47,7 @@
     """
 
     NOVACLIENT_VERSION = '2'
+    CINDERCLIENT_VERSION = '1'
 
     def __init__(self):
         super(OfficialClientManager, self).__init__()
@@ -56,11 +55,13 @@
         self.image_client = self._get_image_client()
         self.identity_client = self._get_identity_client()
         self.network_client = self._get_network_client()
+        self.volume_client = self._get_volume_client()
         self.client_attr_names = [
             'compute_client',
             'image_client',
             'identity_client',
             'network_client',
+            'volume_client'
         ]
 
     def _get_compute_client(self, username=None, password=None,
@@ -103,6 +104,22 @@
         return glanceclient.Client('1', endpoint=endpoint, token=token,
                                    insecure=dscv)
 
+    def _get_volume_client(self, username=None, password=None,
+                           tenant_name=None):
+        if not username:
+            username = self.config.identity.username
+        if not password:
+            password = self.config.identity.password
+        if not tenant_name:
+            tenant_name = self.config.identity.tenant_name
+
+        auth_url = self.config.identity.uri
+        return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
+                                          username,
+                                          password,
+                                          tenant_name,
+                                          auth_url)
+
     def _get_identity_client(self, username=None, password=None,
                              tenant_name=None):
         # This identity client is not intended to check the security
@@ -263,6 +280,11 @@
             self.fail("SecurityGroup object not successfully created.")
 
         # Add rules to the security group
+
+        # These rules are intended to permit inbound ssh and icmp
+        # traffic from all sources, so no group_id is provided.
+        # Setting a group_id would only permit traffic from ports
+        # belonging to the same security group.
         rulesets = [
             {
                 # ssh
@@ -270,7 +292,6 @@
                 'from_port': 22,
                 'to_port': 22,
                 'cidr': '0.0.0.0/0',
-                'group_id': secgroup.id
             },
             {
                 # ping
@@ -278,7 +299,6 @@
                 'from_port': -1,
                 'to_port': -1,
                 'cidr': '0.0.0.0/0',
-                'group_id': secgroup.id
             }
         ]
         for ruleset in rulesets:
@@ -420,3 +440,22 @@
 
         # TODO(mnewby) Allow configuration of execution and sleep duration.
         return tempest.test.call_until_true(ping, 20, 1)
+
+    def _is_reachable_via_ssh(self, ip_address, username, private_key,
+                              timeout=120):
+        ssh_client = ssh.Client(ip_address, username,
+                                pkey=private_key,
+                                timeout=timeout)
+        return ssh_client.test_connection_auth()
+
+    def _check_vm_connectivity(self, ip_address, username, private_key,
+                               timeout=120):
+        self.assertTrue(self._ping_ip_address(ip_address),
+                        "Timed out waiting for %s to become "
+                        "reachable" % ip_address)
+        self.assertTrue(self._is_reachable_via_ssh(ip_address,
+                                                   username,
+                                                   private_key,
+                                                   timeout=timeout),
+                        'Auth failure in connecting to %s@%s via ssh' %
+                        (username, ip_address))
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
new file mode 100644
index 0000000..a55bbb2
--- /dev/null
+++ b/tempest/scenario/test_minimum_basic.py
@@ -0,0 +1,208 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import logging
+
+from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.scenario import manager
+
+
+LOG = logging.getLogger(__name__)
+
+
+class TestMinimumBasicScenario(manager.OfficialClientTest):
+
+    """
+    This is a basic minimum scenario test.
+
+    This test below:
+    * across the multiple components
+    * as a regular user
+    * with and without optional parameters
+    * check command outputs
+
+    """
+
+    def _wait_for_server_status(self, status):
+        server_id = self.server.id
+        self.status_timeout(
+            self.compute_client.servers, server_id, status)
+
+    def _wait_for_volume_status(self, status):
+        volume_id = self.volume.id
+        self.status_timeout(
+            self.volume_client.volumes, volume_id, status)
+
+    def _image_create(self, name, fmt, path, properties={}):
+        name = rand_name('%s-' % name)
+        image_file = open(path, 'rb')
+        self.addCleanup(image_file.close)
+        params = {
+            'name': name,
+            'container_format': fmt,
+            'disk_format': fmt,
+            'is_public': 'True',
+        }
+        params.update(properties)
+        image = self.image_client.images.create(**params)
+        self.addCleanup(self.image_client.images.delete, image)
+        self.assertEqual("queued", image.status)
+        image.update(data=image_file)
+        return image.id
+
+    def glance_image_create(self):
+        aki_img_path = self.config.scenario.img_dir + "/" + \
+            self.config.scenario.aki_img_file
+        ari_img_path = self.config.scenario.img_dir + "/" + \
+            self.config.scenario.ari_img_file
+        ami_img_path = self.config.scenario.img_dir + "/" + \
+            self.config.scenario.ami_img_file
+        LOG.debug("paths: ami: %s, ari: %s, aki: %s"
+                  % (ami_img_path, ari_img_path, aki_img_path))
+        kernel_id = self._image_create('scenario-aki', 'aki', aki_img_path)
+        ramdisk_id = self._image_create('scenario-ari', 'ari', ari_img_path)
+        properties = {
+            'properties': {'kernel_id': kernel_id, 'ramdisk_id': ramdisk_id}
+        }
+        self.image = self._image_create('scenario-ami', 'ami',
+                                        path=ami_img_path,
+                                        properties=properties)
+
+    def nova_keypair_add(self):
+        name = rand_name('scenario-keypair-')
+
+        self.keypair = self.compute_client.keypairs.create(name=name)
+        self.addCleanup(self.compute_client.keypairs.delete, self.keypair)
+        self.assertEqual(name, self.keypair.name)
+
+    def nova_boot(self):
+        name = rand_name('scenario-server-')
+        client = self.compute_client
+        flavor_id = self.config.compute.flavor_ref
+        self.server = client.servers.create(name=name, image=self.image,
+                                            flavor=flavor_id,
+                                            key_name=self.keypair.name)
+        self.addCleanup(self.compute_client.servers.delete, self.server)
+        self.assertEqual(name, self.server.name)
+        self._wait_for_server_status('ACTIVE')
+
+    def nova_list(self):
+        servers = self.compute_client.servers.list()
+        LOG.debug("server_list:%s" % servers)
+        self.assertTrue(self.server in servers)
+
+    def nova_show(self):
+        got_server = self.compute_client.servers.get(self.server)
+        LOG.debug("got server:%s" % got_server)
+        self.assertEqual(self.server, got_server)
+
+    def cinder_create(self):
+        name = rand_name('scenario-volume-')
+        LOG.debug("volume display-name:%s" % name)
+        self.volume = self.volume_client.volumes.create(size=1,
+                                                        display_name=name)
+        LOG.debug("volume created:%s" % self.volume.display_name)
+        self._wait_for_volume_status('available')
+
+        self.addCleanup(self.volume_client.volumes.delete, self.volume)
+        self.assertEqual(name, self.volume.display_name)
+
+    def cinder_list(self):
+        volumes = self.volume_client.volumes.list()
+        self.assertTrue(self.volume in volumes)
+
+    def cinder_show(self):
+        volume = self.volume_client.volumes.get(self.volume.id)
+        self.assertEqual(self.volume, volume)
+
+    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_reboot(self):
+        self.server.reboot()
+        self._wait_for_server_status('ACTIVE')
+
+    def nova_floating_ip_create(self):
+        self.floating_ip = self.compute_client.floating_ips.create()
+        self.addCleanup(self.floating_ip.delete)
+
+    def nova_floating_ip_add(self):
+        self.server.add_floating_ip(self.floating_ip)
+
+    def nova_security_group_rule_create(self):
+        sgs = self.compute_client.security_groups.list()
+        for sg in sgs:
+            if sg.name == 'default':
+                secgroup = sg
+
+        ruleset = {
+            # ssh
+            'ip_protocol': 'tcp',
+            'from_port': 22,
+            'to_port': 22,
+            'cidr': '0.0.0.0/0',
+            'group_id': None
+        }
+        sg_rule = self.compute_client.security_group_rules.create(secgroup.id,
+                                                                  **ruleset)
+        self.addCleanup(self.compute_client.security_group_rules.delete,
+                        sg_rule.id)
+
+    def ssh_to_server(self):
+        username = self.config.scenario.ssh_user
+        self.linux_client = RemoteClient(self.floating_ip.ip,
+                                         username,
+                                         pkey=self.keypair.private_key)
+
+    def check_partitions(self):
+        partitions = self.linux_client.get_partitions()
+        self.assertEqual(1, partitions.count('vdb'))
+
+    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 test_minimum_basic_scenario(self):
+        self.glance_image_create()
+        self.nova_keypair_add()
+        self.nova_boot()
+        self.nova_list()
+        self.nova_show()
+        self.cinder_create()
+        self.cinder_list()
+        self.cinder_show()
+        self.nova_volume_attach()
+        self.cinder_show()
+        self.nova_reboot()
+
+        self.nova_floating_ip_create()
+        self.nova_floating_ip_add()
+        self.nova_security_group_rule_create()
+        self.ssh_to_server()
+        self.check_partitions()
+
+        self.nova_volume_detach()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 5ccfd52..b94caaa 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -31,10 +31,15 @@
 
      * For a freshly-booted VM with an IP address ("port") on a given network:
 
-       - the Tempest host can ping the IP address.  This implies that
-         the VM has been assigned the correct IP address and has
+       - the Tempest host can ping the IP address.  This implies, but
+         does not guarantee (see the ssh check that follows), that the
+         VM has been assigned the correct IP address and has
          connectivity to the Tempest host.
 
+       - the Tempest host can perform key-based authentication to an
+         ssh server hosted at the IP address.  This check guarantees
+         that the IP address is associated with the target VM.
+
        #TODO(mnewby) - Need to implement the following:
        - the Tempest host can ssh into the VM via the IP address and
          successfully execute the following:
@@ -214,12 +219,15 @@
             raise self.skipTest(msg)
         if not self.servers:
             raise self.skipTest("No VM's have been created")
+        # The target login is assumed to have been configured for
+        # key-based authentication by cloud-init.
+        ssh_login = self.config.compute.image_ssh_user
+        private_key = self.keypairs[self.tenant_id].private_key
         for server in self.servers:
             for net_name, ip_addresses in server.networks.iteritems():
                 for ip_address in ip_addresses:
-                    self.assertTrue(self._ping_ip_address(ip_address),
-                                    "Timed out waiting for %s's ip to become "
-                                    "reachable" % server.name)
+                    self._check_vm_connectivity(ip_address, ssh_login,
+                                                private_key)
 
     @attr(type='smoke')
     def test_007_assign_floating_ips(self):
@@ -237,9 +245,11 @@
     def test_008_check_public_network_connectivity(self):
         if not self.floating_ips:
             raise self.skipTest('No floating ips have been allocated.')
+        # The target login is assumed to have been configured for
+        # key-based authentication by cloud-init.
+        ssh_login = self.config.compute.image_ssh_user
+        private_key = self.keypairs[self.tenant_id].private_key
         for server, floating_ips in self.floating_ips.iteritems():
             for floating_ip in floating_ips:
                 ip_address = floating_ip.floating_ip_address
-                self.assertTrue(self._ping_ip_address(ip_address),
-                                "Timed out waiting for %s's ip to become "
-                                "reachable" % server.name)
+                self._check_vm_connectivity(ip_address, ssh_login, private_key)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 9ac0cc0..6202e91 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -28,6 +28,7 @@
     This test case stresses some advanced server instance operations:
 
      * Resizing an instance
+     * Sequence suspend resume
     """
 
     @classmethod
@@ -44,11 +45,6 @@
             msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
             raise cls.skipException(msg)
 
-    @classmethod
-    def tearDownClass(cls):
-        for thing in cls.resources:
-            thing.delete()
-
     def test_resize_server_confirm(self):
         # We create an instance for use in this test
         i_name = rand_name('instance')
@@ -56,12 +52,8 @@
         base_image_id = self.config.compute.image_ref
         self.instance = self.compute_client.servers.create(
             i_name, base_image_id, flavor_id)
-        try:
-            self.assertEqual(self.instance.name, i_name)
-            self.set_resource('instance', self.instance)
-        except AttributeError:
-            self.fail("Instance not successfully created.")
-
+        self.assertEqual(self.instance.name, i_name)
+        self.set_resource('instance', self.instance)
         self.assertEqual(self.instance.status, 'BUILD')
         instance_id = self.get_resource('instance').id
         self.status_timeout(
@@ -77,5 +69,42 @@
 
         LOG.debug("Confirming resize of instance %s", instance_id)
         instance.confirm_resize()
+
         self.status_timeout(
             self.compute_client.servers, instance_id, 'ACTIVE')
+
+    def test_server_sequence_suspend_resume(self):
+        # We create an instance for use in this test
+        i_name = rand_name('instance')
+        flavor_id = self.config.compute.flavor_ref
+        base_image_id = self.config.compute.image_ref
+        self.instance = self.compute_client.servers.create(
+            i_name, base_image_id, flavor_id)
+        self.assertEqual(self.instance.name, i_name)
+        self.set_resource('instance', self.instance)
+        self.assertEqual(self.instance.status, 'BUILD')
+        instance_id = self.get_resource('instance').id
+        self.status_timeout(
+            self.compute_client.servers, instance_id, 'ACTIVE')
+        instance = self.get_resource('instance')
+        instance_id = instance.id
+        LOG.debug("Suspending instance %s. Current status: %s",
+                  instance_id, instance.status)
+        instance.suspend()
+        self.status_timeout(self.compute_client.servers, instance_id,
+                            'SUSPENDED')
+        LOG.debug("Resuming instance %s. Current status: %s",
+                  instance_id, instance.status)
+        instance.resume()
+        self.status_timeout(self.compute_client.servers, instance_id,
+                            'ACTIVE')
+        LOG.debug("Suspending instance %s. Current status: %s",
+                  instance_id, instance.status)
+        instance.suspend()
+        self.status_timeout(self.compute_client.servers, instance_id,
+                            'SUSPENDED')
+        LOG.debug("Resuming instance %s. Current status: %s",
+                  instance_id, instance.status)
+        instance.resume()
+        self.status_timeout(self.compute_client.servers, instance_id,
+                            'ACTIVE')
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
new file mode 100644
index 0000000..e2e5c7b
--- /dev/null
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -0,0 +1,65 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class HypervisorClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorClientJSON, self).__init__(config, username,
+                                                   password, auth_url,
+                                                   tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def get_hypervisor_list(self):
+        """List hypervisors information."""
+        resp, body = self.get('os-hypervisors')
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_list_details(self):
+        """Show detailed hypervisors information."""
+        resp, body = self.get('os-hypervisors/detail')
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_show_details(self, hyper_id):
+        """Display the details of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s' % hyper_id)
+        body = json.loads(body)
+        return resp, body['hypervisor']
+
+    def get_hypervisor_servers(self, hyper_name):
+        """List instances belonging to the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/servers' % hyper_name)
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_stats(self):
+        """Get hypervisor statistics over all compute nodes."""
+        resp, body = self.get('os-hypervisors/statistics')
+        body = json.loads(body)
+        return resp, body['hypervisor_statistics']
+
+    def get_hypervisor_uptime(self, hyper_id):
+        """Display the uptime of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id)
+        body = json.loads(body)
+        return resp, body['hypervisor']
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 376dafc..b13d0f1 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -150,3 +150,10 @@
         resp, body = self.delete("images/%s/metadata/%s" %
                                  (str(image_id), key))
         return resp, body
+
+    def is_resource_deleted(self, id):
+        try:
+            self.get_image(id)
+        except exceptions.NotFound:
+            return True
+        return False
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 3569b50..d4822da 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -26,9 +26,11 @@
 
 class ServersClientJSON(RestClient):
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
+    def __init__(self, config, username, password, auth_url, tenant_name=None,
+                 auth_version='v2'):
         super(ServersClientJSON, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
+                                                auth_url, tenant_name,
+                                                auth_version=auth_version)
         self.service = self.config.compute.catalog_type
 
     def create_server(self, name, image_ref, flavor_ref, **kwargs):
diff --git a/tempest/services/compute/xml/hypervisor_client.py b/tempest/services/compute/xml/hypervisor_client.py
new file mode 100644
index 0000000..3c4f2b8
--- /dev/null
+++ b/tempest/services/compute/xml/hypervisor_client.py
@@ -0,0 +1,72 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class HypervisorClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorClientXML, self).__init__(config, username,
+                                                  password, auth_url,
+                                                  tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _parse_array(self, node):
+        return [xml_to_json(x) for x in node]
+
+    def get_hypervisor_list(self):
+        """List hypervisors information."""
+        resp, body = self.get('os-hypervisors', self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_list_details(self):
+        """Show detailed hypervisors information."""
+        resp, body = self.get('os-hypervisors/detail', self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_show_details(self, hyper_id):
+        """Display the details of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s' % hyper_id,
+                              self.headers)
+        hypervisor = xml_to_json(etree.fromstring(body))
+        return resp, hypervisor
+
+    def get_hypervisor_servers(self, hyper_name):
+        """List instances belonging to the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/servers' % hyper_name,
+                              self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_stats(self):
+        """Get hypervisor statistics over all compute nodes."""
+        resp, body = self.get('os-hypervisors/statistics', self.headers)
+        stats = xml_to_json(etree.fromstring(body))
+        return resp, stats
+
+    def get_hypervisor_uptime(self, hyper_id):
+        """Display the uptime of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id,
+                              self.headers)
+        uptime = xml_to_json(etree.fromstring(body))
+        return resp, uptime
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index c7e337b..cc13aa1 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -226,3 +226,10 @@
         """Deletes a single image metadata key/value pair."""
         return self.delete("images/%s/metadata/%s" % (str(image_id), key),
                            self.headers)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.get_image(id)
+        except exceptions.NotFound:
+            return True
+        return False
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 6d811a5..1ec4df0 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -111,9 +111,11 @@
 
 class ServersClientXML(RestClientXML):
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
+    def __init__(self, config, username, password, auth_url, tenant_name=None,
+                 auth_version='v2'):
         super(ServersClientXML, self).__init__(config, username, password,
-                                               auth_url, tenant_name)
+                                               auth_url, tenant_name,
+                                               auth_version=auth_version)
         self.service = self.config.compute.catalog_type
 
     def _parse_key_value(self, node):
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
old mode 100755
new mode 100644
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 014df1e..adbdc83 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -160,3 +160,51 @@
                               (project_id, user_id, role_id), None,
                               self.headers)
         return resp, body
+
+    def create_domain(self, name, **kwargs):
+        """Creates a domain."""
+        description = kwargs.get('description', None)
+        en = kwargs.get('enabled', True)
+        post_body = {
+            'description': description,
+            'enabled': en,
+            'name': name
+        }
+        post_body = json.dumps({'domain': post_body})
+        resp, body = self.post('domains', post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['domain']
+
+    def delete_domain(self, domain_id):
+        """Delete a domain."""
+        resp, body = self.delete('domains/%s' % str(domain_id))
+        return resp, body
+
+    def list_domains(self):
+        """List Domains."""
+        resp, body = self.get('domains')
+        body = json.loads(body)
+        return resp, body['domains']
+
+    def update_domain(self, domain_id, **kwargs):
+        """Updates a domain."""
+        resp, body = self.get_domain(domain_id)
+        description = kwargs.get('description', body['description'])
+        en = kwargs.get('enabled', body['enabled'])
+        name = kwargs.get('name', body['name'])
+        post_body = {
+            'description': description,
+            'enabled': en,
+            'name': name
+        }
+        post_body = json.dumps({'domain': post_body})
+        resp, body = self.patch('domains/%s' % domain_id, post_body,
+                                self.headers)
+        body = json.loads(body)
+        return resp, body['domain']
+
+    def get_domain(self, domain_id):
+        """Get Domain details."""
+        resp, body = self.get('domains/%s' % domain_id)
+        body = json.loads(body)
+        return resp, body['domain']
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
old mode 100755
new mode 100644
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index 92151dd..708ee28 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -44,6 +44,14 @@
                 array.append(xml_to_json(child))
         return array
 
+    def _parse_domains(self, node):
+        array = []
+        for child in node.getchildren():
+            tag_list = child.tag.split('}', 1)
+            if tag_list[1] == "domain":
+                array.append(xml_to_json(child))
+        return array
+
     def _parse_array(self, node):
         array = []
         for child in node.getchildren():
@@ -185,3 +193,51 @@
         resp, body = self.put('projects/%s/users/%s/roles/%s' %
                               (project_id, user_id, role_id), '', self.headers)
         return resp, body
+
+    def create_domain(self, name, **kwargs):
+        """Creates a domain."""
+        description = kwargs.get('description', None)
+        en = kwargs.get('enabled', True)
+        post_body = Element("domain",
+                            xmlns=XMLNS,
+                            name=name,
+                            description=description,
+                            enabled=str(en).lower())
+        resp, body = self.post('domains', str(Document(post_body)),
+                               self.headers)
+        body = self._parse_body(etree.fromstring(body))
+        return resp, body
+
+    def list_domains(self):
+        """Get the list of domains."""
+        resp, body = self.get("domains", self.headers)
+        body = self._parse_domains(etree.fromstring(body))
+        return resp, body
+
+    def delete_domain(self, domain_id):
+        """Delete a domain."""
+        resp, body = self.delete('domains/%s' % domain_id, self.headers)
+        return resp, body
+
+    def update_domain(self, domain_id, **kwargs):
+        """Updates a domain."""
+        resp, body = self.get_domain(domain_id)
+        description = kwargs.get('description', body['description'])
+        en = kwargs.get('enabled', body['enabled'])
+        name = kwargs.get('name', body['name'])
+        post_body = Element("domain",
+                            xmlns=XMLNS,
+                            name=name,
+                            description=description,
+                            enabled=str(en).lower())
+        resp, body = self.patch('domains/%s' % domain_id,
+                                str(Document(post_body)),
+                                self.headers)
+        body = self._parse_body(etree.fromstring(body))
+        return resp, body
+
+    def get_domain(self, domain_id):
+        """Get Domain details."""
+        resp, body = self.get('domains/%s' % domain_id, self.headers)
+        body = self._parse_body(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index 410ed3e..b35c43e 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -48,7 +48,10 @@
 
         resp, body = self.get(url, self.headers)
         body = etree.fromstring(body)
-        return resp, xml_to_json(body)
+        snapshots = []
+        for snap in body:
+            snapshots.append(xml_to_json(snap))
+        return resp, snapshots
 
     def list_snapshots_with_detail(self, params=None):
         """List all the details of snapshot."""
@@ -60,7 +63,9 @@
         resp, body = self.get(url, self.headers)
         body = etree.fromstring(body)
         snapshots = []
-        return resp, snapshots(xml_to_json(body))
+        for snap in body:
+            snapshots.append(xml_to_json(snap))
+        return resp, snapshots
 
     def get_snapshot(self, snapshot_id):
         """Returns the details of a single snapshot."""
diff --git a/tempest/stress/README.rst b/tempest/stress/README.rst
index 2fcdf2e..661763c 100644
--- a/tempest/stress/README.rst
+++ b/tempest/stress/README.rst
@@ -1,5 +1,5 @@
 Tempest Field Guide to Stress Tests
-======================================================
+===================================
 
 Nova is a distributed, asynchronous system that is prone to race condition
 bugs. These bugs will not be easily found during
@@ -9,7 +9,7 @@
 
 
 Environment
-------------
+-----------
 This particular framework assumes your working Nova cluster understands Nova
 API 2.0. The stress tests can read the logs from the cluster. To enable this
 you have to provide the hostname to call 'nova-manage' and
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index 2c0d8ae..0f836d0 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -72,21 +72,22 @@
         retrieved_image = self.images_client.get_image(image["image_id"])
         self.assertTrue(retrieved_image.name == image["name"])
         self.assertTrue(retrieved_image.id == image["image_id"])
-        if retrieved_image.state != "available":
+        state = retrieved_image.state
+        if state != "available":
             def _state():
                 retr = self.images_client.get_image(image["image_id"])
                 return retr.state
             state = state_wait(_state, "available")
         self.assertEqual("available", state)
         self.images_client.deregister_image(image["image_id"])
-        #TODO(afazekas): double deregister ?
+        self.assertNotIn(image["image_id"], str(
+            self.images_client.get_all_images()))
         self.cancelResourceCleanUp(image["cleanUp"])
 
-    @testtools.skip("Skipped until the Bug #1074904 is resolved")
     def test_register_get_deregister_aki_image(self):
         # Register and deregister aki image
         image = {"name": rand_name("aki-name-"),
-                 "location": self.bucket_name + "/" + self.ari_manifest,
+                 "location": self.bucket_name + "/" + self.aki_manifest,
                  "type": "aki"}
         image["image_id"] = self.images_client.register_image(
             name=image["name"],
@@ -102,9 +103,8 @@
         if retrieved_image.state != "available":
             self.assertImageStateWait(retrieved_image, "available")
         self.images_client.deregister_image(image["image_id"])
-        #TODO(afazekas): verify deregister in  a better way
-        retrieved_image = self.images_client.get_image(image["image_id"])
-        self.assertIn(retrieved_image.state, self.valid_image_state)
+        self.assertNotIn(image["image_id"], str(
+            self.images_client.get_all_images()))
         self.cancelResourceCleanUp(image["cleanUp"])
 
     @testtools.skip("Skipped until the Bug #1074908 and #1074904 is resolved")
diff --git a/tempest/whitebox/README.rst b/tempest/whitebox/README.rst
index dabf758..0e45421 100644
--- a/tempest/whitebox/README.rst
+++ b/tempest/whitebox/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to Whitebox tests
-========
+===============================
 
 
 What are these tests?
---------
+---------------------
 
 When you hit the OpenStack API, this causes internal state changes in
 the system. This might be database transitions, vm modifications,
@@ -20,7 +20,7 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 
 Especially when it comes to something like VM state changing, which is
 a coordination of numerous running daemons, and a functioning VM, it's
@@ -28,7 +28,7 @@
 
 
 Scope of these tests
---------
+--------------------
 
 White box tests should be limitted to tests where black box testing
 (using the OpenStack API to verify results) isn't sufficient.
@@ -40,7 +40,7 @@
 
 
 Example of a good test
---------
+----------------------
 
 Pushing VMs through a series of state transitions, and ensuring along
 the way the database state transitions match what's expected.
diff --git a/tempest/whitebox/test_images_whitebox.py b/tempest/whitebox/test_images_whitebox.py
index 8a23e8f..dc68336 100644
--- a/tempest/whitebox/test_images_whitebox.py
+++ b/tempest/whitebox/test_images_whitebox.py
@@ -18,11 +18,13 @@
 from tempest.api.compute import base
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
-from tempest.test import attr
 from tempest.whitebox import manager
 
+#TODO(afazekas): The whitebox tests are using complex testclass/manager
+# hierarchy, without a real need. It is difficult to maintain.
+# They could share more code with scenario tests.
 
-@attr(type='whitebox')
+
 class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest):
     _interface = 'json'
 
@@ -36,7 +38,8 @@
 
     @classmethod
     def tearDownClass(cls):
-        """Delete images after a test is executed."""
+        """Delete images and server after a test is executed."""
+        cls.servers_client.delete_server(cls.shared_server['id'])
         for image_id in cls.image_ids:
             cls.client.delete_image(image_id)
             cls.image_ids.remove(image_id)
diff --git a/tempest/whitebox/test_servers_whitebox.py b/tempest/whitebox/test_servers_whitebox.py
index 5db0dc6..2694b95 100644
--- a/tempest/whitebox/test_servers_whitebox.py
+++ b/tempest/whitebox/test_servers_whitebox.py
@@ -17,11 +17,9 @@
 
 from tempest.api.identity.base import BaseIdentityAdminTest
 from tempest import exceptions
-from tempest.test import attr
 from tempest.whitebox import manager
 
 
-@attr(type='whitebox')
 class ServersWhiteboxTest(manager.ComputeWhiteboxTest):
     _interface = 'json'
 
@@ -52,70 +50,6 @@
             except exceptions.NotFound:
                 continue
 
-    def test_create_server_vcpu_quota_full(self):
-        # Disallow server creation when tenant's vcpu quota is full
-        quotas = self.meta.tables['quotas']
-        stmt = (quotas.select().
-                where(quotas.c.project_id == self.tenant_id).
-                where(quotas.c.resource == 'cores'))
-        result = self.connection.execute(stmt).first()
-
-        # Set vcpu quota for tenant if not already set
-        if not result:
-            cores_hard_limit = 2
-            stmt = quotas.insert().values(deleted=0,
-                                          project_id=self.tenant_id,
-                                          resource='cores',
-                                          hard_limit=cores_hard_limit)
-
-            self.connection.execute(stmt, autocommit=True)
-        else:
-            cores_hard_limit = result.hard_limit
-
-        # Create servers assuming 1 VCPU per instance i.e flavor_id=1
-        try:
-            for count in range(cores_hard_limit + 1):
-                self.create_server()
-        except exceptions.OverLimit:
-            pass
-        else:
-            self.fail("Could create servers over the VCPU quota limit")
-        finally:
-            stmt = quotas.delete()
-            self.connection.execute(stmt, autocommit=True)
-
-    def test_create_server_memory_quota_full(self):
-        # Disallow server creation when tenant's memory quota is full
-        quotas = self.meta.tables['quotas']
-        stmt = (quotas.select().
-                where(quotas.c.project_id == self.tenant_id).
-                where(quotas.c.resource == 'ram'))
-        result = self.connection.execute(stmt).first()
-
-        # Set memory quota for tenant if not already set
-        if not result:
-            ram_hard_limit = 1024
-            stmt = quotas.insert().values(deleted=0,
-                                          project_id=self.tenant_id,
-                                          resource='ram',
-                                          hard_limit=ram_hard_limit)
-
-            self.connection.execute(stmt, autocommit=True)
-        else:
-            ram_hard_limit = result.hard_limit
-
-        try:
-            # Set a hard range of 3 servers for reaching the RAM quota
-            for count in range(3):
-                self.create_server()
-        except exceptions.OverLimit:
-            pass
-        else:
-            self.fail("Could create servers over the RAM quota limit")
-        finally:
-            stmt = quotas.delete()
-            self.connection.execute(stmt, autocommit=True)
-
     def update_state(self, server_id, vm_state, task_state, deleted=0):
         """Update states of an instance in database for validation."""
         if not task_state:
diff --git a/tools/test-requires b/test-requirements.txt
similarity index 100%
rename from tools/test-requires
rename to test-requirements.txt
diff --git a/tools/install_venv.py b/tools/install_venv.py
index 5d4b290..1664b35 100644
--- a/tools/install_venv.py
+++ b/tools/install_venv.py
@@ -62,8 +62,8 @@
 def main(argv):
     root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
     venv = os.path.join(root, '.venv')
-    pip_requires = os.path.join(root, 'tools', 'pip-requires')
-    test_requires = os.path.join(root, 'tools', 'test-requires')
+    pip_requires = os.path.join(root, 'requirements.txt')
+    test_requires = os.path.join(root, 'test-requirements.txt')
     py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
     project = 'Tempest'
     install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index a4cf394..c7b0033 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -28,7 +28,7 @@
 from launchpadlib import launchpad
 
 BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
-TESTDIR = os.path.join(BASEDIR, 'tempest', 'tests')
+TESTDIR = os.path.join(BASEDIR, 'tempest')
 LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
 
 
diff --git a/tox.ini b/tox.ini
index 924e844..634b7df 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,6 +10,18 @@
          NOSE_OPENSTACK_SHOW_ELAPSED=1
          NOSE_OPENSTACK_STDOUT=1
 
+[testenv:all]
+sitepackages = True
+setenv = VIRTUAL_ENV={envdir}
+         NOSE_WITH_OPENSTACK=1
+         NOSE_OPENSTACK_COLOR=1
+         NOSE_OPENSTACK_RED=15
+         NOSE_OPENSTACK_YELLOW=3
+         NOSE_OPENSTACK_SHOW_ELAPSED=1
+         NOSE_OPENSTACK_STDOUT=1
+commands =
+  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-all.xml -sv tempest
+
 [testenv:full]
 sitepackages = True
 setenv = VIRTUAL_ENV={envdir}
@@ -51,13 +63,13 @@
 
 [testenv:venv]
 commands = {posargs}
-deps = -r{toxinidir}/tools/pip-requires
-       -r{toxinidir}/tools/test-requires
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
 
 [testenv:pep8]
 commands = flake8
-deps = -r{toxinidir}/tools/pip-requires
-       -r{toxinidir}/tools/test-requires
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
 
 [hacking]
 local-check-factory = tempest.hacking.checks.factory