Merge "Set smoke/gate attributes for tests in "identity""
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 7920ab5..3147859 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -117,6 +117,10 @@
 # performed, which requires XenServer pools in case of using XS)
 use_block_migration_for_live_migration = false
 
+# Supports iSCSI block migration - depends on a XAPI supporting
+# relax-xsm-sr-check
+block_migrate_supports_cinder_iscsi = false
+
 # By default, rely on the status of the diskConfig extension to
 # decide if to execute disk config tests. When set to false, tests
 # are forced to skip, regardless of the extension status
@@ -285,3 +289,26 @@
 
 # Status change wait interval
 build_interval = 1
+
+[orchestration]
+# Status change wait interval
+build_interval = 1
+
+# Status change wait timout. This may vary across environments as some some
+# tests spawn full VMs, which could be slow if the test is already in a VM.
+build_timeout = 300
+
+# Whether or not Heat is expected to be available
+heat_available = false
+
+# Instance type for tests. Needs to be big enough for a
+# full OS plus the test workload
+instance_type = m1.tiny
+
+# Name of heat-cfntools enabled image to use when launching test instances
+# If not specified, tests that spawn instances will not run
+#image_ref = ubuntu-vm-heat-cfntools
+
+# Name of existing keypair to launch servers with. The default is not to specify
+# any key, which will generate a keypair for each test class
+#keypair_name = heat_key
diff --git a/tempest/README.rst b/tempest/README.rst
index c41ef96..6718ee0 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -12,11 +12,11 @@
 to make this clear.
 
 tempest/
-   3rdparty/ - 3rd party api tests
    api/ - API tests
    cli/ - CLI tests
    scenario/ - complex scenario tests
    stress/ - stress tests
+   thirdparty/ - 3rd party api tests
    whitebox/ - white box testing
 
 Each of these directories contains different types of tests. What
@@ -24,17 +24,6 @@
 documented in a README.rst file in the directory.
 
 
-3rdparty
-------------
-
-Many openstack components include 3rdparty API support. It is
-completely legitmate for Tempest to include tests of 3rdparty APIs,
-but those should be kept seperate from the normal OpenStack
-validation.
-
-TODO: tempest/tests/boto should become tempest/3rdparty/boto
-
-
 api
 ------------
 
@@ -88,6 +77,17 @@
 moves into here.
 
 
+thirdparty
+------------
+
+Many openstack components include 3rdparty API support. It is
+completely legitmate for Tempest to include tests of 3rdparty APIs,
+but those should be kept seperate from the normal OpenStack
+validation.
+
+TODO: tempest/tests/boto should become tempest/3rdparty/boto
+
+
 whitebox
 ----------
 
diff --git a/tempest/clients.py b/tempest/clients.py
index 9b2c1f5..037a1c4 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -40,6 +40,7 @@
 from tempest.services.compute.json.security_groups_client import \
     SecurityGroupsClientJSON
 from tempest.services.compute.json.servers_client import ServersClientJSON
+from tempest.services.compute.json.services_client import ServicesClientJSON
 from tempest.services.compute.json.volumes_extensions_client import \
     VolumesExtensionsClientJSON
 from tempest.services.compute.xml.aggregates_client import AggregatesClientXML
@@ -59,6 +60,7 @@
 from tempest.services.compute.xml.security_groups_client \
     import SecurityGroupsClientXML
 from tempest.services.compute.xml.servers_client import ServersClientXML
+from tempest.services.compute.xml.services_client import ServicesClientXML
 from tempest.services.compute.xml.volumes_extensions_client import \
     VolumesExtensionsClientXML
 from tempest.services.identity.json.identity_client import IdentityClientJSON
@@ -86,6 +88,8 @@
 from tempest.services.object_storage.object_client import ObjectClient
 from tempest.services.object_storage.object_client import \
     ObjectClientCustomizedHeader
+from tempest.services.orchestration.json.orchestration_client import \
+    OrchestrationClient
 from tempest.services.volume.json.admin.volume_types_client import \
     VolumeTypesClientJSON
 from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
@@ -207,6 +211,11 @@
     "xml": AggregatesClientXML,
 }
 
+SERVICES_CLIENT = {
+    "json": ServicesClientJSON,
+    "xml": ServicesClientXML,
+}
+
 
 class Manager(object):
 
@@ -277,6 +286,7 @@
                 AVAILABILITY_ZONE_CLIENT[interface](*client_args)
             self.service_client = SERVICE_CLIENT[interface](*client_args)
             self.aggregates_client = AGGREGATES_CLIENT[interface](*client_args)
+            self.services_client = SERVICES_CLIENT[interface](*client_args)
         except KeyError:
             msg = "Unsupported interface type `%s'" % interface
             raise exceptions.InvalidConfiguration(msg)
@@ -287,6 +297,7 @@
         self.image_client_v2 = ImageClientV2JSON(*client_args)
         self.container_client = ContainerClient(*client_args)
         self.object_client = ObjectClient(*client_args)
+        self.orchestration_client = OrchestrationClient(*client_args)
         self.ec2api_client = botoclients.APIClientEC2(*client_args)
         self.s3_client = botoclients.ObjectClientS3(*client_args)
         self.custom_object_client = ObjectClientCustomizedHeader(*client_args)
@@ -337,3 +348,17 @@
                       conf.compute_admin.password,
                       conf.compute_admin.tenant_name,
                       interface=interface)
+
+
+class OrchestrationManager(Manager):
+    """
+    Manager object that uses the admin credentials for its
+    so that heat templates can create users
+    """
+    def __init__(self, interface='json'):
+        conf = config.TempestConfig()
+        base = super(OrchestrationManager, self)
+        base.__init__(conf.identity.admin_username,
+                      conf.identity.admin_password,
+                      conf.identity.admin_tenant_name,
+                      interface=interface)
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index 448708e..04cc851 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -47,9 +47,10 @@
         self.channel_timeout = float(channel_timeout)
         self.buf_size = 1024
 
-    def _get_ssh_connection(self):
+    def _get_ssh_connection(self, sleep=1.5, backoff=1.01):
         """Returns an ssh connection to the specified host."""
         _timeout = True
+        bsleep = sleep
         ssh = paramiko.SSHClient()
         ssh.set_missing_host_key_policy(
             paramiko.AutoAddPolicy())
@@ -64,10 +65,10 @@
                             timeout=self.timeout, pkey=self.pkey)
                 _timeout = False
                 break
-            except socket.error:
-                continue
-            except paramiko.AuthenticationException:
-                time.sleep(5)
+            except (socket.error,
+                    paramiko.AuthenticationException):
+                time.sleep(bsleep)
+                bsleep *= backoff
                 continue
         if _timeout:
             raise exceptions.SSHTimeout(host=self.host,
diff --git a/tempest/config.py b/tempest/config.py
index d43c5d7..6d6bc2b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -129,6 +129,10 @@
                 default=False,
                 help="Does the test environment use block devices for live "
                      "migration"),
