Merge "Use channel_timeout for SSH connection timeout"
diff --git a/HACKING.rst b/HACKING.rst
index 377c647..a74ff73 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -186,3 +186,9 @@
 
 - Scenario tests
 - API tests that have a wide focus
+
+Sample Configuration File
+-------------------------
+The sample config file is autogenerated using a script. If any changes are made
+to the config variables in tempest then the sample config file must be
+regenerated. This can be done running the script: tools/generate_sample.sh
diff --git a/README.rst b/README.rst
index 0996022..96f6e4c 100644
--- a/README.rst
+++ b/README.rst
@@ -79,6 +79,9 @@
 document. The etc/tempest.conf.sample attempts to be a self
 documenting version of the configuration.
 
+The sample config file is auto generated using the script:
+tools/generate_sample.sh
+
 The most important pieces that are needed are the user ids, openstack
 endpoints, and basic flavors and images needed to run tests.
 
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 567b85a..8742b67 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -236,10 +236,10 @@
 # value)
 #image_ref_alt={$IMAGE_ID_ALT}
 
-# Valid primary flavor to use in tests. (integer value)
+# Valid primary flavor to use in tests. (string value)
 #flavor_ref=1
 
-# Valid secondary flavor to be used in tests. (integer value)
+# Valid secondary flavor to be used in tests. (string value)
 #flavor_ref_alt=2
 
 # User name used to authenticate to an instance. (string
@@ -674,7 +674,7 @@
 #
 
 # If false, skip all nova v3 tests. (boolean value)
-#api_v3=false
+#api_v3=true
 
 # If false, skip disk config tests (boolean value)
 #disk_config=true
@@ -711,7 +711,7 @@
 # Options defined in tempest.config
 #
 
-# Set to True if the container quota middleware is enabled
+# Set to True if the Container Quota middleware is enabled
 # (boolean value)
 #container_quotas=true
 
@@ -723,6 +723,10 @@
 # (boolean value)
 #crossdomain=true
 
+# Set to True if the TempURL middleware is enabled (boolean
+# value)
+#tempurl=true
+
 
 [volume-feature-enabled]
 
diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml
index e6d28f5..e5a0d4d 100644
--- a/etc/whitelist.yaml
+++ b/etc/whitelist.yaml
@@ -31,6 +31,14 @@
       message: "Getting disk size of instance"
     - module: "nova.virt.libvirt.driver"
       message: "No such file or directory: '/opt/stack/data/nova/instances"
+    - module: "nova.virt.libvirt.driver"
+      message: "Nova requires libvirt version 0\\.9\\.11 or greater"
+    - module: "nova.compute.manager"
+      message: "error during stop\\(\\) in sync_power_state"
+    - module: "nova.compute.manager"
+      message: "Instance failed network setup after 1 attempt"
+    - module: "nova.compute.manager"
+      message: "Periodic sync_power_state task had an error"
 
 g-api:
     - module: "glance.store.sheepdog"
@@ -38,18 +46,42 @@
         running command"
     - module: "swiftclient"
       message: "Container HEAD failed: .*404 Not Found"
+    - module: "glance.api.middleware.cache"
+      message: "however the registry did not contain metadata for that image"
+    - module: "oslo.messaging.notify._impl_messaging"
+      message: ".*"
 
 ceilometer-acompute:
     - module: "ceilometer.compute.pollsters.disk"
+      message: "Unable to read from monitor: Connection reset by peer"
+    - module: "ceilometer.compute.pollsters.disk"
+      message: "Requested operation is not valid: domain is not running"
+    - module: "ceilometer.compute.pollsters.net"
       message: "Requested operation is not valid: domain is not running"
     - module: "ceilometer.compute.pollsters.disk"
       message: "Domain not found: no domain with matching uuid"
     - module: "ceilometer.compute.pollsters.net"
+      message: "Domain not found: no domain with matching uuid"
+    - module: "ceilometer.compute.pollsters.net"
       message: "No module named libvirt"
+    - module: "ceilometer.compute.pollsters.net"
+      message: "Unable to write to monitor: Broken pipe"
+    - module: "ceilometer.compute.pollsters.cpu"
+      message: "Domain not found: no domain with matching uuid"
+    - module: "ceilometer.compute.pollsters.net"
+      message: ".*"
+    - module: "ceilometer.compute.pollsters.disk"
+      message: ".*"
 
 ceilometer-alarm-evaluator:
     - module: "ceilometer.alarm.service"
       message: "alarm evaluation cycle failed"
+    - module: "ceilometer.alarm.evaluator.threshold"
+      message: ".*"
+
+ceilometer-api:
+    - module: "wsme.api"
+      message: ".*"
 
 h-api:
     - module: "root"
@@ -81,26 +113,50 @@
       message: "\\{u'kernel_id'.*u'ramdisk_id':"
     - module: "nova.api.openstack.wsgi"
       message: "takes exactly 4 arguments"
+    - module: "nova.api.openstack"
+      message: "Caught error: Instance .* could not be found"
+    - module: "nova.api.metadata.handler"
+      message: "Failed to get metadata for instance id:"
 
 n-cond:
     - module: "nova.notifications"
       message: "Failed to send state update notification"
+    - module: "nova.openstack.common.rpc.amqp"
+      message: "Exception during message handling"
+    - module: "nova.openstack.common.rpc.common"
+      message: "but the actual state is deleting to caller"
+    - module: "nova.openstack.common.rpc.common"
+      message: "Traceback \\(most recent call last"
 
 n-sch:
     - module: "nova.scheduler.filter_scheduler"
       message: "Error from last host: "
 
+n-net:
+    - module: "nova.openstack.common.rpc.amqp"
+      message: "Exception during message handling"
+    - module: "nova.openstack.common.rpc.common"
+      message: "'NoneType' object has no attribute '__getitem__'"
+    - module: "nova.openstack.common.rpc.common"
+      message: "Instance .* could not be found"
+
 c-api:
     - module: "cinder.api.middleware.fault"
       message: "Caught error: Volume .* could not be found"
     - module: "cinder.api.middleware.fault"
       message: "Caught error: Snapshot .* could not be found"
+    - module: "cinder.api.openstack.wsgi"
+      message: "argument must be a string or a number, not 'NoneType'"
+    - module: "cinder.volume.api"
+      message: "Volume status must be available to reserve"
 
 c-vol:
     - module: "cinder.brick.iscsi.iscsi"
       message: "Failed to create iscsi target for volume id"
     - module: "cinder.brick.local_dev.lvm"
-      message: "/dev/dm-1: stat failed: No such file or directory"
+      message: "stat failed: No such file or directory"
+    - module: "cinder.brick.local_dev.lvm"
+      message: "LV stack-volumes.*in use: not deactivating"
     - module: "cinder.brick.local_dev.lvm"
       message: "Can't remove open logical volume"
 
@@ -119,6 +175,14 @@
       message: "duplicate key value violates unique constraint"
     - module: "ceilometer.collector.dispatcher.database"
       message: "Failed to record metering data: QueuePool limit"
+    - module: "ceilometer.dispatcher.database"
+      message: "\\(DataError\\) integer out of range"
+    - module: "ceilometer.collector.dispatcher.database"
+      message: "Failed to record metering data: .* integer out of range"
+    - module: "ceilometer.collector.dispatcher.database"
+      message: "Failed to record metering data: .* integer out of range"
+    - module: "ceilometer.openstack.common.db.sqlalchemy.session"
+      message: "DB exception wrapped"
 
 q-agt:
     - module: "neutron.agent.linux.ovs_lib"
@@ -159,4 +223,6 @@
       message: "(Network|Pool|Subnet|Agent|Port) .* could not be found"
     - module: "neutron.api.v2.resource"
       message: ".* failed"
+    - module: ".*"
+      message: ".*"
 
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 8d2fcac..c5a8772 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -15,6 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import uuid
+
 from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
@@ -53,18 +55,16 @@
         self.assertEqual(resp.status, 202)
         self.client.wait_for_resource_deletion(flavor_id)
 
-    @attr(type='gate')
-    def test_create_flavor(self):
+    def _create_flavor(self, flavor_id):
         # Create a flavor and ensure it is listed
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram, self.vcpus,
                                                  self.disk,
-                                                 new_flavor_id,
+                                                 flavor_id,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
@@ -74,7 +74,6 @@
         self.assertEqual(flavor['vcpus'], self.vcpus)
         self.assertEqual(flavor['disk'], self.disk)
         self.assertEqual(flavor['ram'], self.ram)
-        self.assertEqual(int(flavor['id']), new_flavor_id)
         self.assertEqual(flavor['swap'], self.swap)
         self.assertEqual(flavor['rxtx_factor'], self.rxtx)
         self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'],
@@ -82,10 +81,32 @@
         self.assertEqual(flavor['os-flavor-access:is_public'], True)
 
         # Verify flavor is retrieved
-        resp, flavor = self.client.get_flavor_details(new_flavor_id)
+        resp, flavor = self.client.get_flavor_details(flavor['id'])
         self.assertEqual(resp.status, 200)
         self.assertEqual(flavor['name'], flavor_name)
 
