Merge "skip test_lock_unlock_server"
diff --git a/HACKING.rst b/HACKING.rst
index 7871f60..7d995c3 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -105,6 +105,19 @@
 in tempest.api.compute would require a service tag for those services, however
 they do not need to be tagged as compute.
 
+Negative Tests
+--------------
+When adding negative tests to tempest there are 2 requirements. First the tests
+must be marked with a negative attribute. For example::
+
+  @attr(type=negative)
+  def test_resource_no_uuid(self):
+    ...
+
+The second requirement is that all negative tests must be added to a negative
+test file. If such a file doesn't exist for the particular resource being
+tested a new test file should be added.
+
 Test skips because of Known Bugs
 --------------------------------
 
diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml
new file mode 100644
index 0000000..6762f9f
--- /dev/null
+++ b/etc/whitelist.yaml
@@ -0,0 +1,131 @@
+n-cpu:
+    - module: "nova.virt.libvirt.driver"
+      message: "During wait destroy, instance disappeared"
+    - module: "glanceclient.common.http"
+      message: "Request returned failure status"
+    - module: "nova.openstack.common.periodic_task"
+      message: "Error during ComputeManager\\.update_available_resource: \
+        'NoneType' object is not iterable"
+    - module: "nova.compute.manager"
+      message: "Possibly task preempted"
+    - module: "nova.openstack.common.rpc.amqp"
+      message: "Exception during message handling"
+    - module: "nova.network.api"
+      message: "Failed storing info cache"
+    - module: "nova.compute.manager"
+      message: "Error while trying to clean up image"
+    - module: "nova.virt.libvirt.driver"
+      message: "Error injecting data into image.*\\(Unexpected error while \
+        running command"
+    - module: "nova.compute.manager"
+      message: "Instance failed to spawn"
+    - module: "nova.compute.manager"
+      message: "Error: Unexpected error while running command"
+
+g-api:
+    - module: "glance.store.sheepdog"
+      message: "Error in store configuration: Unexpected error while \
+        running command"
+    - module: "swiftclient"
+      message: "Container HEAD failed: .*404 Not Found"
+
+ceilometer-acompute:
+    - module: "ceilometer.compute.pollsters.disk"
+      message: "Requested operation is not valid: domain is not running"
+    - module: "ceilometer.compute.pollsters.disk"
+      message: "Domain not found: no domain with matching uuid"
+
+h-api:
+    - module: "root"
+      message: "Returning 400 to user: The server could not comply with \
+        the request since it is either malformed or otherwise incorrect"
+    - module: "root"
+      message: "Unexpected error occurred serving API: Request limit \
+        exceeded: Template exceeds maximum allowed size"
+    - module: "root"
+      message: "Unexpected error occurred serving API: The Stack \
+        .*could not be found"
+
+h-eng:
+    - module: "heat.openstack.common.rpc.amqp"
+      message: "Exception during message handling"
+    - module: "heat.openstack.common.rpc.common"
+      message: "The Stack .* could not be found"
+
+n-api:
+    - module: "glanceclient.common.http"
+      message: "Request returned failure status"
+    - module: "nova.api.openstack"
+      message: "Caught error: Quota exceeded for"
+    - module: "nova.compute.api"
+      message: "ServerDiskConfigTest"
+    - module: "nova.compute.api"
+      message: "ServersTest"
+    - module: "nova.compute.api"
+      message: "\\{u'kernel_id'.*u'ramdisk_id':"
+
+n-cond:
+    - module: "nova.notifications"
+      message: "Failed to send state update notification"
+
+n-sch:
+    - module: "nova.scheduler.filter_scheduler"
+      message: "Error from last host: "
+
+c-api:
+    - module: "cinder.api.middleware.fault"
+      message: "Caught error: Volume .* could not be found"
+
+q-dhpc:
+    - module: "neutron.common.legacy"
+      message: "Skipping unknown group key: firewall_driver"
+    - module: "neutron.agent.dhcp_agent"
+      message: "Unable to enable dhcp"
+    - module: "neutron.agent.dhcp_agent"
+      message: " Network .* RPC info call failed"
+
+ceilometer-collector:
+    - module: "stevedore.extension"
+      message: ".*"
+    - module: "ceilometer.collector.dispatcher.database"
+      message: "duplicate key value violates unique constraint"
+
+q-agt:
+    - module: "neutron.agent.linux.ovs_lib"
+      message: "Unable to execute.*Exception:"
+
+q-dhcp:
+    - module: "neutron.common.legacy"
+      message: "Skipping unknown group key: firewall_driver"
+    - module: "neutron.agent.dhcp_agent"
+      message: "Unable to enable dhcp"
+    - module: "neutron.agent.dhcp_agent"
+      message: "Network .* RPC info call failed"
+
+q-l3:
+    - module: "neutron.common.legacy"
+      message: "Skipping unknown group key: firewall_driver"
+    - module: "neutron.agent.l3_agent"
+      message: "Failed synchronizing routers"
+
+
+q-lbaas:
+    - module: "neutron.common.legacy"
+      message: "Skipping unknown group key: firewall_driver"
+    - module: "neutron.services.loadbalancer.drivers.haproxy.agent_manager"
+      message: "Error upating stats"
+    - module: "neutron.services.loadbalancer.drivers.haproxy.agent_manager"
+      message: "Unable to destroy device for pool"
+
+q-svc:
+    - module: "neutron.common.legacy"
+      message: "Skipping unknown group key: firewall_driver"
+    - module: "neutron.openstack.common.rpc.amqp"
+      message: "Exception during message handling"
+    - module: "neutron.openstack.common.rpc.common"
+      message: "Network .* could not be found"
+    - module: "neutron.openstack.common.rpc.common"
+      message: "Pool .* could not be found"
+    - module: "neutron.api.v2.resource"
+      message: "show failed"
+
diff --git a/run_tests.sh b/run_tests.sh
index 970da51..5c8ce7d 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -63,7 +63,7 @@
     -l|--logging) logging=1;;
     -L|--logging-config) logging_config=$2; shift;;
     --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs="$testrargs $1"
+    *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
   esac
   shift
 done
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 85b03e6..ee262df 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -16,7 +16,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import config
 from tempest import exceptions
 from tempest.test import attr
 
@@ -24,8 +23,6 @@
 class FixedIPsTestJson(base.BaseComputeAdminTest):
     _interface = 'json'
 
-    CONF = config.TempestConfig()
-
     @classmethod
     def setUpClass(cls):
         super(FixedIPsTestJson, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index ce326a3..fb6a463 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -115,6 +115,14 @@
                           self.flavor['id'],
                           'key1')
 
+    @attr(type=['negative', 'gate'])
+    def test_flavor_unset_nonexistent_key(self):
+        nonexistent_key = rand_name('flavor_key')
+        self.assertRaises(exceptions.NotFound,
+                          self.client.unset_flavor_extra_spec,
+                          self.flavor['id'],
+                          nonexistent_key)
+
 
 class FlavorsExtraSpecsTestXML(FlavorsExtraSpecsTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index f55f152..e744200 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -52,15 +52,6 @@
                                      'instances', 'security_group_rules',
                                      'cores', 'security_groups'))
 
-    @classmethod
-    def tearDownClass(cls):
-        for server in cls.servers:
-            try:
-                cls.servers_client.delete_server(server['id'])
-            except exceptions.NotFound:
-                continue
-        super(QuotasAdminTestJSON, cls).tearDownClass()
-
     @attr(type='smoke')
     def test_get_default_quotas(self):
         # Admin can get the default resource quota set for a tenant
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index e730d31..97e0e69 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -19,6 +19,7 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
+from tempest.test import skip_because
 
 
 class ServersAdminTestJSON(base.BaseComputeAdminTest):
@@ -33,10 +34,10 @@
     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.admin_client = cls._get_identity_admin_client()