+    cfg.BoolOpt('block_migrate_supports_cinder_iscsi',
+                default=False,
+                help="Does the test environment block migration support "
+                     "cinder iSCSI volumes"),
     cfg.BoolOpt('change_password_available',
                 default=False,
                 help="Does the test environment support changing the admin "
@@ -351,6 +355,48 @@
     for opt in ObjectStoreConfig:
         conf.register_opt(opt, group='object-storage')
 
+
+orchestration_group = cfg.OptGroup(name='orchestration',
+                                   title='Orchestration Service Options')
+
+OrchestrationGroup = [
+    cfg.StrOpt('catalog_type',
+               default='orchestration',
+               help="Catalog type of the Orchestration service."),
+    cfg.BoolOpt('allow_tenant_isolation',
+                default=False,
+                help="Allows test cases to create/destroy tenants and "
+                     "users. This option enables isolated test cases and "
+                     "better parallel execution, but also requires that "
+                     "OpenStack Identity API admin credentials are known."),
+    cfg.IntOpt('build_interval',
+               default=1,
+               help="Time in seconds between build status checks."),
+    cfg.IntOpt('build_timeout',
+               default=300,
+               help="Timeout in seconds to wait for a stack to build."),
+    cfg.BoolOpt('heat_available',
+                default=False,
+                help="Whether or not Heat is expected to be available"),
+    cfg.StrOpt('instance_type',
+               default='m1.tiny',
+               help="Instance type for tests. Needs to be big enough for a "
+                    "full OS plus the test workload"),
+    cfg.StrOpt('image_ref',
+               default=None,
+               help="Name of heat-cfntools enabled image to use when "
+                    "launching test instances."),
+    cfg.StrOpt('keypair_name',
+               default=None,
+               help="Name of existing keypair to launch servers with."),
+]
+
+
+def register_orchestration_opts(conf):
+    conf.register_group(orchestration_group)
+    for opt in OrchestrationGroup:
+        conf.register_opt(opt, group='orchestration')
+
 boto_group = cfg.OptGroup(name='boto',
                           title='EC2/S3 options')
 BotoConfig = [
@@ -485,6 +531,7 @@
         register_network_opts(cfg.CONF)
         register_volume_opts(cfg.CONF)
         register_object_storage_opts(cfg.CONF)
+        register_orchestration_opts(cfg.CONF)
         register_boto_opts(cfg.CONF)
         register_compute_admin_opts(cfg.CONF)
         register_stress_opts(cfg.CONF)
@@ -495,6 +542,7 @@
         self.network = cfg.CONF.network
         self.volume = cfg.CONF.volume
         self.object_storage = cfg.CONF['object-storage']
+        self.orchestration = cfg.CONF.orchestration
         self.boto = cfg.CONF.boto
         self.compute_admin = cfg.CONF['compute-admin']
         self.stress = cfg.CONF.stress
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 235a2e7..448fbdf 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -90,6 +90,11 @@
     message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
 
 
+class StackBuildErrorException(TempestException):
+    message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
+               "due to '%(stack_status_reason)s'")
+
+
 class BadRequest(RestClientException):
     message = "Bad request"
 
diff --git a/tempest/manager.py b/tempest/manager.py
index 6f23727..047ad41 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -17,15 +17,6 @@
 
 import logging
 
-# Default client libs
-import glanceclient
-import keystoneclient.v2_0.client
-import novaclient.client
-try:
-    import quantumclient.v2_0.client
-except ImportError:
-    pass
-
 import tempest.config
 from tempest import exceptions
 # Tempest REST Fuzz testing client libs
@@ -86,121 +77,6 @@
     pass
 
 
-class DefaultClientManager(Manager):
-
-    """
-    Manager that provides the default clients to access the various
-    OpenStack APIs.
-    """
-
-    NOVACLIENT_VERSION = '2'
-
-    def __init__(self):
-        super(DefaultClientManager, self).__init__()
-        self.compute_client = self._get_compute_client()
-        self.image_client = self._get_image_client()
-        self.identity_client = self._get_identity_client()
-        self.network_client = self._get_network_client()
-        self.client_attr_names = [
-            'compute_client',
-            'image_client',
-            'identity_client',
-            'network_client',
-        ]
-
-    def _get_compute_client(self, username=None, password=None,
-                            tenant_name=None):
-        # Novaclient will not execute operations for anyone but the
-        # identified user, so a new client needs to be created for
-        # each user that operations need to be performed for.
-        if not username:
-            username = self.config.identity.username
-        if not password:
-            password = self.config.identity.password
-        if not tenant_name:
-            tenant_name = self.config.identity.tenant_name
-
-        if None in (username, password, tenant_name):
-            msg = ("Missing required credentials for compute client. "
-                   "username: %(username)s, password: %(password)s, "
-                   "tenant_name: %(tenant_name)s") % locals()
-            raise exceptions.InvalidConfiguration(msg)
-
-        auth_url = self.config.identity.uri
-        dscv = self.config.identity.disable_ssl_certificate_validation
-
-        client_args = (username, password, tenant_name, auth_url)
-
-        # Create our default Nova client to use in testing
-        service_type = self.config.compute.catalog_type
-        return novaclient.client.Client(self.NOVACLIENT_VERSION,
-                                        *client_args,
-                                        service_type=service_type,
-                                        no_cache=True,
-                                        insecure=dscv)
-
-    def _get_image_client(self):
-        keystone = self._get_identity_client()
-        token = keystone.auth_token
-        endpoint = keystone.service_catalog.url_for(service_type='image',
-                                                    endpoint_type='publicURL')
-        dscv = self.config.identity.disable_ssl_certificate_validation
-        return glanceclient.Client('1', endpoint=endpoint, token=token,
-                                   insecure=dscv)
-
-    def _get_identity_client(self, username=None, password=None,
-                             tenant_name=None):
-        # This identity client is not intended to check the security
-        # of the identity service, so use admin credentials by default.
-        if not username:
-            username = self.config.identity.admin_username
-        if not password:
-            password = self.config.identity.admin_password
-        if not tenant_name:
-            tenant_name = self.config.identity.admin_tenant_name
-
-        if None in (username, password, tenant_name):
-            msg = ("Missing required credentials for identity client. "
-                   "username: %(username)s, password: %(password)s, "
-                   "tenant_name: %(tenant_name)s") % locals()
-            raise exceptions.InvalidConfiguration(msg)
-
-        auth_url = self.config.identity.uri
-        dscv = self.config.identity.disable_ssl_certificate_validation
-
-        return keystoneclient.v2_0.client.Client(username=username,
-                                                 password=password,
-                                                 tenant_name=tenant_name,
-                                                 auth_url=auth_url,
-                                                 insecure=dscv)
-
-    def _get_network_client(self):
-        # The intended configuration is for the network client to have
-        # admin privileges and indicate for whom resources are being
-        # created via a 'tenant_id' parameter.  This will often be
-        # preferable to authenticating as a specific user because
-        # working with certain resources (public routers and networks)
-        # often requires admin privileges anyway.
-        username = self.config.identity.admin_username
-        password = self.config.identity.admin_password
-        tenant_name = self.config.identity.admin_tenant_name
-
-        if None in (username, password, tenant_name):
-            msg = ("Missing required credentials for network client. "
-                   "username: %(username)s, password: %(password)s, "
-                   "tenant_name: %(tenant_name)s") % locals()
-            raise exceptions.InvalidConfiguration(msg)
-
-        auth_url = self.config.identity.uri
-        dscv = self.config.identity.disable_ssl_certificate_validation
-
-        return quantumclient.v2_0.client.Client(username=username,
-                                                password=password,
-                                                tenant_name=tenant_name,
-                                                auth_url=auth_url,
-                                                insecure=dscv)
-
-
 class ComputeFuzzClientManager(FuzzClientManager):
 
     """
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
new file mode 100644
index 0000000..c5fa0d3
--- /dev/null
+++ b/tempest/scenario/README.rst
@@ -0,0 +1,45 @@
+Tempest Guide to Scenario tests
+========
+
+
+What are these tests?
+--------
+
+Scenario tests are "through path" tests of OpenStack
+function. Complicated setups where one part might depend on completion
+of a previous part. They ideally involve the integration between
+multiple OpenStack services to exercise the touch points between them.
+
+An example would be: start with a blank environment, upload a glance
+image, deploy a vm from it, ssh to the guest, make changes, capture
+that vm's image back into glance as a snapshot, and launch a second vm
+from that snapshot.
+
+
+Why are these tests in tempest?
+--------
+This is one of tempests core purposes, testing the integration between
+projects.
+
+
+Scope of these tests
+--------
+Scenario tests should always test at least 2 services in
+interaction. They should use the official python client libraries for
+OpenStack, as they provide a more realistic approach in how people
+will interact with the services.
+
+TODO: once we have service tags, tests should be tagged with which
+services they exercise.
+
+
+Example of a good test
+--------
+While we are looking for interaction of 2 or more services, be
+specific in your interactions. A giant "this is my data center" smoke
+test is hard to debug when it goes wrong.
+
+A flow of interactions between glance and nova, like in the
+introduction, is a good example. Especially if it involves a repeated
+interaction when a resource is setup, modified, detached, and then
+reused later again.
diff --git a/tempest/tests/boto/__init__.py b/tempest/scenario/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tempest/scenario/__init__.py
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
new file mode 100644
index 0000000..4f94195
--- /dev/null
+++ b/tempest/scenario/manager.py
@@ -0,0 +1,422 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import logging
+import subprocess
+
+# Default client libs
+import glanceclient
+import keystoneclient.v2_0.client
+import netaddr
+import novaclient.client
+try:
+    # TODO(sdague): is there are reason this is still optional
+    from quantumclient.common import exceptions as exc
+    import quantumclient.v2_0.client
+
+except ImportError:
+    pass
+
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+import tempest.manager
+import tempest.test
+from tempest.tests.network import common as net_common
+
+
+LOG = logging.getLogger(__name__)
+
+
+class OfficialClientManager(tempest.manager.Manager):
+    """
+    Manager that provides access to the official python clients for
+    calling various OpenStack APIs.
+    """
+
+    NOVACLIENT_VERSION = '2'
+
+    def __init__(self):
+        super(OfficialClientManager, self).__init__()
+        self.compute_client = self._get_compute_client()
+        self.image_client = self._get_image_client()
+        self.identity_client = self._get_identity_client()
+        self.network_client = self._get_network_client()
+        self.client_attr_names = [
+            'compute_client',
+            'image_client',
+            'identity_client',
+            'network_client',
+        ]
+
+    def _get_compute_client(self, username=None, password=None,
+                            tenant_name=None):
+        # Novaclient will not execute operations for anyone but the
+        # identified user, so a new client needs to be created for
+        # each user that operations need to be performed for.
+        if not username:
+            username = self.config.identity.username
+        if not password:
+            password = self.config.identity.password
+        if not tenant_name:
+            tenant_name = self.config.identity.tenant_name
+
+        if None in (username, password, tenant_name):
+            msg = ("Missing required credentials for compute client. "
+                   "username: %(username)s, password: %(password)s, "
+                   "tenant_name: %(tenant_name)s") % locals()
+            raise exceptions.InvalidConfiguration(msg)
+
+        auth_url = self.config.identity.uri
+        dscv = self.config.identity.disable_ssl_certificate_validation
+
+        client_args = (username, password, tenant_name, auth_url)
+
+        # Create our default Nova client to use in testing
+        service_type = self.config.compute.catalog_type
+        return novaclient.client.Client(self.NOVACLIENT_VERSION,
+                                        *client_args,
+                                        service_type=service_type,
+                                        no_cache=True,
+                                        insecure=dscv)
+
+    def _get_image_client(self):
+        keystone = self._get_identity_client()
+        token = keystone.auth_token
+        endpoint = keystone.service_catalog.url_for(service_type='image',
+                                                    endpoint_type='publicURL')
+        dscv = self.config.identity.disable_ssl_certificate_validation
+        return glanceclient.Client('1', endpoint=endpoint, token=token,
+                                   insecure=dscv)
+
+    def _get_identity_client(self, username=None, password=None,
+                             tenant_name=None):
+        # This identity client is not intended to check the security
+        # of the identity service, so use admin credentials by default.
+        if not username:
+            username = self.config.identity.admin_username
+        if not password:
+            password = self.config.identity.admin_password
+        if not tenant_name:
+            tenant_name = self.config.identity.admin_tenant_name
+
+        if None in (username, password, tenant_name):
+            msg = ("Missing required credentials for identity client. "
+                   "username: %(username)s, password: %(password)s, "
+                   "tenant_name: %(tenant_name)s") % locals()
+            raise exceptions.InvalidConfiguration(msg)
+
+        auth_url = self.config.identity.uri
+        dscv = self.config.identity.disable_ssl_certificate_validation
+
+        return keystoneclient.v2_0.client.Client(username=username,
+                                                 password=password,
+                                                 tenant_name=tenant_name,
+                                                 auth_url=auth_url,
+                                                 insecure=dscv)
+
+    def _get_network_client(self):
+        # The intended configuration is for the network client to have
+        # admin privileges and indicate for whom resources are being
+        # created via a 'tenant_id' parameter.  This will often be
+        # preferable to authenticating as a specific user because
+        # working with certain resources (public routers and networks)
+        # often requires admin privileges anyway.
+        username = self.config.identity.admin_username
+        password = self.config.identity.admin_password
+        tenant_name = self.config.identity.admin_tenant_name
+
+        if None in (username, password, tenant_name):
+            msg = ("Missing required credentials for network client. "
+                   "username: %(username)s, password: %(password)s, "
+                   "tenant_name: %(tenant_name)s") % locals()
+            raise exceptions.InvalidConfiguration(msg)
+
+        auth_url = self.config.identity.uri
+        dscv = self.config.identity.disable_ssl_certificate_validation
+
+        return quantumclient.v2_0.client.Client(username=username,
+                                                password=password,
+                                                tenant_name=tenant_name,
+                                                auth_url=auth_url,
+                                                insecure=dscv)
+
+
+class OfficialClientTest(tempest.test.TestCase):
+    """
+    Official Client test base class for scenario testing.
+
+    Official Client tests are tests that have the following characteristics:
+
+     * Test basic operations of an API, typically in an order that
+       a regular user would perform those operations
+     * Test only the correct inputs and action paths -- no fuzz or
+       random input data is sent, only valid inputs.
+     * Use only the default client tool for calling an API
+    """
+
+    manager_class = OfficialClientManager
+
+    @classmethod
+    def tearDownClass(cls):
+        # NOTE(jaypipes): Because scenario tests are typically run in a
+        # specific order, and because test methods in scenario tests
+        # generally create resources in a particular order, we destroy
+        # resources in the reverse order in which resources are added to
+        # the scenario test class object
+        while cls.os_resources:
+            thing = cls.os_resources.pop()
+            LOG.debug("Deleting %r from shared resources of %s" %
+                      (thing, cls.__name__))
+
+            try:
+                # OpenStack resources are assumed to have a delete()
+                # method which destroys the resource...
+                thing.delete()
+            except Exception as e:
+                # If the resource is already missing, mission accomplished.
+                if e.__class__.__name__ == 'NotFound':
+                    continue
+                raise
+
+            def is_deletion_complete():
+                # Deletion testing is only required for objects whose
+                # existence cannot be checked via retrieval.
+                if isinstance(thing, dict):
+                    return True
+                try:
+                    thing.get()
+                except Exception as e:
+                    # Clients are expected to return an exception
+                    # called 'NotFound' if retrieval fails.
+                    if e.__class__.__name__ == 'NotFound':
+                        return True
+                    raise
+                return False
+
+            # Block until resource deletion has completed or timed-out
+            tempest.test.call_until_true(is_deletion_complete, 10, 1)
+
+
+class NetworkScenarioTest(OfficialClientTest):
+    """
+    Base class for network scenario tests
+    """
+
+    @classmethod
+    def check_preconditions(cls):
+        if (cls.config.network.quantum_available):
+            cls.enabled = True
+            #verify that quantum_available is telling the truth
+            try:
+                cls.network_client.list_networks()
+            except exc.EndpointNotFound:
+                cls.enabled = False
+                raise
+        else:
+            cls.enabled = False
+            msg = 'Quantum not available'
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setUpClass(cls):
+        super(NetworkScenarioTest, cls).setUpClass()
+        cls.tenant_id = cls.manager._get_identity_client(
+            cls.config.identity.username,
+            cls.config.identity.password,
+            cls.config.identity.tenant_name).tenant_id
+
+    def _create_keypair(self, client, namestart='keypair-smoke-'):
+        kp_name = rand_name(namestart)
+        keypair = client.keypairs.create(kp_name)
+        try:
+            self.assertEqual(keypair.id, kp_name)
+            self.set_resource(kp_name, keypair)
+        except AttributeError:
+            self.fail("Keypair object not successfully created.")
+        return keypair
+
+    def _create_security_group(self, client, namestart='secgroup-smoke-'):
+        # Create security group
+        sg_name = rand_name(namestart)
+        sg_desc = sg_name + " description"
+        secgroup = client.security_groups.create(sg_name, sg_desc)
+        try:
+            self.assertEqual(secgroup.name, sg_name)
+            self.assertEqual(secgroup.description, sg_desc)
+            self.set_resource(sg_name, secgroup)
+        except AttributeError:
+            self.fail("SecurityGroup object not successfully created.")
+
+        # Add rules to the security group
+        rulesets = [
+            {
+                # ssh
+                'ip_protocol': 'tcp',
+                'from_port': 22,
+                'to_port': 22,
+                'cidr': '0.0.0.0/0',
+                'group_id': secgroup.id
+            },
+            {
+                # ping
+                'ip_protocol': 'icmp',
+                'from_port': -1,
+                'to_port': -1,
+                'cidr': '0.0.0.0/0',
+                'group_id': secgroup.id
+            }
+        ]
+        for ruleset in rulesets:
+            try:
+                client.security_group_rules.create(secgroup.id, **ruleset)
+            except Exception:
+                self.fail("Failed to create rule in security group.")
+
+        return secgroup
+
+    def _create_network(self, tenant_id, namestart='network-smoke-'):
+        name = rand_name(namestart)
+        body = dict(
+            network=dict(
+                name=name,
+                tenant_id=tenant_id,
+            ),
+        )
+        result = self.network_client.create_network(body=body)
+        network = net_common.DeletableNetwork(client=self.network_client,
+                                              **result['network'])
+        self.assertEqual(network.name, name)
+        self.set_resource(name, network)
+        return network
+
+    def _list_networks(self):
+        nets = self.network_client.list_networks()
+        return nets['networks']
+
+    def _list_subnets(self):
+        subnets = self.network_client.list_subnets()
+        return subnets['subnets']
+
+    def _list_routers(self):
+        routers = self.network_client.list_routers()
+        return routers['routers']
+
+    def _create_subnet(self, network, namestart='subnet-smoke-'):
+        """
+        Create a subnet for the given network within the cidr block
+        configured for tenant networks.
+        """
+        cfg = self.config.network
+        tenant_cidr = netaddr.IPNetwork(cfg.tenant_network_cidr)
+        result = None
+        # Repeatedly attempt subnet creation with sequential cidr
+        # blocks until an unallocated block is found.
+        for subnet_cidr in tenant_cidr.subnet(cfg.tenant_network_mask_bits):
+            body = dict(
+                subnet=dict(
+                    ip_version=4,
+                    network_id=network.id,
+                    tenant_id=network.tenant_id,
+                    cidr=str(subnet_cidr),
+                ),
+            )
+            try:
+                result = self.network_client.create_subnet(body=body)
+                break
+            except exc.QuantumClientException as e:
+                is_overlapping_cidr = 'overlaps with another subnet' in str(e)
+                if not is_overlapping_cidr:
+                    raise
+        self.assertIsNotNone(result, 'Unable to allocate tenant network')
+        subnet = net_common.DeletableSubnet(client=self.network_client,
+                                            **result['subnet'])
+        self.assertEqual(subnet.cidr, str(subnet_cidr))
+        self.set_resource(rand_name(namestart), subnet)
+        return subnet
+
+    def _create_port(self, network, namestart='port-quotatest-'):
+        name = rand_name(namestart)
+        body = dict(
+            port=dict(name=name,
+                      network_id=network.id,
+                      tenant_id=network.tenant_id))
+        result = self.network_client.create_port(body=body)
+        self.assertIsNotNone(result, 'Unable to allocate port')
+        port = net_common.DeletablePort(client=self.network_client,
+                                        **result['port'])
+        self.set_resource(name, port)
+        return port
+
+    def _create_server(self, client, network, name, key_name, security_groups):
+        flavor_id = self.config.compute.flavor_ref
+        base_image_id = self.config.compute.image_ref
+        create_kwargs = {
+            'nics': [
+                {'net-id': network.id},
+            ],
+            'key_name': key_name,
+            'security_groups': security_groups,
+        }
+        server = client.servers.create(name, base_image_id, flavor_id,
+                                       **create_kwargs)
+        try:
+            self.assertEqual(server.name, name)
+            self.set_resource(name, server)
+        except AttributeError:
+            self.fail("Server not successfully created.")
+        self.status_timeout(client.servers, server.id, 'ACTIVE')
+        # The instance retrieved on creation is missing network
+        # details, necessitating retrieval after it becomes active to
+        # ensure correct details.
+        server = client.servers.get(server.id)
+        self.set_resource(name, server)
+        return server
+
+    def _create_floating_ip(self, server, external_network_id):
+        result = self.network_client.list_ports(device_id=server.id)
+        ports = result.get('ports', [])
+        self.assertEqual(len(ports), 1,
+                         "Unable to determine which port to target.")
+        port_id = ports[0]['id']
+        body = dict(
+            floatingip=dict(
+                floating_network_id=external_network_id,
+                port_id=port_id,
+                tenant_id=server.tenant_id,
+            )
+        )
+        result = self.network_client.create_floatingip(body=body)
+        floating_ip = net_common.DeletableFloatingIp(
+            client=self.network_client,
+            **result['floatingip'])
+        self.set_resource(rand_name('floatingip-'), floating_ip)
+        return floating_ip
+
+    def _ping_ip_address(self, ip_address):
+        cmd = ['ping', '-c1', '-w1', ip_address]
+
+        def ping():
+            proc = subprocess.Popen(cmd,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
+            proc.wait()
+            if proc.returncode == 0:
+                return True
+
+        # TODO(mnewby) Allow configuration of execution and sleep duration.
+        return tempest.test.call_until_true(ping, 20, 1)
diff --git a/tempest/tests/network/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
similarity index 98%
rename from tempest/tests/network/test_network_basic_ops.py
rename to tempest/scenario/test_network_basic_ops.py
index 92ca65f..ee2dc0d 100644
--- a/tempest/tests/network/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -17,11 +17,12 @@
 #    under the License.
 
 from tempest.common.utils.data_utils import rand_name
+from tempest.scenario import manager
 from tempest.test import attr
-import tempest.tests.network.common as net_common
+from tempest.tests.network import common as net_common
 
 
-class TestNetworkBasicOps(net_common.TestNetworkSmokeCommon):
+class TestNetworkBasicOps(manager.NetworkScenarioTest):
 
     """
     This smoke test suite assumes that Nova has been configured to
diff --git a/tempest/tests/network/test_network_quota_basic.py b/tempest/scenario/test_network_quotas.py
similarity index 95%
rename from tempest/tests/network/test_network_quota_basic.py
rename to tempest/scenario/test_network_quotas.py
index eaec708..8c3af73 100644
--- a/tempest/tests/network/test_network_quota_basic.py
+++ b/tempest/scenario/test_network_quotas.py
@@ -16,12 +16,12 @@
 #    under the License.
 
 from quantumclient.common import exceptions as exc
-from tempest.tests.network.common import TestNetworkSmokeCommon
+from tempest.scenario.manager import NetworkScenarioTest
 
 MAX_REASONABLE_ITERATIONS = 51  # more than enough. Default for port is 50.
 
 
-class TestNetworkQuotaBasic(TestNetworkSmokeCommon):
+class TestNetworkQuotaBasic(NetworkScenarioTest):
     """
     This test suite contains tests that each loop trying to grab a
     particular resource until a quota limit is hit.
diff --git a/tempest/tests/compute/servers/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
similarity index 96%
rename from tempest/tests/compute/servers/test_server_advanced_ops.py
rename to tempest/scenario/test_server_advanced_ops.py
index ad859d0..e48157e 100644
--- a/tempest/tests/compute/servers/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -19,12 +19,12 @@
 
 
 from tempest.common.utils.data_utils import rand_name
-from tempest import test
+from tempest.scenario import manager
 
 LOG = logging.getLogger(__name__)
 
 
-class TestServerAdvancedOps(test.DefaultClientSmokeTest):
+class TestServerAdvancedOps(manager.OfficialClientTest):
 
     """
     This test case stresses some advanced server instance operations:
diff --git a/tempest/tests/compute/servers/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
similarity index 97%
rename from tempest/tests/compute/servers/test_server_basic_ops.py
rename to tempest/scenario/test_server_basic_ops.py
index fdbbd3c..c5c6728 100644
--- a/tempest/tests/compute/servers/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -18,12 +18,12 @@
 import logging
 
 from tempest.common.utils.data_utils import rand_name
-from tempest import test
+from tempest.scenario import manager
 
 LOG = logging.getLogger(__name__)
 
 
-class TestServerBasicOps(test.DefaultClientSmokeTest):
+class TestServerBasicOps(manager.OfficialClientTest):
 
     """
     This smoke test case follows this basic set of operations:
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 5b1e48f..a910dec 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -43,7 +43,8 @@
         body = json.loads(body)
         return resp, body['quota_set']
 
-    def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
+    def update_quota_set(self, tenant_id, force=None,
+                         injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
                          fixed_ips=None, key_pairs=None, instances=None,
                          security_group_rules=None, injected_files=None,
@@ -54,6 +55,9 @@
         """
         post_body = {}
 
+        if force is not None:
+            post_body['force'] = force
+
         if injected_file_content_bytes is not None:
             post_body['injected_file_content_bytes'] = \
                 injected_file_content_bytes
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
new file mode 100644
index 0000000..d054f72
--- /dev/null
+++ b/tempest/services/compute/json/services_client.py
@@ -0,0 +1,33 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class ServicesClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(ServicesClientJSON, self).__init__(config, username, password,
+                                                 auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_services(self):
+        resp, body = self.get("os-services")
+        body = json.loads(body)
+        return resp, body['services']
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 8912443..ef5362c 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -64,7 +64,8 @@
         body = self._format_quota(body)
         return resp, body
 
-    def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
+    def update_quota_set(self, tenant_id, force=None,
+                         injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
                          fixed_ips=None, key_pairs=None, instances=None,
                          security_group_rules=None, injected_files=None,
@@ -76,6 +77,9 @@
         post_body = Element("quota_set",
                             xmlns=XMLNS_11)
 
+        if force is not None:
+            post_body.add_attr('force', force)
+
         if injected_file_content_bytes is not None:
             post_body.add_attr('injected_file_content_bytes',
                                injected_file_content_bytes)
diff --git a/tempest/services/compute/xml/services_client.py b/tempest/services/compute/xml/services_client.py
new file mode 100644
index 0000000..ce23403
--- /dev/null
+++ b/tempest/services/compute/xml/services_client.py
@@ -0,0 +1,34 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from lxml import etree
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class ServicesClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(ServicesClientXML, self).__init__(config, username, password,
+                                                auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_services(self):
+        resp, body = self.get("os-services", self.headers)
+        node = etree.fromstring(body)
+        body = [xml_to_json(x) for x in node.getchildren()]
+        return resp, body
diff --git a/tempest/tests/boto/__init__.py b/tempest/services/orchestration/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tempest/services/orchestration/__init__.py
diff --git a/tempest/tests/boto/__init__.py b/tempest/services/orchestration/json/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tempest/services/orchestration/json/__init__.py
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
new file mode 100644
index 0000000..81162df
--- /dev/null
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -0,0 +1,99 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+import time
+import urllib
+
+from tempest.common import rest_client
+from tempest import exceptions
+
+
+class OrchestrationClient(rest_client.RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(OrchestrationClient, self).__init__(config, username, password,
+                                                  auth_url, tenant_name)
+        self.service = self.config.orchestration.catalog_type
+        self.build_interval = self.config.orchestration.build_interval
+        self.build_timeout = self.config.orchestration.build_timeout
+
+    def list_stacks(self, params=None):
+        """Lists all stacks for a user."""
+
+        uri = 'stacks'
+        if params:
+            uri += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(uri)
+        body = json.loads(body)
+        return resp, body
+
+    def create_stack(self, name, disable_rollback=True, parameters={},
+                     timeout_mins=60, template=None, template_url=None):
+        post_body = {
+            "stack_name": name,
+            "disable_rollback": disable_rollback,
+            "parameters": parameters,
+            "timeout_mins": timeout_mins,
+            "template": "HeatTemplateFormatVersion: '2012-12-12'\n"
+        }
+        if template:
+            post_body['template'] = template
+        if template_url:
+            post_body['template_url'] = template_url
+        body = json.dumps(post_body)
+        uri = 'stacks'
+        resp, body = self.post(uri, headers=self.headers, body=body)
+        return resp, body
+
+    def get_stack(self, stack_identifier):
+        """Returns the details of a single stack."""
+        url = "stacks/%s" % stack_identifier
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['stack']
+
+    def delete_stack(self, stack_identifier):
+        """Deletes the specified Stack."""
+        return self.delete("stacks/%s" % str(stack_identifier))
+
+    def wait_for_stack_status(self, stack_identifier, status, failure_status=(
+            'CREATE_FAILED',
+            'DELETE_FAILED',
+            'UPDATE_FAILED',
+            'ROLLBACK_FAILED')):
+        """Waits for a Volume to reach a given status."""
+        stack_status = None
+        start = int(time.time())
+
+        while stack_status != status:
+            resp, body = self.get_stack(stack_identifier)
+            stack_name = body['stack_name']
+            stack_status = body['stack_status']
+            if stack_status in failure_status:
+                raise exceptions.StackBuildErrorException(
+                    stack_identifier=stack_identifier,
+                    stack_status=stack_status,
+                    stack_status_reason=body['stack_status_reason'])
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('Stack %s failed to reach %s status within '
+                           'the required time (%s s).' %
+                           (stack_name, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+            time.sleep(self.build_interval)
diff --git a/tempest/test.py b/tempest/test.py
index 9d6c2d3..c69a94c 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -39,9 +39,13 @@
     def decorator(f):
         if 'type' in kwargs and isinstance(kwargs['type'], str):
             f = testtools.testcase.attr(kwargs['type'])(f)
+            if kwargs['type'] == 'smoke':
+                f = testtools.testcase.attr('gate')(f)
         elif 'type' in kwargs and isinstance(kwargs['type'], list):
             for attr in kwargs['type']:
                 f = testtools.testcase.attr(attr)(f)
+                if attr == 'smoke':
+                    f = testtools.testcase.attr('gate')(f)
         return nose.plugins.attrib.attr(*args, **kwargs)(f)
 
     return decorator
@@ -146,63 +150,6 @@
                       % (thing_id, expected_status))
 
 
-class DefaultClientSmokeTest(TestCase):
-
-    """
-    Base smoke test case class that provides the default clients to
-    access the various OpenStack APIs.
-
-    Smoke tests are tests that have the following characteristics:
-
-     * Test basic operations of an API, typically in an order that
-       a regular user would perform those operations
-     * Test only the correct inputs and action paths -- no fuzz or
-       random input data is sent, only valid inputs.
-     * Use only the default client tool for calling an API
-    """
-
-    manager_class = manager.DefaultClientManager
-
-    @classmethod
-    def tearDownClass(cls):
-        # NOTE(jaypipes): Because smoke tests are typically run in a specific
-        # order, and because test methods in smoke tests generally create
-        # resources in a particular order, we destroy resources in the reverse
-        # order in which resources are added to the smoke test class object
-        while cls.os_resources:
-            thing = cls.os_resources.pop()
-            LOG.debug("Deleting %r from shared resources of %s" %
-                      (thing, cls.__name__))
-
-            try:
-                # OpenStack resources are assumed to have a delete()
-                # method which destroys the resource...
-                thing.delete()
-            except Exception as e:
-                # If the resource is already missing, mission accomplished.
-                if e.__class__.__name__ == 'NotFound':
-                    continue
-                raise
-
-            def is_deletion_complete():
-                # Deletion testing is only required for objects whose
-                # existence cannot be checked via retrieval.
-                if isinstance(thing, dict):
-                    return True
-                try:
-                    thing.get()
-                except Exception as e:
-                    # Clients are expected to return an exception
-                    # called 'NotFound' if retrieval fails.
-                    if e.__class__.__name__ == 'NotFound':
-                        return True
-                    raise
-                return False
-
-            # Block until resource deletion has completed or timed-out
-            call_until_true(is_deletion_complete, 10, 1)
-
-
 class ComputeFuzzClientTest(TestCase):
 
     """
diff --git a/tempest/tests/compute/__init__.py b/tempest/tests/compute/__init__.py
index 36893e3..968f17e 100644
--- a/tempest/tests/compute/__init__.py
+++ b/tempest/tests/compute/__init__.py
@@ -28,7 +28,6 @@
 CREATE_IMAGE_ENABLED = CONFIG.compute.create_image_enabled
 RESIZE_AVAILABLE = CONFIG.compute.resize_available
 CHANGE_PASSWORD_AVAILABLE = CONFIG.compute.change_password_available
-WHITEBOX_ENABLED = CONFIG.whitebox.whitebox_enabled
 DISK_CONFIG_ENABLED = True
 DISK_CONFIG_ENABLED_OVERRIDE = CONFIG.compute.disk_config_enabled_override
 FLAVOR_EXTRA_DATA_ENABLED = True
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index 8f520f9..7160aed 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -15,6 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.compute import base
@@ -30,6 +31,7 @@
         cls.client = cls.os.quotas_client
         cls.adm_client = cls.os_adm.quotas_client
         cls.identity_admin_client = cls._get_identity_admin_client()
+        cls.sg_client = cls.security_groups_client
 
         resp, tenants = cls.identity_admin_client.list_tenants()
 
@@ -69,8 +71,13 @@
         self.assertEqual(expected_quota_set, quota_set)
 
     def test_update_all_quota_resources_for_tenant(self):
+        self.skipTest("This test require the change in nova component "
+                      "https://review.openstack.org/#/c/25887/, the related "
+                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
+                      "once the change is merged I will enable this testcase")
         # Admin can update all the resource quota limits for a tenant
-        new_quota_set = {'injected_file_content_bytes': 20480,
+        new_quota_set = {'force': True,
+                         'injected_file_content_bytes': 20480,
                          'metadata_items': 256, 'injected_files': 10,
                          'ram': 10240, 'floating_ips': 20, 'fixed_ips': 10,
                          'key_pairs': 200, 'injected_file_path_bytes': 512,
@@ -117,12 +124,17 @@
                              "defaults")
 
     def test_create_server_when_cpu_quota_is_full(self):
+        self.skipTest("This test require the change in nova component "
+                      "https://review.openstack.org/#/c/25887/, the related "
+                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
+                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's vcpu quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_vcpu_quota = quota_set['cores']
         vcpu_quota = 0  # Set the quota to zero to conserve resources
 
         resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
+                                                           force=True,
                                                            cores=vcpu_quota)
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
@@ -130,12 +142,17 @@
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
     def test_create_server_when_memory_quota_is_full(self):
+        self.skipTest("This test require the change in nova component "
+                      "https://review.openstack.org/#/c/25887/, the related "
+                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
+                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's memory quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_mem_quota = quota_set['ram']
         mem_quota = 0  # Set the quota to zero to conserve resources
 
         self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
                                          ram=mem_quota)
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
@@ -146,17 +163,76 @@
 
     @attr(type='negative')
     def test_create_server_when_instances_quota_is_full(self):
+        self.skipTest("This test require the change in nova component "
+                      "https://review.openstack.org/#/c/25887/, the related "
+                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
+                      "once the change is merged I will enable this testcase")
         #Once instances quota limit is reached, disallow server creation
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_instances_quota = quota_set['instances']
         instances_quota = 0  # Set quota to zero to disallow server creation
 
         self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
+    @attr(type='negative')
+    def test_security_groups_exceed_limit(self):
+        # Negative test: Creation Security Groups over limit should FAIL
+
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_sg_quota = quota_set['security_groups']
+        sg_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set =\
+            self.adm_client.update_quota_set(self.demo_tenant_id,
+                                             security_groups=sg_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set,
+                        self.demo_tenant_id,
+                        security_groups=default_sg_quota)
+
+        # Check we cannot create anymore
+        self.assertRaises(exceptions.OverLimit,
+                          self.sg_client.create_security_group,
+                          "sg-overlimit", "sg-desc")
+
+    @attr(type='negative')
+    def test_security_groups_rules_exceed_limit(self):
+        # Negative test: Creation of Security Group Rules should FAIL
+        # when we reach limit maxSecurityGroupRules
+
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_sg_rules_quota = quota_set['security_group_rules']
+        sg_rules_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set =\
+            self.adm_client.update_quota_set(
+                self.demo_tenant_id,
+                security_group_rules=sg_rules_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set,
+                        self.demo_tenant_id,
+                        security_group_rules=default_sg_rules_quota)
+
+        s_name = rand_name('securitygroup-')
+        s_description = rand_name('description-')
+        resp, securitygroup =\
+            self.sg_client.create_security_group(s_name, s_description)
+        self.addCleanup(self.sg_client.delete_security_group,
+                        securitygroup['id'])
+
+        secgroup_id = securitygroup['id']
+        ip_protocol = 'tcp'
+
+        # Check we cannot create SG rule anymore
+        self.assertRaises(exceptions.OverLimit,
+                          self.sg_client.create_security_group_rule,
+                          secgroup_id, ip_protocol, 1025, 1025)
+
 
 class QuotasAdminTestXML(QuotasAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/tests/compute/admin/test_services.py b/tempest/tests/compute/admin/test_services.py
new file mode 100644
index 0000000..0577164
--- /dev/null
+++ b/tempest/tests/compute/admin/test_services.py
@@ -0,0 +1,52 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import exceptions
+from tempest.test import attr
+from tempest.tests.compute import base
+
+
+class ServicesAdminTestJSON(base.BaseComputeAdminTest):
+
+    """
+    Tests Services API. List and Enable/Disable require admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServicesAdminTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.services_client
+        cls.non_admin_client = cls.services_client
+
+    @attr(type='positive')
+    def test_list_services(self):
+        # List Compute services
+        resp, services = self.client.list_services()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(services) >= 2)
+
+    @attr(type='negative')
+    def test_list_services_with_non_admin_user(self):
+        # List Compute service with non admin user
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.list_services)
+
+
+class ServicesAdminTestXML(ServicesAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/tests/compute/base.py b/tempest/tests/compute/base.py
index b313e0b..fbefe35 100644
--- a/tempest/tests/compute/base.py
+++ b/tempest/tests/compute/base.py
@@ -63,6 +63,7 @@
         cls.fixed_ips_client = os.fixed_ips_client
         cls.availability_zone_client = os.availability_zone_client
         cls.aggregates_client = os.aggregates_client
+        cls.services_client = os.services_client
         cls.build_interval = cls.config.compute.build_interval
         cls.build_timeout = cls.config.compute.build_timeout
         cls.ssh_user = cls.config.compute.ssh_user
diff --git a/tempest/tests/compute/images/test_images.py b/tempest/tests/compute/images/test_images.py
index d9e4153..1dae8a5 100644
--- a/tempest/tests/compute/images/test_images.py
+++ b/tempest/tests/compute/images/test_images.py
@@ -100,14 +100,6 @@
         self.assertRaises(exceptions.Duplicate, self.client.create_image,
                           server['id'], snapshot_name)
 
-    @attr(type='negative')
-    def test_create_image_when_server_is_building(self):
-        # Return error when creating an image of a server that is building
-        resp, server = self.create_server(wait_until='BUILD')
-        snapshot_name = rand_name('test-snap-')
-        self.assertRaises(exceptions.Duplicate, self.client.create_image,
-                          server['id'], snapshot_name)
-
     @testtools.skip("Until Bug #1039739 is fixed")
     @attr(type='negative')
     def test_create_image_when_server_is_rebooting(self):
diff --git a/tempest/tests/compute/test_live_block_migration.py b/tempest/tests/compute/test_live_block_migration.py
index 30ff882..e22d45a 100644
--- a/tempest/tests/compute/test_live_block_migration.py
+++ b/tempest/tests/compute/test_live_block_migration.py
@@ -91,6 +91,13 @@
             self.created_server_ids.append(server_id)
             return server_id
 
+    def _volume_clean_up(self, server_id, volume_id):
+        resp, body = self.volumes_client.get_volume(volume_id)
+        if body['status'] == 'in-use':
+            self.servers_client.detach_volume(server_id, volume_id)
+            self.volumes_client.wait_for_volume_status(volume_id, 'available')
+        self.volumes_client.delete_volume(volume_id)
+
     @attr(type='positive')
     @testtools.skipIf(not CONF.compute.live_migration_available,
                       'Live migration not available')
@@ -117,6 +124,37 @@
                           server_id, target_host)
         self.assertEquals('ACTIVE', self._get_server_status(server_id))
 
+    @attr(type='positive')
+    @testtools.skipIf(not CONF.compute.live_migration_available or
+                      not CONF.compute.use_block_migration_for_live_migration,
+                      'Block Live migration not available')
+    @testtools.skipIf(not CONF.compute.block_migrate_supports_cinder_iscsi,
+                      'Block Live migration not configured for iSCSI')
+    def test_iscsi_volume(self):
+        # Live block migrate an instance to another host
+        if len(self._get_compute_hostnames()) < 2:
+            raise self.skipTest(
+                "Less than 2 compute nodes, skipping migration test.")
+        server_id = self._get_an_active_server()
+        actual_host = self._get_host_for_server(server_id)
+        target_host = self._get_host_other_than(actual_host)
+
+        resp, volume = self.volumes_client.create_volume(1,
+                                                         display_name='test')
+
+        self.volumes_client.wait_for_volume_status(volume['id'],
+                                                   'available')
+        self.addCleanup(self._volume_clean_up, server_id, volume['id'])
+
+        # Attach the volume to the server
+        self.servers_client.attach_volume(server_id, volume['id'],
+                                          device='/dev/xvdb')
+        self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
+
+        self._migrate_server_to(server_id, target_host)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+        self.assertEquals(target_host, self._get_host_for_server(server_id))
+
     @classmethod
     def tearDownClass(cls):
         for server_id in cls.created_server_ids:
diff --git a/tempest/tests/identity/admin/v3/test_endpoints.py b/tempest/tests/identity/admin/v3/test_endpoints.py
old mode 100755
new mode 100644
diff --git a/tempest/tests/image/v1/test_image_members.py b/tempest/tests/image/v1/test_image_members.py
index 92052fc..7293d59 100644
--- a/tempest/tests/image/v1/test_image_members.py
+++ b/tempest/tests/image/v1/test_image_members.py
@@ -17,6 +17,7 @@
 import cStringIO as StringIO
 
 from tempest import clients
+from tempest.test import attr
 from tempest.tests.image import base
 
 
@@ -45,6 +46,7 @@
         image_id = image['id']
         return image_id
 
+    @attr(type='gate')
     def test_add_image_member(self):
         image = self._create_image()
         resp = self.client.add_member(self.tenants[0], image)
@@ -55,6 +57,7 @@
         members = map(lambda x: x['member_id'], members)
         self.assertIn(self.tenants[0], members)
 
+    @attr(type='gate')
     def test_get_shared_images(self):
         image = self._create_image()
         resp = self.client.add_member(self.tenants[0], image)
@@ -69,6 +72,7 @@
         self.assertIn(share_image, images)
         self.assertIn(image, images)
 
+    @attr(type='gate')
     def test_remove_member(self):
         image_id = self._create_image()
         resp = self.client.add_member(self.tenants[0], image_id)
diff --git a/tempest/tests/image/v1/test_images.py b/tempest/tests/image/v1/test_images.py
index 19c0aa0..70e5762 100644
--- a/tempest/tests/image/v1/test_images.py
+++ b/tempest/tests/image/v1/test_images.py
@@ -25,18 +25,18 @@
 class CreateRegisterImagesTest(base.BaseV1ImageTest):
     """Here we test the registration and creation of images."""
 
-    @attr(type='negative')
+    @attr(type='gate')
     def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
         self.assertRaises(exceptions.BadRequest, self.client.create_image,
                           'test', 'wrong', 'vhd')
 
-    @attr(type='negative')
+    @attr(type='gate')
     def test_register_with_invalid_disk_format(self):
         self.assertRaises(exceptions.BadRequest, self.client.create_image,
                           'test', 'bare', 'wrong')
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_register_then_upload(self):
         # Register, then upload an image
         properties = {'prop1': 'val1'}
@@ -60,7 +60,7 @@
         self.assertTrue('size' in body)
         self.assertEqual(1024, body.get('size'))
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_register_remote_image(self):
         # Register a new remote image
         resp, body = self.create_image(name='New Remote Image',
@@ -80,6 +80,7 @@
         self.assertEqual(properties['key1'], 'value1')
         self.assertEqual(properties['key2'], 'value2')
 
+    @attr(type='gate')
     def test_register_http_image(self):
         resp, body = self.create_image(name='New Http Image',
                                        container_format='bare',
@@ -94,7 +95,7 @@
         resp, body = self.client.get_image(image_id)
         self.assertEqual(resp['status'], '200')
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_register_image_with_min_ram(self):
         # Register an image with min ram
         properties = {'prop1': 'val1'}
@@ -182,7 +183,7 @@
         image_id = image['id']
         return image_id
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
         resp, images_list = self.client.image_list()
@@ -191,7 +192,7 @@
         for image_id in self.created_images:
             self.assertTrue(image_id in image_list)
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_disk_format(self):
         resp, images_list = self.client.image_list(disk_format='ami')
         self.assertEqual(resp['status'], '200')
@@ -201,7 +202,7 @@
         self.assertTrue(self.ami_set <= result_set)
         self.assertFalse(self.created_set - self.ami_set <= result_set)
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_container_format(self):
         resp, images_list = self.client.image_list(container_format='bare')
         self.assertEqual(resp['status'], '200')
@@ -211,7 +212,7 @@
         self.assertTrue(self.bare_set <= result_set)
         self.assertFalse(self.created_set - self.bare_set <= result_set)
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_max_size(self):
         resp, images_list = self.client.image_list(size_max=42)
         self.assertEqual(resp['status'], '200')
@@ -221,7 +222,7 @@
         self.assertTrue(self.size42_set <= result_set)
         self.assertFalse(self.created_set - self.size42_set <= result_set)
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_min_size(self):
         resp, images_list = self.client.image_list(size_min=142)
         self.assertEqual(resp['status'], '200')
@@ -231,7 +232,7 @@
         self.assertTrue(self.size142_set <= result_set)
         self.assertFalse(self.size42_set <= result_set)
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_status_active_detail(self):
         resp, images_list = self.client.image_list_detail(status='active',
                                                           sort_key='size',
@@ -244,7 +245,7 @@
             top_size = size
             self.assertEqual(image['status'], 'active')
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_name(self):
         resp, images_list = self.client.image_list_detail(
             name='New Remote Image dup')
diff --git a/tempest/tests/image/v2/test_images.py b/tempest/tests/image/v2/test_images.py
index 15db519..6356b4c 100644
--- a/tempest/tests/image/v2/test_images.py
+++ b/tempest/tests/image/v2/test_images.py
@@ -30,18 +30,18 @@
     Here we test the registration and creation of images
     """
 
-    @attr(type='negative')
+    @attr(type='gate')
     def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
         self.assertRaises(exceptions.BadRequest, self.client.create_image,
                           'test', 'wrong', 'vhd')
 
-    @attr(type='negative')
+    @attr(type='gate')
     def test_register_with_invalid_disk_format(self):
         self.assertRaises(exceptions.BadRequest, self.client.create_image,
                           'test', 'bare', 'wrong')
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_register_then_upload(self):
         # Register, then upload an image
         resp, body = self.create_image(name='New Name',
@@ -98,7 +98,7 @@
 
         return image_id
 
-    @attr(type='image')
+    @attr(type='gate')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
         resp, images_list = self.client.image_list()
diff --git a/tempest/tests/network/common.py b/tempest/tests/network/common.py
index 6811acf..22eb1d3 100644
--- a/tempest/tests/network/common.py
+++ b/tempest/tests/network/common.py
@@ -15,14 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import subprocess
-
-import netaddr
-
-from quantumclient.common import exceptions as exc
-from tempest.common.utils.data_utils import rand_name
-from tempest import test
-
 
 class AttributeDict(dict):
 
@@ -100,212 +92,3 @@
 
     def delete(self):
         self.client.delete_port(self.id)
-
-
-class TestNetworkSmokeCommon(test.DefaultClientSmokeTest):
-    """
-    Base class for network smoke tests
-    """
-
-    @classmethod
-    def check_preconditions(cls):
-        if (cls.config.network.quantum_available):
-            cls.enabled = True
-            #verify that quantum_available is telling the truth
-            try:
-                cls.network_client.list_networks()
-            except exc.EndpointNotFound:
-                cls.enabled = False
-                raise
-        else:
-            cls.enabled = False
-            msg = 'Quantum not available'
-            raise cls.skipException(msg)
-
-    @classmethod
-    def setUpClass(cls):
-        super(TestNetworkSmokeCommon, cls).setUpClass()
-        cls.tenant_id = cls.manager._get_identity_client(
-            cls.config.identity.username,
-            cls.config.identity.password,
-            cls.config.identity.tenant_name).tenant_id
-
-    def _create_keypair(self, client, namestart='keypair-smoke-'):
-        kp_name = rand_name(namestart)
-        keypair = client.keypairs.create(kp_name)
-        try:
-            self.assertEqual(keypair.id, kp_name)
-            self.set_resource(kp_name, keypair)
-        except AttributeError:
-            self.fail("Keypair object not successfully created.")
-        return keypair
-
-    def _create_security_group(self, client, namestart='secgroup-smoke-'):
-        # Create security group
-        sg_name = rand_name(namestart)
-        sg_desc = sg_name + " description"
-        secgroup = client.security_groups.create(sg_name, sg_desc)
-        try:
-            self.assertEqual(secgroup.name, sg_name)
-            self.assertEqual(secgroup.description, sg_desc)
-            self.set_resource(sg_name, secgroup)
-        except AttributeError:
-            self.fail("SecurityGroup object not successfully created.")
-
-        # Add rules to the security group
-        rulesets = [
-            {
-                # ssh
-                'ip_protocol': 'tcp',
-                'from_port': 22,
-                'to_port': 22,
-                'cidr': '0.0.0.0/0',
-                'group_id': secgroup.id
-            },
-            {
-                # ping
-                'ip_protocol': 'icmp',
-                'from_port': -1,
-                'to_port': -1,
-                'cidr': '0.0.0.0/0',
-                'group_id': secgroup.id
-            }
-        ]
-        for ruleset in rulesets:
-            try:
-                client.security_group_rules.create(secgroup.id, **ruleset)
-            except Exception:
-                self.fail("Failed to create rule in security group.")
-
-        return secgroup
-
-    def _create_network(self, tenant_id, namestart='network-smoke-'):
-        name = rand_name(namestart)
-        body = dict(
-            network=dict(
-                name=name,
-                tenant_id=tenant_id,
-            ),
-        )
-        result = self.network_client.create_network(body=body)
-        network = DeletableNetwork(client=self.network_client,
-                                   **result['network'])
-        self.assertEqual(network.name, name)
-        self.set_resource(name, network)
-        return network
-
-    def _list_networks(self):
-        nets = self.network_client.list_networks()
-        return nets['networks']
-
-    def _list_subnets(self):
-        subnets = self.network_client.list_subnets()
-        return subnets['subnets']
-
-    def _list_routers(self):
-        routers = self.network_client.list_routers()
-        return routers['routers']
-
-    def _create_subnet(self, network, namestart='subnet-smoke-'):
-        """
-        Create a subnet for the given network within the cidr block
-        configured for tenant networks.
-        """
-        cfg = self.config.network
-        tenant_cidr = netaddr.IPNetwork(cfg.tenant_network_cidr)
-        result = None
-        # Repeatedly attempt subnet creation with sequential cidr
-        # blocks until an unallocated block is found.
-        for subnet_cidr in tenant_cidr.subnet(cfg.tenant_network_mask_bits):
-            body = dict(
-                subnet=dict(
-                    ip_version=4,
-                    network_id=network.id,
-                    tenant_id=network.tenant_id,
-                    cidr=str(subnet_cidr),
-                ),
-            )
-            try:
-                result = self.network_client.create_subnet(body=body)
-                break
-            except exc.QuantumClientException as e:
-                is_overlapping_cidr = 'overlaps with another subnet' in str(e)
-                if not is_overlapping_cidr:
-                    raise
-        self.assertIsNotNone(result, 'Unable to allocate tenant network')
-        subnet = DeletableSubnet(client=self.network_client,
-                                 **result['subnet'])
-        self.assertEqual(subnet.cidr, str(subnet_cidr))
-        self.set_resource(rand_name(namestart), subnet)
-        return subnet
-
-    def _create_port(self, network, namestart='port-quotatest-'):
-        name = rand_name(namestart)
-        body = dict(
-            port=dict(name=name,
-                      network_id=network.id,
-                      tenant_id=network.tenant_id))
-        result = self.network_client.create_port(body=body)
-        self.assertIsNotNone(result, 'Unable to allocate port')
-        port = DeletablePort(client=self.network_client,
-                             **result['port'])
-        self.set_resource(name, port)
-        return port
-
-    def _create_server(self, client, network, name, key_name, security_groups):
-        flavor_id = self.config.compute.flavor_ref
-        base_image_id = self.config.compute.image_ref
-        create_kwargs = {
-            'nics': [
-                {'net-id': network.id},
-            ],
-            'key_name': key_name,
-            'security_groups': security_groups,
-        }
-        server = client.servers.create(name, base_image_id, flavor_id,
-                                       **create_kwargs)
-        try:
-            self.assertEqual(server.name, name)
-            self.set_resource(name, server)
-        except AttributeError:
-            self.fail("Server not successfully created.")
-        self.status_timeout(client.servers, server.id, 'ACTIVE')
-        # The instance retrieved on creation is missing network
-        # details, necessitating retrieval after it becomes active to
-        # ensure correct details.
-        server = client.servers.get(server.id)
-        self.set_resource(name, server)
-        return server
-
-    def _create_floating_ip(self, server, external_network_id):
-        result = self.network_client.list_ports(device_id=server.id)
-        ports = result.get('ports', [])
-        self.assertEqual(len(ports), 1,
-                         "Unable to determine which port to target.")
-        port_id = ports[0]['id']
-        body = dict(
-            floatingip=dict(
-                floating_network_id=external_network_id,
-                port_id=port_id,
-                tenant_id=server.tenant_id,
-            )
-        )
-        result = self.network_client.create_floatingip(body=body)
-        floating_ip = DeletableFloatingIp(client=self.network_client,
-                                          **result['floatingip'])
-        self.set_resource(rand_name('floatingip-'), floating_ip)
-        return floating_ip
-
-    def _ping_ip_address(self, ip_address):
-        cmd = ['ping', '-c1', '-w1', ip_address]
-
-        def ping():
-            proc = subprocess.Popen(cmd,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            proc.wait()
-            if proc.returncode == 0:
-                return True
-
-        # TODO(mnewby) Allow configuration of execution and sleep duration.
-        return test.call_until_true(ping, 20, 1)
diff --git a/tempest/tests/object_storage/test_account_services.py b/tempest/tests/object_storage/test_account_services.py
index 14f94f7..eb66de8 100644
--- a/tempest/tests/object_storage/test_account_services.py
+++ b/tempest/tests/object_storage/test_account_services.py
@@ -22,12 +22,9 @@
 
 
 class AccountTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(AccountTest, cls).setUpClass()
-
-        #Create a container
         cls.container_name = rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
 
@@ -37,8 +34,7 @@
 
     @attr(type='smoke')
     def test_list_containers(self):
-        # List of all containers should not be empty
-
+        # list of all containers should not be empty
         params = {'format': 'json'}
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
@@ -49,8 +45,7 @@
 
     @attr(type='smoke')
     def test_list_account_metadata(self):
-        # List all account metadata
-
+        # list all account metadata
         resp, metadata = self.account_client.list_account_metadata()
         self.assertEqual(resp['status'], '204')
         self.assertIn('x-account-object-count', resp)
@@ -59,8 +54,7 @@
 
     @attr(type='smoke')
     def test_create_account_metadata(self):
-        # Add metadata to account
-
+        # add metadata to account
         metadata = {'test-account-meta': 'Meta!'}
         resp, _ = \
             self.account_client.create_account_metadata(metadata=metadata)
@@ -72,8 +66,7 @@
 
     @attr(type='smoke')
     def test_delete_account_metadata(self):
-        # Delete metadata from account
-
+        # delete metadata from account
         metadata = ['test-account-meta']
         resp, _ = \
             self.account_client.delete_account_metadata(metadata=metadata)
@@ -84,11 +77,10 @@
 
     @attr(type='negative')
     def test_list_containers_with_non_authorized_user(self):
-        #Listing containers with using non authorized user
+        # list containers using non-authorized user
 
-        # Randomly creating user
+        # create user
         self.data.setup_test_user()
-
         resp, body = \
             self.token_client.auth(self.data.test_user,
                                    self.data.test_password,
@@ -97,14 +89,11 @@
             self.token_client.get_token(self.data.test_user,
                                         self.data.test_password,
                                         self.data.test_tenant)
-
         custom_headers = {'X-Auth-Token': new_token}
-
         params = {'format': 'json'}
-        # Trying to list containers with non authorized user token
+        # list containers with non-authorized user token
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_account_client.list_account_containers,
                           params=params, metadata=custom_headers)
-
-        #Attempt to the delete the user setup created
+        # delete the user which was created
         self.data.teardown_all()
diff --git a/tempest/tests/object_storage/test_container_services.py b/tempest/tests/object_storage/test_container_services.py
index 223744c..508132a 100644
--- a/tempest/tests/object_storage/test_container_services.py
+++ b/tempest/tests/object_storage/test_container_services.py
@@ -22,7 +22,6 @@
 
 
 class ContainerTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(ContainerTest, cls).setUpClass()
@@ -31,73 +30,58 @@
     @classmethod
     def tearDownClass(cls):
         for container in cls.containers:
-            #Get list of all object in the container
             objlist = \
                 cls.container_client.list_all_container_objects(container)
-
-            #Attempt to delete every object in the container
+            # delete every object in the container
             for obj in objlist:
                 resp, _ = \
                     cls.object_client.delete_object(container, obj['name'])
-
-            #Attempt to delete the container
+            # delete the container
             resp, _ = cls.container_client.delete_container(container)
 
     @attr(type='smoke')
     def test_create_container(self):
-        # Create a container, test responses
-
-        #Create a container
         container_name = rand_name(name='TestContainer')
         resp, body = self.container_client.create_container(container_name)
         self.containers.append(container_name)
-
         self.assertTrue(resp['status'] in ('202', '201'))
 
     @attr(type='smoke')
     def test_delete_container(self):
-        # Create and Delete a container, test responses
-
-        #Create a container
+        # create a container
         container_name = rand_name(name='TestContainer')
         resp, _ = self.container_client.create_container(container_name)
         self.containers.append(container_name)
-
-        #Delete Container
+        # delete container
         resp, _ = self.container_client.delete_container(container_name)
         self.assertEqual(resp['status'], '204')
         self.containers.remove(container_name)
 
     @attr(type='smoke')
     def test_list_container_contents_json(self):
-        # Add metadata to object
+        # add metadata to an object
 
-        #Create a container
+        # create a container
         container_name = rand_name(name='TestContainer')
         resp, _ = self.container_client.create_container(container_name)
         self.containers.append(container_name)
-
-        #Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(container_name,
                                                    object_name, data)
-
-        #Set Object Metadata
+        # set object metadata
         meta_key = rand_name(name='Meta-Test-')
         meta_value = rand_name(name='MetaValue-')
         orig_metadata = {meta_key: meta_value}
-
         resp, _ = self.object_client.update_object_metadata(container_name,
                                                             object_name,
                                                             orig_metadata)
-
-        #Get Container contents list json format
+        # get container contents list
         params = {'format': 'json'}
         resp, object_list = \
             self.container_client.\
             list_container_contents(container_name, params=params)
-
         self.assertEqual(resp['status'], '200')
         self.assertIsNotNone(object_list)
 
@@ -106,14 +90,13 @@
 
     @attr(type='smoke')
     def test_container_metadata(self):
-        # Update/Retrieve/Delete Container Metadata
+        # update/retrieve/delete container metadata
 
-        # Create a container
+        # create a container
         container_name = rand_name(name='TestContainer')
         resp, _ = self.container_client.create_container(container_name)
         self.containers.append(container_name)
-
-        # Update container metadata
+        # update container metadata
         metadata = {'name': 'Pictures',
                     'description': 'Travel'
                     }
@@ -122,7 +105,7 @@
                                                             metadata=metadata)
         self.assertEqual(resp['status'], '204')
 
-        # List container metadata
+        # list container metadata
         resp, _ = self.container_client.list_container_metadata(
             container_name)
         self.assertEqual(resp['status'], '204')
@@ -131,18 +114,19 @@
         self.assertEqual(resp['x-container-meta-name'], 'Pictures')
         self.assertEqual(resp['x-container-meta-description'], 'Travel')
 
-        # Delete container metadata
+        # delete container metadata
         resp, _ = self.container_client.delete_container_metadata(
             container_name,
             metadata=metadata.keys())
         self.assertEqual(resp['status'], '204')
 
+        # check if the metadata are no longer there
         resp, _ = self.container_client.list_container_metadata(container_name)
         self.assertEqual(resp['status'], '204')
         self.assertNotIn('x-container-meta-name', resp)
         self.assertNotIn('x-container-meta-description', resp)
 
-        # Delete Container
+        # delete container
         resp, _ = self.container_client.delete_container(container_name)
         self.assertEqual(resp['status'], '204')
         self.containers.remove(container_name)
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
index d5fa96c..666d356 100644
--- a/tempest/tests/object_storage/test_container_sync.py
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -23,11 +23,9 @@
 
 
 class ContainerSyncTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(ContainerSyncTest, cls).setUpClass()
-
         cls.containers = []
         cls.objects = []
         container_sync_timeout = \
@@ -36,8 +34,7 @@
             int(cls.config.object_storage.container_sync_interval)
         cls.attempts = \
             int(container_sync_timeout / cls.container_sync_interval)
-
-        # Define container and object clients
+        # define container and object clients
         cls.clients = {}
         cls.clients[rand_name(name='TestContainerSync')] = \
             (cls.container_client, cls.object_client)
@@ -50,29 +47,25 @@
     @classmethod
     def tearDownClass(cls):
         for cont_name, client in cls.clients.items():
-            #Get list of all object in the container
             objlist = client[0].list_all_container_objects(cont_name)
-
-            #Attempt to delete every object in the container
+            # delete every object in the container
             if objlist:
                 for obj in objlist:
                     resp, _ = client[1].delete_object(cont_name, obj['name'])
-
-            #Attempt to delete the container
+            # delete the container
             resp, _ = client[0].delete_container(cont_name)
 
     @testtools.skip('Until Bug #1093743 is resolved.')
     @attr(type='positive')
     def test_container_synchronization(self):
-        #Container to container synchronization
-        #To allow/accept sync requests to/from other accounts
+        # container to container synchronization
+        # to allow/accept sync requests to/from other accounts
 
-        #Switch container synchronization on and create objects in a containers
+        # turn container synchronization on and create object in container
         for cont in (self.containers, self.containers[::-1]):
             cont_client = [self.clients[c][0] for c in cont]
             obj_client = [self.clients[c][1] for c in cont]
-
-            #tell first container to syncronize to a second
+            # tell first container to synchronize to a second
             headers = {'X-Container-Sync-Key': 'sync_key',
                        'X-Container-Sync-To': "%s/%s" %
                        (cont_client[1].base_url, str(cont[1]))}
@@ -81,8 +74,7 @@
             self.assertTrue(resp['status'] in ('202', '201'),
                             'Error installing X-Container-Sync-To '
                             'for the container "%s"' % (cont[0]))
-
-            #Create Object in container
+            # create object in container
             object_name = rand_name(name='TestSyncObject')
             data = object_name[::-1]  # arbitrary_string()
             resp, _ = obj_client[0].create_object(cont[0], object_name, data)
@@ -92,7 +84,7 @@
                              % (object_name, cont[0]))
             self.objects.append(object_name)
 
-        #Wait for Container contents list json format will be not empty
+        # wait until container contents list is not empty
         cont_client = [self.clients[c][0] for c in self.containers]
         params = {'format': 'json'}
         while self.attempts > 0:
@@ -112,15 +104,13 @@
                              'Error listing the destination container`s'
                              ' "%s" contents' % (self.containers[1]))
             object_list_1 = dict((obj['name'], obj) for obj in object_list_1)
-            # check that containers is not empty and has equal keys()
-            # or wait for next attepmt
+            # check that containers are not empty and have equal keys()
+            # or wait for next attempt
             if not object_list_0 or not object_list_1 or \
                     set(object_list_0.keys()) != set(object_list_1.keys()):
                 time.sleep(self.container_sync_interval)
                 self.attempts -= 1
             else:
                 break
-
-        # Check for synchronization
         self.assertEqual(object_list_0, object_list_1,
                          'Different object lists in containers.')
diff --git a/tempest/tests/object_storage/test_object_expiry.py b/tempest/tests/object_storage/test_object_expiry.py
index e1b1dbd..76370b1 100644
--- a/tempest/tests/object_storage/test_object_expiry.py
+++ b/tempest/tests/object_storage/test_object_expiry.py
@@ -25,12 +25,9 @@
 
 
 class ObjectExpiryTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(ObjectExpiryTest, cls).setUpClass()
-
-        #Create a container
         cls.container_name = rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
 
@@ -41,54 +38,45 @@
         But delete action for the expired object is raising
         NotFound exception and also non empty container cannot be deleted.
         """
-
-        #Get list of all object in the container
         objlist = \
             cls.container_client.list_all_container_objects(cls.container_name)
-
-        #Attempt to delete every object in the container
+        # delete every object in the container
         if objlist:
             for obj in objlist:
                 resp, _ = cls.object_client.delete_object(cls.container_name,
                                                           obj['name'])
-
-        #Attempt to delete the container
+        # delete the container
         resp, _ = cls.container_client.delete_container(cls.container_name)
 
     @testtools.skip('Until Bug #1069849 is resolved.')
     @attr(type='regression')
     def test_get_object_after_expiry_time(self):
-        # GET object after expiry time
-        #TODO(harika-vakadi): Similar test case has to be created for
+        #TODO(harika-vakadi): similar test case has to be created for
         # "X-Delete-At", after this test case works.
 
-        #Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
-        #Update object metadata with expiry time of 3 seconds
+        # update object metadata with expiry time of 3 seconds
         metadata = {'X-Delete-After': '3'}
         resp, _ = \
             self.object_client.update_object_metadata(self.container_name,
                                                       object_name, metadata,
                                                       metadata_prefix='')
-
         resp, _ = \
             self.object_client.list_object_metadata(self.container_name,
                                                     object_name)
-
         self.assertEqual(resp['status'], '200')
         self.assertIn('x-delete-at', resp)
-
         resp, body = self.object_client.get_object(self.container_name,
                                                    object_name)
         self.assertEqual(resp['status'], '200')
-        # Check data
+        # check data
         self.assertEqual(body, data)
-        # Sleep for over 5 seconds, so that object is expired
+        # sleep for over 5 seconds, so that object expires
         time.sleep(5)
-        # Verification of raised exception after object gets expired
+        # object should not be there anymore
         self.assertRaises(exceptions.NotFound, self.object_client.get_object,
                           self.container_name, object_name)
diff --git a/tempest/tests/object_storage/test_object_services.py b/tempest/tests/object_storage/test_object_services.py
index 4fcc617..2c196cf 100644
--- a/tempest/tests/object_storage/test_object_services.py
+++ b/tempest/tests/object_storage/test_object_services.py
@@ -25,55 +25,42 @@
 
 
 class ObjectTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(ObjectTest, cls).setUpClass()
-
-        #Create a container
         cls.container_name = rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
 
-        # Randomly creating user
         cls.data.setup_test_user()
-
         resp, body = cls.token_client.auth(cls.data.test_user,
                                            cls.data.test_password,
                                            cls.data.test_tenant)
         cls.new_token = cls.token_client.get_token(cls.data.test_user,
                                                    cls.data.test_password,
                                                    cls.data.test_tenant)
-
         cls.custom_headers = {'X-Auth-Token': cls.new_token}
 
     @classmethod
     def tearDownClass(cls):
-        #Get list of all object in the container
         objlist = cls.container_client.list_all_container_objects(
             cls.container_name)
-
-        #Attempt to delete every object in the container
+        # delete every object in the container
         for obj in objlist:
             resp, _ = cls.object_client.delete_object(cls.container_name,
                                                       obj['name'])
-
-        #Attempt to delete the container
+        # delete the container
         resp, _ = cls.container_client.delete_container(cls.container_name)
-
-        #Attempt to the delete the user setup created
+        # delete the user setup created
         cls.data.teardown_all()
 
     @attr(type='smoke')
     def test_create_object(self):
-        # Create storage object, test response
-
-        #Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
-        #Create another Object
+        # create another object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
@@ -82,42 +69,36 @@
 
     @attr(type='smoke')
     def test_delete_object(self):
-        # Create and delete a storage object, test responses
-
-        #Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
+        # delete object
         resp, _ = self.object_client.delete_object(self.container_name,
                                                    object_name)
         self.assertEqual(resp['status'], '204')
 
     @attr(type='smoke')
     def test_object_metadata(self):
-        # Add metadata to storage object, test if metadata is retrievable
+        # add metadata to storage object, test if metadata is retrievable
 
-        #Create Object
+        # create Object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
-        #Set Object Metadata
+        # set object metadata
         meta_key = rand_name(name='test-')
         meta_value = rand_name(name='MetaValue-')
         orig_metadata = {meta_key: meta_value}
-
         resp, _ = self.object_client.update_object_metadata(
-            self.container_name, object_name,
-            orig_metadata)
+            self.container_name, object_name, orig_metadata)
         self.assertEqual(resp['status'], '202')
 
-        #Get Object Metadata
+        # get object metadata
         resp, resp_metadata = self.object_client.list_object_metadata(
             self.container_name, object_name)
-
         self.assertEqual(resp['status'], '200')
         actual_meta_key = 'x-object-meta-' + meta_key
         self.assertTrue(actual_meta_key in resp)
@@ -125,138 +106,121 @@
 
     @attr(type='smoke')
     def test_get_object(self):
-        # Retrieve object's data(in response body)
+        # retrieve object's data (in response body)
 
-        #Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
+        # get object
         resp, body = self.object_client.get_object(self.container_name,
                                                    object_name)
         self.assertEqual(resp['status'], '200')
-        # Check data
         self.assertEqual(body, data)
 
     @attr(type='smoke')
     def test_copy_object_in_same_container(self):
-        # Copy storage object
-
-        # Create source Object
+        # create source object
         src_object_name = rand_name(name='SrcObject')
         src_data = arbitrary_string(size=len(src_object_name) * 2,
                                     base_text=src_object_name)
         resp, _ = self.object_client.create_object(self.container_name,
-                                                   src_object_name, src_data)
-
-        # Create destination Object
+                                                   src_object_name,
+                                                   src_data)
+        # create destination object
         dst_object_name = rand_name(name='DstObject')
         dst_data = arbitrary_string(size=len(dst_object_name) * 3,
                                     base_text=dst_object_name)
         resp, _ = self.object_client.create_object(self.container_name,
-                                                   dst_object_name, dst_data)
-
-        # Copy source object to destination
+                                                   dst_object_name,
+                                                   dst_data)
+        # copy source object to destination
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, src_object_name, dst_object_name)
         self.assertEqual(resp['status'], '201')
-
-        # Check data
+        # check data
         resp, body = self.object_client.get_object(self.container_name,
                                                    dst_object_name)
         self.assertEqual(body, src_data)
 
     @attr(type='smoke')
     def test_copy_object_to_itself(self):
-        # Change the content type of an existing object
+        # change the content type of an existing object
 
-        # Create Object
+        # create object
         object_name = rand_name(name='TestObject')
         data = arbitrary_string()
-        resp, _ = self.object_client.create_object(self.container_name,
-                                                   object_name, data)
-        # Get the old content type
+        self.object_client.create_object(self.container_name,
+                                         object_name, data)
+        # get the old content type
         resp_tmp, _ = self.object_client.list_object_metadata(
-            self.container_name,
-            object_name)
-        # Change the content type of the object
+            self.container_name, object_name)
+        # change the content type of the object
         metadata = {'content-type': 'text/plain; charset=UTF-8'}
         self.assertNotEqual(resp_tmp['content-type'], metadata['content-type'])
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, object_name, object_name, metadata)
         self.assertEqual(resp['status'], '201')
-
-        # Check the content type
+        # check the content type
         resp, _ = self.object_client.list_object_metadata(self.container_name,
                                                           object_name)
         self.assertEqual(resp['content-type'], metadata['content-type'])
 
     @attr(type='smoke')
     def test_copy_object_2d_way(self):
-        # Copy storage object
-
-        # Create source Object
+        # create source object
         src_object_name = rand_name(name='SrcObject')
         src_data = arbitrary_string(size=len(src_object_name) * 2,
                                     base_text=src_object_name)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    src_object_name, src_data)