+        return flavor['id']
+
+    @attr(type='gate')
+    def test_create_flavor_with_int_id(self):
+        flavor_id = data_utils.rand_int_id(start=1000)
+        new_flavor_id = self._create_flavor(flavor_id)
+        self.assertEqual(new_flavor_id, str(flavor_id))
+
+    @attr(type='gate')
+    def test_create_flavor_with_uuid_id(self):
+        flavor_id = str(uuid.uuid4())
+        new_flavor_id = self._create_flavor(flavor_id)
+        self.assertEqual(new_flavor_id, flavor_id)
+
+    @attr(type='gate')
+    def test_create_flavor_with_none_id(self):
+        # If nova receives a request with None as flavor_id,
+        # nova generates flavor_id of uuid.
+        flavor_id = None
+        new_flavor_id = self._create_flavor(flavor_id)
+        self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
+
     @attr(type='gate')
     def test_create_flavor_verify_entry_in_list_details(self):
         # Create a flavor and ensure it's details are listed
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index a3bccc3..5028cad 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -33,7 +33,6 @@
     def setUpClass(cls):
         super(ServersAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.servers_client
-        cls.non_adm_client = cls.servers_client
         cls.flavors_client = cls.os_adm.flavors_client
         cls.identity_client = cls._get_identity_admin_client()
         tenant = cls.identity_client.get_tenant_by_name(
@@ -87,42 +86,6 @@
         self.assertEqual('204', resp['status'])
         self.servers_client.wait_for_server_termination(server['id'])
 
-    @attr(type=['negative', 'gate'])
-    def test_resize_server_using_overlimit_ram(self):
-        flavor_name = data_utils.rand_name("flavor-")
-        flavor_id = self._get_unused_flavor_id()
-        resp, quota_set = self.quotas_client.get_default_quota_set(
-            self.tenant_id)
-        ram = int(quota_set['ram']) + 1
-        vcpus = 8
-        disk = 10
-        resp, flavor_ref = self.flavors_client.create_flavor(flavor_name,
-                                                             ram, vcpus, disk,
-                                                             flavor_id)
-        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
-                          self.client.resize,
-                          self.servers[0]['id'],
-                          flavor_ref['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_resize_server_using_overlimit_vcpus(self):
-        flavor_name = data_utils.rand_name("flavor-")
-        flavor_id = self._get_unused_flavor_id()
-        ram = 512
-        resp, quota_set = self.quotas_client.get_default_quota_set(
-            self.tenant_id)
-        vcpus = int(quota_set['cores']) + 1
-        disk = 10
-        resp, flavor_ref = self.flavors_client.create_flavor(flavor_name,
-                                                             ram, vcpus, disk,
-                                                             flavor_id)
-        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
-                          self.client.resize,
-                          self.servers[0]['id'],
-                          flavor_ref['id'])
-
     @attr(type='gate')
     def test_reset_state_server(self):
         # Reset server's state to 'error'
@@ -141,23 +104,6 @@
         resp, server = self.client.get_server(self.s1_id)
         self.assertEqual(server['status'], 'ACTIVE')
 
-    @attr(type=['negative', 'gate'])
-    def test_reset_state_server_invalid_state(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.reset_state, self.s1_id,
-                          state='invalid')
-
-    @attr(type=['negative', 'gate'])
-    def test_reset_state_server_invalid_type(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.reset_state, self.s1_id,
-                          state=1)
-
-    @attr(type=['negative', 'gate'])
-    def test_reset_state_server_nonexistent_server(self):
-        self.assertRaises(exceptions.NotFound,
-                          self.client.reset_state, '999')
-
     @attr(type='gate')
     @skip_because(bug="1240043")
     def test_get_server_diagnostics_by_admin(self):
@@ -170,13 +116,6 @@
         for key in basic_attrs:
             self.assertIn(key, str(diagnostic.keys()))
 
-    @attr(type=['negative', 'gate'])
-    def test_get_server_diagnostics_by_non_admin(self):
-        # Non-admin user can not view server diagnostics according to policy
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_adm_client.get_server_diagnostics,
-                          self.s1_id)
-
 
 class ServersAdminTestXML(ServersAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
new file mode 100644
index 0000000..77d873b
--- /dev/null
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -0,0 +1,143 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+#
+#    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 uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServersAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Servers API using admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersAdminNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.servers_client
+        cls.non_adm_client = cls.servers_client
+        cls.flavors_client = cls.os_adm.flavors_client
+        cls.identity_client = cls._get_identity_admin_client()
+        tenant = cls.identity_client.get_tenant_by_name(
+            cls.client.tenant_name)
+        cls.tenant_id = tenant['id']
+
+        cls.s1_name = data_utils.rand_name('server')
+        resp, server = cls.create_test_server(name=cls.s1_name,
+                                              wait_until='ACTIVE')
+        cls.s1_id = server['id']
+
+    def _get_unused_flavor_id(self):
+        flavor_id = data_utils.rand_int_id(start=1000)
+        while True:
+            try:
+                resp, body = self.flavors_client.get_flavor_details(flavor_id)
+            except exceptions.NotFound:
+                break
+            flavor_id = data_utils.rand_int_id(start=1000)
+        return flavor_id
+
+    @attr(type=['negative', 'gate'])
+    def test_resize_server_using_overlimit_ram(self):
+        flavor_name = data_utils.rand_name("flavor-")
+        flavor_id = self._get_unused_flavor_id()
+        resp, quota_set = self.quotas_client.get_default_quota_set(
+            self.tenant_id)
+        ram = int(quota_set['ram']) + 1
+        vcpus = 8
+        disk = 10
+        resp, flavor_ref = self.flavors_client.create_flavor(flavor_name,
+                                                             ram, vcpus, disk,
+                                                             flavor_id)
+        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
+        self.assertRaises(exceptions.OverLimit,
+                          self.client.resize,
+                          self.servers[0]['id'],
+                          flavor_ref['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_resize_server_using_overlimit_vcpus(self):
+        flavor_name = data_utils.rand_name("flavor-")
+        flavor_id = self._get_unused_flavor_id()
+        ram = 512
+        resp, quota_set = self.quotas_client.get_default_quota_set(
+            self.tenant_id)
+        vcpus = int(quota_set['cores']) + 1
+        disk = 10
+        resp, flavor_ref = self.flavors_client.create_flavor(flavor_name,
+                                                             ram, vcpus, disk,
+                                                             flavor_id)
+        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
+        self.assertRaises(exceptions.OverLimit,
+                          self.client.resize,
+                          self.servers[0]['id'],
+                          flavor_ref['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_reset_state_server_invalid_state(self):
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.reset_state, self.s1_id,
+                          state='invalid')
+
+    @attr(type=['negative', 'gate'])
+    def test_reset_state_server_invalid_type(self):
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.reset_state, self.s1_id,
+                          state=1)
+
+    @attr(type=['negative', 'gate'])
+    def test_reset_state_server_nonexistent_server(self):
+        self.assertRaises(exceptions.NotFound,
+                          self.client.reset_state, '999')
+
+    @attr(type=['negative', 'gate'])
+    def test_get_server_diagnostics_by_non_admin(self):
+        # Non-admin user can not view server diagnostics according to policy
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_adm_client.get_server_diagnostics,
+                          self.s1_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_migrate_non_existent_server(self):
+        # migrate a non existent server
+        self.assertRaises(exceptions.NotFound,
+                          self.client.migrate_server,
+                          str(uuid.uuid4()))
+
+    @attr(type=['negative', 'gate'])
+    def test_migrate_server_invalid_state(self):
+        # create server.
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        self.assertEqual(202, resp.status)
+        server_id = server['id']
+        # suspend the server.
+        resp, _ = self.client.suspend_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(server_id, 'SUSPENDED')
+        # migrate an suspended server should fail
+        self.assertRaises(exceptions.Conflict,
+                          self.client.migrate_server,
+                          server_id)
+
+
+class ServersAdminNegativeTestXML(ServersAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 4b6816b..7ef5466 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -225,6 +225,7 @@
     def setUpClass(cls):
         super(BaseV3ComputeTest, cls).setUpClass()
         if not cls.config.compute_feature_enabled.api_v3:
+            cls.tearDownClass()
             skip_msg = ("%s skipped as nova v3 api is not available" %
                         cls.__name__)
             raise cls.skipException(skip_msg)
@@ -233,6 +234,9 @@
         cls.images_client = cls.os.image_client
         cls.services_client = cls.os.services_v3_client
         cls.extensions_client = cls.os.extensions_v3_client
+        cls.availability_zone_client = cls.os.availability_zone_v3_client
+        cls.interfaces_client = cls.os.interfaces_v3_client
+        cls.hypervisor_client = cls.os.hypervisor_v3_client
 
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
@@ -293,3 +297,6 @@
         cls.os_adm = os_adm
         cls.severs_admin_client = cls.os_adm.servers_v3_client
         cls.services_admin_client = cls.os_adm.services_v3_client
+        cls.availability_zone_admin_client = \
+            cls.os_adm.availability_zone_v3_client
+        cls.hypervisor_admin_client = cls.os_adm.hypervisor_v3_client
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index eac98ea..fa99422 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -48,7 +48,7 @@
     def test_get_flavor(self):
         # The expected flavor details should be returned
         resp, flavor = self.client.get_flavor_details(self.flavor_ref)
-        self.assertEqual(self.flavor_ref, int(flavor['id']))
+        self.assertEqual(self.flavor_ref, flavor['id'])
 
     @attr(type=['negative', 'gate'])
     def test_get_non_existant_flavor(self):
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 475b218..50b6c77 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -17,7 +17,6 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -120,69 +119,6 @@
         resp, _ = self.client.delete_keypair(k_name)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['negative', 'gate'])
-    def test_keypair_create_with_invalid_pub_key(self):
-        # Keypair should not be created with a non RSA public key
-        k_name = data_utils.rand_name('keypair-')
-        pub_key = "ssh-rsa JUNK nova@ubuntu"
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_keypair, k_name, pub_key)
-
-    @attr(type=['negative', 'gate'])
-    def test_keypair_delete_nonexistant_key(self):
-        # Non-existant key deletion should throw a proper error
-        k_name = data_utils.rand_name("keypair-non-existant-")
-        self.assertRaises(exceptions.NotFound, self.client.delete_keypair,
-                          k_name)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_with_empty_public_key(self):
-        # Keypair should not be created with an empty public key
-        k_name = data_utils.rand_name("keypair-")
-        pub_key = ' '
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
-                          k_name, pub_key)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
-        # Keypair should not be created when public key bits are too long
-        k_name = data_utils.rand_name("keypair-")
-        pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
-                          k_name, pub_key)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_with_duplicate_name(self):
-        # Keypairs with duplicate names should not be created
-        k_name = data_utils.rand_name('keypair-')
-        resp, _ = self.client.create_keypair(k_name)
-        self.assertEqual(200, resp.status)
-        # Now try the same keyname to create another key
-        self.assertRaises(exceptions.Conflict, self.client.create_keypair,
-                          k_name)
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_with_empty_name_string(self):
-        # Keypairs with name being an empty string should not be created
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
-                          '')
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_with_long_keynames(self):
-        # Keypairs with name longer than 255 chars should not be created
-        k_name = 'keypair-'.ljust(260, '0')
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
-                          k_name)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_keypair_invalid_name(self):
-        # Keypairs with name being an invalid name should not be created
-        k_name = 'key_/.\@:'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
-                          k_name)
-
 
 class KeyPairsTestXML(KeyPairsTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
new file mode 100644
index 0000000..fad985e
--- /dev/null
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -0,0 +1,98 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# Copyright 2013 IBM Corp
+# 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.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(KeyPairsNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.keypairs_client
+
+    @attr(type=['negative', 'gate'])
+    def test_keypair_create_with_invalid_pub_key(self):
+        # Keypair should not be created with a non RSA public key
+        k_name = data_utils.rand_name('keypair-')
+        pub_key = "ssh-rsa JUNK nova@ubuntu"
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_keypair, k_name, pub_key)
+
+    @attr(type=['negative', 'gate'])
+    def test_keypair_delete_nonexistant_key(self):
+        # Non-existant key deletion should throw a proper error
+        k_name = data_utils.rand_name("keypair-non-existant-")
+        self.assertRaises(exceptions.NotFound, self.client.delete_keypair,
+                          k_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_with_empty_public_key(self):
+        # Keypair should not be created with an empty public key
+        k_name = data_utils.rand_name("keypair-")
+        pub_key = ' '
+        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+                          k_name, pub_key)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
+        # Keypair should not be created when public key bits are too long
+        k_name = data_utils.rand_name("keypair-")
+        pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
+        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+                          k_name, pub_key)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_with_duplicate_name(self):
+        # Keypairs with duplicate names should not be created
+        k_name = data_utils.rand_name('keypair-')
+        resp, _ = self.client.create_keypair(k_name)
+        self.assertEqual(200, resp.status)
+        # Now try the same keyname to create another key
+        self.assertRaises(exceptions.Conflict, self.client.create_keypair,
+                          k_name)
+        resp, _ = self.client.delete_keypair(k_name)
+        self.assertEqual(202, resp.status)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_with_empty_name_string(self):
+        # Keypairs with name being an empty string should not be created
+        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+                          '')
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_with_long_keynames(self):
+        # Keypairs with name longer than 255 chars should not be created
+        k_name = 'keypair-'.ljust(260, '0')
+        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+                          k_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_keypair_invalid_name(self):
+        # Keypairs with name being an invalid name should not be created
+        k_name = 'key_/.\@:'
+        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+                          k_name)
+
+
+class KeyPairsNegativeTestXML(KeyPairsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 44ce405..24ade96 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -72,7 +72,7 @@
                          str(netaddr.IPAddress(self.accessIPv6)))
         self.assertEqual(self.name, self.server['name'])
         self.assertEqual(self.image_ref, self.server['image']['id'])
-        self.assertEqual(str(self.flavor_ref), self.server['flavor']['id'])
+        self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
         self.assertEqual(self.meta, self.server['metadata'])
 
     @attr(type='smoke')
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 1044ae1..e3441bd 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -128,7 +128,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(self.flavor_ref, int(rebuilt_server['flavor']['id']))
+        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
 
         # Verify the server properties after the rebuild completes
         self.client.wait_for_server_status(rebuilt_server['id'], 'ACTIVE')
@@ -147,8 +147,8 @@
         resp, server = self.client.get_server(self.server_id)
         current_flavor = server['flavor']['id']
         new_flavor_ref = self.flavor_ref_alt \
-            if int(current_flavor) == self.flavor_ref else self.flavor_ref
-        return int(current_flavor), int(new_flavor_ref)
+            if current_flavor == self.flavor_ref else self.flavor_ref
+        return current_flavor, new_flavor_ref
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='smoke')
@@ -167,7 +167,7 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
         resp, server = self.client.get_server(self.server_id)
-        self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
+        self.assertEqual(new_flavor_ref, server['flavor']['id'])
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='gate')
@@ -189,7 +189,7 @@
         resp, server = self.client.get_server(self.server_id)
         start = int(time.time())
 
-        while int(server['flavor']['id']) != previous_flavor_ref:
+        while server['flavor']['id'] != previous_flavor_ref:
             time.sleep(self.build_interval)
             resp, server = self.client.get_server(self.server_id)
 
@@ -198,7 +198,6 @@
                 required time (%s s).' % (self.server_id, self.build_timeout)
                 raise exceptions.TimeoutException(message)
 
-    @skip_because(bug="1251920")
     @attr(type='gate')
     def test_create_backup(self):
         # Positive test:create backup successfully and rotate backups correctly
@@ -271,6 +270,16 @@
     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
+
+        # This reboot is necessary for outputting some console log after
+        # creating a instance backup. If a instance backup, the console
+        # log file is truncated and we cannot get any console log through
+        # "console-log" API.
+        # The detail is https://bugs.launchpad.net/nova/+bug/1251920
+        resp, body = self.servers_client.reboot(self.server_id, 'HARD')
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
         def get_output():
             resp, output = self.servers_client.get_console_output(
                 self.server_id, 10)
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index d6488c4..ff2765c 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -20,7 +20,7 @@
 from tempest.test import attr
 
 
-class AvailabilityZoneAdminTestJSON(base.BaseV2ComputeAdminTest):
+class AvailabilityZoneAdminV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
     Tests Availability Zone API List that require admin privileges
@@ -30,8 +30,8 @@
 
     @classmethod
     def setUpClass(cls):
-        super(AvailabilityZoneAdminTestJSON, cls).setUpClass()
-        cls.client = cls.os_adm.availability_zone_client
+        super(AvailabilityZoneAdminV3TestJSON, cls).setUpClass()
+        cls.client = cls.availability_zone_admin_client
         cls.non_adm_client = cls.availability_zone_client
 
     @attr(type='gate')
@@ -66,5 +66,5 @@
             self.non_adm_client.get_availability_zone_list_detail)
 
 