-        tenant = cls.admin_client.get_tenant_by_name(
+        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']
 
@@ -158,6 +159,25 @@
         self.assertRaises(exceptions.NotFound,
                           self.client.reset_state, '999')
 
+    @attr(type='gate')
+    @skip_because(bug="1240043")
+    def test_get_server_diagnostics_by_admin(self):
+        # Retrieve server diagnostics by admin user
+        resp, diagnostic = self.client.get_server_diagnostics(self.s1_id)
+        self.assertEqual(200, resp.status)
+        basic_attrs = ['rx_packets', 'rx_errors', 'rx_drop',
+                       'tx_packets', 'tx_errors', 'tx_drop',
+                       'read_req', 'write_req', 'cpu', 'memory']
+        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/base.py b/tempest/api/compute/base.py
index 0b527d9..885adcf 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -100,6 +100,19 @@
                 pass
 
     @classmethod
+    def rebuild_server(cls, **kwargs):
+        # Destroy an existing server and creates a new one
+        try:
+            cls.servers_client.delete_server(cls.server_id)
+            cls.servers_client.wait_for_server_termination(cls.server_id)
+        except Exception as exc:
+            LOG.exception(exc)
+            pass
+        resp, server = cls.create_server(wait_until='ACTIVE', **kwargs)
+        cls.server_id = server['id']
+        cls.password = server['adminPass']
+
+    @classmethod
     def clear_images(cls):
         for image_id in cls.images:
             try:
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 983258d..9dd2e27 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -37,7 +37,7 @@
         blocks while the servers are being deleted.
         """
         if len(servers):
-            if not compute.MULTI_USER:
+            if not cls.config.compute.allow_tenant_isolation:
                 for srv in servers:
                     cls.client.wait_for_server_termination(srv['id'],
                                                            ignore_error=True)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 6e8afa0..255beb7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -44,13 +44,13 @@
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
             # Rebuild server if something happened to it during a test
-            self.rebuild_servers()
+            self.rebuild_server()
 
     @classmethod
     def setUpClass(cls):
         super(ServerActionsTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
-        cls.rebuild_servers()
+        cls.rebuild_server()
 
     @testtools.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
                           'Change password not available.')
@@ -118,7 +118,8 @@
         password = 'rebuildPassw0rd'
         resp, rebuilt_server = self.client.rebuild(self.server_id,
                                                    self.image_ref_alt,
-                                                   name=new_name, meta=meta,
+                                                   name=new_name,
+                                                   metadata=meta,
                                                    personality=personality,
                                                    adminPass=password)
 
@@ -226,7 +227,8 @@
         self.assertRaises(exceptions.NotFound,
                           self.client.rebuild,
                           999, self.image_ref_alt,
-                          name=new_name, meta=meta,
+                          name=new_name,
+                          metadata=meta,
                           personality=personality,
                           adminPass='rebuild')
 
@@ -284,14 +286,6 @@
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
-    @classmethod
-    def rebuild_servers(cls):
-        # Destroy any existing server and creates a new one
-        cls.clear_servers()
-        resp, server = cls.create_server(wait_until='ACTIVE')
-        cls.server_id = server['id']
-        cls.password = server['adminPass']
-
     @attr(type='gate')
     def test_stop_start_server(self):
         resp, server = self.servers_client.stop(self.server_id)
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 5d9a5ce..c896224 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -28,6 +28,13 @@
 class ServersNegativeTestJSON(base.BaseComputeTest):
     _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()
@@ -35,6 +42,8 @@
         cls.img_client = cls.images_client
         cls.alt_os = clients.AltManager()
         cls.alt_client = cls.alt_os.servers_client
+        resp, server = cls.create_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
 
     @attr(type=['negative', 'gate'])
     def test_server_name_blank(self):
@@ -92,8 +101,6 @@
     @attr(type=['negative', 'gate'])
     def test_reboot_deleted_server(self):
         # Reboot a deleted server
-        resp, server = self.create_server()
-        self.server_id = server['id']
         self.client.delete_server(self.server_id)
         self.client.wait_for_server_termination(self.server_id)
         self.assertRaises(exceptions.NotFound, self.client.reboot,
@@ -102,8 +109,6 @@
     @attr(type=['negative', 'gate'])
     def test_pause_paused_server(self):
         # Pause a paused server.
-        resp, server = self.create_server(wait_until='ACTIVE')
-        self.server_id = server['id']
         self.client.pause_server(self.server_id)
         self.client.wait_for_server_status(self.server_id, 'PAUSED')
         self.assertRaises(exceptions.Duplicate,
@@ -113,9 +118,6 @@
     @attr(type=['negative', 'gate'])
     def test_rebuild_deleted_server(self):
         # Rebuild a deleted server
-
-        resp, server = self.create_server()
-        self.server_id = server['id']
         self.client.delete_server(self.server_id)
         self.client.wait_for_server_termination(self.server_id)
 
@@ -195,21 +197,19 @@
     def test_update_server_of_another_tenant(self):
         # Update name of a server that belongs to another tenant
 
-        resp, server = self.create_server(wait_until='ACTIVE')
-        new_name = server['id'] + '_new'
+        new_name = self.server_id + '_new'
         self.assertRaises(exceptions.NotFound,
-                          self.alt_client.update_server, server['id'],
+                          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
 
-        resp, server = self.create_server(wait_until='ACTIVE')
         new_name = 'a' * 256
         self.assertRaises(exceptions.BadRequest,
                           self.client.update_server,
-                          server['id'],
+                          self.server_id,
                           name=new_name)
 
     @attr(type=['negative', 'gate'])
@@ -222,10 +222,9 @@
     @attr(type=['negative', 'gate'])
     def test_delete_a_server_of_another_tenant(self):
         # Delete a server that belongs to another tenant
-        resp, server = self.create_server(wait_until='ACTIVE')
         self.assertRaises(exceptions.NotFound,
                           self.alt_client.delete_server,
-                          server['id'])
+                          self.server_id)
 
     @attr(type=['negative', 'gate'])
     def test_delete_server_pass_negative_id(self):
@@ -277,11 +276,9 @@
     @attr(type=['negative', 'gate'])
     def test_unpause_server_invalid_state(self):
         # unpause an active server.
-        resp, server = self.create_server(wait_until='ACTIVE')
-        server_id = server['id']
         self.assertRaises(exceptions.Duplicate,
                           self.client.unpause_server,
-                          server_id)
+                          self.server_id)
 
     @attr(type=['negative', 'gate'])
     def test_suspend_non_existent_server(self):
@@ -291,17 +288,13 @@
 
     @attr(type=['negative', 'gate'])
     def test_suspend_server_invalid_state(self):
-        # create server.
-        resp, server = self.create_server(wait_until='ACTIVE')
-        server_id = server['id']
-
         # suspend a suspended server.
-        resp, _ = self.client.suspend_server(server_id)
+        resp, _ = self.client.suspend_server(self.server_id)
         self.assertEqual(202, resp.status)
-        self.client.wait_for_server_status(server_id, 'SUSPENDED')
+        self.client.wait_for_server_status(self.server_id, 'SUSPENDED')
         self.assertRaises(exceptions.Duplicate,
                           self.client.suspend_server,
-                          server_id)
+                          self.server_id)
 
     @attr(type=['negative', 'gate'])
     def test_resume_non_existent_server(self):
@@ -311,14 +304,10 @@
 
     @attr(type=['negative', 'gate'])
     def test_resume_server_invalid_state(self):
-        # create server.
-        resp, server = self.create_server(wait_until='ACTIVE')
-        server_id = server['id']
-
         # resume an active server.
         self.assertRaises(exceptions.Duplicate,
                           self.client.resume_server,
-                          server_id)
+                          self.server_id)
 
 
 class ServersNegativeTestXML(ServersNegativeTestJSON):
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index 689ab29..66d35cb 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -19,7 +19,6 @@
 
 from tempest.api.identity import base
 from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -46,60 +45,19 @@
         self.assertEqual('200', resp['status'])
         self.assertEqual(self.alt_user, user['name'])
 
-    @attr(type=['negative', 'gate'])
-    def test_create_user_by_unauthorized_user(self):
-        # Non-administrator should not be authorized to create a user
+    @attr(type='smoke')
+    def test_create_user_with_enabled(self):
+        # Create a user with enabled : False
         self.data.setup_test_tenant()
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.create_user, self.alt_user,
-                          self.alt_password, self.data.tenant['id'],
-                          self.alt_email)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_user_with_empty_name(self):
-        # User with an empty name should not be created
-        self.data.setup_test_tenant()
-        self.assertRaises(exceptions.BadRequest, self.client.create_user, '',
-                          self.alt_password, self.data.tenant['id'],
-                          self.alt_email)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_user_with_name_length_over_255(self):
-        # Length of user name filed should be restricted to 255 characters
-        self.data.setup_test_tenant()
-        self.assertRaises(exceptions.BadRequest, self.client.create_user,
-                          'a' * 256, self.alt_password,
-                          self.data.tenant['id'], self.alt_email)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_user_with_duplicate_name(self):
-        # Duplicate user should not be created
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Duplicate, self.client.create_user,
-                          self.data.test_user, self.data.test_password,
-                          self.data.tenant['id'], self.data.test_email)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_user_for_non_existant_tenant(self):
-        # Attempt to create a user in a non-existent tenant should fail
-        self.assertRaises(exceptions.NotFound, self.client.create_user,
-                          self.alt_user, self.alt_password, '49ffgg99999',
-                          self.alt_email)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_user_request_without_a_token(self):
-        # Request to create a user without a valid token should fail
-        self.data.setup_test_tenant()
-        # Get the token of the current client
-        token = self.client.get_auth()
-        # Delete the token from database
-        self.client.delete_token(token)
-        self.assertRaises(exceptions.Unauthorized, self.client.create_user,
-                          self.alt_user, self.alt_password,
-                          self.data.tenant['id'], self.alt_email)
-
-        # Unset the token to allow further tests to generate a new token
-        self.client.clear_auth()
+        name = rand_name('test_user_')
+        resp, user = self.client.create_user(name, self.alt_password,
+                                             self.data.tenant['id'],
+                                             self.alt_email, enabled=False)
+        self.data.users.append(user)
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(name, user['name'])
+        self.assertEqual('false', str(user['enabled']).lower())
+        self.assertEqual(self.alt_email, user['email'])
 
     @attr(type='smoke')
     def test_update_user(self):
@@ -141,20 +99,6 @@
         resp, body = self.client.delete_user(user['id'])
         self.assertEqual('204', resp['status'])
 
-    @attr(type=['negative', 'gate'])
-    def test_delete_users_by_unauthorized_user(self):
-        # Non-administrator user should not be authorized to delete a user
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.delete_user,
-                          self.data.user['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_delete_non_existant_user(self):
-        # Attempt to delete a non-existent user should fail
-        self.assertRaises(exceptions.NotFound, self.client.delete_user,
-                          'junk12345123')
-
     @attr(type='smoke')
     def test_user_authentication(self):
         # Valid user's token is authenticated
@@ -168,51 +112,6 @@
                                             self.data.test_tenant)
         self.assertEqual('200', resp['status'])
 
-    @attr(type=['negative', 'gate'])
-    def test_authentication_for_disabled_user(self):
-        # Disabled user's token should not get authenticated
-        self.data.setup_test_user()
-        self.disable_user(self.data.test_user)
-        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
-                          self.data.test_user,
-                          self.data.test_password,
-                          self.data.test_tenant)
-
-    @attr(type=['negative', 'gate'])
-    def test_authentication_when_tenant_is_disabled(self):
-        # User's token for a disabled tenant should not be authenticated
-        self.data.setup_test_user()
-        self.disable_tenant(self.data.test_tenant)
-        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
-                          self.data.test_user,
-                          self.data.test_password,
-                          self.data.test_tenant)
-
-    @attr(type=['negative', 'gate'])
-    def test_authentication_with_invalid_tenant(self):
-        # User's token for an invalid tenant should not be authenticated
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
-                          self.data.test_user,
-                          self.data.test_password,
-                          'junktenant1234')
-
-    @attr(type=['negative', 'gate'])
-    def test_authentication_with_invalid_username(self):
-        # Non-existent user's token should not get authenticated
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
-                          'junkuser123', self.data.test_password,
-                          self.data.test_tenant)
-
-    @attr(type=['negative', 'gate'])
-    def test_authentication_with_invalid_password(self):
-        # User's token with invalid password should not be authenticated
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
-                          self.data.test_user, 'junkpass1234',
-                          self.data.test_tenant)
-
     @attr(type='gate')
     def test_authentication_request_without_token(self):
         # Request for token authentication with a valid token in header
@@ -239,21 +138,6 @@
                         Contains(self.data.test_user),
                         "Could not find %s" % self.data.test_user)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_users_by_unauthorized_user(self):
-        # Non-administrator user should not be authorized to get user list
-        self.data.setup_test_user()
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.get_users)
-
-    @attr(type=['negative', 'gate'])
-    def test_get_users_request_without_token(self):
-        # Request to get list of users without a valid token should fail
-        token = self.client.get_auth()
-        self.client.delete_token(token)
-        self.assertRaises(exceptions.Unauthorized, self.client.get_users)
-        self.client.clear_auth()
-
     @attr(type='gate')
     def test_list_users_for_tenant(self):
         # Return a list of all users for a tenant
@@ -326,21 +210,6 @@
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
-    @attr(type=['negative', 'gate'])
-    def test_list_users_with_invalid_tenant(self):
-        # Should not be able to return a list of all
-        # users for a non-existent tenant
-        # Assign invalid tenant ids
-        invalid_id = list()
-        invalid_id.append(rand_name('999'))
-        invalid_id.append('alpha')
-        invalid_id.append(rand_name("dddd@#%%^$"))
-        invalid_id.append('!@#()$%^&*?<>{}[]')
-        # List the users with invalid tenant id
-        for invalid in invalid_id:
-            self.assertRaises(exceptions.NotFound,
-                              self.client.list_users_for_tenant, invalid)
-
 
 class UsersTestXML(UsersTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_users_negative.py b/tempest/api/identity/admin/test_users_negative.py
new file mode 100644
index 0000000..7cb9aef
--- /dev/null
+++ b/tempest/api/identity/admin/test_users_negative.py
@@ -0,0 +1,236 @@
+# 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.
+
+from tempest.api.identity import base
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+from tempest.test import attr
+import uuid
+
+
+class UsersNegativeTestJSON(base.BaseIdentityAdminTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(UsersNegativeTestJSON, cls).setUpClass()
+        cls.alt_user = rand_name('test_user_')
+        cls.alt_password = rand_name('pass_')
+        cls.alt_email = cls.alt_user + '@testmail.tm'
+        cls.alt_tenant = rand_name('test_tenant_')
+        cls.alt_description = rand_name('desc_')
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_by_unauthorized_user(self):
+        # Non-administrator should not be authorized to create a user
+        self.data.setup_test_tenant()
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.create_user, self.alt_user,
+                          self.alt_password, self.data.tenant['id'],
+                          self.alt_email)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_with_empty_name(self):
+        # User with an empty name should not be created
+        self.data.setup_test_tenant()
+        self.assertRaises(exceptions.BadRequest, self.client.create_user, '',
+                          self.alt_password, self.data.tenant['id'],
+                          self.alt_email)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_with_name_length_over_255(self):
+        # Length of user name filed should be restricted to 255 characters
+        self.data.setup_test_tenant()
+        self.assertRaises(exceptions.BadRequest, self.client.create_user,
+                          'a' * 256, self.alt_password,
+                          self.data.tenant['id'], self.alt_email)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_with_duplicate_name(self):
+        # Duplicate user should not be created
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Duplicate, self.client.create_user,
+                          self.data.test_user, self.data.test_password,
+                          self.data.tenant['id'], self.data.test_email)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_for_non_existant_tenant(self):
+        # Attempt to create a user in a non-existent tenant should fail
+        self.assertRaises(exceptions.NotFound, self.client.create_user,
+                          self.alt_user, self.alt_password, '49ffgg99999',
+                          self.alt_email)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_request_without_a_token(self):
+        # Request to create a user without a valid token should fail
+        self.data.setup_test_tenant()
+        # Get the token of the current client
+        token = self.client.get_auth()
+        # Delete the token from database
+        self.client.delete_token(token)
+        self.assertRaises(exceptions.Unauthorized, self.client.create_user,
+                          self.alt_user, self.alt_password,
+                          self.data.tenant['id'], self.alt_email)
+
+        # Unset the token to allow further tests to generate a new token
+        self.client.clear_auth()
+
+    @attr(type=['negative', 'gate'])
+    def test_create_user_with_enabled_non_bool(self):
+        # Attempt to create a user with valid enabled para should fail
+        self.data.setup_test_tenant()
+        name = rand_name('test_user_')
+        self.assertRaises(exceptions.BadRequest, self.client.create_user,
+                          name, self.alt_password,
+                          self.data.tenant['id'],
+                          self.alt_email, enabled=3)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_user_for_non_existant_user(self):
+        # Attempt to update a user non-existent user should fail
+        user_name = rand_name('user-')
+        non_existent_id = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.update_user,
+                          non_existent_id, name=user_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_user_request_without_a_token(self):
+        # Request to update a user without a valid token should fail
+
+        # Get the token of the current client
+        token = self.client.get_auth()
+        # Delete the token from database
+        self.client.delete_token(token)
+        self.assertRaises(exceptions.Unauthorized, self.client.update_user,
+                          self.alt_user)
+
+        # Unset the token to allow further tests to generate a new token
+        self.client.clear_auth()
+
+    @attr(type=['negative', 'gate'])
+    def test_update_user_by_unauthorized_user(self):
+        # Non-administrator should not be authorized to update user
+        self.data.setup_test_tenant()
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.update_user, self.alt_user)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_users_by_unauthorized_user(self):
+        # Non-administrator user should not be authorized to delete a user
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.delete_user,
+                          self.data.user['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_non_existant_user(self):
+        # Attempt to delete a non-existent user should fail
+        self.assertRaises(exceptions.NotFound, self.client.delete_user,
+                          'junk12345123')
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_user_request_without_a_token(self):
+        # Request to delete a user without a valid token should fail
+
+        # Get the token of the current client
+        token = self.client.get_auth()
+        # Delete the token from database
+        self.client.delete_token(token)
+        self.assertRaises(exceptions.Unauthorized, self.client.delete_user,
+                          self.alt_user)
+
+        # Unset the token to allow further tests to generate a new token
+        self.client.clear_auth()
+
+    @attr(type=['negative', 'gate'])
+    def test_authentication_for_disabled_user(self):
+        # Disabled user's token should not get authenticated
+        self.data.setup_test_user()
+        self.disable_user(self.data.test_user)
+        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
+                          self.data.test_user,
+                          self.data.test_password,
+                          self.data.test_tenant)
+
+    @attr(type=['negative', 'gate'])
+    def test_authentication_when_tenant_is_disabled(self):
+        # User's token for a disabled tenant should not be authenticated
+        self.data.setup_test_user()
+        self.disable_tenant(self.data.test_tenant)
+        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
+                          self.data.test_user,
+                          self.data.test_password,
+                          self.data.test_tenant)
+
+    @attr(type=['negative', 'gate'])
+    def test_authentication_with_invalid_tenant(self):
+        # User's token for an invalid tenant should not be authenticated
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
+                          self.data.test_user,
+                          self.data.test_password,
+                          'junktenant1234')
+
+    @attr(type=['negative', 'gate'])
+    def test_authentication_with_invalid_username(self):
+        # Non-existent user's token should not get authenticated
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
+                          'junkuser123', self.data.test_password,
+                          self.data.test_tenant)
+
+    @attr(type=['negative', 'gate'])
+    def test_authentication_with_invalid_password(self):
+        # User's token with invalid password should not be authenticated
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Unauthorized, self.token_client.auth,
+                          self.data.test_user, 'junkpass1234',
+                          self.data.test_tenant)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_users_by_unauthorized_user(self):
+        # Non-administrator user should not be authorized to get user list
+        self.data.setup_test_user()
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.get_users)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_users_request_without_token(self):
+        # Request to get list of users without a valid token should fail
+        token = self.client.get_auth()
+        self.client.delete_token(token)
+        self.assertRaises(exceptions.Unauthorized, self.client.get_users)
+        self.client.clear_auth()
+
+    @attr(type=['negative', 'gate'])
+    def test_list_users_with_invalid_tenant(self):
+        # Should not be able to return a list of all
+        # users for a non-existent tenant
+        # Assign invalid tenant ids
+        invalid_id = list()
+        invalid_id.append(rand_name('999'))
+        invalid_id.append('alpha')
+        invalid_id.append(rand_name("dddd@#%%^$"))
+        invalid_id.append('!@#()$%^&*?<>{}[]')
+        # List the users with invalid tenant id
+        for invalid in invalid_id:
+            self.assertRaises(exceptions.NotFound,
+                              self.client.list_users_for_tenant, invalid)
+
+
+class UsersNegativeTestXML(UsersNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index cfac257..c3a66c5 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -56,6 +56,7 @@
         cls.networks = []
         cls.subnets = []
         cls.ports = []
+        cls.routers = []
         cls.pools = []
         cls.vips = []
         cls.members = []
@@ -73,6 +74,8 @@
             cls.client.delete_pool(pool['id'])
         for port in cls.ports:
             cls.client.delete_port(port['id'])
+        for router in cls.routers:
+            cls.client.delete_router(router['id'])
         for subnet in cls.subnets:
             cls.client.delete_subnet(subnet['id'])
         for network in cls.networks:
@@ -125,6 +128,21 @@
         return port
 
     @classmethod
+    def create_router(cls, router_name=None, admin_state_up=False,
+                      external_network_id=None, enable_snat=None):
+        ext_gw_info = {}
+        if external_network_id:
+            ext_gw_info['network_id'] = external_network_id
+        if enable_snat:
+            ext_gw_info['enable_snat'] = enable_snat
+        resp, body = cls.client.create_router(
+            router_name, external_gateway_info=ext_gw_info,
+            admin_state_up=admin_state_up)
+        router = body['router']
+        cls.routers.append(router)
+        return router
+
+    @classmethod
     def create_pool(cls, name, lb_method, protocol, subnet):
         """Wrapper utility that returns a test pool."""
         resp, body = cls.client.create_pool(name, lb_method, protocol,
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index ca2c879..9acb6c5 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -47,11 +47,9 @@
         # Create network, subnet, router and add interface
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
-        resp, router = cls.client.create_router(
+        cls.router = cls.create_router(
             rand_name('router-'),
-            external_gateway_info={"network_id":
-                                   cls.network_cfg.public_network_id})
-        cls.router = router['router']
+            external_network_id=cls.network_cfg.public_network_id)
         resp, _ = cls.client.add_router_interface_with_subnet_id(
             cls.router['id'], cls.subnet['id'])
         cls.port = list()
@@ -66,7 +64,6 @@
                                                           cls.subnet['id'])
         for i in range(2):
             cls.client.delete_port(cls.port[i]['id'])
-        cls.client.delete_router(cls.router['id'])
         super(FloatingIPTestJSON, cls).tearDownClass()
 
     def _delete_floating_ip(self, floating_ip_id):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 8b939fe..2cfbf61 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -52,6 +52,8 @@
     @attr(type='smoke')
     def test_create_show_list_update_delete_router(self):
         # Create a router
+        # NOTE(salv-orlando): Do not invoke self.create_router
+        # as we need to check the response code
         name = rand_name('router-')
         resp, create_body = self.client.create_router(
             name, external_gateway_info={
@@ -94,41 +96,37 @@
     def test_add_remove_router_interface_with_subnet_id(self):
         network = self.create_network()
         subnet = self.create_subnet(network)
-        name = rand_name('router-')
-        resp, create_body = self.client.create_router(name)
-        self.addCleanup(self.client.delete_router, create_body['router']['id'])
+        router = self.create_router(rand_name('router-'))
         # Add router interface with subnet id
         resp, interface = self.client.add_router_interface_with_subnet_id(
-            create_body['router']['id'], subnet['id'])
+            router['id'], subnet['id'])
         self.assertEqual('200', resp['status'])
         self.addCleanup(self._remove_router_interface_with_subnet_id,
-                        create_body['router']['id'], subnet['id'])
+                        router['id'], subnet['id'])
         self.assertTrue('subnet_id' in interface.keys())
         self.assertTrue('port_id' in interface.keys())
         # Verify router id is equal to device id in port details
         resp, show_port_body = self.client.show_port(
             interface['port_id'])
         self.assertEqual(show_port_body['port']['device_id'],
-                         create_body['router']['id'])
+                         router['id'])
 
     @attr(type='smoke')
     def test_add_remove_router_interface_with_port_id(self):
         network = self.create_network()
         self.create_subnet(network)
-        name = rand_name('router-')
-        resp, create_body = self.client.create_router(name)
-        self.addCleanup(self.client.delete_router, create_body['router']['id'])
+        router = self.create_router(rand_name('router-'))
         resp, port_body = self.client.create_port(network['id'])
         # add router interface to port created above
         resp, interface = self.client.add_router_interface_with_port_id(
-            create_body['router']['id'], port_body['port']['id'])
+            router['id'], port_body['port']['id'])
         self.assertEqual('200', resp['status'])
         self.addCleanup(self._remove_router_interface_with_port_id,
-                        create_body['router']['id'], port_body['port']['id'])
+                        router['id'], port_body['port']['id'])
         self.assertTrue('subnet_id' in interface.keys())
         self.assertTrue('port_id' in interface.keys())
         # Verify router id is equal to device id in port details
         resp, show_port_body = self.client.show_port(
             interface['port_id'])
         self.assertEqual(show_port_body['port']['device_id'],
-                         create_body['router']['id'])
+                         router['id'])
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 60ca88a..914dcff 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from tempest.api.network import base
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
 from tempest import exceptions
 from tempest.test import attr
 
@@ -66,9 +66,9 @@
         self.assertIsNotNone(found, msg)
 
     @attr(type='smoke')
-    def test_create_show_delete_security_group_and_rule(self):
+    def test_create_show_delete_security_group(self):
         # Create a security group
-        name = rand_name('secgroup-')
+        name = data_utils.rand_name('secgroup-')
         resp, group_create_body = self.client.create_security_group(name)
         self.assertEqual('201', resp['status'])
         self.addCleanup(self._delete_security_group,
@@ -88,14 +88,29 @@
         for secgroup in list_body['security_groups']:
             secgroup_list.append(secgroup['id'])
         self.assertIn(group_create_body['security_group']['id'], secgroup_list)
-        # No Update in security group
-        # Create rule
-        resp, rule_create_body = self.client.create_security_group_rule(
-            group_create_body['security_group']['id']
-        )
+
+    @attr(type='smoke')
+    def test_create_show_delete_security_group_rule(self):
+        # Create a security group
+        name = data_utils.rand_name('secgroup-')
+        resp, group_create_body = self.client.create_security_group(name)
         self.assertEqual('201', resp['status'])
-        self.addCleanup(self._delete_security_group_rule,
-                        rule_create_body['security_group_rule']['id'])
+        self.addCleanup(self._delete_security_group,
+                        group_create_body['security_group']['id'])
+        self.assertEqual(group_create_body['security_group']['name'], name)
+
+        # Create rules for each protocol
+        protocols = ['tcp', 'udp', 'icmp']
+        for protocol in protocols:
+            resp, rule_create_body = self.client.create_security_group_rule(
+                group_create_body['security_group']['id'],
+                protocol=protocol
+            )
+            self.assertEqual('201', resp['status'])
+            self.addCleanup(self._delete_security_group_rule,
+                            rule_create_body['security_group_rule']['id']
+                            )
+
         # Show details of the created security rule
         resp, show_rule_body = self.client.show_security_group_rule(
             rule_create_body['security_group_rule']['id']
@@ -111,13 +126,13 @@
 
     @attr(type=['negative', 'smoke'])
     def test_show_non_existent_security_group(self):
-        non_exist_id = rand_name('secgroup-')
+        non_exist_id = data_utils.rand_name('secgroup-')
         self.assertRaises(exceptions.NotFound, self.client.show_security_group,
                           non_exist_id)
 
     @attr(type=['negative', 'smoke'])
     def test_show_non_existent_security_group_rule(self):
-        non_exist_id = rand_name('rule-')
+        non_exist_id = data_utils.rand_name('rule-')
         self.assertRaises(exceptions.NotFound,
                           self.client.show_security_group_rule,
                           non_exist_id)
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 32eecfb..2aaa71d 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -1,6 +1,7 @@
 # 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
@@ -16,6 +17,7 @@
 #    under the License.
 
 from tempest.api.volume import base
+from tempest.common.utils.data_utils import rand_int_id
 from tempest.common.utils.data_utils import rand_name
 from tempest.openstack.common import log as logging
 from tempest.test import attr
@@ -103,6 +105,66 @@
         self.assertEqual(200, resp.status)
         self.assertVolumesIn(fetched_list, self.volume_list)
 
+    @attr(type='gate')
+    def test_volume_list_by_name(self):
+        volume = self.volume_list[rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name']}
+        resp, fetched_vol = self.client.list_volumes(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(1, len(fetched_vol), str(fetched_vol))
+        self.assertEqual(fetched_vol[0]['display_name'],
+                         volume['display_name'])
+
+    @attr(type='gate')
+    def test_volume_list_details_by_name(self):
+        volume = self.volume_list[rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name']}
+        resp, fetched_vol = self.client.list_volumes_with_detail(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(1, len(fetched_vol), str(fetched_vol))
+        self.assertEqual(fetched_vol[0]['display_name'],
+                         volume['display_name'])
+
+    @attr(type='gate')
+    def test_volumes_list_by_status(self):
+        params = {'status': 'available'}
+        resp, fetched_list = self.client.list_volumes(params)
+        self.assertEqual(200, resp.status)
+        for volume in fetched_list:
+            self.assertEqual('available', volume['status'])
+        self.assertVolumesIn(fetched_list, self.volume_list)
+
+    @attr(type='gate')
+    def test_volumes_list_details_by_status(self):
+        params = {'status': 'available'}
+        resp, fetched_list = self.client.list_volumes_with_detail(params)
+        self.assertEqual(200, resp.status)
+        for volume in fetched_list:
+            self.assertEqual('available', volume['status'])
+        self.assertVolumesIn(fetched_list, self.volume_list)
+
+    @attr(type='gate')
+    def test_volumes_list_by_availability_zone(self):
+        volume = self.volume_list[rand_int_id(0, 2)]
+        zone = volume['availability_zone']
+        params = {'availability_zone': zone}
+        resp, fetched_list = self.client.list_volumes(params)
+        self.assertEqual(200, resp.status)
+        for volume in fetched_list:
+            self.assertEqual(zone, volume['availability_zone'])
+        self.assertVolumesIn(fetched_list, self.volume_list)
+
+    @attr(type='gate')
+    def test_volumes_list_details_by_availability_zone(self):
+        volume = self.volume_list[rand_int_id(0, 2)]
+        zone = volume['availability_zone']
+        params = {'availability_zone': zone}
+        resp, fetched_list = self.client.list_volumes_with_detail(params)
+        self.assertEqual(200, resp.status)
+        for volume in fetched_list:
+            self.assertEqual(zone, volume['availability_zone'])
+        self.assertVolumesIn(fetched_list, self.volume_list)
+
 
 class VolumeListTestXML(VolumesListTest):
     _interface = 'xml'
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index a48cea2..3e2b6ad 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -38,19 +38,19 @@
         cls.client.wait_for_volume_status(cls.volume['id'], 'available')
         cls.mountpoint = "/dev/vdc"
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_volume_get_nonexistant_volume_id(self):
         # Should not be able to get a non-existant volume
         self.assertRaises(exceptions.NotFound, self.client.get_volume,
                           str(uuid.uuid4()))
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_volume_delete_nonexistant_volume_id(self):
         # Should not be able to delete a non-existant Volume
         self.assertRaises(exceptions.NotFound, self.client.delete_volume,
                           str(uuid.uuid4()))
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_invalid_size(self):
         # Should not be able to create volume with invalid size
         # in request
@@ -59,7 +59,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='#$%', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_out_passing_size(self):
         # Should not be able to create volume without passing size
         # in request
@@ -68,7 +68,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_size_zero(self):
         # Should not be able to create volume with size zero
         v_name = rand_name('Volume-')
@@ -76,24 +76,56 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='0', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
+    def test_create_volume_with_size_negative(self):
+        # Should not be able to create volume with size negative
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.BadRequest, self.client.create_volume,
+                          size='-1', display_name=v_name, metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_nonexistant_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id=str(uuid.uuid4()), display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_invalid_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id='#$%%&^&^', display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_empty_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id='', display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
     def test_get_invalid_volume_id(self):
         # Should not be able to get volume with invalid id
         self.assertRaises(exceptions.NotFound, self.client.get_volume,
                           '#$%%&^&^')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_get_volume_without_passing_volume_id(self):
         # Should not be able to get volume when empty ID is passed
         self.assertRaises(exceptions.NotFound, self.client.get_volume, '')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_invalid_volume_id(self):
         # Should not be able to delete volume when invalid ID is passed
         self.assertRaises(exceptions.NotFound, self.client.delete_volume,
                           '!@#$%^&*()')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_volume_without_passing_volume_id(self):
         # Should not be able to delete volume when empty ID is passed
         self.assertRaises(exceptions.NotFound, self.client.delete_volume, '')
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/test_cinder.py
index 3ff997a..25157a4 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/test_cinder.py
@@ -84,6 +84,24 @@
         roles = self.parser.listing(self.cinder('list-extensions'))
         self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
 
+    def test_cinder_credentials(self):
+        self.cinder('credentials')
+
+    def test_cinder_availability_zone_list(self):
+        self.cinder('availability-zone-list')
+
+    def test_cinder_endpoints(self):
+        self.cinder('endpoints')
+
+    def test_cinder_service_list(self):
+        self.cinder('service-list')
+
+    def test_cinder_transfer_list(self):
+        self.cinder('transfer-list')
+
+    def test_cinder_bash_completion(self):
+        self.cinder('bash-completion')
+
     def test_admin_help(self):
         help_text = self.cinder('help')
         lines = help_text.split('\n')
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index ae3a1a7..3c266be 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -67,6 +67,12 @@
     def test_neutron_floatingip_list(self):
         self.neutron('floatingip-list')
 
+    def test_neutron_meter_label_list(self):
+        self.neutron('meter-label-list')
+
+    def test_neutron_meter_label_rule_list(self):
+        self.neutron('meter-label-rule-list')
+
     def test_neutron_net_external_list(self):
         self.neutron('net-external-list')
 
diff --git a/tempest/cli/simple_read_only/test_compute.py b/tempest/cli/simple_read_only/test_nova.py
similarity index 97%
rename from tempest/cli/simple_read_only/test_compute.py
rename to tempest/cli/simple_read_only/test_nova.py
index 9b358e6..94415f0 100644
--- a/tempest/cli/simple_read_only/test_compute.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -167,6 +167,10 @@
     def test_admin_net_list(self):
         self.nova('net-list')
 
+    def test_agent_list(self):
+        self.nova('agent-list')
+        self.nova('agent-list', flags='--debug')
+
     # Optional arguments:
 
     def test_admin_version(self):
diff --git a/tempest/cli/simple_read_only/test_compute_manage.py b/tempest/cli/simple_read_only/test_nova_manage.py
similarity index 92%
rename from tempest/cli/simple_read_only/test_compute_manage.py
rename to tempest/cli/simple_read_only/test_nova_manage.py
index 523c65f..9a33556 100644
--- a/tempest/cli/simple_read_only/test_compute_manage.py
+++ b/tempest/cli/simple_read_only/test_nova_manage.py
@@ -81,3 +81,11 @@
 
     def test_db_version(self):
         self.assertNotEqual("", self.nova_manage('db version'))
+
+    def test_cell_list(self):
+        # make sure command doesn't error out
+        self.nova_manage('cell list')
+
+    def test_host_list(self):
+        # make sure command doesn't error out
+        self.nova_manage('host list')
diff --git a/tempest/common/tempest_fixtures.py b/tempest/common/tempest_fixtures.py
index 081b271..ebc9ad3 100644
--- a/tempest/common/tempest_fixtures.py
+++ b/tempest/common/tempest_fixtures.py
@@ -15,16 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import fixtures
-
 from tempest.openstack.common import lockutils
 
 
-class LockFixture(fixtures.Fixture):
+class LockFixture(lockutils.LockFixture):
     def __init__(self, name):
-        self.mgr = lockutils.lock(name, 'tempest-', True)
-
-    def setUp(self):
-        super(LockFixture, self).setUp()
-        self.addCleanup(self.mgr.__exit__, None, None, None)
-        self.mgr.__enter__()
+        super(LockFixture, self).__init__(name, 'tempest-')
diff --git a/tempest/config.py b/tempest/config.py
index af78381..db923e9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -27,6 +27,12 @@
 from tempest.openstack.common import log as logging
 
 
+def register_opt_group(conf, opt_group, options):
+    conf.register_group(opt_group)
+    for opt in options:
+        conf.register_opt(opt, group=opt_group.name)
+
+
 identity_group = cfg.OptGroup(name='identity',
                               title="Keystone Configuration Options")
 
@@ -87,13 +93,6 @@
                secret=True),
 ]
 
-
-def register_identity_opts(conf):
-    conf.register_group(identity_group)
-    for opt in IdentityGroup:
-        conf.register_opt(opt, group='identity')
-
-
 compute_group = cfg.OptGroup(name='compute',
                              title='Compute Service Options')
 
@@ -225,12 +224,6 @@
                     "an instance")
 ]
 
-
-def register_compute_opts(conf):
-    conf.register_group(compute_group)
-    for opt in ComputeGroup:
-        conf.register_opt(opt, group='compute')
-
 compute_admin_group = cfg.OptGroup(name='compute-admin',
                                    title="Compute Admin Options")
 
@@ -248,12 +241,6 @@
                secret=True),
 ]
 
-
-def register_compute_admin_opts(conf):
-    conf.register_group(compute_admin_group)
-    for opt in ComputeAdminGroup:
-        conf.register_opt(opt, group='compute-admin')
-
 image_group = cfg.OptGroup(name='image',
                            title="Image Service Options")
 
@@ -277,12 +264,6 @@
 ]
 
 
-def register_image_opts(conf):
-    conf.register_group(image_group)
-    for opt in ImageGroup:
-        conf.register_opt(opt, group='image')
-
-
 network_group = cfg.OptGroup(name='network',
                              title='Network Service Options')
 
@@ -316,12 +297,6 @@
                     "connectivity"),
 ]
 
-
-def register_network_opts(conf):
-    conf.register_group(network_group)
-    for opt in NetworkGroup:
-        conf.register_opt(opt, group='network')
-
 volume_group = cfg.OptGroup(name='volume',
                             title='Block Storage Options')
 
@@ -363,12 +338,6 @@
 ]
 
 
-def register_volume_opts(conf):
-    conf.register_group(volume_group)
-    for opt in VolumeGroup:
-        conf.register_opt(opt, group='volume')
-
-
 object_storage_group = cfg.OptGroup(name='object-storage',
                                     title='Object Storage Service Options')
 
@@ -404,12 +373,6 @@
 ]
 
 
-def register_object_storage_opts(conf):
-    conf.register_group(object_storage_group)
-    for opt in ObjectStoreGroup:
-        conf.register_opt(opt, group='object-storage')
-
-
 orchestration_group = cfg.OptGroup(name='orchestration',
                                    title='Orchestration Service Options')
 
@@ -447,17 +410,11 @@
                default=None,
                help="Name of existing keypair to launch servers with."),
     cfg.IntOpt('max_template_size',
-               default=10240,
+               default=32768,
                help="Value must match heat configuration of the same name."),
 ]
 
 
-def register_orchestration_opts(conf):
-    conf.register_group(orchestration_group)
-    for opt in OrchestrationGroup:
-        conf.register_opt(opt, group='orchestration')
-
-
 dashboard_group = cfg.OptGroup(name="dashboard",
                                title="Dashboard options")
 
@@ -471,12 +428,6 @@
 ]
 
 
-def register_dashboard_opts(conf):
-    conf.register_group(dashboard_group)
-    for opt in DashboardGroup:
-        conf.register_opt(opt, group='dashboard')
-
-
 boto_group = cfg.OptGroup(name='boto',
                           title='EC2/S3 options')
 BotoGroup = [
@@ -523,12 +474,6 @@
                help="Status Change Test Interval"),
 ]
 
-
-def register_boto_opts(conf):
-    conf.register_group(boto_group)
-    for opt in BotoGroup:
-        conf.register_opt(opt, group='boto')
-
 stress_group = cfg.OptGroup(name='stress', title='Stress Test Options')
 
 StressGroup = [
@@ -563,12 +508,6 @@
 ]
 
 
-def register_stress_opts(conf):
-    conf.register_group(stress_group)
-    for opt in StressGroup:
-        conf.register_opt(opt, group='stress')
-
-
 scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options')
 
 ScenarioGroup = [
@@ -596,12 +535,6 @@
 ]
 
 
-def register_scenario_opts(conf):
-    conf.register_group(scenario_group)
-    for opt in ScenarioGroup:
-        conf.register_opt(opt, group='scenario')
-
-
 service_available_group = cfg.OptGroup(name="service_available",
                                        title="Available OpenStack Services")
 
@@ -629,12 +562,6 @@
                 help="Whether or not Horizon is expected to be available"),
 ]
 
-
-def register_service_available_opts(conf):
-    conf.register_group(service_available_group)
-    for opt in ServiceAvailableGroup:
-        conf.register_opt(opt, group='service_available')
-
 debug_group = cfg.OptGroup(name="debug",
                            title="Debug System")
 
@@ -645,12 +572,6 @@
 ]
 
 
-def register_debug_opts(conf):
-    conf.register_group(debug_group)
-    for opt in DebugGroup:
-        conf.register_opt(opt, group='debug')
-
-
 @singleton
 class TempestConfig:
     """Provides OpenStack configuration information."""
@@ -689,20 +610,21 @@
         LOG = logging.getLogger('tempest')
         LOG.info("Using tempest config file %s" % path)
 
-        register_compute_opts(cfg.CONF)
-        register_identity_opts(cfg.CONF)
-        register_image_opts(cfg.CONF)
-        register_network_opts(cfg.CONF)
-        register_volume_opts(cfg.CONF)
-        register_object_storage_opts(cfg.CONF)
-        register_orchestration_opts(cfg.CONF)
-        register_dashboard_opts(cfg.CONF)
-        register_boto_opts(cfg.CONF)
-        register_compute_admin_opts(cfg.CONF)
-        register_stress_opts(cfg.CONF)
-        register_scenario_opts(cfg.CONF)
-        register_service_available_opts(cfg.CONF)
-        register_debug_opts(cfg.CONF)
+        register_opt_group(cfg.CONF, compute_group, ComputeGroup)
+        register_opt_group(cfg.CONF, identity_group, IdentityGroup)
+        register_opt_group(cfg.CONF, image_group, ImageGroup)
+        register_opt_group(cfg.CONF, network_group, NetworkGroup)
+        register_opt_group(cfg.CONF, volume_group, VolumeGroup)
+        register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
+        register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
+        register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
+        register_opt_group(cfg.CONF, boto_group, BotoGroup)
+        register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
+        register_opt_group(cfg.CONF, stress_group, StressGroup)
+        register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
+        register_opt_group(cfg.CONF, service_available_group,
+                           ServiceAvailableGroup)
+        register_opt_group(cfg.CONF, debug_group, DebugGroup)
         self.compute = cfg.CONF.compute
         self.identity = cfg.CONF.identity
         self.images = cfg.CONF.image
diff --git a/tempest/openstack/common/lockutils.py b/tempest/openstack/common/lockutils.py
index 0abd1a7..a55fd94 100644
--- a/tempest/openstack/common/lockutils.py
+++ b/tempest/openstack/common/lockutils.py
@@ -24,6 +24,7 @@
 import time
 import weakref
 
+import fixtures
 from oslo.config import cfg
 
 from tempest.openstack.common import fileutils
@@ -275,3 +276,36 @@
     """
 
     return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
+
+
+class LockFixture(fixtures.Fixture):
+    """External locking fixture.
+
+    This fixture is basically an alternative to the synchronized decorator with
+    the external flag so that tearDowns and addCleanups will be included in
+    the lock context for locking between tests. The fixture is recommended to
+    be the first line in a test method, like so::
+
+        def test_method(self):
+            self.useFixture(LockFixture)
+                ...
+
+    or the first line in setUp if all the test methods in the class are
+    required to be serialized. Something like::
+
+        class TestCase(testtools.testcase):
+            def setUp(self):
+                self.useFixture(LockFixture)
+                super(TestCase, self).setUp()
+                    ...
+
+    This is because addCleanups are put on a LIFO queue that gets run after the
+    test method exits. (either by completing or raising an exception)
+    """
+    def __init__(self, name, lock_file_prefix=None):
+        self.mgr = lock(name, lock_file_prefix, True)
+
+    def setUp(self):
+        super(LockFixture, self).setUp()
+        self.addCleanup(self.mgr.__exit__, None, None, None)
+        self.mgr.__enter__()
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index c4b98d5..8ccc899 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -280,16 +280,23 @@
         cls.os_resources.remove(thing)
         del cls.resource_keys[key]
 
-    def status_timeout(self, things, thing_id, expected_status):
+    def status_timeout(self, things, thing_id, expected_status,
+                       error_status='ERROR',
+                       not_found_exception=nova_exceptions.NotFound):
         """
         Given a thing and an expected status, do a loop, sleeping
         for a configurable amount of time, checking for the
         expected status to show. At any time, if the returned
         status of the thing is ERROR, fail out.
         """
-        self._status_timeout(things, thing_id, expected_status=expected_status)
+        self._status_timeout(things, thing_id,
+                             expected_status=expected_status,
+                             error_status=error_status,
+                             not_found_exception=not_found_exception)
 
-    def delete_timeout(self, things, thing_id):
+    def delete_timeout(self, things, thing_id,
+                       error_status='ERROR',
+                       not_found_exception=nova_exceptions.NotFound):
         """
         Given a thing, do a loop, sleeping
         for a configurable amount of time, checking for the
@@ -298,13 +305,17 @@
         """
         self._status_timeout(things,
                              thing_id,
-                             allow_notfound=True)
+                             allow_notfound=True,
+                             error_status=error_status,
+                             not_found_exception=not_found_exception)
 
     def _status_timeout(self,
                         things,
                         thing_id,
                         expected_status=None,
-                        allow_notfound=False):
+                        allow_notfound=False,
+                        error_status='ERROR',
+                        not_found_exception=nova_exceptions.NotFound):
 
         log_status = expected_status if expected_status else ''
         if allow_notfound:
@@ -316,16 +327,16 @@
             # for the singular resource to retrieve.
             try:
                 thing = things.get(thing_id)
-            except nova_exceptions.NotFound:
+            except not_found_exception:
                 if allow_notfound:
                     return True
                 else:
                     raise
 
             new_status = thing.status
-            if new_status == 'ERROR':
+            if new_status == error_status:
                 message = "%s failed to get to expected status. \
-                          In ERROR state." % (thing)
+                          In %s state." % (thing, new_status)
                 raise exceptions.BuildErrorException(message)
             elif new_status == expected_status and expected_status is not None:
                 return True  # All good.
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 33b7adc..22c543b 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -24,7 +24,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class TestLargeOpsScenario(manager.OfficialClientTest):
+class TestLargeOpsScenario(manager.NetworkScenarioTest):
 
     """
     Test large operations.
@@ -82,19 +82,19 @@
                                         properties=properties)
 
     def nova_boot(self):
-        def delete(servers):
-            [x.delete() for x in servers]
-
         name = rand_name('scenario-server-')
         client = self.compute_client
         flavor_id = self.config.compute.flavor_ref
+        secgroup = self._create_security_group()
         self.servers = client.servers.create(
             name=name, image=self.image,
             flavor=flavor_id,
-            min_count=self.config.scenario.large_ops_number)
+            min_count=self.config.scenario.large_ops_number,
+            security_groups=[secgroup.name])
         # needed because of bug 1199788
         self.servers = [x for x in client.servers.list() if name in x.name]
-        self.addCleanup(delete, self.servers)
+        for server in self.servers:
+            self.set_resource(server.name, server)
         self._wait_for_server_status('ACTIVE')
 
     @services('compute', 'image')
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 990c986..eda0ede 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -366,6 +366,11 @@
         """Unrescue the provided server."""
         return self.action(server_id, 'unrescue', None)
 
+    def get_server_diagnostics(self, server_id):
+        """Get the usage data for a server."""
+        resp, body = self.get("servers/%s/diagnostics" % str(server_id))
+        return resp, json.loads(body)
+
     def list_instance_actions(self, server_id):
         """List the provided server action."""
         resp, body = self.get("servers/%s/os-instance-actions" %
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index c58c3ee..cb21c61 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -575,6 +575,13 @@
                                  (server_id, volume_id), headers)
         return resp, body
 
+    def get_server_diagnostics(self, server_id):
+        """Get the usage data for a server."""
+        resp, body = self.get("servers/%s/diagnostics" % server_id,
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
     def list_instance_actions(self, server_id):
         """List the provided server action."""
         resp, body = self.get("servers/%s/os-instance-actions" % server_id,
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index 18132ed..94045b8 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -139,7 +139,7 @@
         body = json.loads(body)
         return resp, body['tenant']
 
-    def create_user(self, name, password, tenant_id, email):
+    def create_user(self, name, password, tenant_id, email, **kwargs):
         """Create a user."""
         post_body = {
             'name': name,
@@ -147,6 +147,8 @@
             'tenantId': tenant_id,
             'email': email
         }
+        if kwargs.get('enabled') is not None:
+            post_body['enabled'] = kwargs.get('enabled')
         post_body = json.dumps({'user': post_body})
         resp, body = self.post('users', post_body, self.headers)
         body = json.loads(body)
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index 9d44826..9c0a72c 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -159,7 +159,7 @@
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
-    def create_user(self, name, password, tenant_id, email):
+    def create_user(self, name, password, tenant_id, email, **kwargs):
         """Create a user."""
         create_user = Element("user",
                               xmlns=XMLNS,
@@ -167,6 +167,9 @@
                               password=password,
                               tenantId=tenant_id,
                               email=email)
+        if 'enabled' in kwargs:
+            create_user.add_attr('enabled', str(kwargs['enabled']).lower())
+
         resp, body = self.post('users', str(Document(create_user)),
                                self.headers)
         body = self._parse_body(etree.fromstring(body))
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 55404ce..b5cab68 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -196,7 +196,7 @@
 
         if not logfiles:
             continue
-        if _has_error_in_logs(logfiles, computes):
+        if _has_error_in_logs(logfiles, computes, stop_on_error):
             had_errors = True
             break
 
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index 1a5af00..dbe3420 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -20,8 +20,6 @@
 import tempfile
 import testtools
 
-from tempest.test import attr
-
 DEVNULL = open(os.devnull, 'wb')
 
 
@@ -46,7 +44,6 @@
         shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file)
         shutil.copy('tempest/tests/files/__init__.py', self.init_file)
 
-    @attr(type='smoke')
     def test_pretty_tox(self):
         # Copy wrapper script and requirements:
         pretty_tox = os.path.join(self.directory, 'pretty_tox.sh')
@@ -62,7 +59,6 @@
                                     shell=True, stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 0)
 
-    @attr(type='smoke')
     def test_pretty_tox_fails(self):
         # Copy wrapper script and requirements:
         pretty_tox = os.path.join(self.directory, 'pretty_tox.sh')
@@ -78,7 +74,6 @@
                                     stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 1)
 
-    @attr(type='smoke')
     def test_pretty_tox_serial(self):
         # Copy wrapper script and requirements:
         pretty_tox = os.path.join(self.directory, 'pretty_tox_serial.sh')
@@ -90,7 +85,6 @@
                                     shell=True, stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 0)
 
-    @attr(type='smoke')
     def test_pretty_tox_serial_fails(self):
         # Copy wrapper script and requirements:
         pretty_tox = os.path.join(self.directory, 'pretty_tox_serial.sh')
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 0cc3677..2ad4f70 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -16,7 +16,140 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import argparse
+import gzip
+import os
+import re
+import StringIO
 import sys
+import urllib2
+import yaml
+
+
+def process_files(file_specs, url_specs, whitelists):
+    regexp = re.compile(r"^.*(ERROR|CRITICAL).*\[.*\-.*\]")
+    had_errors = False
+    for (name, filename) in file_specs:
+        whitelist = whitelists.get(name, [])
+        with open(filename) as content:
+            if scan_content(name, content, regexp, whitelist):
+                had_errors = True
+    for (name, url) in url_specs:
+        whitelist = whitelists.get(name, [])
+        req = urllib2.Request(url)
+        req.add_header('Accept-Encoding', 'gzip')
+        page = urllib2.urlopen(req)
+        buf = StringIO.StringIO(page.read())
+        f = gzip.GzipFile(fileobj=buf)
+        if scan_content(name, f.read().splitlines(), regexp, whitelist):
+            had_errors = True
+    return had_errors
+
+
+def scan_content(name, content, regexp, whitelist):
+    had_errors = False
+    for line in content:
+        if not line.startswith("Stderr:") and regexp.match(line):
+            whitelisted = False
+            for w in whitelist:
+                pat = ".*%s.*%s.*" % (w['module'].replace('.', '\\.'),
+                                      w['message'])
+                if re.match(pat, line):
+                    whitelisted = True
+                    break
+            if not whitelisted:
+                if not had_errors:
+                    print("Log File: %s" % name)
+                had_errors = True
+                print(line)
+    return had_errors
+
+
+def collect_url_logs(url):
+    page = urllib2.urlopen(url)
+    content = page.read()
+    logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
+    return logs
+
+
+def main(opts):
+    if opts.directory and opts.url or not (opts.directory or opts.url):
+        print("Must provide exactly one of -d or -u")
+        exit(1)
+    print("Checking logs...")
+    WHITELIST_FILE = os.path.join(
+        os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
+        "etc", "whitelist.yaml")
+
+    file_matcher = re.compile(r".*screen-([\w-]+)\.log")
+    files = []
+    if opts.directory:
+        d = opts.directory
+        for f in os.listdir(d):
+            files.append(os.path.join(d, f))
+    files_to_process = []
+    for f in files:
+        m = file_matcher.match(f)
+        if m:
+            files_to_process.append((m.group(1), f))
+
+    url_matcher = re.compile(r".*screen-([\w-]+)\.txt\.gz")
+    urls = []
+    if opts.url:
+        for logfile in collect_url_logs(opts.url):
+            urls.append("%s/%s" % (opts.url, logfile))
+    urls_to_process = []
+    for u in urls:
+        m = url_matcher.match(u)
+        if m:
+            urls_to_process.append((m.group(1), u))
+
+    whitelists = {}
+    with open(WHITELIST_FILE) as stream:
+        loaded = yaml.safe_load(stream)
+        if loaded:
+            for (name, l) in loaded.iteritems():
+                for w in l:
+                    assert 'module' in w, 'no module in %s' % name
+                    assert 'message' in w, 'no message in %s' % name
+            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
+    else:
+        print("ok")
+        return 0
+
+usage = """
+Find non-white-listed log errors in log files from a devstack-gate run.
+Log files will be searched for ERROR or CRITICAL messages. If any
+error messages do not match any of the whitelist entries contained in
+etc/whitelist.yaml, those messages will be printed to the console and
+failure will be returned. A file directory containing logs or a url to the
+log files of an OpenStack gate job can be provided.
+
+The whitelist yaml looks like:
+
+log-name:
+    - module: "a.b.c"
+      message: "regexp"
+    - module: "a.b.c"
+      message: "regexp"
+
+repeated for each log file with a whitelist.
+"""
+
+parser = argparse.ArgumentParser(description=usage)
+parser.add_argument('-d', '--directory',
+                    help="Directory containing log files")
+parser.add_argument('-u', '--url',
+                    help="url containing logs from an OpenStack gate job")
 
 if __name__ == "__main__":
-    sys.exit(0)
+    try:
+        sys.exit(main(parser.parse_args()))
+    except Exception as e:
+        print("Failure in script: %s" % e)
+        # Don't fail if there is a problem with the script.
+        sys.exit(0)
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 0ce1500..52a5a66 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -65,7 +65,9 @@
 
 def hunt_for_stacktrace(url):
     """Return TRACE or ERROR lines out of logs."""
-    page = urllib2.urlopen(url)
+    req = urllib2.Request(url)
+    req.add_header('Accept-Encoding', 'gzip')
+    page = urllib2.urlopen(req)
     buf = StringIO.StringIO(page.read())
     f = gzip.GzipFile(fileobj=buf)
     content = f.read()
diff --git a/tools/tempest_auto_config.py b/tools/tempest_auto_config.py
new file mode 100644
index 0000000..aef6a1f
--- /dev/null
+++ b/tools/tempest_auto_config.py
@@ -0,0 +1,234 @@
+# 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.
+
+# Config
+import ConfigParser
+import os
+
+# Default client libs
+import keystoneclient.v2_0.client as keystone_client
+
+# Import Openstack exceptions
+import keystoneclient.exceptions as keystone_exception
+
+
+DEFAULT_CONFIG_DIR = "%s/etc" % os.path.abspath(os.path.pardir)
+DEFAULT_CONFIG_FILE = "tempest.conf"
+DEFAULT_CONFIG_SAMPLE = "tempest.conf.sample"
+
+# Environment variables override defaults
+TEMPEST_CONFIG_DIR = os.environ.get('TEMPEST_CONFIG_DIR') or DEFAULT_CONFIG_DIR
+TEMPEST_CONFIG = os.environ.get('TEMPEST_CONFIG') or "%s/%s" % \
+    (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_FILE)
+TEMPEST_CONFIG_SAMPLE = os.environ.get('TEMPEST_CONFIG_SAMPLE') or "%s/%s" % \
+    (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_SAMPLE)
+
+# Admin credentials
+OS_USERNAME = os.environ.get('OS_USERNAME')
+OS_PASSWORD = os.environ.get('OS_PASSWORD')
+OS_TENANT_NAME = os.environ.get('OS_TENANT_NAME')
+OS_AUTH_URL = os.environ.get('OS_AUTH_URL')
+
+# Image references
+IMAGE_ID = os.environ.get('IMAGE_ID')
+IMAGE_ID_ALT = os.environ.get('IMAGE_ID_ALT')
+
+
+class ClientManager(object):
+    """
+    Manager that provides access to the official python clients for
+    calling various OpenStack APIs.
+    """
+    def __init__(self):
+        self.identity_client = None
+        self.image_client = None
+        self.network_client = None
+        self.compute_client = None
+        self.volume_client = None
+
+    def get_identity_client(self, **kwargs):
+        """
+        Returns the openstack identity python client
+        :param username: a string representing the username
+        :param password: a string representing the user's password
+        :param tenant_name: a string representing the tenant name of the user
+        :param auth_url: a string representing the auth url of the identity
+        :param insecure: True if we wish to disable ssl certificate validation,
+        False otherwise
+        :returns an instance of openstack identity python client
+        """
+        if not self.identity_client:
+            self.identity_client = keystone_client.Client(**kwargs)
+
+        return self.identity_client
+
+
+def getTempestConfigSample():
+    """
+    Gets the tempest configuration file as a ConfigParser object
+    :return: the tempest configuration file
+    """
+    # get the sample config file from the sample
+    config_sample = ConfigParser.ConfigParser()
+    config_sample.readfp(open(TEMPEST_CONFIG_SAMPLE))
+
+    return config_sample
+
+
+def update_config_admin_credentials(config, config_section):
+    """
+    Updates the tempest config with the admin credentials
+    :param config: an object representing the tempest config file
+    :param config_section: the section name where the admin credentials are
+    """
+    # Check if credentials are present
+    if not (OS_AUTH_URL and
+            OS_USERNAME and
+            OS_PASSWORD and
+            OS_TENANT_NAME):
+        raise Exception("Admin environment variables not found.")
+
+    # TODO(tkammer): Add support for uri_v3
+    config_identity_params = {'uri': OS_AUTH_URL,
+                              'admin_username': OS_USERNAME,
+                              'admin_password': OS_PASSWORD,
+                              'admin_tenant_name': OS_TENANT_NAME}
+
+    update_config_section_with_params(config,
+                                      config_section,
+                                      config_identity_params)
+
+
+def update_config_section_with_params(config, section, params):
+    """
+    Updates a given config object with given params
+    :param config: the object representing the config file of tempest
+    :param section: the section we would like to update
+    :param params: the parameters we wish to update for that section
+    """
+    for option, value in params.items():
+        config.set(section, option, value)
+
+
+def get_identity_client_kwargs(config, section_name):
+    """
+    Get the required arguments for the identity python client
+    :param config: the tempest configuration file
+    :param section_name: the section name in the configuration where the
+    arguments can be found
+    :return: a dictionary representing the needed arguments for the identity
+    client
+    """
+    username = config.get(section_name, 'admin_username')
+    password = config.get(section_name, 'admin_password')
+    tenant_name = config.get(section_name, 'admin_tenant_name')
+    auth_url = config.get(section_name, 'uri')
+    dscv = config.get(section_name, 'disable_ssl_certificate_validation')
+    kwargs = {'username': username,
+              'password': password,
+              'tenant_name': tenant_name,
+              'auth_url': auth_url,
+              'insecure': dscv}
+
+    return kwargs
+
+
+def create_user_with_tenant(identity_client, username, password, tenant_name):
+    """
+    Creates a user using a given identity client
+    :param identity_client: openstack identity python client
+    :param username: a string representing the username
+    :param password: a string representing the user's password
+    :param tenant_name: a string representing the tenant name of the user
+    """
+    # Try to create the necessary tenant
+    tenant_id = None
+    try:
+        tenant_description = "Tenant for Tempest %s user" % username
+        tenant = identity_client.tenants.create(tenant_name,
+                                                tenant_description)
+        tenant_id = tenant.id
+    except keystone_exception.Conflict:
+
+        # if already exist, use existing tenant
+        tenant_list = identity_client.tenants.list()
+        for tenant in tenant_list:
+            if tenant.name == tenant_name:
+                tenant_id = tenant.id
+
+    # Try to create the user
+    try:
+        email = "%s@test.com" % username
+        identity_client.users.create(name=username,
+                                     password=password,
+                                     email=email,
+                                     tenant_id=tenant_id)
+    except keystone_exception.Conflict:
+
+        # if already exist, use existing user
+        pass
+
+
+def create_users_and_tenants(identity_client,
+                             config,
+                             identity_section):
+    """
+    Creates the two non admin users and tenants for tempest
+    :param identity_client: openstack identity python client
+    :param config: tempest configuration file
+    :param identity_section: the section name of identity in the config
+    """
+    # Get the necessary params from the config file
+    tenant_name = config.get(identity_section, 'tenant_name')
+    username = config.get(identity_section, 'username')
+    password = config.get(identity_section, 'password')
+
+    alt_tenant_name = config.get(identity_section, 'alt_tenant_name')
+    alt_username = config.get(identity_section, 'alt_username')
+    alt_password = config.get(identity_section, 'alt_password')
+
+    # Create the necessary users for the test runs
+    create_user_with_tenant(identity_client, username, password, tenant_name)
+    create_user_with_tenant(identity_client, alt_username, alt_password,
+                            alt_tenant_name)
+
+
+def main():
+    """
+    Main module to control the script
+    """
+    # TODO(tkammer): add support for existing config file
+    config_sample = getTempestConfigSample()
+    update_config_admin_credentials(config_sample, 'identity')
+
+    client_manager = ClientManager()
+
+    # Set the identity related info for tempest
+    identity_client_kwargs = get_identity_client_kwargs(config_sample,
+                                                        'identity')
+    identity_client = client_manager.get_identity_client(
+        **identity_client_kwargs)
+
+    # Create the necessary users and tenants for tempest run
+    create_users_and_tenants(identity_client,
+                             config_sample,
+                             'identity')
+
+    # TODO(tkammer): add image implementation
+
+if __name__ == "__main__":
+    main()
diff --git a/tox.ini b/tox.ini
index ff09b3f..d93112c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,23 @@
 [tox]
 envlist = pep8
+minversion = 1.6
+skipsdist = True
 
 [testenv]
 setenv = VIRTUAL_ENV={envdir}
          LANG=en_US.UTF-8
          LANGUAGE=en_US:en
          LC_ALL=C
+usedevelop = True
+
+[testenv:py26]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+
+[testenv:py33]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+
+[testenv:py27]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
 sitepackages = True
@@ -15,29 +27,25 @@
 
 [testenv:full]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 # The regex below is used to select which tests to run and exclude the slow tag:
 # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
-  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests)) {posargs}'
+  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:testr-full]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 commands =
-  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests)) {posargs}'
+  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:heat-slow]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
-         OS_TEST_TIMEOUT=1200
+setenv = OS_TEST_TIMEOUT=1200
 # The regex below is used to select heat api/scenario tests tagged as slow.
 commands =
   sh tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
 
 [testenv:large-ops]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 commands =
   python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
 
@@ -53,7 +61,7 @@
          NOSE_OPENSTACK_STDOUT=1
          TEMPEST_PY26_NOSE_COMPAT=1
 commands =
-  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli tempest/tests {posargs}
+  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli {posargs}
 
 [testenv:py26-smoke]
 setenv = VIRTUAL_ENV={envdir}
@@ -69,7 +77,6 @@
 
 [testenv:smoke]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 # This is still serial because neutron doesn't work with parallel. See:
 # https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
 # job would fail if we moved it to parallel.
@@ -78,15 +85,13 @@
 
 [testenv:coverage]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 commands =
    python -m tools/tempest_coverage -c start --combine
-   sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests))'
+   sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli))'
    python -m tools/tempest_coverage -c report --html {posargs}
 
 [testenv:stress]
 sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
 commands =
     python -m tempest/stress/run_stress -a -d 3600 -S