-
-        # Create destination Object
+        # create destination object
         dst_object_name = rand_name(name='DstObject')
         dst_data = arbitrary_string(size=len(dst_object_name) * 3,
                                     base_text=dst_object_name)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    dst_object_name, dst_data)
-
-        # Copy source object to destination
+        # copy source object to destination
         resp, _ = self.object_client.copy_object_2d_way(self.container_name,
                                                         src_object_name,
                                                         dst_object_name)
         self.assertEqual(resp['status'], '201')
-
-        # Check data
+        # check data
         resp, body = self.object_client.get_object(self.container_name,
                                                    dst_object_name)
         self.assertEqual(body, src_data)
 
     @attr(type='smoke')
     def test_copy_object_across_containers(self):
-        # Copy storage object across containers
-
-        #Create a container so as to use as source container
+        # create a container to use as  asource container
         src_container_name = rand_name(name='TestSourceContainer')
         self.container_client.create_container(src_container_name)
-
-        #Create a container so as to use as destination container
+        # create a container to use as a destination container
         dst_container_name = rand_name(name='TestDestinationContainer')
         self.container_client.create_container(dst_container_name)
-
-        # Create Object in source container
+        # create object in source container
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name) * 2,
                                 base_text=object_name)
         resp, _ = self.object_client.create_object(src_container_name,
                                                    object_name, data)