-class AvailabilityZoneAdminTestXML(AvailabilityZoneAdminTestJSON):
+class AvailabilityZoneAdminV3TestXML(AvailabilityZoneAdminV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
new file mode 100644
index 0000000..3da3369
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -0,0 +1,105 @@
+# 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.test import attr
+
+
+class HypervisorAdminV3TestJSON(base.BaseV3ComputeAdminTest):
+
+    """
+    Tests Hypervisors API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(HypervisorAdminV3TestJSON, cls).setUpClass()
+        cls.client = cls.hypervisor_admin_client
+
+    def _list_hypervisors(self):
+        # List of hypervisors
+        resp, hypers = self.client.get_hypervisor_list()
+        self.assertEqual(200, resp.status)
+        return hypers
+
+    @attr(type='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='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='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='gate')
+    def test_get_hypervisor_show_servers(self):
+        # Show instances about the specific hypervisors
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        hypervisor_id = hypers[0]['id']
+        resp, hypervisors = self.client.get_hypervisor_servers(hypervisor_id)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypervisors) > 0)
+
+    @attr(type='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='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='gate')
+    def test_search_hypervisor(self):
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+        resp, hypers = self.client.search_hypervisor(
+            hypers[0]['hypervisor_hostname'])
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypers) > 0)
+
+
+class HypervisorAdminV3TestXML(HypervisorAdminV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_hypervisor_negative.py b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
new file mode 100644
index 0000000..847679e
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
@@ -0,0 +1,144 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+# 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 uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class HypervisorAdminNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
+
+    """
+    Tests Hypervisors API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(HypervisorAdminNegativeV3TestJSON, cls).setUpClass()
+        cls.client = cls.hypervisor_admin_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=['negative', 'gate'])
+    def test_show_nonexistent_hypervisor(self):
+        nonexistent_hypervisor_id = str(uuid.uuid4())
+
+        self.assertRaises(
+            exceptions.NotFound,
+            self.client.get_hypervisor_show_details,
+            nonexistent_hypervisor_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_show_hypervisor_with_non_admin_user(self):
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_show_details,
+            hypers[0]['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_show_servers_with_non_admin_user(self):
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_servers,
+            hypers[0]['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_show_servers_with_nonexistent_hypervisor(self):
+        nonexistent_hypervisor_id = str(uuid.uuid4())
+
+        self.assertRaises(
+            exceptions.NotFound,
+            self.client.get_hypervisor_servers,
+            nonexistent_hypervisor_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_stats_with_non_admin_user(self):
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_stats)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_nonexistent_hypervisor_uptime(self):
+        nonexistent_hypervisor_id = str(uuid.uuid4())
+
+        self.assertRaises(
+            exceptions.NotFound,
+            self.client.get_hypervisor_uptime,
+            nonexistent_hypervisor_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_uptime_with_non_admin_user(self):
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_uptime,
+            hypers[0]['id'])
+
+    @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)
+
+    @attr(type=['negative', 'gate'])
+    def test_search_nonexistent_hypervisor(self):
+        nonexistent_hypervisor_name = data_utils.rand_name('test_hypervisor')
+
+        resp, hypers = self.client.search_hypervisor(
+            nonexistent_hypervisor_name)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(0, len(hypers))
+
+    @attr(type=['negative', 'gate'])
+    def test_search_hypervisor_with_non_admin_user(self):
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.search_hypervisor,
+            hypers[0]['hypervisor_hostname'])
+
+
+class HypervisorAdminNegativeV3TestXML(HypervisorAdminNegativeV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_simple_tenant_usage.py b/tempest/api/compute/v3/admin/test_simple_tenant_usage.py
new file mode 100644
index 0000000..a599f06
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_simple_tenant_usage.py
@@ -0,0 +1,115 @@
+# 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 datetime
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+import time
+
+
+class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TenantUsagesTestJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.tenant_usages_client
+        cls.client = cls.os.tenant_usages_client
+        cls.identity_client = cls._get_identity_admin_client()
+
+        resp, tenants = cls.identity_client.list_tenants()
+        cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+                         cls.client.tenant_name][0]
+
+        # Create a server in the demo tenant
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        time.sleep(2)
+
+        now = datetime.datetime.now()
+        cls.start = cls._parse_strtime(now - datetime.timedelta(days=1))
+        cls.end = cls._parse_strtime(now + datetime.timedelta(days=1))
+
+    @classmethod
+    def _parse_strtime(cls, at):
+        # Returns formatted datetime
+        return at.strftime('%Y-%m-%dT%H:%M:%S.%f')
+
+    @attr(type='gate')
+    def test_list_usage_all_tenants(self):
+        # Get usage for all tenants
+        params = {'start': self.start,
+                  'end': self.end,
+                  'detailed': int(bool(True))}
+        resp, tenant_usage = self.adm_client.list_tenant_usages(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(tenant_usage), 8)
+
+    @attr(type='gate')
+    def test_get_usage_tenant(self):
+        # Get usage for a specific tenant
+        params = {'start': self.start,
+                  'end': self.end}
+        resp, tenant_usage = self.adm_client.get_tenant_usage(
+            self.tenant_id, params)
+
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(tenant_usage), 8)
+
+    @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,
+                  'end': self.end}
+        resp, tenant_usage = self.client.get_tenant_usage(
+            self.tenant_id, params)
+
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(tenant_usage), 8)
+
+    @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,
+                  'end': self.end}
+        self.assertRaises(exceptions.NotFound,
+                          self.adm_client.get_tenant_usage,
+                          '', params)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_usage_tenant_with_invalid_date(self):
+        # Get usage for tenant with invalid date
+        params = {'start': self.end,
+                  'end': self.start}
+        self.assertRaises(exceptions.BadRequest,
+                          self.adm_client.get_tenant_usage,
+                          self.tenant_id, params)
+
+    @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,
+                  'end': self.end,
+                  'detailed': int(bool(True))}
+        self.assertRaises(exceptions.Unauthorized,
+                          self.client.list_tenant_usages, params)
+
+
+class TenantUsagesTestXML(TenantUsagesTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index a177cea..f208a4b 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -19,15 +19,15 @@
 import time
 
 
-class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
+class AttachInterfacesV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
         if not cls.config.service_available.neutron:
             raise cls.skipException("Neutron is required")
-        super(AttachInterfacesTestJSON, cls).setUpClass()
-        cls.client = cls.os.interfaces_client
+        super(AttachInterfacesV3TestJSON, cls).setUpClass()
+        cls.client = cls.interfaces_client
 
     def _check_interface(self, iface, port_id=None, network_id=None,
                          fixed_ip=None):
@@ -114,5 +114,5 @@
         self.assertEqual(len(ifs) - 1, len(_ifs))
 
 
-class AttachInterfacesTestXML(AttachInterfacesTestJSON):
+class AttachInterfacesV3TestXML(AttachInterfacesV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 92b9e30..20cdf30 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -128,7 +128,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(self.flavor_ref, int(rebuilt_server['flavor']['id']))
+        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
 
         # Verify the server properties after the rebuild completes
         self.client.wait_for_server_status(rebuilt_server['id'], 'ACTIVE')
@@ -147,8 +147,8 @@
         resp, server = self.client.get_server(self.server_id)
         current_flavor = server['flavor']['id']
         new_flavor_ref = self.flavor_ref_alt \
-            if int(current_flavor) == self.flavor_ref else self.flavor_ref
-        return int(current_flavor), int(new_flavor_ref)
+            if current_flavor == self.flavor_ref else self.flavor_ref
+        return current_flavor, new_flavor_ref
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='smoke')
@@ -167,7 +167,7 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
         resp, server = self.client.get_server(self.server_id)
-        self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
+        self.assertEqual(new_flavor_ref, server['flavor']['id'])
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='gate')
@@ -189,7 +189,7 @@
         resp, server = self.client.get_server(self.server_id)
         start = int(time.time())
 
-        while int(server['flavor']['id']) != previous_flavor_ref:
+        while server['flavor']['id'] != previous_flavor_ref:
             time.sleep(self.build_interval)
             resp, server = self.client.get_server(self.server_id)
 
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index 7ca8a52..82588b6 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -20,12 +20,12 @@
 from tempest.test import attr
 
 
-class ServerAddressesTest(base.BaseV2ComputeTest):
+class ServerAddressesV3Test(base.BaseV3ComputeTest):
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(ServerAddressesTest, cls).setUpClass()
+        super(ServerAddressesV3Test, cls).setUpClass()
         cls.client = cls.servers_client
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
@@ -80,5 +80,5 @@
                 self.assertTrue(any([a for a in addr if a == address]))
 
 