-        #Set Object Metadata
+        # set object metadata
         meta_key = rand_name(name='test-')
         meta_value = rand_name(name='MetaValue-')
         orig_metadata = {meta_key: meta_value}
-
         resp, _ = self.object_client.update_object_metadata(src_container_name,
                                                             object_name,
                                                             orig_metadata)
         self.assertEqual(resp['status'], '202')
-
         try:
-            # Copy object from source container to destination container
+            # copy object from source container to destination container
             resp, _ = self.object_client.copy_object_across_containers(
                 src_container_name, object_name, dst_container_name,
                 object_name)
             self.assertEqual(resp['status'], '201')
 
-            # Check if object is present in destination container
+            # check if object is present in destination container
             resp, body = self.object_client.get_object(dst_container_name,
                                                        object_name)
             self.assertEqual(body, data)
@@ -268,254 +232,25 @@
             self.fail("Got exception :%s ; while copying"
                       " object across containers" % e)
         finally:
-            #Delete objects from respective containers
+            # delete objects from respective containers
             resp, _ = self.object_client.delete_object(dst_container_name,
                                                        object_name)
             resp, _ = self.object_client.delete_object(src_container_name,
                                                        object_name)
-            #Delete containers created in this method
+            # delete containers created in this method
             resp, _ = self.container_client.delete_container(
                 src_container_name)
             resp, _ = self.container_client.delete_container(
                 dst_container_name)
 
-    @attr(type='smoke')
-    def test_access_public_container_object_without_using_creds(self):
-        # Make container public-readable, and access the object
-           # anonymously, e.g. without using credentials
-
-        try:
-            resp_meta = None
-            # Update Container Metadata to make public readable
-            cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers,
-                metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-
-            # Create Object
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name),
-                                    base_text=object_name)
-            resp, _ = self.object_client.create_object(self.container_name,
-                                                       object_name, data)
-            self.assertEqual(resp['status'], '201')
-
-            # List container metadata
-            resp_meta, _ = self.container_client.list_container_metadata(
-                self.container_name)
-            self.assertEqual(resp_meta['status'], '204')
-            self.assertIn('x-container-read', resp_meta)
-            self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings')
-
-            # Trying to Get Object with empty Headers as it is public readable
-            resp, body = self.custom_object_client.get_object(
-                self.container_name, object_name,
-                metadata={})
-            self.assertEqual(body, data)
-        finally:
-            if resp_meta['status'] == '204':
-                # Delete updated container metadata, to revert back.
-                resp, body = self.container_client.delete_container_metadata(
-                    self.container_name, metadata=cont_headers,
-                    metadata_prefix='')
-
-                resp, _ = self.container_client.list_container_metadata(
-                    self.container_name)
-                self.assertEqual(resp['status'], '204')
-                self.assertIn('x-container-read', resp)
-                self.assertEqual(resp['x-container-read'], 'x')
-
-    @attr(type='smoke')
-    def test_access_public_object_with_another_user_creds(self):
-        #Make container public-readable, and access the object
-            #anonymously, e.g. using another user credentials
-
-        try:
-            resp_meta = None
-            cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers,
-                metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-            # Create Object
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name) * 1,
-                                    base_text=object_name)
-            resp, _ = self.object_client.create_object(self.container_name,
-                                                       object_name, data)
-            self.assertEqual(resp['status'], '201')
-
-            # List container metadata
-            resp, _ = self.container_client.list_container_metadata(
-                self.container_name)
-            self.assertEqual(resp['status'], '204')
-            self.assertIn('x-container-read', resp)
-            self.assertEqual(resp['x-container-read'], '.r:*,.rlistings')
-
-            # Trying to GET Auth Token of Alternate user
-            token = self.identity_client_alt.get_auth()
-            headers = {'X-Auth-Token': token}
-
-            # Trying to create object with Alternate user creds
-            resp, body = self.custom_object_client.get_object(
-                self.container_name, object_name,
-                metadata=headers)
-            self.assertEqual(body, data)
-
-        except Exception as e:
-            self.fail("Failed to get public readable object with another"
-                      " user creds raised exception is %s" % e)
-
-        finally:
-            if resp_meta['status'] == '204':
-                # Delete updated container metadata, to revert back.
-                resp, body = self.container_client.delete_container_metadata(
-                    self.container_name, metadata=cont_headers,
-                    metadata_prefix='')
-
-                resp, _ = self.container_client.list_container_metadata(
-                    self.container_name)
-                self.assertEqual(resp['status'], '204')
-                self.assertIn('x-container-read', resp)
-                self.assertEqual(resp['x-container-read'], 'x')
-
-    @testtools.skip('Until Bug #1020722 is resolved.')
-    @attr(type='smoke')
-    def test_write_public_object_without_using_creds(self):
-        #Make container public-writable, and create object
-            #anonymously, e.g. without using credentials
-        try:
-            resp_meta = None
-            # Update Container Metadata to make public readable
-            cont_headers = {'X-Container-Write': '-*'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers,
-                metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-            # List container metadata
-            resp, _ = self.container_client.list_container_metadata(
-                self.container_name)
-
-            self.assertEqual(resp['status'], '204')
-            self.assertIn('x-container-write', resp)
-            self.assertEqual(resp['x-container-write'], '-*')
-
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name),
-                                    base_text=object_name)
-
-            headers = {'Content-Type': 'application/json',
-                       'Accept': 'application/json'}
-
-            #Trying to Create object without using creds
-            resp, body = self.custom_object_client.create_object(
-                self.container_name, object_name,
-                data, metadata=headers)
-            self.assertEqual(resp['status'], '201')
-
-        except Exception as e:
-            self.fail("Failed to create public writable object without using"
-                      " creds raised exception is %s" % e)
-
-        finally:
-            if resp_meta['status'] == '204':
-                # Delete updated container metadata, to revert back.
-                resp, body = self.container_client.delete_container_metadata(
-                    self.container_name, metadata=cont_headers,
-                    metadata_prefix='')
-
-                resp, _ = self.container_client.list_container_metadata(
-                    self.container_name)
-                self.assertEqual(resp['status'], '204')
-                self.assertIn('x-container-write', resp)
-                self.assertEqual(resp['x-container-write'], 'x')
-
-    @testtools.skip('Until Bug #1020722 is resolved.')
-    @attr(type='smoke')
-    def test_write_public_with_another_user_creds(self):
-        #Make container public-writable, and create object
-            #anonymously, e.g. with another user credentials
-
-        try:
-            resp_meta = None
-            # Update Container Metadata to make public readable
-            cont_headers = {'X-Container-Write': '-*'}
-            resp_meta, body = self.container_client.update_container_metadata(
-                self.container_name, metadata=cont_headers,
-                metadata_prefix='')
-            self.assertEqual(resp_meta['status'], '204')
-            # List container metadata
-            resp, _ = self.container_client.list_container_metadata(
-                self.container_name)
-
-            self.assertEqual(resp['status'], '204')
-            self.assertIn('x-container-write', resp)
-            self.assertEqual(resp['x-container-write'], '-*')
-
-            #Trying to GET auth token of Alternate user
-            token = self.identity_client_alt.get_auth()
-
-            headers = {'Content-Type': 'application/json',
-                       'Accept': 'application/json',
-                       'X-Auth-Token': token}
-
-            #Trying to Create an object with another user creds
-            object_name = rand_name(name='Object')
-            data = arbitrary_string(size=len(object_name),
-                                    base_text=object_name)
-            resp, body = self.custom_object_client.create_object(
-                self.container_name, object_name,
-                data, metadata=headers)
-            self.assertEqual(resp['status'], '201')
-
-        except Exception as e:
-            self.fail("Failed to create public writable object with another"
-                      " user creds raised exception is %s" % e)
-
-        finally:
-            if resp_meta['status'] == '204':
-                # Delete updated container metadata, to revert back.
-                resp, body = self.container_client.delete_container_metadata(
-                    self.container_name, metadata=cont_headers,
-                    metadata_prefix='')
-
-                resp, _ = self.container_client.list_container_metadata(
-                    self.container_name)
-                self.assertEqual(resp['status'], '204')
-                self.assertIn('x-container-write', resp)
-                self.assertEqual(resp['x-container-write'], 'x')
-
-    @attr(type='negative')
-    def test_access_object_without_using_creds(self):
-        # Attempt to access the object anonymously, e.g.
-            # not using any credentials
-
-        # Create Object
-        object_name = rand_name(name='Object')
-        data = arbitrary_string(size=len(object_name),
-                                base_text=object_name)
-        resp, _ = self.object_client.create_object(self.container_name,
-                                                   object_name, data)
-        self.assertEqual(resp['status'], '201')
-
-        # Trying to Get Object with empty Headers
-        self.assertRaises(exceptions.Unauthorized,
-                          self.custom_object_client.get_object,
-                          self.container_name, object_name, metadata={})
-
     @attr(type='negative')
     def test_write_object_without_using_creds(self):