-class ServerAddressesTestXML(ServerAddressesTest):
+class ServerAddressesV3TestXML(ServerAddressesV3Test):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
new file mode 100644
index 0000000..5ec0cbe
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -0,0 +1,449 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import base64
+import sys
+import uuid
+
+from tempest.api.compute import base
+from tempest import clients
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServersNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    def setUp(self):
+        super(ServersNegativeTestJSON, self).setUp()
+        try:
+            self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+        except Exception:
+            self.rebuild_server()
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+        cls.img_client = cls.images_client
+        cls.alt_os = clients.AltManager()
+        cls.alt_client = cls.alt_os.servers_client
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
+
+    @attr(type=['negative', 'gate'])
+    def test_server_name_blank(self):
+        # Create a server with name parameter empty
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          name='')
+
+    @attr(type=['negative', 'gate'])
+    def test_personality_file_contents_not_encoded(self):
+        # Use an unencoded file when creating a server with personality
+
+        file_contents = 'This is a test file.'
+        person = [{'path': '/etc/testfile.txt',
+                   'contents': file_contents}]
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          personality=person)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_invalid_image(self):
+        # Create a server with an unknown image
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          image_id=-1)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_invalid_flavor(self):
+        # Create a server with an unknown flavor
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          flavor=-1,)
+
+    @attr(type=['negative', 'gate'])
+    def test_invalid_access_ip_v4_address(self):
+        # An access IPv4 address must match a valid address pattern
+
+        IPv4 = '1.1.1.1.1.1'
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server, accessIPv4=IPv4)
+
+    @attr(type=['negative', 'gate'])
+    def test_invalid_ip_v6_address(self):
+        # An access IPv6 address must match a valid address pattern
+
+        IPv6 = 'notvalid'
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server, accessIPv6=IPv6)
+
+    @attr(type=['negative', 'gate'])
+    def test_resize_nonexistent_server(self):
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound,
+                          self.client.resize,
+                          nonexistent_server, self.flavor_ref)
+
+    @attr(type=['negative', 'gate'])
+    def test_resize_server_with_non_existent_flavor(self):
+        # Resize a server with non-existent flavor
+        nonexistent_flavor = str(uuid.uuid4())
+        self.assertRaises(exceptions.BadRequest, self.client.resize,
+                          self.server_id, flavor_ref=nonexistent_flavor)
+
+    @attr(type=['negative', 'gate'])
+    def test_resize_server_with_null_flavor(self):
+        # Resize a server with null flavor
+        self.assertRaises(exceptions.BadRequest, self.client.resize,
+                          self.server_id, flavor_ref="")
+
+    @attr(type=['negative', 'gate'])
+    def test_reboot_non_existent_server(self):
+        # Reboot a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.reboot,
+                          nonexistent_server, 'SOFT')
+
+    @attr(type=['negative', 'gate'])
+    def test_pause_paused_server(self):
+        # Pause a paused server.
+        self.client.pause_server(self.server_id)
+        self.addCleanup(self.client.unpause_server,
+                        self.server_id)
+        self.client.wait_for_server_status(self.server_id, 'PAUSED')
+        self.assertRaises(exceptions.Conflict,
+                          self.client.pause_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_rebuild_reboot_deleted_server(self):
+        # Rebuild and Reboot a deleted server
+        _, server = self.create_test_server()
+        self.client.delete_server(server['id'])
+        self.client.wait_for_server_termination(server['id'])
+
+        self.assertRaises(exceptions.NotFound,
+                          self.client.rebuild,
+                          server['id'], self.image_ref_alt)
+        self.assertRaises(exceptions.NotFound, self.client.reboot,
+                          server['id'], 'SOFT')
+
+    @attr(type=['negative', 'gate'])
+    def test_rebuild_non_existent_server(self):
+        # Rebuild a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        meta = {'rebuild': 'server'}
+        new_name = data_utils.rand_name('server')
+        file_contents = 'Test server rebuild.'
+        personality = [{'path': '/etc/rebuild.txt',
+                        'contents': base64.b64encode(file_contents)}]
+        self.assertRaises(exceptions.NotFound,
+                          self.client.rebuild,
+                          nonexistent_server,
+                          self.image_ref_alt,
+                          name=new_name, meta=meta,
+                          personality=personality,
+                          adminPass='rebuild')
+
+    @attr(type=['negative', 'gate'])
+    def test_create_numeric_server_name(self):
+        # Create a server with a numeric name
+        if self.__class__._interface == "xml":
+            raise self.skipException("Not testable in XML")
+
+        server_name = 12345
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          name=server_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_server_name_length_exceeds_256(self):
+        # Create a server with name length exceeding 256 characters
+
+        server_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          name=server_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_invalid_network_uuid(self):
+        # Pass invalid network uuid while creating a server
+
+        networks = [{'fixed_ip': '10.0.1.1', 'uuid': 'a-b-c-d-e-f-g-h-i-j'}]
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          networks=networks)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_non_existant_keypair(self):
+        # Pass a non-existent keypair while creating a server
+
+        key_name = data_utils.rand_name('key')
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          key_name=key_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_server_metadata_exceeds_length_limit(self):
+        # Pass really long metadata while creating a server
+
+        metadata = {'a': 'b' * 260}
+        self.assertRaises(exceptions.OverLimit,
+                          self.create_test_server,
+                          meta=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_name_of_non_existent_server(self):
+        # Update name of a non-existent server
+
+        server_name = data_utils.rand_name('server')
+        new_name = data_utils.rand_name('server') + '_updated'
+
+        self.assertRaises(exceptions.NotFound, self.client.update_server,
+                          server_name, name=new_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_server_set_empty_name(self):
+        # Update name of the server to an empty string
+
+        server_name = data_utils.rand_name('server')
+        new_name = ''
+
+        self.assertRaises(exceptions.BadRequest, self.client.update_server,
+                          server_name, name=new_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_server_of_another_tenant(self):
+        # Update name of a server that belongs to another tenant
+
+        new_name = self.server_id + '_new'
+        self.assertRaises(exceptions.NotFound,
+                          self.alt_client.update_server, self.server_id,
+                          name=new_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_server_name_length_exceeds_256(self):
+        # Update name of server exceed the name length limit
+
+        new_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.update_server,
+                          self.server_id,
+                          name=new_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_non_existent_server(self):
+        # Delete a non existent server
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server,
+                          '999erra43')
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_a_server_of_another_tenant(self):
+        # Delete a server that belongs to another tenant
+        self.assertRaises(exceptions.NotFound,
+                          self.alt_client.delete_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_server_pass_negative_id(self):
+        # Pass an invalid string parameter to delete server
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server, -1)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_server_pass_id_exceeding_length_limit(self):
+        # Pass a server ID that exceeds length limit to delete server
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server,
+                          sys.maxint + 1)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_nonexistent_security_group(self):
+        # Create a server with a nonexistent security group
+
+        security_groups = [{'name': 'does_not_exist'}]
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          security_groups=security_groups)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_non_existent_server(self):
+        # Get a non existent server details
+
+        self.assertRaises(exceptions.NotFound, self.client.get_server,
+                          '999erra43')
+
+    @attr(type=['negative', 'gate'])
+    def test_stop_non_existent_server(self):
+        # Stop a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.servers_client.stop,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_pause_non_existent_server(self):
+        # pause a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.pause_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_unpause_non_existent_server(self):
+        # unpause a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.unpause_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_unpause_server_invalid_state(self):
+        # unpause an active server.
+        self.assertRaises(exceptions.Conflict,
+                          self.client.unpause_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_suspend_non_existent_server(self):
+        # suspend a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.suspend_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_suspend_server_invalid_state(self):
+        # suspend a suspended server.
+        resp, _ = self.client.suspend_server(self.server_id)
+        self.addCleanup(self.client.resume_server,
+                        self.server_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(self.server_id, 'SUSPENDED')
+        self.assertRaises(exceptions.Conflict,
+                          self.client.suspend_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_resume_non_existent_server(self):
+        # resume a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.resume_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_resume_server_invalid_state(self):
+        # resume an active server.
+        self.assertRaises(exceptions.Conflict,
+                          self.client.resume_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_console_output_of_non_existent_server(self):
+        # get the console output for a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_console_output,
+                          nonexistent_server, 10)
+
+    @attr(type=['negative', 'gate'])
+    def test_force_delete_nonexistent_server_id(self):
+        non_existent_server_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.NotFound,
+                          self.client.force_delete_server,
+                          non_existent_server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_force_delete_server_invalid_state(self):
+        # we can only force-delete a server in 'soft-delete' state
+        self.assertRaises(exceptions.Conflict,
+                          self.client.force_delete_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_restore_nonexistent_server_id(self):
+        non_existent_server_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.NotFound,
+                          self.client.restore_soft_deleted_server,
+                          non_existent_server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_restore_server_invalid_state(self):
+        # we can only restore-delete a server in 'soft-delete' state
+        self.assertRaises(exceptions.Conflict,
+                          self.client.restore_soft_deleted_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_shelve_non_existent_server(self):
+        # shelve a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.shelve_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_shelve_shelved_server(self):
+        # shelve a shelved server.
+        resp, server = self.client.shelve_server(self.server_id)
+        self.assertEqual(202, resp.status)
+        self.addCleanup(self.client.unshelve_server, self.server_id)
+
+        offload_time = self.config.compute.shelved_offload_time
+        if offload_time >= 0:
+            self.client.wait_for_server_status(self.server_id,
+                                               'SHELVED_OFFLOADED',
+                                               extra_timeout=offload_time)
+        else:
+            self.client.wait_for_server_status(self.server_id,
+                                               'SHELVED')
+
+        resp, server = self.client.get_server(self.server_id)
+        image_name = server['name'] + '-shelved'
+        params = {'name': image_name}
+        resp, images = self.images_client.list_images(params)
+        self.assertEqual(1, len(images))
+        self.assertEqual(image_name, images[0]['name'])
+
+        self.assertRaises(exceptions.Conflict,
+                          self.client.shelve_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_unshelve_non_existent_server(self):
+        # unshelve a non existent server
+        nonexistent_server = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.unshelve_server,
+                          nonexistent_server)
+
+    @attr(type=['negative', 'gate'])
+    def test_unshelve_server_invalid_state(self):
+        # unshelve an active server.
+        self.assertRaises(exceptions.Conflict,
+                          self.client.unshelve_server,
+                          self.server_id)
+
+
+class ServersNegativeTestXML(ServersNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 133bae0..6408c15 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -1,8 +1,8 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
 # Copyright 2013 OpenStack Foundation
+# Copyright 2013 IBM Corp
 # All Rights Reserved.
-# 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
@@ -21,28 +21,16 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
-class CreateRegisterImagesTest(base.BaseV2ImageTest):
+class BasicOperationsImagesTest(base.BaseV2ImageTest):
 
     """
-    Here we test the registration and creation of images
+    Here we test the basic operations of images
     """
 
     @attr(type='gate')
-    def test_register_with_invalid_container_format(self):
-        # Negative tests for invalid data supplied to POST /images
-        self.assertRaises(exceptions.BadRequest, self.client.create_image,
-                          'test', 'wrong', 'vhd')
-
-    @attr(type='gate')
-    def test_register_with_invalid_disk_format(self):
-        self.assertRaises(exceptions.BadRequest, self.client.create_image,
-                          'test', 'bare', 'wrong')
-
-    @attr(type='gate')
     def test_register_upload_get_image_file(self):
 
         """
@@ -83,6 +71,28 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(file_content, body)
 
+    @attr(type='gate')
+    def test_delete_image(self):
+        # Deletes a image by image_id
+
+        # Create image
+        image_name = data_utils.rand_name('image')
+        resp, body = self.client.create_image(name=image_name,
+                                              container_format='bare',
+                                              disk_format='raw',
+                                              visibility='public')
+        self.assertEqual(201, resp.status)
+        image_id = body['id']
+
+        # Delete Image
+        self.client.delete_image(image_id)
+        self.client.wait_for_resource_deletion(image_id)
+
+        # Verifying deletion
+        resp, images = self.client.image_list()
+        self.assertEqual(resp.status, 200)
+        self.assertNotIn(image_id, images)
+
 
 class ListImagesTest(base.BaseV2ImageTest):
 
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 5bdaa99..1cd6f29 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -82,3 +82,14 @@
         image_id = ""
         self.assertRaises(exceptions.NotFound, self.client.delete_image,
                           image_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_register_with_invalid_container_format(self):
+        # Negative tests for invalid data supplied to POST /images
+        self.assertRaises(exceptions.BadRequest, self.client.create_image,
+                          'test', 'wrong', 'vhd')
+
+    @attr(type=['negative', 'gate'])
+    def test_register_with_invalid_disk_format(self):
+        self.assertRaises(exceptions.BadRequest, self.client.create_image,
+                          'test', 'bare', 'wrong')
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
index 43e7f68..ab19fa8 100644
--- a/tempest/api/network/common.py
+++ b/tempest/api/network/common.py
@@ -94,3 +94,18 @@
 
     def delete(self):
         self.client.delete_port(self.id)
+
+
+class DeletableSecurityGroup(DeletableResource):
+
+    def delete(self):
+        self.client.delete_security_group(self.id)
+
+
+class DeletableSecurityGroupRule(DeletableResource):
+
+    def __repr__(self):
+        return '<%s id="%s">' % (self.__class__.__name__, self.id)
+
+    def delete(self):
+        self.client.delete_security_group_rule(self.id)
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index c6639c2..e7cb806 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -18,6 +18,7 @@
 
 from tempest.api.identity.base import DataGenerator
 from tempest import clients
+from tempest.common import custom_matchers
 from tempest.common import isolated_creds
 from tempest import exceptions
 import tempest.test
@@ -120,3 +121,12 @@
                 container_client.delete_container(cont)
             except exceptions.NotFound:
                 pass
+
+    def assertHeaders(self, resp, target, method):
+        """
+        Common method to check the existence and the format of common response
+        headers
+        """
+        self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
+                        target, method))
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 615b179..12c823b 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -46,6 +46,7 @@
         params = {'format': 'json'}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
 
         self.assertIsNotNone(container_list)
         container_names = [c['name'] for c in container_list]
@@ -59,6 +60,8 @@
             params = {'limit': limit}
             resp, container_list = \
                 self.account_client.list_account_containers(params=params)
+            self.assertHeaders(resp, 'Account', 'GET')
+
             self.assertEqual(len(container_list), limit)
 
     @attr(type='smoke')
@@ -70,10 +73,15 @@
         params = {'marker': self.containers[-1]}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
+
         self.assertEqual(len(container_list), 0)
+
         params = {'marker': self.containers[self.containers_count / 2]}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
+
         self.assertEqual(len(container_list), self.containers_count / 2 - 1)
 
     @attr(type='smoke')
@@ -85,10 +93,13 @@
         params = {'end_marker': self.containers[0]}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list), 0)
+
         params = {'end_marker': self.containers[self.containers_count / 2]}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list), self.containers_count / 2)
 
     @attr(type='smoke')
@@ -101,6 +112,8 @@
                       'limit': limit}
             resp, container_list = \
                 self.account_client.list_account_containers(params=params)
+            self.assertHeaders(resp, 'Account', 'GET')
+
             self.assertTrue(len(container_list) <= limit, str(container_list))
 
     @attr(type='smoke')
@@ -108,9 +121,7 @@
         # list all account metadata
         resp, metadata = self.account_client.list_account_metadata()
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
-        self.assertIn('x-account-object-count', resp)
-        self.assertIn('x-account-container-count', resp)
-        self.assertIn('x-account-bytes-used', resp)
+        self.assertHeaders(resp, 'Account', 'HEAD')
 
     @attr(type='smoke')
     def test_create_and_delete_account_metadata(self):
@@ -120,8 +131,11 @@
         resp, _ = self.account_client.create_account_metadata(
             metadata={header: data})
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
+        self.assertHeaders(resp, 'Account', 'HEAD')
+
         self.assertIn('x-account-meta-' + header, resp)
         self.assertEqual(resp['x-account-meta-' + header], data)
 
@@ -129,8 +143,10 @@
         resp, _ = \
             self.account_client.delete_account_metadata(metadata=[header])
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
+        self.assertHeaders(resp, 'Account', 'HEAD')
         self.assertNotIn('x-account-meta-' + header, resp)
 
     @attr(type=['negative', 'gate'])
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 4fae953..04de072 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -38,6 +38,7 @@
         resp, body = self.container_client.create_container(container_name)
         self.containers.append(container_name)
         self.assertIn(resp['status'], ('202', '201'))
+        self.assertHeaders(resp, 'Container', 'PUT')
 
     @attr(type='smoke')
     def test_delete_container(self):
@@ -48,6 +49,8 @@
         # delete container
         resp, _ = self.container_client.delete_container(container_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'DELETE')
+
         self.containers.remove(container_name)
 
     @attr(type='smoke')
@@ -76,6 +79,8 @@
             self.container_client.\
             list_container_contents(container_name, params=params)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'GET')
+
         self.assertIsNotNone(object_list)
 
         object_names = [obj['name'] for obj in object_list]
@@ -97,11 +102,14 @@
             self.container_client.update_container_metadata(container_name,
                                                             metadata=metadata)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'POST')
 
         # list container metadata
         resp, _ = self.container_client.list_container_metadata(
             container_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'HEAD')
+
         self.assertIn('x-container-meta-name', resp)
         self.assertIn('x-container-meta-description', resp)
         self.assertEqual(resp['x-container-meta-name'], 'Pictures')
@@ -112,9 +120,12 @@
             container_name,
             metadata=metadata.keys())
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'POST')
 
         # check if the metadata are no longer there
         resp, _ = self.container_client.list_container_metadata(container_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'HEAD')
+
         self.assertNotIn('x-container-meta-name', resp)
         self.assertNotIn('x-container-meta-description', resp)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 9e405d6..1eea30a 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -16,7 +16,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class StaticWebTest(base.BaseObjectTest):
@@ -48,7 +48,7 @@
         cls.data.teardown_all()
         super(StaticWebTest, cls).tearDownClass()
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_index(self):
         headers = {'web-index': self.object_name}
 
@@ -59,7 +59,7 @@
         # we should retrieve the self.object_name file
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertEqual(resp['status'], '200')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertEqual(body, self.object_data)
 
         # clean up before exiting
@@ -70,7 +70,7 @@
             self.container_name)
         self.assertNotIn('x-container-meta-web-index', body)
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_listing(self):
         headers = {'web-listings': 'true'}
 
@@ -81,7 +81,7 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertEqual(resp['status'], '200')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertIn(self.object_name, body)
 
         # clean up before exiting
@@ -91,3 +91,41 @@
         _, body = self.container_client.list_container_metadata(
             self.container_name)
         self.assertNotIn('x-container-meta-web-listings', body)
+
+    @test.attr('gate')
+    def test_web_listing_css(self):
+        headers = {'web-listings': 'true',
+                   'web-listings-css': 'listings.css'}
+
+        self.container_client.update_container_metadata(
+            self.container_name, metadata=headers)
+
+        # test GET on http://account_url/container_name
+        # we should retrieve a listing of objects
+        resp, body = self.custom_account_client.request("GET",
+                                                        self.container_name)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertIn(self.object_name, body)
+        css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
+        self.assertIn(css, body)
+
+    @test.attr('gate')
+    def test_web_error(self):
+        headers = {'web-listings': 'true',
+                   'web-error': self.object_name}
+
+        self.container_client.update_container_metadata(
+            self.container_name, metadata=headers)
+
+        # Create object to return when requested object not found
+        object_name_404 = "404" + self.object_name
+        object_data_404 = data_utils.arbitrary_string()
+        self.object_client.create_object(self.container_name,
+                                         object_name_404,
+                                         object_data_404)
+
+        # Request non-existing object
+        resp, body = self.custom_object_client.get_object(self.container_name,
+                                                          "notexisting")
+        self.assertEqual(resp['status'], '404')
+        self.assertEqual(body, object_data_404)
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
new file mode 100644
index 0000000..63393e4
--- /dev/null
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -0,0 +1,135 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Christian Schwede <christian.schwede@enovance.com>
+#
+# 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 hashlib
+import hmac
+import time
+import urlparse
+
+from tempest.api.object_storage import base
+from tempest.common.utils import data_utils
+from tempest.test import attr
+from tempest.test import HTTP_SUCCESS
+
+
+class ObjectFormPostTest(base.BaseObjectTest):
+
+    @classmethod
+    def setUpClass(cls):
+        super(ObjectFormPostTest, cls).setUpClass()
+        cls.container_name = data_utils.rand_name(name='TestContainer')
+        cls.object_name = data_utils.rand_name(name='ObjectTemp')
+
+        cls.container_client.create_container(cls.container_name)
+        cls.containers = [cls.container_name]
+
+        cls.key = 'Meta'
+        cls.metadata = {'Temp-URL-Key': cls.key}
+        cls.account_client.create_account_metadata(metadata=cls.metadata)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.account_client.delete_account_metadata(metadata=cls.metadata)
+        cls.delete_containers(cls.containers)
+        cls.data.teardown_all()
+        super(ObjectFormPostTest, cls).tearDownClass()
+
+    def get_multipart_form(self, expires=600):
+        path = "%s/%s/%s" % (
+            urlparse.urlparse(self.container_client.base_url).path,
+            self.container_name,
+            self.object_name)
+
+        redirect = ''
+        max_file_size = 104857600
+        max_file_count = 10
+        expires += int(time.time())
+        hmac_body = '%s\n%s\n%s\n%s\n%s' % (path,
+                                            redirect,
+                                            max_file_size,
+                                            max_file_count,
+                                            expires)
+
+        signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+
+        fields = {'redirect': redirect,
+                  'max_file_size': str(max_file_size),
+                  'max_file_count': str(max_file_count),
+                  'expires': str(expires),
+                  'signature': signature}
+
+        boundary = '--boundary--'
+        data = []
+        for (key, value) in fields.items():
+            data.append('--' + boundary)
+            data.append('Content-Disposition: form-data; name="%s"' % key)
+            data.append('')
+            data.append(value)
+
+        data.append('--' + boundary)
+        data.append('Content-Disposition: form-data; '
+                    'name="file1"; filename="testfile"')
+        data.append('Content-Type: application/octet-stream')
+        data.append('')
+        data.append('hello world')
+
+        data.append('--' + boundary + '--')
+        data.append('')
+
+        body = '\r\n'.join(data)
+        content_type = 'multipart/form-data; boundary=%s' % boundary
+        return body, content_type
+
+    @attr(type='gate')
+    def test_post_object_using_form(self):
+        body, content_type = self.get_multipart_form()
+
+        headers = {'Content-Type': content_type,
+                   'Content-Length': str(len(body))}
+
+        url = "%s/%s/%s" % (self.container_client.base_url,
+                            self.container_name,
+                            self.object_name)
+
+        # Use a raw request, otherwise authentication headers are used
+        resp, body = self.object_client.http_obj.request(url, "POST",
+                                                         body, headers=headers)
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+
+        # Ensure object is available
+        resp, body = self.object_client.get("%s/%s%s" % (
+            self.container_name, self.object_name, "testfile"))
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertEqual(body, "hello world")
+
+    @attr(type=['gate', 'negative'])
+    def test_post_object_using_form_expired(self):
+        body, content_type = self.get_multipart_form(expires=1)
+        time.sleep(2)
+
+        headers = {'Content-Type': content_type,
+                   'Content-Length': str(len(body))}
+
+        url = "%s/%s/%s" % (self.container_client.base_url,
+                            self.container_name,
+                            self.object_name)
+
+        # Use a raw request, otherwise authentication headers are used
+        resp, body = self.object_client.http_obj.request(url, "POST",
+                                                         body, headers=headers)
+        self.assertEqual(int(resp['status']), 401)
+        self.assertIn('FormPost: Form Expired', body)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 7626af1..c7fdd0e 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -16,8 +16,10 @@
 #    under the License.
 
 import hashlib
+import re
 
 from tempest.api.object_storage import base
+from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest.test import attr
 from tempest.test import HTTP_SUCCESS
@@ -60,6 +62,7 @@
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
 
     @attr(type='smoke')
     def test_delete_object(self):
@@ -72,6 +75,7 @@
         resp, _ = self.object_client.delete_object(self.container_name,
                                                    object_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'DELETE')
 
     @attr(type='smoke')
     def test_object_metadata(self):
@@ -89,11 +93,14 @@
         resp, _ = self.object_client.update_object_metadata(
             self.container_name, object_name, orig_metadata)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
 
         # get object metadata
         resp, resp_metadata = self.object_client.list_object_metadata(
             self.container_name, object_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'HEAD')
+
         actual_meta_key = 'x-object-meta-' + meta_key
         self.assertIn(actual_meta_key, resp)
         self.assertEqual(resp[actual_meta_key], meta_value)
@@ -111,6 +118,8 @@
         resp, body = self.object_client.get_object(self.container_name,
                                                    object_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'GET')
+
         self.assertEqual(body, data)
 
     @attr(type='smoke')
@@ -133,6 +142,8 @@
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, src_object_name, dst_object_name)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
         # check data
         resp, body = self.object_client.get_object(self.container_name,
                                                    dst_object_name)
@@ -156,6 +167,8 @@
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, object_name, object_name, metadata)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
         # check the content type
         resp, _ = self.object_client.list_object_metadata(self.container_name,
                                                           object_name)
@@ -180,6 +193,17 @@
                                                         src_object_name,
                                                         dst_object_name)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'COPY')
+
+        self.assertIn('last-modified', resp)
+        self.assertIn('x-copied-from', resp)
+        self.assertIn('x-copied-from-last-modified', resp)
+        self.assertNotEqual(len(resp['last-modified']), 0)
+        self.assertEqual(
+            resp['x-copied-from'],
+            self.container_name + "/" + src_object_name)
+        self.assertNotEqual(len(resp['x-copied-from-last-modified']), 0)
+
         # check data
         resp, body = self.object_client.get_object(self.container_name,
                                                    dst_object_name)
@@ -210,11 +234,15 @@
                                                             object_name,
                                                             orig_metadata)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
         # copy object from source container to destination container
         resp, _ = self.object_client.copy_object_across_containers(
             src_container_name, object_name, dst_container_name,
             object_name)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
         # check if object is present in destination container
         resp, body = self.object_client.get_object(dst_container_name,
                                                    object_name)
@@ -238,13 +266,34 @@
         # creating a manifest file
         metadata = {'X-Object-Manifest': '%s/%s/'
                     % (self.container_name, object_name)}
-        self.object_client.create_object(self.container_name,
-                                         object_name, data='')
+        resp, _ = self.object_client.create_object(self.container_name,
+                                                   object_name, data='')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
         resp, _ = self.object_client.update_object_metadata(
             self.container_name, object_name, metadata, metadata_prefix='')
+        self.assertHeaders(resp, 'Object', 'POST')
+
         resp, _ = self.object_client.list_object_metadata(
             self.container_name, object_name)
+
+        # Check only the existence of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
+                        'Object', 'HEAD'))
         self.assertIn('x-object-manifest', resp)
+
+        # Etag value of a large object is enclosed in double-quotations.
+        # This is a special case, therefore the formats of response headers
+        # are checked without a custom matcher.
+        self.assertTrue(resp['etag'].startswith('\"'))
+        self.assertTrue(resp['etag'].endswith('\"'))
+        self.assertTrue(resp['etag'].strip('\"').isalnum())
+        self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
+        self.assertNotEqual(len(resp['content-type']), 0)
+        self.assertTrue(re.match("^tx[0-9a-f]*-[0-9a-f]*$",
+                                 resp['x-trans-id']))
+        self.assertNotEqual(len(resp['date']), 0)
+        self.assertEqual(resp['accept-ranges'], 'bytes')
         self.assertEqual(resp['x-object-manifest'],
                          '%s/%s/' % (self.container_name, object_name))
 
@@ -270,12 +319,23 @@
         resp, _ = self.object_client.get(url, headers=headers)
         self.assertEqual(resp['status'], '304')
 
+        # When the file is not downloaded from Swift server, response does
+        # not contain 'X-Timestamp' header. This is the special case, therefore
+        # the existence of response headers is checked without custom matcher.
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+        self.assertIn('accept-ranges', resp)
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
         # 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.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'GET')
 
 
 class PublicObjectTest(base.BaseObjectTest):
@@ -298,6 +358,8 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers, metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
+
         # create object
         object_name = data_utils.rand_name(name='Object')
         data = data_utils.arbitrary_string(size=len(object_name),
@@ -305,17 +367,22 @@
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
 
         # list container metadata
         resp_meta, _ = self.container_client.list_container_metadata(
             self.container_name)
-        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'HEAD')
+
         self.assertIn('x-container-read', resp_meta)
         self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings')
 
         # trying to get object with empty headers as it is public readable
         resp, body = self.custom_object_client.get_object(
             self.container_name, object_name, metadata={})
+        self.assertHeaders(resp, 'Object', 'GET')
+
         self.assertEqual(body, data)
 
     @attr(type='smoke')
@@ -327,6 +394,7 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
 
         # create object
         object_name = data_utils.rand_name(name='Object')
@@ -335,11 +403,14 @@
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
 
         # list container metadata
         resp, _ = self.container_client.list_container_metadata(
             self.container_name)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Container', 'HEAD')
+
         self.assertIn('x-container-read', resp)
         self.assertEqual(resp['x-container-read'], '.r:*,.rlistings')
 
@@ -350,4 +421,6 @@
         resp, body = self.custom_object_client.get_object(
             self.container_name, object_name,
             metadata=headers)
+        self.assertHeaders(resp, 'Object', 'GET')
+
         self.assertEqual(body, data)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 77f3a53..c8ce57a 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -22,6 +22,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest import config
 from tempest import exceptions
 from tempest.test import attr
 from tempest.test import HTTP_SUCCESS
@@ -29,9 +30,19 @@
 
 class ObjectTempUrlTest(base.BaseObjectTest):
 
+    tempurl_available = \
+        config.TempestConfig().object_storage_feature_enabled.tempurl
+
     @classmethod
     def setUpClass(cls):
         super(ObjectTempUrlTest, cls).setUpClass()
+
+        # skip this test if CORS isn't enabled in the conf file.
+        if not cls.tempurl_available:
+            skip_msg = ("%s skipped as TempUrl middleware not available"
+                        % cls.__name__)
+            raise cls.skipException(skip_msg)
+
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
         cls.containers = [cls.container_name]
@@ -47,9 +58,9 @@
     def tearDownClass(cls):
         resp, _ = cls.account_client.delete_account_metadata(
             metadata=cls.metadata)
-        resp, _ = cls.account_client.list_account_metadata()
 
         cls.delete_containers(cls.containers)
+
         # delete the user setup created
         cls.data.teardown_all()
         super(ObjectTempUrlTest, cls).tearDownClass()
@@ -71,8 +82,11 @@
         self.object_client.create_object(self.container_name,
                                          self.object_name, self.data)
 
-    def get_temp_url(self, container, object_name, method, expires,
-                     key):
+    def _get_expiry_date(self, expiration_time=1000):
+        return int(time.time() + expiration_time)
+
+    def _get_temp_url(self, container, object_name, method, expires,
+                      key):
         """Create the temporary URL."""
 
         path = "%s/%s/%s" % (
@@ -90,17 +104,17 @@
 
     @attr(type='gate')
     def test_get_object_using_temp_url(self):
-        EXPIRATION_TIME = 10000  # high to ensure the test finishes.
-        expires = int(time.time() + EXPIRATION_TIME)
+        expires = self._get_expiry_date()
 
         # get a temp URL for the created object
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
         # trying to get object using temp url within expiry time
-        _, body = self.object_client.get_object_using_temp_url(url)
+        resp, body = self.object_client.get_object_using_temp_url(url)
 
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
         self.assertEqual(body, self.data)
 
         # Testing a HEAD on this Temp URL
@@ -108,18 +122,35 @@
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
 
     @attr(type='gate')
+    def test_get_object_using_temp_url_key_2(self):
+        key2 = 'Meta2-'
+        metadata = {'Temp-URL-Key-2': key2}
+        self.account_client.create_account_metadata(metadata=metadata)
+
+        self.account_client_metadata, _ = \
+            self.account_client.list_account_metadata()
+        self.assertIn('x-account-meta-temp-url-key-2',
+                      self.account_client_metadata)
+
+        expires = self._get_expiry_date()
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, key2)
+        resp, body = self.object_client.get_object_using_temp_url(url)
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertEqual(body, self.data)
+
+    @attr(type='gate')
     def test_put_object_using_temp_url(self):
         # make sure the metadata has been set
         new_data = data_utils.arbitrary_string(
             size=len(self.object_name),
             base_text=data_utils.rand_name(name="random"))
 
-        EXPIRATION_TIME = 10000  # high to ensure the test finishes.
-        expires = int(time.time() + EXPIRATION_TIME)
-
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "PUT",
-                                expires, self.key)
+        expires = self._get_expiry_date()
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "PUT",
+                                 expires, self.key)
 
         # trying to put random data in the object using temp url
         resp, body = self.object_client.put_object_using_temp_url(
@@ -132,25 +163,24 @@
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
 
         # Validate that the content of the object has been modified
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
         _, body = self.object_client.get_object_using_temp_url(url)
         self.assertEqual(body, new_data)
 
     @attr(type=['gate', 'negative'])
     def test_get_object_after_expiration_time(self):
-        EXPIRATION_TIME = 1
-        expires = int(time.time() + EXPIRATION_TIME)
 
+        expires = self._get_expiry_date(1)
         # get a temp URL for the created object
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
-        # temp URL is valid for 1 seconds, let's wait 3
-        time.sleep(EXPIRATION_TIME + 2)
+        # temp URL is valid for 1 seconds, let's wait 2
+        time.sleep(2)
 
         self.assertRaises(exceptions.Unauthorized,
                           self.object_client.get_object_using_temp_url,
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 6bc350a..03e8469 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -29,6 +29,7 @@
     def setUpClass(cls):
         super(VolumeMultiBackendTest, cls).setUpClass()
         if not cls.config.volume_feature_enabled.multi_backend:
+            cls.tearDownClass()
             raise cls.skipException("Cinder multi-backend feature disabled")
 
         cls.backend1_name = cls.config.volume.backend1_name
@@ -89,12 +90,14 @@
     @classmethod
     def tearDownClass(cls):
         # volumes deletion
-        for volume_id in cls.volume_id_list:
+        volume_id_list = getattr(cls, 'volume_id_list', [])
+        for volume_id in volume_id_list:
             cls.volume_client.delete_volume(volume_id)
             cls.volume_client.wait_for_resource_deletion(volume_id)
 
         # volume types deletion
-        for volume_type_id in cls.volume_type_id_list:
+        volume_type_id_list = getattr(cls, 'volume_type_id_list', [])
+        for volume_type_id in volume_type_id_list:
             cls.type_client.delete_volume_type(volume_type_id)
 
         super(VolumeMultiBackendTest, cls).tearDownClass()
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 4063eef..cb9ff11 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -47,7 +47,7 @@
         super(VolumesActionsTest, cls).tearDownClass()
 
     def _reset_volume_status(self, volume_id, status):
-        #Reset the volume status
+        # Reset the volume status
         resp, body = self.admin_volume_client.reset_volume_status(volume_id,
                                                                   status)
         return resp, body
@@ -57,6 +57,26 @@
         self._reset_volume_status(self.volume['id'], 'available')
         super(VolumesActionsTest, self).tearDown()
 
+    def _create_temp_volume(self):
+        # Create a temp volume for force delete tests
+        vol_name = utils.rand_name('Volume')
+        resp, temp_volume = self.client.create_volume(size=1,
+                                                      display_name=vol_name)
+        self.client.wait_for_volume_status(temp_volume['id'], 'available')
+
+        return temp_volume
+
+    def _create_reset_and_force_delete_temp_volume(self, status=None):
+        # Create volume, reset volume status, and force delete temp volume
+        temp_volume = self._create_temp_volume()
+        if status:
+            resp, body = self._reset_volume_status(temp_volume['id'], status)
+            self.assertEqual(202, resp.status)
+        resp_delete, volume_delete = self.admin_volume_client.\
+            force_delete_volume(temp_volume['id'])
+        self.assertEqual(202, resp_delete.status)
+        self.client.wait_for_resource_deletion(temp_volume['id'])
+
     @attr(type='gate')
     def test_volume_reset_status(self):
         # test volume reset status : available->error->available
@@ -84,6 +104,19 @@
         resp_get, volume_get = self.client.get_volume(self.volume['id'])
         self.assertEqual('in-use', volume_get['status'])
 
+    def test_volume_force_delete_when_volume_is_creating(self):
+        # test force delete when status of volume is creating
+        self._create_reset_and_force_delete_temp_volume('creating')
+
+    def test_volume_force_delete_when_volume_is_attaching(self):
+        # test force delete when status of volume is attaching
+        self._create_reset_and_force_delete_temp_volume('attaching')
+
+    @attr(type='gate')
+    def test_volume_force_delete_when_volume_is_error(self):
+        # test force delete when status of volume is error
+        self._create_reset_and_force_delete_temp_volume('error')
+
 
 class VolumesActionsTestXML(VolumesActionsTest):
     _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 30c2c74..8581d16 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -140,6 +140,35 @@
         self.assertEqual(200, resp.status)
         self.assertIn('available', body['status'])
 
+    def _is_true(self, val):
+        return val in ['true', 'True', True]
+
+    @attr(type='gate')
+    def test_volume_readonly_update(self):
+        # Update volume readonly true
+        readonly = True
+        resp, body = self.client.update_volume_readonly(self.volume['id'],
+                                                        readonly)
+        self.assertEqual(202, resp.status)
+
+        # Get Volume information
+        resp, fetched_volume = self.client.get_volume(self.volume['id'])
+        bool_flag = self._is_true(fetched_volume['metadata']['readonly'])
+        self.assertEqual(200, resp.status)
+        self.assertEqual(True, bool_flag)
+
+        # Update volume readonly false
+        readonly = False
+        resp, body = self.client.update_volume_readonly(self.volume['id'],
+                                                        readonly)
+        self.assertEqual(202, resp.status)
+
+        # Get Volume information
+        resp, fetched_volume = self.client.get_volume(self.volume['id'])
+        bool_flag = self._is_true(fetched_volume['metadata']['readonly'])
+        self.assertEqual(200, resp.status)
+        self.assertEqual(False, bool_flag)
+
 
 class VolumesActionsTestXML(VolumesActionsTest):
     _interface = "xml"
diff --git a/tempest/clients.py b/tempest/clients.py
index 9029d5f..291b946 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -50,14 +50,26 @@
     TenantUsagesClientJSON
 from tempest.services.compute.json.volumes_extensions_client import \
     VolumesExtensionsClientJSON
+from tempest.services.compute.v3.json.availability_zone_client import \
+    AvailabilityZoneV3ClientJSON
 from tempest.services.compute.v3.json.extensions_client import \
     ExtensionsV3ClientJSON
+from tempest.services.compute.v3.json.hypervisor_client import \
+    HypervisorV3ClientJSON
+from tempest.services.compute.v3.json.interfaces_client import \
+    InterfacesV3ClientJSON
 from tempest.services.compute.v3.json.servers_client import \
     ServersV3ClientJSON
 from tempest.services.compute.v3.json.services_client import \
     ServicesV3ClientJSON
+from tempest.services.compute.v3.xml.availability_zone_client import \
+    AvailabilityZoneV3ClientXML
 from tempest.services.compute.v3.xml.extensions_client import \
     ExtensionsV3ClientXML
+from tempest.services.compute.v3.xml.hypervisor_client import \
+    HypervisorV3ClientXML
+from tempest.services.compute.v3.xml.interfaces_client import \
+    InterfacesV3ClientXML
 from tempest.services.compute.v3.xml.servers_client import ServersV3ClientXML
 from tempest.services.compute.v3.xml.services_client import \
     ServicesV3ClientXML
@@ -206,9 +218,12 @@
             self.token_client = TokenClientXML(self.config)
             self.security_groups_client = SecurityGroupsClientXML(
                 *client_args)
+            self.interfaces_v3_client = InterfacesV3ClientXML(*client_args)
             self.interfaces_client = InterfacesClientXML(*client_args)
             self.endpoints_client = EndPointClientXML(*client_args)
             self.fixed_ips_client = FixedIPsClientXML(*client_args)
+            self.availability_zone_v3_client = AvailabilityZoneV3ClientXML(
+                *client_args)
             self.availability_zone_client = AvailabilityZoneClientXML(
                 *client_args)
             self.services_v3_client = ServicesV3ClientXML(*client_args)
@@ -217,6 +232,7 @@
             self.services_client = ServicesClientXML(*client_args)
             self.tenant_usages_client = TenantUsagesClientXML(*client_args)
             self.policy_client = PolicyClientXML(*client_args)
+            self.hypervisor_v3_client = HypervisorV3ClientXML(*client_args)
             self.hypervisor_client = HypervisorClientXML(*client_args)
             self.token_v3_client = V3TokenClientXML(*client_args)
             self.network_client = NetworkClientXML(*client_args)
@@ -250,9 +266,12 @@
             self.token_client = TokenClientJSON(self.config)
             self.security_groups_client = SecurityGroupsClientJSON(
                 *client_args)
+            self.interfaces_v3_client = InterfacesV3ClientJSON(*client_args)
             self.interfaces_client = InterfacesClientJSON(*client_args)
             self.endpoints_client = EndPointClientJSON(*client_args)
             self.fixed_ips_client = FixedIPsClientJSON(*client_args)
+            self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
+                *client_args)
             self.availability_zone_client = AvailabilityZoneClientJSON(
                 *client_args)
             self.services_v3_client = ServicesV3ClientJSON(*client_args)
@@ -261,6 +280,7 @@
             self.services_client = ServicesClientJSON(*client_args)
             self.tenant_usages_client = TenantUsagesClientJSON(*client_args)
             self.policy_client = PolicyClientJSON(*client_args)
+            self.hypervisor_v3_client = HypervisorV3ClientJSON(*client_args)
             self.hypervisor_client = HypervisorClientJSON(*client_args)
             self.token_v3_client = V3TokenClientJSON(*client_args)
             self.network_client = NetworkClientJSON(*client_args)
@@ -298,11 +318,12 @@
     managed client objects
     """
 
-    def __init__(self):
+    def __init__(self, interface='json'):
         conf = config.TempestConfig()
         super(AltManager, self).__init__(conf.identity.alt_username,
                                          conf.identity.alt_password,
-                                         conf.identity.alt_tenant_name)
+                                         conf.identity.alt_tenant_name,
+                                         interface=interface)
 
 
 class AdminManager(Manager):
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
new file mode 100644
index 0000000..307d5db
--- /dev/null
+++ b/tempest/common/custom_matchers.py
@@ -0,0 +1,154 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NTT Corporation
+#
+#    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 re
+
+
+class ExistsAllResponseHeaders(object):
+    """
+    Specific matcher to check the existence of Swift's response headers
+
+    This matcher checks the existence of common headers for each HTTP method
+    or the target, which means account, container or object.
+    When checking the existence of 'specific' headers such as
+    X-Account-Meta-* or X-Object-Manifest for example, those headers must be
+    checked in each test code.
+    """
+
+    def __init__(self, target, method):
+        """
+        param: target Account/Container/Object
+        param: method PUT/GET/HEAD/DELETE/COPY/POST
+        """
+        self.target = target
+        self.method = method
+
+    def match(self, actual):
+        """
+        param: actual HTTP response headers
+        """
+        # Check common headers for all HTTP methods
+        if 'content-length' not in actual:
+            return NonExistentHeader('content-length')
+        if 'content-type' not in actual:
+            return NonExistentHeader('content-type')
+        if 'x-trans-id' not in actual:
+            return NonExistentHeader('x-trans-id')
+        if 'date' not in actual:
+            return NonExistentHeader('date')
+
+        # Check headers for a specific method or target
+        if self.method == 'GET' or self.method == 'HEAD':
+            if 'x-timestamp' not in actual:
+                return NonExistentHeader('x-timestamp')
+            if 'accept-ranges' not in actual:
+                return NonExistentHeader('accept-ranges')
+            if self.target == 'Account':
+                if 'x-account-bytes-used' not in actual:
+                    return NonExistentHeader('x-account-bytes-used')
+                if 'x-account-container-count' not in actual:
+                    return NonExistentHeader('x-account-container-count')
+                if 'x-account-object-count' not in actual:
+                    return NonExistentHeader('x-account-object-count')
+            elif self.target == 'Container':
+                if 'x-container-bytes-used' not in actual:
+                    return NonExistentHeader('x-container-bytes-used')
+                if 'x-container-object-count' not in actual:
+                    return NonExistentHeader('x-container-object-count')
+            elif self.target == 'Object':
+                if 'etag' not in actual:
+                    return NonExistentHeader('etag')
+        elif self.method == 'PUT' or self.method == 'COPY':
+            if self.target == 'Object':
+                if 'etag' not in actual:
+                    return NonExistentHeader('etag')
+
+        return None
+
+
+class NonExistentHeader(object):
+    """
+    Informs an error message for end users in the case of missing a
+    certain header in Swift's responses
+    """
+
+    def __init__(self, header):
+        self.header = header
+
+    def describe(self):
+        return "%s header does not exist" % self.header
+
+    def get_details(self):
+        return {}
+
+
+class AreAllWellFormatted(object):
+    """
+    Specific matcher to check the correctness of formats of values of Swift's
+    response headers
+
+    This matcher checks the format of values of response headers.
+    When checking the format of values of 'specific' headers such as
+    X-Account-Meta-* or X-Object-Manifest for example, those values must be
+    checked in each test code.
+    """
+
+    def match(self, actual):
+        for key, value in actual.iteritems():
+            if key == 'content-length' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'x-timestamp' and not re.match("^\d+\.?\d*\Z", value):
+                return InvalidFormat(key, value)
+            elif key == 'x-account-bytes-used' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'x-account-container-count' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'x-account-object-count' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'x-container-bytes-used' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'x-container-object-count' and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key == 'content-type' and not value:
+                return InvalidFormat(key, value)
+            elif key == 'x-trans-id' and \
+                not re.match("^tx[0-9a-f]*-[0-9a-f]*$", value):
+                return InvalidFormat(key, value)
+            elif key == 'date' and not value:
+                return InvalidFormat(key, value)
+            elif key == 'accept-ranges' and not value == 'bytes':
+                return InvalidFormat(key, value)
+            elif key == 'etag' and not value.isalnum():
+                return InvalidFormat(key, value)
+
+        return None
+
+
+class InvalidFormat(object):
+    """
+    Informs an error message for end users if a format of a certain header
+    is invalid
+    """
+
+    def __init__(self, key, value):
+        self.key = key
+        self.value = value
+
+    def describe(self):
+        return "InvalidFormat (%s, %s)" % (self.key, self.value)
+
+    def get_details(self):
+        return {}
diff --git a/tempest/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
index 3811088..545703b 100644
--- a/tempest/common/generate_sample_tempest.py
+++ b/tempest/common/generate_sample_tempest.py
@@ -21,6 +21,15 @@
 from tempest import config
 from tempest.openstack.common.config import generator
 
+# NOTE(mtreinish): This hack is needed because of how oslo config is used in
+# tempest. Tempest is run from inside a test runner and so we can't rely on the
+# global CONF object being fully populated when we run a test. (test runners
+# don't init every file for running a test) So to get around that we manually
+# load the config file in tempest for each test class to ensure that every
+# config option is set. However, the tool expects the CONF object to be fully
+# populated when it inits all the files in the project. This just works around
+# the issue by manually loading the config file (which may or may not exist)
+# which will populate all the options before running the generator.
 
 config.TempestConfig()
 generator.generate(sys.argv[1:])
diff --git a/tempest/config.py b/tempest/config.py
index 009147b..d97c7b2 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -117,11 +117,11 @@
     cfg.StrOpt('image_ref_alt',
                default="{$IMAGE_ID_ALT}",
                help="Valid secondary image reference to be used in tests."),
-    cfg.IntOpt('flavor_ref',
-               default=1,
+    cfg.StrOpt('flavor_ref',
+               default="1",
                help="Valid primary flavor to use in tests."),
-    cfg.IntOpt('flavor_ref_alt',
-               default=2,
+    cfg.StrOpt('flavor_ref_alt',
+               default="2",
                help='Valid secondary flavor to be used in tests.'),
     cfg.StrOpt('image_ssh_user',
                default="root",
@@ -211,7 +211,7 @@
 
 ComputeFeaturesGroup = [
     cfg.BoolOpt('api_v3',
-                default=False,
+                default=True,
                 help="If false, skip all nova v3 tests."),
     cfg.BoolOpt('disk_config',
                 default=True,
@@ -406,7 +406,7 @@
 ObjectStoreFeaturesGroup = [
     cfg.BoolOpt('container_quotas',
                 default=True,
-                help="Set to True if the container quota middleware "
+                help="Set to True if the Container Quota middleware "
                      "is enabled"),
     cfg.BoolOpt('accounts_quotas',
                 default=True,
@@ -414,6 +414,9 @@
     cfg.BoolOpt('crossdomain',
                 default=True,
                 help="Set to True if the Crossdomain middleware is enabled"),
+    cfg.BoolOpt('tempurl',
+                default=True,
+                help="Set to True if the TempURL middleware is enabled"),
 ]
 
 
diff --git a/tempest/openstack/common/lockutils.py b/tempest/openstack/common/lockutils.py
index 8ea8766..65f3548 100644
--- a/tempest/openstack/common/lockutils.py
+++ b/tempest/openstack/common/lockutils.py
@@ -20,6 +20,10 @@
 import errno
 import functools
 import os
+import shutil
+import subprocess
+import sys
+import tempfile
 import threading
 import time
 import weakref
@@ -39,6 +43,7 @@
     cfg.BoolOpt('disable_process_locking', default=False,
                 help='Whether to disable inter-process locks'),
     cfg.StrOpt('lock_path',
+               default=os.environ.get("TEMPEST_LOCK_PATH"),
                help=('Directory to use for lock files.'))
 ]
 
@@ -131,6 +136,7 @@
     InterProcessLock = _PosixLock
 
 _semaphores = weakref.WeakValueDictionary()
+_semaphores_lock = threading.Lock()
 
 
 @contextlib.contextmanager
@@ -153,15 +159,12 @@
     special location for external lock files to live. If nothing is set, then
     CONF.lock_path is used as a default.
     """
-    # NOTE(soren): If we ever go natively threaded, this will be racy.
-    #              See http://stackoverflow.com/questions/5390569/dyn
-    #              amically-allocating-and-destroying-mutexes
-    sem = _semaphores.get(name, threading.Semaphore())
-    if name not in _semaphores:
-        # this check is not racy - we're already holding ref locally
-        # so GC won't remove the item and there was no IO switch
-        # (only valid in greenthreads)
-        _semaphores[name] = sem
+    with _semaphores_lock:
+        try:
+            sem = _semaphores[name]
+        except KeyError:
+            sem = threading.Semaphore()
+            _semaphores[name] = sem
 
     with sem:
         LOG.debug(_('Got semaphore "%(lock)s"'), {'lock': name})
@@ -276,3 +279,27 @@
     """
 
     return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
+
+
+def main(argv):
+    """Create a dir for locks and pass it to command from arguments
+
+    If you run this:
+    python -m openstack.common.lockutils python setup.py testr <etc>
+
+    a temporary directory will be created for all your locks and passed to all
+    your tests in an environment variable. The temporary dir will be deleted
+    afterwards and the return value will be preserved.
+    """
+
+    lock_dir = tempfile.mkdtemp()
+    os.environ["TEMPEST_LOCK_PATH"] = lock_dir
+    try:
+        ret_val = subprocess.call(argv[1:])
+    finally:
+        shutil.rmtree(lock_dir, ignore_errors=True)
+    return ret_val
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 7848afc..06841e1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -360,7 +360,8 @@
                       to become %s" % (thing_id, log_status)
             raise exceptions.TimeoutException(message)
 
-    def create_loginable_secgroup_rule(self, client=None, secgroup_id=None):
+    def _create_loginable_secgroup_rule_nova(self, client=None,
+                                             secgroup_id=None):
         if client is None:
             client = self.compute_client
         if secgroup_id is None:
@@ -389,10 +390,13 @@
                 'cidr': '0.0.0.0/0',
             }
         ]
+        rules = list()
         for ruleset in rulesets:
             sg_rule = client.security_group_rules.create(secgroup_id,
                                                          **ruleset)
             self.set_resource(sg_rule.id, sg_rule)
+            rules.append(sg_rule)
+        return rules
 
     def create_server(self, client=None, name=None, image=None, flavor=None,
                       create_kwargs={}):
@@ -506,22 +510,6 @@
                 cls.config.identity.password,
                 cls.config.identity.tenant_name).tenant_id
 
-    def _create_security_group(self, client=None, namestart='secgroup-smoke-'):
-        if client is None:
-            client = self.compute_client
-        # Create security group
-        sg_name = data_utils.rand_name(namestart)
-        sg_desc = sg_name + " description"
-        secgroup = client.security_groups.create(sg_name, sg_desc)
-        self.assertEqual(secgroup.name, sg_name)
-        self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
-
-        # Add rules to the security group
-        self.create_loginable_secgroup_rule(client, secgroup.id)
-
-        return secgroup
-
     def _create_network(self, tenant_id, namestart='network-smoke-'):
         name = data_utils.rand_name(namestart)
         body = dict(
@@ -648,6 +636,171 @@
             'Auth failure in connecting to %s@%s via ssh' %
             (username, ip_address))
 
+    def _create_security_group_nova(self, client=None,
+                                    namestart='secgroup-smoke-',
+                                    tenant_id=None):
+        if client is None:
+            client = self.compute_client
+        # Create security group
+        sg_name = data_utils.rand_name(namestart)
+        sg_desc = sg_name + " description"
+        secgroup = client.security_groups.create(sg_name, sg_desc)
+        self.assertEqual(secgroup.name, sg_name)
+        self.assertEqual(secgroup.description, sg_desc)
+        self.set_resource(sg_name, secgroup)
+
+        # Add rules to the security group
+        self._create_loginable_secgroup_rule_nova(client, secgroup.id)
+
+        return secgroup
+
+    def _create_security_group_neutron(self, tenant_id, client=None,
+                                       namestart='secgroup-smoke-'):
+        if client is None:
+            client = self.network_client
+        secgroup = self._create_empty_security_group(namestart=namestart,
+                                                     client=client,
+                                                     tenant_id=tenant_id)
+
+        # Add rules to the security group
+        rules = self._create_loginable_secgroup_rule_neutron(secgroup=secgroup)
+        for rule in rules:
+            self.assertEqual(tenant_id, rule.tenant_id)
+            self.assertEqual(secgroup.id, rule.security_group_id)
+        return secgroup
+
+    def _create_empty_security_group(self, tenant_id, client=None,
+                                     namestart='secgroup-smoke-'):
+        """Create a security group without rules.
+
+        Default rules will be created:
+         - IPv4 egress to any
+         - IPv6 egress to any
+
+        :param tenant_id: secgroup will be created in this tenant
+        :returns: DeletableSecurityGroup -- containing the secgroup created
+        """
+        if client is None:
+            client = self.network_client
+        sg_name = data_utils.rand_name(namestart)
+        sg_desc = sg_name + " description"
+        sg_dict = dict(name=sg_name,
+                       description=sg_desc)
+        sg_dict['tenant_id'] = tenant_id
+        body = dict(security_group=sg_dict)
+        result = client.create_security_group(body=body)
+        secgroup = net_common.DeletableSecurityGroup(
+            client=client,
+            **result['security_group']
+        )
+        self.assertEqual(secgroup.name, sg_name)
+        self.assertEqual(tenant_id, secgroup.tenant_id)
+        self.assertEqual(secgroup.description, sg_desc)
+        self.set_resource(sg_name, secgroup)
+        return secgroup
+
+    def _default_security_group(self, tenant_id, client=None):
+        """Get default secgroup for given tenant_id.
+
+        :returns: DeletableSecurityGroup -- default secgroup for given tenant
+        """
+        if client is None:
+            client = self.network_client
+        sgs = [
+            sg for sg in client.list_security_groups().values()[0]
+            if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
+        ]
+        msg = "No default security group for tenant %s." % (tenant_id)
+        self.assertTrue(len(sgs) > 0, msg)
+        if len(sgs) > 1:
+            msg = "Found %d default security groups" % len(sgs)
+            raise exc.NeutronClientNoUniqueMatch(msg=msg)
+        return net_common.DeletableSecurityGroup(client=client,
+                                                 **sgs[0])
+
+    def _create_security_group_rule(self, client=None, secgroup=None,
+                                    tenant_id=None, **kwargs):
+        """Create a rule from a dictionary of rule parameters.
+
+        Create a rule in a secgroup. if secgroup not defined will search for
+        default secgroup in tenant_id.
+
+        :param secgroup: type DeletableSecurityGroup.
+        :param secgroup_id: search for secgroup by id
+            default -- choose default secgroup for given tenant_id
+        :param tenant_id: if secgroup not passed -- the tenant in which to
+            search for default secgroup
+        :param kwargs: a dictionary containing rule parameters:
+            for example, to allow incoming ssh:
+            rule = {
+                    direction: 'ingress'
+                    protocol:'tcp',
+                    port_range_min: 22,
+                    port_range_max: 22
+                    }
+        """
+        if client is None:
+            client = self.network_client
+        if secgroup is None:
+            secgroup = self._default_security_group(tenant_id)
+
+        ruleset = dict(security_group_id=secgroup.id,
+                       tenant_id=secgroup.tenant_id,
+                       )
+        ruleset.update(kwargs)
+
+        body = dict(security_group_rule=dict(ruleset))
+        sg_rule = client.create_security_group_rule(body=body)
+        sg_rule = net_common.DeletableSecurityGroupRule(
+            client=client,
+            **sg_rule['security_group_rule']
+        )
+        self.set_resource(sg_rule.id, sg_rule)
+        self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
+        self.assertEqual(secgroup.id, sg_rule.security_group_id)
+
+        return sg_rule
+
+    def _create_loginable_secgroup_rule_neutron(self, client=None,
+                                                secgroup=None):
+        """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.
+        """
+
+        if client is None:
+            client = self.network_client
+        rules = []
+        rulesets = [
+            dict(
+                # ssh
+                protocol='tcp',
+                port_range_min=22,
+                port_range_max=22,
+            ),
+            dict(
+                # ping
+                protocol='icmp',
+            )
+        ]
+        for ruleset in rulesets:
+            for r_direction in ['ingress', 'egress']:
+                ruleset['direction'] = r_direction
+                try:
+                    sg_rule = self._create_security_group_rule(
+                        client=client, secgroup=secgroup, **ruleset)
+                except exc.NeutronClientException as ex:
+                    # if rule already exist - skip rule and continue
+                    if not (ex.status_code is 409 and 'Security group rule'
+                            ' already exists' in ex.message):
+                        raise ex
+                else:
+                    self.assertEqual(r_direction, sg_rule.direction)
+                    rules.append(sg_rule)
+
+        return rules
+
 
 class OrchestrationScenarioTest(OfficialClientTest):
     """
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 30c223f..7f8d3e4 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -85,7 +85,7 @@
         name = data_utils.rand_name('scenario-server-')
         client = self.compute_client
         flavor_id = self.config.compute.flavor_ref
-        secgroup = self._create_security_group()
+        secgroup = self._create_security_group_nova()
         self.servers = client.servers.create(
             name=name, image=self.image,
             flavor=flavor_id,
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 9cc8541..8a51cd1 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -161,7 +161,7 @@
 
         self.nova_floating_ip_create()
         self.nova_floating_ip_add()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
         self.ssh_to_server()
         self.check_partitions()
 
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index a7618b1..bfded53 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -164,7 +164,8 @@
             name=data_utils.rand_name('keypair-smoke-'))
 
     def _create_security_groups(self):
-        self.security_groups[self.tenant_id] = self._create_security_group()
+        self.security_groups[self.tenant_id] =\
+            self._create_security_group_neutron(tenant_id=self.tenant_id)
 
     def _create_networks(self):
         network = self._create_network(self.tenant_id)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 0b08f9c..1e1a310 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -50,7 +50,7 @@
         self.set_resource('secgroup', self.secgroup)
 
         # Add rules to the security group
-        self.create_loginable_secgroup_rule(secgroup_id=self.secgroup.id)
+        self._create_loginable_secgroup_rule_nova(secgroup_id=self.secgroup.id)
 
     def boot_instance(self):
         create_kwargs = {
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index ba347e0..00139f0 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -65,7 +65,7 @@
     def test_snapshot_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # boot a instance and create a timestamp file in it
         server = self._boot_image(self.config.compute.image_ref)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index a8cedc7..5eac55c 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -146,7 +146,7 @@
     def test_stamp_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # boot an instance and create a timestamp file in it
         volume = self._create_volume()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 84846c1..fa9a228 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -120,7 +120,7 @@
     @services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
         keypair = self.create_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # create an instance from volume
         volume_origin = self._create_volume_from_image()
diff --git a/tempest/services/compute/v3/json/availability_zone_client.py b/tempest/services/compute/v3/json/availability_zone_client.py
index b11871b..9a3fe8b 100644
--- a/tempest/services/compute/v3/json/availability_zone_client.py
+++ b/tempest/services/compute/v3/json/availability_zone_client.py
@@ -20,20 +20,20 @@
 from tempest.common.rest_client import RestClient
 
 
-class AvailabilityZoneClientJSON(RestClient):
+class AvailabilityZoneV3ClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(AvailabilityZoneClientJSON, self).__init__(config, username,
-                                                         password, auth_url,
-                                                         tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(AvailabilityZoneV3ClientJSON, self).__init__(config, username,
+                                                           password, auth_url,
+                                                           tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def get_availability_zone_list(self):
         resp, body = self.get('os-availability-zone')
         body = json.loads(body)
-        return resp, body['availabilityZoneInfo']
+        return resp, body['availability_zone_info']
 
     def get_availability_zone_list_detail(self):
         resp, body = self.get('os-availability-zone/detail')
         body = json.loads(body)
-        return resp, body['availabilityZoneInfo']
+        return resp, body['availability_zone_info']
diff --git a/tempest/services/compute/v3/json/hypervisor_client.py b/tempest/services/compute/v3/json/hypervisor_client.py
new file mode 100644
index 0000000..fa1255a
--- /dev/null
+++ b/tempest/services/compute/v3/json/hypervisor_client.py
@@ -0,0 +1,71 @@
+# 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 HypervisorV3ClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorV3ClientJSON, self).__init__(config, username,
+                                                     password, auth_url,
+                                                     tenant_name)
+        self.service = self.config.compute.catalog_v3_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['hypervisor']
+
+    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']
+
+    def search_hypervisor(self, hyper_name):
+        """Search specified hypervisor."""
+        resp, body = self.get('os-hypervisors/search?query=%s' % hyper_name)
+        body = json.loads(body)
+        return resp, body['hypervisors']
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
index 06e6476..7fb0fa9 100644
--- a/tempest/services/compute/v3/json/interfaces_client.py
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -20,21 +20,22 @@
 from tempest import exceptions
 
 
-class InterfacesClientJSON(RestClient):
+class InterfacesV3ClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(InterfacesClientJSON, self).__init__(config, username, password,
-                                                   auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(InterfacesV3ClientJSON, self).__init__(config, username,
+                                                     password, auth_url,
+                                                     tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def list_interfaces(self, server):
-        resp, body = self.get('servers/%s/os-interface' % server)
+        resp, body = self.get('servers/%s/os-attach-interfaces' % server)
         body = json.loads(body)
-        return resp, body['interfaceAttachments']
+        return resp, body['interface_attachments']
 
     def create_interface(self, server, port_id=None, network_id=None,
                          fixed_ip=None):
-        post_body = dict(interfaceAttachment=dict())
+        post_body = dict(interface_attachment=dict())
         if port_id:
             post_body['port_id'] = port_id
         if network_id:
@@ -42,20 +43,22 @@
         if fixed_ip:
             post_body['fixed_ips'] = [dict(ip_address=fixed_ip)]
         post_body = json.dumps(post_body)
-        resp, body = self.post('servers/%s/os-interface' % server,
+        resp, body = self.post('servers/%s/os-attach-interfaces' % server,
                                headers=self.headers,
                                body=post_body)
         body = json.loads(body)
-        return resp, body['interfaceAttachment']
+        return resp, body['interface_attachment']
 
     def show_interface(self, server, port_id):
-        resp, body = self.get('servers/%s/os-interface/%s' % (server, port_id))
+        resp, body =\
+            self.get('servers/%s/os-attach-interfaces/%s' % (server, port_id))
         body = json.loads(body)
-        return resp, body['interfaceAttachment']
+        return resp, body['interface_attachment']
 
     def delete_interface(self, server, port_id):
-        resp, body = self.delete('servers/%s/os-interface/%s' % (server,
-                                                                 port_id))
+        resp, body =\
+            self.delete('servers/%s/os-attach-interfaces/%s' % (server,
+                                                                port_id))
         return resp, body
 
     def wait_for_interface_status(self, server, port_id, status):
diff --git a/tempest/services/compute/v3/json/tenant_usages_client.py b/tempest/services/compute/v3/json/tenant_usages_client.py
new file mode 100644
index 0000000..4dd6964
--- /dev/null
+++ b/tempest/services/compute/v3/json/tenant_usages_client.py
@@ -0,0 +1,47 @@
+# 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 json
+import urllib
+
+from tempest.common.rest_client import RestClient
+
+
+class TenantUsagesClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(TenantUsagesClientJSON, self).__init__(
+            config, username, password, auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_tenant_usages(self, params=None):
+        url = 'os-simple-tenant-usage'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['tenant_usages'][0]
+
+    def get_tenant_usage(self, tenant_id, params=None):
+        url = 'os-simple-tenant-usage/%s' % tenant_id
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['tenant_usage']
diff --git a/tempest/services/compute/v3/xml/availability_zone_client.py b/tempest/services/compute/v3/xml/availability_zone_client.py
index ae93774..35fb2b1 100644
--- a/tempest/services/compute/v3/xml/availability_zone_client.py
+++ b/tempest/services/compute/v3/xml/availability_zone_client.py
@@ -21,13 +21,13 @@
 from tempest.services.compute.xml.common import xml_to_json
 
 
-class AvailabilityZoneClientXML(RestClientXML):
+class AvailabilityZoneV3ClientXML(RestClientXML):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(AvailabilityZoneClientXML, self).__init__(config, username,
-                                                        password, auth_url,
-                                                        tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(AvailabilityZoneV3ClientXML, self).__init__(config, username,
+                                                          password, auth_url,
+                                                          tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def _parse_array(self, node):
         return [xml_to_json(x) for x in node]
diff --git a/tempest/services/compute/v3/xml/hypervisor_client.py b/tempest/services/compute/v3/xml/hypervisor_client.py
new file mode 100644
index 0000000..ce0207d
--- /dev/null
+++ b/tempest/services/compute/v3/xml/hypervisor_client.py
@@ -0,0 +1,79 @@
+# 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 HypervisorV3ClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorV3ClientXML, self).__init__(config, username,
+                                                    password, auth_url,
+                                                    tenant_name)
+        self.service = self.config.compute.catalog_v3_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
+
+    def search_hypervisor(self, hyper_name):
+        """Search specified hypervisor."""
+        resp, body = self.get('os-hypervisors/search?query=%s' % hyper_name,
+                              self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
diff --git a/tempest/services/compute/v3/xml/interfaces_client.py b/tempest/services/compute/v3/xml/interfaces_client.py
index a84e0bd..870c130 100644
--- a/tempest/services/compute/v3/xml/interfaces_client.py
+++ b/tempest/services/compute/v3/xml/interfaces_client.py
@@ -25,12 +25,12 @@
 from tempest.services.compute.xml.common import xml_to_json
 
 
-class InterfacesClientXML(RestClientXML):
+class InterfacesV3ClientXML(RestClientXML):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(InterfacesClientXML, self).__init__(config, username, password,
-                                                  auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(InterfacesV3ClientXML, self).__init__(config, username, password,
+                                                    auth_url, tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def _process_xml_interface(self, node):
         iface = xml_to_json(node)
@@ -40,7 +40,8 @@
         return iface
 
     def list_interfaces(self, server):
-        resp, body = self.get('servers/%s/os-interface' % server, self.headers)
+        resp, body = self.get('servers/%s/os-attach-interfaces' % server,
+                              self.headers)
         node = etree.fromstring(body)
         interfaces = [self._process_xml_interface(x)
                       for x in node.getchildren()]
@@ -49,7 +50,7 @@
     def create_interface(self, server, port_id=None, network_id=None,
                          fixed_ip=None):
         doc = Document()
-        iface = Element('interfaceAttachment')
+        iface = Element('interface_attachment')
         if port_id:
             _port_id = Element('port_id')
             _port_id.append(Text(port_id))
@@ -67,21 +68,23 @@
             _fixed_ips.append(_fixed_ip)
             iface.append(_fixed_ips)
         doc.append(iface)
-        resp, body = self.post('servers/%s/os-interface' % server,
+        resp, body = self.post('servers/%s/os-attach-interfaces' % server,
                                headers=self.headers,
                                body=str(doc))
         body = self._process_xml_interface(etree.fromstring(body))
         return resp, body
 
     def show_interface(self, server, port_id):
-        resp, body = self.get('servers/%s/os-interface/%s' % (server, port_id),
-                              self.headers)
+        resp, body =\
+            self.get('servers/%s/os-attach-interfaces/%s' % (server, port_id),
+                     self.headers)
         body = self._process_xml_interface(etree.fromstring(body))
         return resp, body
 
     def delete_interface(self, server, port_id):
-        resp, body = self.delete('servers/%s/os-interface/%s' % (server,
-                                                                 port_id))
+        resp, body =\
+            self.delete('servers/%s/os-attach-interfaces/%s' % (server,
+                                                                port_id))
         return resp, body
 
     def wait_for_interface_status(self, server, port_id, status):
diff --git a/tempest/services/compute/v3/xml/tenant_usages_client.py b/tempest/services/compute/v3/xml/tenant_usages_client.py
new file mode 100644
index 0000000..cb92324
--- /dev/null
+++ b/tempest/services/compute/v3/xml/tenant_usages_client.py
@@ -0,0 +1,54 @@
+# 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 urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class TenantUsagesClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(TenantUsagesClientXML, self).__init__(config, username,
+                                                    password, auth_url,
+                                                    tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _parse_array(self, node):
+        json = xml_to_json(node)
+        return json
+
+    def list_tenant_usages(self, params=None):
+        url = 'os-simple-tenant-usage'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url, self.headers)
+        tenant_usage = self._parse_array(etree.fromstring(body))
+        return resp, tenant_usage['tenant_usage']
+
+    def get_tenant_usage(self, tenant_id, params=None):
+        url = 'os-simple-tenant-usage/%s' % tenant_id
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url, self.headers)
+        tenant_usage = self._parse_array(etree.fromstring(body))
+        return resp, tenant_usage
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index 363c1a8..a1c74d9 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -43,6 +43,10 @@
     def _format_flavor(self, f):
         flavor = {'links': []}
         for k, v in f.items():
+            if k == 'id':
+                flavor['id'] = v
+                continue
+
             if k == 'link':
                 flavor['links'].append(v)
                 continue
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 3e5413c..7d40d0e 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -193,6 +193,10 @@
         server = self._parse_server(etree.fromstring(body))
         return resp, server
 
+    def migrate_server(self, server_id, **kwargs):
+        """Migrates the given server ."""
+        return self.action(server_id, 'migrate', None, **kwargs)
+
     def lock_server(self, server_id, **kwargs):
         """Locks the given server."""
         return self.action(server_id, 'lock', None, **kwargs)
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 93b28a2..967dc09 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -246,3 +246,20 @@
         resp, body = self.post(url, post_body, self.headers)
         body = json.loads(body)
         return resp, body['transfer']
+
+    def update_volume_readonly(self, volume_id, readonly):
+        """Update the Specified Volume readonly."""
+        post_body = {
+            'readonly': readonly
+        }
+        post_body = json.dumps({'os-update_readonly_flag': post_body})
+        url = 'volumes/%s/action' % (volume_id)
+        resp, body = self.post(url, post_body, self.headers)
+        return resp, body
+
+    def force_delete_volume(self, volume_id):
+        """Force Delete Volume."""
+        post_body = json.dumps({'os-force_delete': {}})
+        resp, body = self.post('volumes/%s/action' % volume_id, post_body,
+                               self.headers)
+        return resp, body
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index b1e54ed..1fc63e9 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -337,3 +337,22 @@
         resp, body = self.post(url, str(Document(post_body)), self.headers)
         volume = xml_to_json(etree.fromstring(body))
         return resp, volume
+
+    def update_volume_readonly(self, volume_id, readonly):
+        """Update the Specified Volume readonly."""
+        post_body = Element("os-update_readonly_flag",
+                            readonly=readonly)
+        url = 'volumes/%s/action' % str(volume_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        if body:
+            body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def force_delete_volume(self, volume_id):
+        """Force Delete Volume."""
+        post_body = Element("os-force_delete")
+        url = 'volumes/%s/action' % str(volume_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        if body:
+            body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/test-requirements.txt b/test-requirements.txt
index fbe7e43..41a784e 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,4 +1,4 @@
-hacking>=0.5.6,<0.8
+hacking>=0.8.0,<0.9
 # needed for doc build
 docutils==0.9.1
 sphinx>=1.1.2
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 2ad4f70..6d4436e 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -26,6 +26,10 @@
 import yaml
 
 
+is_neutron = os.environ.get('DEVSTACK_GATE_NEUTRON', "0") == "1"
+dump_all_errors = is_neutron
+
+
 def process_files(file_specs, url_specs, whitelists):
     regexp = re.compile(r"^.*(ERROR|CRITICAL).*\[.*\-.*\]")
     had_errors = False
@@ -48,6 +52,7 @@
 
 def scan_content(name, content, regexp, whitelist):
     had_errors = False
+    print_log_name = True
     for line in content:
         if not line.startswith("Stderr:") and regexp.match(line):
             whitelisted = False
@@ -57,10 +62,12 @@
                 if re.match(pat, line):
                     whitelisted = True
                     break
-            if not whitelisted:
-                if not had_errors:
+            if not whitelisted or dump_all_errors:
+                if print_log_name:
                     print("Log File: %s" % name)
-                had_errors = True
+                    print_log_name = False
+                if not whitelisted:
+                    had_errors = True
                 print(line)
     return had_errors
 
@@ -115,8 +122,11 @@
             whitelists = loaded
     if process_files(files_to_process, urls_to_process, whitelists):
         print("Logs have errors")
-        # Return non-zero to start failing builds
-        return 0
+        if is_neutron:
+            print("Currently not failing neutron builds with errors")
+            return 0
+        print("FAILED")
+        return 1
     else:
         print("ok")
         return 0
diff --git a/tools/config/check_uptodate.sh b/tools/config/check_uptodate.sh
index 9882ab6..45c8629 100755
--- a/tools/config/check_uptodate.sh
+++ b/tools/config/check_uptodate.sh
@@ -5,6 +5,6 @@
 if ! diff $TEMPDIR/$CFGFILE etc/$CFGFILE
 then
     echo "E: tempest.conf.sample is not up to date, please run:"
-    echo "MODULEPATH=tempest.common.generate_sample_tempest tools/config/generate_sample.sh"
+    echo "tools/generate_sample.sh"
     exit 42
 fi
diff --git a/tools/generate_sample.sh b/tools/generate_sample.sh
new file mode 100755
index 0000000..9b312c9
--- /dev/null
+++ b/tools/generate_sample.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+MODULEPATH=tempest.common.generate_sample_tempest tools/config/generate_sample.sh $@
diff --git a/tools/verify_tempest_config.py b/tools/verify_tempest_config.py
index 1b5fe68..347659d 100755
--- a/tools/verify_tempest_config.py
+++ b/tools/verify_tempest_config.py
@@ -36,11 +36,11 @@
     __, versions = os.image_client.get_versions()
     if CONF.image_feature_enabled.api_v1 != ('v1.1' in versions or 'v1.0' in
                                              versions):
-        print 'Config option image api_v1 should be change to: %s' % (
-            not CONF.image_feature_enabled.api_v1)
+        print('Config option image api_v1 should be change to: %s' % (
+            not CONF.image_feature_enabled.api_v1))
     if CONF.image_feature_enabled.api_v2 != ('v2.0' in versions):
-        print 'Config option image api_v2 should be change to: %s' % (
-            not CONF.image_feature_enabled.api_v2)
+        print('Config option image api_v2 should be change to: %s' % (
+            not CONF.image_feature_enabled.api_v2))
 
 
 def verify_extensions(os):
@@ -62,8 +62,8 @@
     for option in NOVA_EXTENSIONS.keys():
         config_value = getattr(CONF.compute_feature_enabled, option)
         if config_value != results['nova_features'][option]:
-            print "Config option: %s should be changed to: %s" % (
-                option, not config_value)
+            print("Config option: %s should be changed to: %s" % (
+                option, not config_value))
 
 
 def main(argv):