-        # Attempt to write to the object anonymously, e.g.
-        # not using any credentials
-
-        # Trying to Create Object with empty Headers
+        # trying to create object with empty headers
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name),
                                 base_text=object_name)
         obj_headers = {'Content-Type': 'application/json',
                        'Accept': 'application/json'}
-
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.create_object,
                           self.container_name, object_name, data,
@@ -523,30 +258,25 @@
 
     @attr(type='negative')
     def test_delete_object_without_using_creds(self):
-        # Attempt to delete the object anonymously,
-            # e.g. not using any credentials
-
-        # Create Object
+        # create object
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name),
                                 base_text=object_name)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-
-        # Trying to Delete Object with empty Headers
+        # trying to delete object with empty headers
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.delete_object,
                           self.container_name, object_name)
 
     @attr(type='negative')
     def test_write_object_with_non_authorized_user(self):
-        #Attempt to upload another file using non authorized user
-
+        # attempt to upload another file using non-authorized user
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name) * 5,
                                 base_text=object_name)
 
-        # Trying to Create Object with non authorized user token
+        # trying to create object with non-authorized user
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.create_object,
                           self.container_name, object_name, data,
@@ -554,18 +284,14 @@
 
     @attr(type='negative')
     def test_read_object_with_non_authorized_user(self):
-        #Attempt to download the file using non authorized user
-
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name) * 5,
                                 base_text=object_name)
-
         resp, body = self.object_client.create_object(
-            self.container_name, object_name,
-            data)
+            self.container_name, object_name, data)
         self.assertEqual(resp['status'], '201')
 
-        # Trying to Get Object with non authorized user token
+        # trying to get object with non authorized user token
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.get_object,
                           self.container_name, object_name,
@@ -573,18 +299,13 @@
 
     @attr(type='negative')
     def test_delete_object_with_non_authorized_user(self):
-        #Attempt to delete container using non authorized user
-
         object_name = rand_name(name='Object')
         data = arbitrary_string(size=len(object_name) * 5,
                                 base_text=object_name)
-
         resp, body = self.object_client.create_object(
-            self.container_name, object_name,
-            data)
+            self.container_name, object_name, data)
         self.assertEqual(resp['status'], '201')
-
-        # Trying to Delete Object with non authorized user token
+        # trying to delete object with non-authorized user token
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.delete_object,
                           self.container_name, object_name,
@@ -593,11 +314,11 @@
     @testtools.skip('Until Bug #1097137 is resolved.')
     @attr(type='positive')
     def test_get_object_using_temp_url(self):
-        #Access object using temp url within expiry time
+        # access object using temporary URL within expiration time
 
         try:
-            #Update Account Metadata
-            # Flag to check if account metadata got updated
+            # update account metadata
+            # flag to check if account metadata got updated
             flag = False
             key = 'Meta'
             metadata = {'Temp-URL-Key': key}
@@ -605,27 +326,23 @@
                 metadata=metadata)
             self.assertEqual(resp['status'], '204')
             flag = True
-
             resp, _ = self.account_client.list_account_metadata()
             self.assertIn('x-account-meta-temp-url-key', resp)
             self.assertEqual(resp['x-account-meta-temp-url-key'], key)
 
-            # Create Object
+            # create object
             object_name = rand_name(name='ObjectTemp')
             data = arbitrary_string(size=len(object_name),
                                     base_text=object_name)
             self.object_client.create_object(self.container_name,
                                              object_name, data)
-
             expires = int(time.time() + 10)
 
-            #Trying to GET object using temp URL with in expiry time
+            # trying to get object using temp url with in expiry time
             _, body = self.object_client.get_object_using_temp_url(
                 self.container_name, object_name,
                 expires, key)
-
             self.assertEqual(body, data)
-
         finally:
             if flag:
                 resp, _ = self.account_client.delete_account_metadata(
@@ -635,35 +352,183 @@
 
     @attr(type='positive')
     def test_object_upload_in_segments(self):
-        #Attempt to upload object in segments
-
-        #Create Object
+        # create object
         object_name = rand_name(name='LObject')
         data = arbitrary_string(size=len(object_name),
                                 base_text=object_name)
         segments = 10
         self.object_client.create_object(self.container_name,
                                          object_name, data)
-        #Uploading 10 segments
+        # uploading 10 segments
         for i in range(segments):
             resp, _ = self.object_client.create_object_segments(
-                self.container_name, object_name,
-                i, data)
-        # Creating a Manifest File (Metadata Update)
-
+                self.container_name, object_name, i, data)
+        # creating a manifest file (metadata update)
         metadata = {'X-Object-Manifest': '%s/%s/'
                     % (self.container_name, object_name)}
         resp, _ = self.object_client.update_object_metadata(
-            self.container_name, object_name,
-            metadata, metadata_prefix='')
+            self.container_name, object_name, metadata, metadata_prefix='')
         resp, _ = self.object_client.list_object_metadata(
             self.container_name, object_name)
         self.assertIn('x-object-manifest', resp)
         self.assertEqual(resp['x-object-manifest'],
                          '%s/%s/' % (self.container_name, object_name))
 
-        #Downloading the object
+        # downloading the object
         resp, body = self.object_client.get_object(
             self.container_name, object_name)
-
         self.assertEqual(data * segments, body)
+
+
+class PublicObjectTest(base.BaseObjectTest):
+    def setUp(self):
+        super(PublicObjectTest, self).setUp()
+        self.container_name = rand_name(name='TestContainer')
+        self.container_client.create_container(self.container_name)
+
+    def tearDown(self):
+        objlist = self.container_client.list_all_container_objects(
+            self.container_name)
+        # delete every object in the container
+        for obj in objlist:
+            resp, _ = self.object_client.delete_object(
+                self.container_name, obj['name'])
+        # delete the container
+        resp, _ = self.container_client.delete_container(self.container_name)
+        super(PublicObjectTest, self).tearDown()
+
+    @attr(type='smoke')
+    def test_access_public_container_object_without_using_creds(self):
+        # make container public-readable and access an object in it object
+        # anonymously, without using credentials
+
+        # update container metadata to make it publicly readable
+        cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
+        resp_meta, body = self.container_client.update_container_metadata(
+            self.container_name, metadata=cont_headers, metadata_prefix='')
+        self.assertEqual(resp_meta['status'], '204')
+        # create object
+        object_name = rand_name(name='Object')
+        data = arbitrary_string(size=len(object_name),
+                                base_text=object_name)
+        resp, _ = self.object_client.create_object(self.container_name,
+                                                   object_name, data)
+        self.assertEqual(resp['status'], '201')
+
+        # list container metadata
+        resp_meta, _ = self.container_client.list_container_metadata(
+            self.container_name)
+        self.assertEqual(resp_meta['status'], '204')
+        self.assertIn('x-container-read', resp_meta)
+        self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings')
+
+        # trying to get object with empty headers as it is public readable
+        resp, body = self.custom_object_client.get_object(
+            self.container_name, object_name, metadata={})
+        self.assertEqual(body, data)
+
+    @attr(type='smoke')
+    def test_access_public_object_with_another_user_creds(self):
+        # make container public-readable and access an object in it using
+        # another user's credentials
+        try:
+            cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
+            resp_meta, body = self.container_client.update_container_metadata(
+                self.container_name, metadata=cont_headers,
+                metadata_prefix='')
+            self.assertEqual(resp_meta['status'], '204')
+            # create object
+            object_name = rand_name(name='Object')
+            data = arbitrary_string(size=len(object_name) * 1,
+                                    base_text=object_name)
+            resp, _ = self.object_client.create_object(self.container_name,
+                                                       object_name, data)
+            self.assertEqual(resp['status'], '201')
+
+            # list container metadata
+            resp, _ = self.container_client.list_container_metadata(
+                self.container_name)
+            self.assertEqual(resp['status'], '204')
+            self.assertIn('x-container-read', resp)
+            self.assertEqual(resp['x-container-read'], '.r:*,.rlistings')
+
+            # get auth token of alternative user
+            token = self.identity_client_alt.get_auth()
+            headers = {'X-Auth-Token': token}
+            # access object using alternate user creds
+            resp, body = self.custom_object_client.get_object(
+                self.container_name, object_name,
+                metadata=headers)
+            self.assertEqual(body, data)
+
+        except Exception as e:
+            self.fail("Failed to get public readable object with another"
+                      " user creds raised exception is %s" % e)
+
+    @testtools.skip('Until Bug #1020722 is resolved.')
+    @attr(type='smoke')
+    def test_write_public_object_without_using_creds(self):
+        # make container public-writable, and create object anonymously, e.g.
+        # without using credentials
+        try:
+            # update container metadata to make publicly writable
+            cont_headers = {'X-Container-Write': '-*'}
+            resp_meta, body = self.container_client.update_container_metadata(
+                self.container_name, metadata=cont_headers, metadata_prefix='')
+            self.assertEqual(resp_meta['status'], '204')
+            # list container metadata
+            resp, _ = self.container_client.list_container_metadata(
+                self.container_name)
+            self.assertEqual(resp['status'], '204')
+            self.assertIn('x-container-write', resp)
+            self.assertEqual(resp['x-container-write'], '-*')
+
+            object_name = rand_name(name='Object')
+            data = arbitrary_string(size=len(object_name),
+                                    base_text=object_name)
+            headers = {'Content-Type': 'application/json',
+                       'Accept': 'application/json'}
+            # create object as anonymous user
+            resp, body = self.custom_object_client.create_object(
+                self.container_name, object_name, data, metadata=headers)
+            self.assertEqual(resp['status'], '201')
+
+        except Exception as e:
+            self.fail("Failed to create public writable object without using"
+                      " creds raised exception is %s" % e)
+
+    @testtools.skip('Until Bug #1020722 is resolved.')
+    @attr(type='smoke')
+    def test_write_public_with_another_user_creds(self):
+        # make container public-writable, and create object with another user's
+        # credentials
+        try:
+            # update container metadata to make it publicly writable
+            cont_headers = {'X-Container-Write': '-*'}
+            resp_meta, body = self.container_client.update_container_metadata(
+                self.container_name, metadata=cont_headers,
+                metadata_prefix='')
+            self.assertEqual(resp_meta['status'], '204')
+            # list container metadata
+            resp, _ = self.container_client.list_container_metadata(
+                self.container_name)
+            self.assertEqual(resp['status'], '204')
+            self.assertIn('x-container-write', resp)
+            self.assertEqual(resp['x-container-write'], '-*')
+
+            # trying to get auth token of alternative user
+            token = self.identity_client_alt.get_auth()
+            headers = {'Content-Type': 'application/json',
+                       'Accept': 'application/json',
+                       'X-Auth-Token': token}
+
+            # trying to create an object with another user's creds
+            object_name = rand_name(name='Object')
+            data = arbitrary_string(size=len(object_name),
+                                    base_text=object_name)
+            resp, body = self.custom_object_client.create_object(
+                self.container_name, object_name, data, metadata=headers)
+            self.assertEqual(resp['status'], '201')
+        except Exception as e:
+            self.fail("Failed to create public writable object with another"
+                      " user creds raised exception is %s" % e)
diff --git a/tempest/tests/object_storage/test_object_version.py b/tempest/tests/object_storage/test_object_version.py
index 80cfc27..4a16965 100644
--- a/tempest/tests/object_storage/test_object_version.py
+++ b/tempest/tests/object_storage/test_object_version.py
@@ -21,7 +21,6 @@
 
 
 class ContainerTest(base.BaseObjectTest):
-
     @classmethod
     def setUpClass(cls):
         super(ContainerTest, cls).setUpClass()
@@ -30,16 +29,13 @@
     @classmethod
     def tearDownClass(cls):
         for container in cls.containers:
-            #Get list of all object in the container
             objlist = \
                 cls.container_client.list_all_container_objects(container)
-
-            #Attempt to delete every object in the container
+            # delete every object in the container
             for obj in objlist:
                 resp, _ = \
                     cls.object_client.delete_object(container, obj['name'])
-
-            #Attempt to delete the container
+            # delete the container
             resp, _ = cls.container_client.delete_container(container)
 
     def assertContainer(self, container, count, byte, versioned):
@@ -54,16 +50,13 @@
 
     @attr(type='smoke')
     def test_versioned_container(self):
-        # Versioned container responses tests
-
-        # Create a containers
+        # create container
         vers_container_name = rand_name(name='TestVersionContainer')
         resp, body = self.container_client.create_container(
             vers_container_name)
         self.containers.append(vers_container_name)
         self.assertIn(resp['status'], ('202', '201'))
-        self.assertContainer(vers_container_name, '0', '0',
-                             'Missing Header')
+        self.assertContainer(vers_container_name, '0', '0', 'Missing Header')
 
         base_container_name = rand_name(name='TestBaseContainer')
         headers = {'X-versions-Location': vers_container_name}
@@ -75,18 +68,17 @@
         self.assertIn(resp['status'], ('202', '201'))
         self.assertContainer(base_container_name, '0', '0',
                              vers_container_name)
-        # Create Object
         object_name = rand_name(name='TestObject')
+        # create object
         resp, _ = self.object_client.create_object(base_container_name,
                                                    object_name, '1')
-
+        # create 2nd version of object
         resp, _ = self.object_client.create_object(base_container_name,
                                                    object_name, '2')
-
         resp, body = self.object_client.get_object(base_container_name,
                                                    object_name)
         self.assertEqual(body, '2')
-        # Delete Object version 2
+        # delete object version 2
         resp, _ = self.object_client.delete_object(base_container_name,
                                                    object_name)
         self.assertContainer(base_container_name, '1', '1',
@@ -94,21 +86,18 @@
         resp, body = self.object_client.get_object(base_container_name,
                                                    object_name)
         self.assertEqual(body, '1')
-
-        # Delete Object version 1
+        # delete object version 1
         resp, _ = self.object_client.delete_object(base_container_name,
                                                    object_name)
-        # Containers are Empty
+        # containers should be empty
         self.assertContainer(base_container_name, '0', '0',
                              vers_container_name)
         self.assertContainer(vers_container_name, '0', '0',
                              'Missing Header')
-
-        # Delete Containers
+        # delete containers
         resp, _ = self.container_client.delete_container(base_container_name)
         self.assertEqual(resp['status'], '204')
         self.containers.remove(base_container_name)
-
         resp, _ = self.container_client.delete_container(vers_container_name)
         self.assertEqual(resp['status'], '204')
         self.containers.remove(vers_container_name)
diff --git a/tempest/tests/volume/admin/test_multi_backend.py b/tempest/tests/volume/admin/test_multi_backend.py
index 3d5fae4..93b3b77 100644
--- a/tempest/tests/volume/admin/test_multi_backend.py
+++ b/tempest/tests/volume/admin/test_multi_backend.py
@@ -22,6 +22,7 @@
 from tempest import config
 from tempest.services.volume.json.admin import volume_types_client
 from tempest.services.volume.json import volumes_client
+from tempest.test import attr
 from tempest.tests.volume import base
 
 LOG = logging.getLogger(__name__)
@@ -108,6 +109,7 @@
 
         super(VolumeMultiBackendTest, cls).tearDownClass()
 
+    @attr(type=['smoke'])
     def test_multi_backend_enabled(self):
         # this test checks that multi backend is enabled for at least the
         # computes where the volumes created in setUp were made
@@ -131,6 +133,7 @@
                "%(volume_host2)s") % locals()
         self.assertTrue(len(volume_host2.split("@")) > 1, msg)
 
+    @attr(type='gate')
     def test_backend_name_distinction(self):
         # this test checks that the two volumes created at setUp doesn't
         # belong to the same backend (if they are in the same backend, that
diff --git a/tempest/tests/volume/admin/test_volume_types.py b/tempest/tests/volume/admin/test_volume_types.py
index 13efca7..a35f017 100644
--- a/tempest/tests/volume/admin/test_volume_types.py
+++ b/tempest/tests/volume/admin/test_volume_types.py
@@ -17,6 +17,7 @@
 
 from tempest.common.utils.data_utils import rand_name
 from tempest.services.volume.json.admin import volume_types_client
+from tempest.test import attr
 from tempest.tests.volume.base import BaseVolumeTest
 
 
@@ -37,6 +38,7 @@
                                                                auth_url,
                                                                adm_tenant)
 
+    @attr(type=['smoke'])
     def test_volume_type_list(self):
         # List Volume types.
         try:
@@ -46,6 +48,7 @@
         except Exception:
             self.fail("Could not list volume types")
 
+    @attr(type=['smoke'])
     def test_create_get_delete_volume_with_volume_type_and_extra_specs(self):
         # Create/get/delete volume with volume_type and extra spec.
         try:
@@ -97,6 +100,7 @@
                 resp, _ = self.client.delete_volume_type(body['id'])
                 self.assertEqual(202, resp.status)
 
+    @attr(type=['smoke'])
     def test_volume_type_create_delete(self):
         # Create/Delete volume type.
         try:
@@ -119,6 +123,7 @@
         except Exception:
             self.fail("Could not create a volume_type")
 
+    @attr(type=['smoke'])
     def test_volume_type_create_get(self):
         # Create/get volume type.
         try:
diff --git a/tempest/tests/volume/admin/test_volume_types_extra_specs.py b/tempest/tests/volume/admin/test_volume_types_extra_specs.py
index 1cd7653..aeb58c7 100644
--- a/tempest/tests/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/tests/volume/admin/test_volume_types_extra_specs.py
@@ -16,6 +16,7 @@
 #    under the License.
 
 from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
 from tempest.tests.volume import base
 
 
@@ -33,6 +34,7 @@
         cls.client.delete_volume_type(cls.volume_type['id'])
         super(VolumeTypesExtraSpecsTest, cls).tearDownClass()
 
+    @attr(type=['smoke'])
     def test_volume_type_extra_specs_list(self):
         # List Volume types extra specs.
         try:
@@ -51,6 +53,7 @@
         except Exception:
             self.fail("Could not list volume types extra specs")
 
+    @attr(type=['gate'])
     def test_volume_type_extra_specs_update(self):
         # Update volume type extra specs
         try:
@@ -74,6 +77,7 @@
         except Exception:
             self.fail("Couldnt update volume type extra spec")
 
+    @attr(type=['smoke'])
     def test_volume_type_extra_spec_create_get_delete(self):
         # Create/Get/Delete volume type extra spec.
         try:
diff --git a/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py
index bd6e279..4a1a0b2 100644
--- a/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.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.tests.volume import base
 
 
@@ -39,6 +40,7 @@
         cls.client.delete_volume_type(cls.volume_type['id'])
         super(ExtraSpecsNegativeTest, cls).tearDownClass()
 
+    @attr(type='gate')
     def test_update_no_body(self):
         # Should not update volume type extra specs with no body
         extra_spec = {"spec1": "val2"}
@@ -46,6 +48,7 @@
                           self.client.update_volume_type_extra_specs,
                           self.volume_type['id'], extra_spec.keys()[0], None)
 
+    @attr(type='gate')
     def test_update_nonexistent_extra_spec_id(self):
         # Should not update volume type extra specs with nonexistent id.
         extra_spec = {"spec1": "val2"}
@@ -54,6 +57,7 @@
                           self.volume_type['id'], str(uuid.uuid4()),
                           extra_spec)
 
+    @attr(type='gate')
     def test_update_none_extra_spec_id(self):
         # Should not update volume type extra specs with none id.
         extra_spec = {"spec1": "val2"}
@@ -61,6 +65,7 @@
                           self.client.update_volume_type_extra_specs,
                           self.volume_type['id'], None, extra_spec)
 
+    @attr(type='gate')
     def test_update_multiple_extra_spec(self):
         # Should not update volume type extra specs with multiple specs as
             # body.
@@ -70,6 +75,7 @@
                           self.volume_type['id'], extra_spec.keys()[0],
                           extra_spec)
 
+    @attr(type='gate')
     def test_create_nonexistent_type_id(self):
         # Should not create volume type extra spec for nonexistent volume
             # type id.
@@ -78,18 +84,21 @@
                           self.client.create_volume_type_extra_specs,
                           str(uuid.uuid4()), extra_specs)
 
+    @attr(type='gate')
     def test_create_none_body(self):
         # Should not create volume type extra spec for none POST body.
         self.assertRaises(exceptions.BadRequest,
                           self.client.create_volume_type_extra_specs,
                           self.volume_type['id'], None)
 
+    @attr(type='gate')
     def test_create_invalid_body(self):
         # Should not create volume type extra spec for invalid POST body.
         self.assertRaises(exceptions.BadRequest,
                           self.client.create_volume_type_extra_specs,
                           self.volume_type['id'], ['invalid'])
 
+    @attr(type='gate')
     def test_delete_nonexistent_volume_type_id(self):
         # Should not delete volume type extra spec for nonexistent
             # type id.
@@ -98,12 +107,14 @@
                           self.client.delete_volume_type_extra_specs,
                           str(uuid.uuid4()), extra_specs.keys()[0])
 
+    @attr(type='gate')
     def test_list_nonexistent_volume_type_id(self):
         # Should not list volume type extra spec for nonexistent type id.
         self.assertRaises(exceptions.NotFound,
                           self.client.list_volume_types_extra_specs,
                           str(uuid.uuid4()))
 
+    @attr(type='gate')
     def test_get_nonexistent_volume_type_id(self):
         # Should not get volume type extra spec for nonexistent type id.
         extra_specs = {"spec1": "val1"}
@@ -111,6 +122,7 @@
                           self.client.get_volume_type_extra_specs,
                           str(uuid.uuid4()), extra_specs.keys()[0])
 
+    @attr(type='gate')
     def test_get_nonexistent_extra_spec_id(self):
         # Should not get volume type extra spec for nonexistent extra spec
             # id.
diff --git a/tempest/tests/volume/admin/test_volume_types_negative.py b/tempest/tests/volume/admin/test_volume_types_negative.py
index daf804d..bd358b8 100644
--- a/tempest/tests/volume/admin/test_volume_types_negative.py
+++ b/tempest/tests/volume/admin/test_volume_types_negative.py
@@ -18,12 +18,14 @@
 import uuid
 
 from tempest import exceptions
+from tempest.test import attr
 from tempest.tests.volume import base
 
 
 class VolumeTypesNegativeTest(base.BaseVolumeAdminTest):
     _interface = 'json'
 
+    @attr(type='gate')
     def test_create_with_nonexistent_volume_type(self):
         # Should not be able to create volume with nonexistent volume_type.
         self.assertRaises(exceptions.NotFound,
@@ -31,16 +33,19 @@
                           display_name=str(uuid.uuid4()),
                           volume_type=str(uuid.uuid4()))
 
+    @attr(type='gate')
     def test_create_with_empty_name(self):
         # Should not be able to create volume type with an empty name.
         self.assertRaises(exceptions.BadRequest,
                           self.client.create_volume_type, '')
 
+    @attr(type='gate')
     def test_get_nonexistent_type_id(self):
         # Should not be able to get volume type with nonexistent type id.
         self.assertRaises(exceptions.NotFound, self.client.get_volume_type,
                           str(uuid.uuid4()))
 
+    @attr(type='gate')
     def test_delete_nonexistent_type_id(self):
         # Should not be able to delete volume type with nonexistent type id.
         self.assertRaises(exceptions.NotFound, self.client.delete_volume_type,
diff --git a/tempest/tests/volume/test_volumes_actions.py b/tempest/tests/volume/test_volumes_actions.py
index e6eb8d8..8664a7d 100644
--- a/tempest/tests/volume/test_volumes_actions.py
+++ b/tempest/tests/volume/test_volumes_actions.py
@@ -52,7 +52,7 @@
 
         super(VolumesActionsTest, cls).tearDownClass()
 
-    @attr(type='smoke')
+    @attr(type=['smoke'])
     def test_attach_detach_volume_to_instance(self):
         # Volume is attached and detached successfully from an instance
         try:
@@ -70,6 +70,7 @@
             self.assertEqual(202, resp.status)
             self.client.wait_for_volume_status(self.volume['id'], 'available')
 
+    @attr(type='gate')
     def test_get_volume_attachment(self):
         # Verify that a volume's attachment information is retrieved
         mountpoint = '/dev/vdc'
diff --git a/tempest/tests/volume/test_volumes_get.py b/tempest/tests/volume/test_volumes_get.py
index 8e80e18..65748e8 100644
--- a/tempest/tests/volume/test_volumes_get.py
+++ b/tempest/tests/volume/test_volumes_get.py
@@ -78,7 +78,7 @@
                 self.assertEqual(202, resp.status)
                 self.client.wait_for_resource_deletion(volume['id'])
 
-    @attr(type='positive')
+    @attr(type='gate')
     def test_volume_get_metadata_none(self):
         # Create a volume without passing metadata, get details, and delete
         try:
@@ -105,11 +105,11 @@
                 self.assertEqual(202, resp.status)
                 self.client.wait_for_resource_deletion(volume['id'])
 
-    @attr(type='smoke')
+    @attr(type=['smoke'])
     def test_volume_create_get_delete(self):
         self._volume_create_get_delete(image_ref=None)
 
-    @attr(type='smoke')
+    @attr(type=['smoke'])
     def test_volume_from_image(self):
         self._volume_create_get_delete(image_ref=self.config.compute.image_ref)
 
diff --git a/tempest/tests/volume/test_volumes_list.py b/tempest/tests/volume/test_volumes_list.py
index a8fedb9..7f5c756 100644
--- a/tempest/tests/volume/test_volumes_list.py
+++ b/tempest/tests/volume/test_volumes_list.py
@@ -76,7 +76,7 @@
             cls.client.wait_for_resource_deletion(volid)
         super(VolumesListTest, cls).tearDownClass()
 
-    @attr(type='smoke')
+    @attr(type=['smoke'])
     def test_volume_list(self):
         # Get a list of Volumes
         # Fetch all volumes
@@ -89,7 +89,7 @@
                          ', '.join(m_vol['display_name']
                                    for m_vol in missing_vols))
 
-    @attr(type='smoke')
+    @attr(type='gate')
     def test_volume_list_with_details(self):
         # Get a list of Volumes with details
         # Fetch all Volumes
diff --git a/tempest/tests/volume/test_volumes_negative.py b/tempest/tests/volume/test_volumes_negative.py
index c7d4374..f02bb3f 100644
--- a/tempest/tests/volume/test_volumes_negative.py
+++ b/tempest/tests/volume/test_volumes_negative.py
@@ -17,6 +17,7 @@
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
+from tempest.test import attr
 from tempest.tests.volume import base
 
 
@@ -28,6 +29,7 @@
         super(VolumesNegativeTest, cls).setUpClass()
         cls.client = cls.volumes_client
 
+    @attr(type='gate')
     def test_volume_get_nonexistant_volume_id(self):
         # Should not be able to get a nonexistant volume
         #Creating a nonexistant volume id
@@ -43,6 +45,7 @@
         self.assertRaises(exceptions.NotFound, self.client.get_volume,
                           non_exist_id)
 
+    @attr(type='gate')
     def test_volume_delete_nonexistant_volume_id(self):
         # Should not be able to delete a nonexistant Volume
         # Creating nonexistant volume id
@@ -58,6 +61,7 @@
         self.assertRaises(exceptions.NotFound, self.client.delete_volume,
                           non_exist_id)
 
+    @attr(type='gate')
     def test_create_volume_with_invalid_size(self):
         # Should not be able to create volume with invalid size
         # in request
@@ -66,6 +70,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='#$%', display_name=v_name, metadata=metadata)
 
+    @attr(type='gate')
     def test_create_volume_with_out_passing_size(self):
         # Should not be able to create volume without passing size
         # in request
@@ -74,6 +79,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='', display_name=v_name, metadata=metadata)
 
+    @attr(type='gate')
     def test_create_volume_with_size_zero(self):
         # Should not be able to create volume with size zero
         v_name = rand_name('Volume-')
@@ -81,20 +87,24 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='0', display_name=v_name, metadata=metadata)
 
+    @attr(type='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')
     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')
     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')
     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/tests/volume/test_volumes_snapshots.py b/tempest/tests/volume/test_volumes_snapshots.py
index ba8ba6c..935d42e 100644
--- a/tempest/tests/volume/test_volumes_snapshots.py
+++ b/tempest/tests/volume/test_volumes_snapshots.py
@@ -37,7 +37,7 @@
     def tearDownClass(cls):
         super(VolumesSnapshotTest, cls).tearDownClass()
 
-    @attr(type='smoke')
+    @attr(type=['smoke'])
     def test_snapshot_create_get_delete(self):
         # Create a snapshot, get some of the details and then deletes it
         resp, snapshot = self.snapshots_client.create_snapshot(
@@ -52,6 +52,7 @@
         self.snapshots_client.delete_snapshot(snapshot['id'])
         self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
 
+    @attr(type=['smoke'])
     def test_volume_from_snapshot(self):
         # Create a temporary snap using wrapper method from base, then
         # create a snap based volume, check resp code and deletes it
diff --git a/tempest/thirdparty/README.rst b/tempest/thirdparty/README.rst
new file mode 100644
index 0000000..41d31f3
--- /dev/null
+++ b/tempest/thirdparty/README.rst
@@ -0,0 +1,33 @@
+Tempest Guide to Third Party API tests
+========
+
+
+What are these tests?
+--------
+
+Third party tests are tests for non native OpenStack APIs that are
+part of OpenStack projects. If we ship an API, we're really required
+to ensure that it's working.
+
+An example is that Nova Compute currently has EC2 API support in tree,
+which should be tested as part of normal process.
+
+
+Why are these tests in tempest?
+--------
+
+If we ship an API in an OpenStack component, there should be tests in
+tempest to exercise it in some way.
+
+
+Scope of these tests
+--------
+
+Third party API testing should be limited to the functional testing of
+third party API compliance. Complex scenarios should be avoided, and
+instead exercised with the OpenStack API, unless the third party API
+can't be tested without those scenarios.
+
+Whenever possible third party API testing should use a client as close
+to the third party API as possible. The point of these tests is API
+validation.
diff --git a/tempest/tests/boto/__init__.py b/tempest/thirdparty/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tempest/thirdparty/__init__.py
diff --git a/tempest/tests/boto/__init__.py b/tempest/thirdparty/boto/__init__.py
similarity index 100%
rename from tempest/tests/boto/__init__.py
rename to tempest/thirdparty/boto/__init__.py
diff --git a/tempest/testboto.py b/tempest/thirdparty/boto/test.py
similarity index 98%
rename from tempest/testboto.py
rename to tempest/thirdparty/boto/test.py
index 9e652cb..afa5c69 100644
--- a/tempest/testboto.py
+++ b/tempest/thirdparty/boto/test.py
@@ -32,9 +32,9 @@
 import tempest.config
 from tempest import exceptions
 import tempest.test
-from tempest.tests.boto.utils.wait import re_search_wait
-from tempest.tests.boto.utils.wait import state_wait
-from tempest.tests.boto.utils.wait import wait_exception
+from tempest.thirdparty.boto.utils.wait import re_search_wait
+from tempest.thirdparty.boto.utils.wait import state_wait
+from tempest.thirdparty.boto.utils.wait import wait_exception
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/tests/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
similarity index 97%
rename from tempest/tests/boto/test_ec2_instance_run.py
rename to tempest/thirdparty/boto/test_ec2_instance_run.py
index b6b93d8..bbe11d1 100644
--- a/tempest/tests/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -25,10 +25,10 @@
 from tempest.common.utils.linux.remote_client import RemoteClient
 from tempest import exceptions
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
-from tempest.tests.boto.utils.s3 import s3_upload_dir
-from tempest.tests.boto.utils.wait import re_search_wait
-from tempest.tests.boto.utils.wait import state_wait
+from tempest.thirdparty.boto.test import BotoTestCase
+from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
+from tempest.thirdparty.boto.utils.wait import re_search_wait
+from tempest.thirdparty.boto.utils.wait import state_wait
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/tests/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
similarity index 97%
rename from tempest/tests/boto/test_ec2_keys.py
rename to tempest/thirdparty/boto/test_ec2_keys.py
index d96ee11..5304649 100644
--- a/tempest/tests/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -20,7 +20,7 @@
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 
 def compare_key_pairs(a, b):
diff --git a/tempest/tests/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
similarity index 96%
rename from tempest/tests/boto/test_ec2_network.py
rename to tempest/thirdparty/boto/test_ec2_network.py
index ef307a1..6878df1 100644
--- a/tempest/tests/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -19,7 +19,7 @@
 
 from tempest import clients
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 
 @attr("EC2")
diff --git a/tempest/tests/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
similarity index 98%
rename from tempest/tests/boto/test_ec2_security_groups.py
rename to tempest/thirdparty/boto/test_ec2_security_groups.py
index dd46a91..54a94f8 100644
--- a/tempest/tests/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -18,7 +18,7 @@
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 
 @attr("EC2")
diff --git a/tempest/tests/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
similarity index 97%
rename from tempest/tests/boto/test_ec2_volumes.py
rename to tempest/thirdparty/boto/test_ec2_volumes.py
index 37a913e..b4d763d 100644
--- a/tempest/tests/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -19,7 +19,7 @@
 
 from tempest import clients
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/tests/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
similarity index 96%
rename from tempest/tests/boto/test_s3_buckets.py
rename to tempest/thirdparty/boto/test_s3_buckets.py
index 0a05ae0..3b7c5a7 100644
--- a/tempest/tests/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -20,7 +20,7 @@
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 
 @attr("S3")
diff --git a/tempest/tests/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
similarity index 96%
rename from tempest/tests/boto/test_s3_ec2_images.py
rename to tempest/thirdparty/boto/test_s3_ec2_images.py
index f77743e..594f416 100644
--- a/tempest/tests/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -22,9 +22,9 @@
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
-from tempest.tests.boto.utils.s3 import s3_upload_dir
-from tempest.tests.boto.utils.wait import state_wait
+from tempest.thirdparty.boto.test import BotoTestCase
+from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
+from tempest.thirdparty.boto.utils.wait import state_wait
 
 
 @attr("S3", "EC2")
diff --git a/tempest/tests/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
similarity index 96%
rename from tempest/tests/boto/test_s3_objects.py
rename to tempest/thirdparty/boto/test_s3_objects.py
index 9d4d79c..b256bc4 100644
--- a/tempest/tests/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -22,7 +22,7 @@
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
-from tempest.testboto import BotoTestCase
+from tempest.thirdparty.boto.test import BotoTestCase
 
 
 @attr("S3")
diff --git a/tempest/tests/boto/utils/__init__.py b/tempest/thirdparty/boto/utils/__init__.py
similarity index 100%
rename from tempest/tests/boto/utils/__init__.py
rename to tempest/thirdparty/boto/utils/__init__.py
diff --git a/tempest/tests/boto/utils/s3.py b/tempest/thirdparty/boto/utils/s3.py
similarity index 100%
rename from tempest/tests/boto/utils/s3.py
rename to tempest/thirdparty/boto/utils/s3.py
diff --git a/tempest/tests/boto/utils/wait.py b/tempest/thirdparty/boto/utils/wait.py
similarity index 100%
rename from tempest/tests/boto/utils/wait.py
rename to tempest/thirdparty/boto/utils/wait.py
diff --git a/tempest/whitebox/README.rst b/tempest/whitebox/README.rst
new file mode 100644
index 0000000..dabf758
--- /dev/null
+++ b/tempest/whitebox/README.rst
@@ -0,0 +1,46 @@
+Tempest Guide to Whitebox tests
+========
+
+
+What are these tests?
+--------
+
+When you hit the OpenStack API, this causes internal state changes in
+the system. This might be database transitions, vm modifications,
+other deep state changes which aren't really accessible from the
+OpenStack API. These side effects are sometimes important to
+validate.
+
+White box testing is an approach there. In white box testing you are
+given database access to the environment, and can verify internal
+record changes after an API call.
+
+This is an optional part of testing, and requires extra setup, but can
+be useful for validating Tempest internals.
+
+
+Why are these tests in tempest?
+--------
+
+Especially when it comes to something like VM state changing, which is
+a coordination of numerous running daemons, and a functioning VM, it's
+very difficult to get a realistic test like this in unit tests.
+
+
+Scope of these tests
+--------
+
+White box tests should be limitted to tests where black box testing
+(using the OpenStack API to verify results) isn't sufficient.
+
+As these poke at internals of OpenStack, it should also be realized
+that these tests are very tightly coupled to current implementation of
+OpenStack. They will need to be maintained agressively to keep up with
+internals changes in OpenStack projects.
+
+
+Example of a good test
+--------
+
+Pushing VMs through a series of state transitions, and ensuring along
+the way the database state transitions match what's expected.
diff --git a/tempest/tests/boto/__init__.py b/tempest/whitebox/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tempest/whitebox/__init__.py
diff --git a/tempest/whitebox.py b/tempest/whitebox/manager.py
similarity index 98%
rename from tempest/whitebox.py
rename to tempest/whitebox/manager.py
index cf9fff0..a75edb0 100644
--- a/tempest/whitebox.py
+++ b/tempest/whitebox/manager.py
@@ -27,7 +27,6 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest import test
-from tempest.tests import compute
 
 LOG = logging.getLogger(__name__)
 
@@ -56,12 +55,11 @@
 
     @classmethod
     def setUpClass(cls):
-        if not compute.WHITEBOX_ENABLED:
+        super(ComputeWhiteboxTest, cls).setUpClass()
+        if not cls.config.whitebox.whitebox_enabled:
             msg = "Whitebox testing disabled"
             raise cls.skipException(msg)
 
-        super(ComputeWhiteboxTest, cls).setUpClass()
-
         # Add some convenience attributes that tests use...
         cls.nova_dir = cls.config.whitebox.source_dir
         cls.compute_bin_dir = cls.config.whitebox.bin_dir
diff --git a/tempest/tests/compute/images/test_images_whitebox.py b/tempest/whitebox/test_images_whitebox.py
similarity index 98%
rename from tempest/tests/compute/images/test_images_whitebox.py
rename to tempest/whitebox/test_images_whitebox.py
index 9ec05dd..304677f 100644
--- a/tempest/tests/compute/images/test_images_whitebox.py
+++ b/tempest/whitebox/test_images_whitebox.py
@@ -19,11 +19,11 @@
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.compute import base
-from tempest import whitebox
+from tempest.whitebox import manager
 
 
 @attr(type='whitebox')
-class ImagesWhiteboxTest(whitebox.ComputeWhiteboxTest, base.BaseComputeTest):
+class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest):
     _interface = 'json'
 
     @classmethod
diff --git a/tempest/tests/compute/servers/test_servers_whitebox.py b/tempest/whitebox/test_servers_whitebox.py
similarity index 98%
rename from tempest/tests/compute/servers/test_servers_whitebox.py
rename to tempest/whitebox/test_servers_whitebox.py
index 6b192dd..2eab393 100644
--- a/tempest/tests/compute/servers/test_servers_whitebox.py
+++ b/tempest/whitebox/test_servers_whitebox.py
@@ -18,11 +18,11 @@
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.identity.base import BaseIdentityAdminTest
-from tempest import whitebox
+from tempest.whitebox import manager
 
 
 @attr(type='whitebox')
-class ServersWhiteboxTest(whitebox.ComputeWhiteboxTest):
+class ServersWhiteboxTest(manager.ComputeWhiteboxTest):
     _interface = 'json'
 
     @classmethod
diff --git a/tempest/tests/boto/utils/__init__.py b/tools/__init__.py
similarity index 100%
copy from tempest/tests/boto/utils/__init__.py
copy to tools/__init__.py
diff --git a/tempest/tests/boto/__init__.py b/tools/hacking/__init__.py
similarity index 100%
copy from tempest/tests/boto/__init__.py
copy to tools/hacking/__init__.py
diff --git a/tools/hacking/tempest.py b/tools/hacking/tempest.py
new file mode 100644
index 0000000..1db8419
--- /dev/null
+++ b/tools/hacking/tempest.py
@@ -0,0 +1,42 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License"); you may
+#   not use this file except in compliance with the License. You may obtain
+#   a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#   License for the specific language governing permissions and limitations
+#   under the License.
+
+import re
+
+
+SKIP_DECORATOR = '@testtools.skip('
+
+
+def skip_bugs(physical_line):
+    """Check skip lines for proper bug entries
+
+    T101: Bug not in skip line
+    T102: Bug in message formatted incorrectly
+    """
+
+    pos = physical_line.find(SKIP_DECORATOR)
+
+    skip_re = re.compile(r'^\s*@testtools.skip.*')
+
+    if pos != -1 and skip_re.match(physical_line):
+        bug = re.compile(r'^.*\bbug\b.*', re.IGNORECASE)
+        if bug.match(physical_line) is None:
+            return (pos, 'T101: skips must have an associated bug')
+
+        bug_re = re.compile(r'.*skip\(.*Bug\s\#\d+', re.IGNORECASE)
+
+        if bug_re.match(physical_line) is None:
+            return (pos, 'T102: Bug number formatted incorrectly')
diff --git a/tox.ini b/tox.ini
index 7d3d245..2449c86 100644
--- a/tox.ini
+++ b/tox.ini
@@ -20,7 +20,7 @@
          NOSE_OPENSTACK_SHOW_ELAPSED=1
          NOSE_OPENSTACK_STDOUT=1
 commands =
-  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/tests tempest/cli
+  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/tests tempest/scenario tempest/thirdparty tempest/cli
 
 [testenv:smoke]
 sitepackages = True
@@ -46,7 +46,7 @@
          NOSE_OPENSTACK_STDOUT=1
 commands =
    python -m tools/tempest_coverage -c start --combine
-   nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/tests tempest/cli
+   nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/tests tempest/scenario tempest/thirdparty tempest/cli
    python -m tools/tempest_coverage -c report --html
 
 [testenv:pep8]
@@ -54,6 +54,9 @@
 deps = -r{toxinidir}/tools/pip-requires
        -r{toxinidir}/tools/test-requires
 
+[hacking]
+local-check = tools.hacking.tempest.skip_bugs
+
 [flake8]
 ignore = E125,H302,H404
 show-source = True