Merge "Handling rate-limit for JSON request- rest_client"
diff --git a/HACKING.rst b/HACKING.rst
index 103f8cd..fed4130 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -56,8 +56,8 @@
   import logging
   import random
   import StringIO
+  import testtools
   import time
-  import unittest
 
   import eventlet
   import webob.exc
diff --git a/etc/TEMPEST_README.txt b/etc/TEMPEST_README.txt
index e46e195..50fa688 100644
--- a/etc/TEMPEST_README.txt
+++ b/etc/TEMPEST_README.txt
@@ -2,13 +2,6 @@
 -rename the /etc/tempest.conf.sample file to tempest.conf
 -Set the fields in the file to values relevant to your system
 -Set the "authentication" value (basic or keystone_v2 currently supported)
--from the root directory of the project, run "nosetests tempest/tests" to
- run all tests
-
-TODO:
-Use virtualenv to install all needed packages. Till then, the following
-packages must be installed:
--httplib2
--unittest2
--paramiko
--nose
\ No newline at end of file
+-From the root directory of the project, run "./run_tests.sh" this will
+create the venv to install the project dependencies and run nosetests tempest
+to run all the tests
diff --git a/tempest/clients.py b/tempest/clients.py
index 29e83bf..7a7ea13 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -32,7 +32,7 @@
 from tempest.services.compute.json.security_groups_client import \
     SecurityGroupsClientJSON
 from tempest.services.compute.json.keypairs_client import KeyPairsClientJSON
-from tempest.services.compute.json.quotas_client import QuotasClient
+from tempest.services.compute.json.quotas_client import QuotasClientJSON
 from tempest.services.compute.json.volumes_extensions_client import \
     VolumesExtensionsClientJSON
 from tempest.services.compute.json.console_output_client import \
@@ -44,6 +44,7 @@
 from tempest.services.compute.xml.images_client import ImagesClientXML
 from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
 from tempest.services.compute.xml.limits_client import LimitsClientXML
+from tempest.services.compute.xml.quotas_client import QuotasClientXML
 from tempest.services.compute.xml.security_groups_client \
     import SecurityGroupsClientXML
 from tempest.services.compute.xml.servers_client import ServersClientXML
@@ -79,6 +80,11 @@
     "xml": KeyPairsClientXML,
 }
 
+QUOTAS_CLIENTS = {
+    "json": QuotasClientJSON,
+    "xml": QuotasClientXML,
+}
+
 SERVERS_CLIENTS = {
     "json": ServersClientJSON,
     "xml": ServersClientXML,
@@ -180,6 +186,7 @@
             self.limits_client = LIMITS_CLIENTS[interface](*client_args)
             self.images_client = IMAGES_CLIENTS[interface](*client_args)
             self.keypairs_client = KEYPAIRS_CLIENTS[interface](*client_args)
+            self.quotas_client = QUOTAS_CLIENTS[interface](*client_args)
             self.flavors_client = FLAVORS_CLIENTS[interface](*client_args)
             ext_cli = EXTENSIONS_CLIENTS[interface](*client_args)
             self.extensions_client = ext_cli
@@ -196,7 +203,6 @@
         except KeyError:
             msg = "Unsupported interface type `%s'" % interface
             raise exceptions.InvalidConfiguration(msg)
-        self.quotas_client = QuotasClient(*client_args)
         self.network_client = NetworkClient(*client_args)
         self.account_client = AccountClient(*client_args)
         self.container_client = ContainerClient(*client_args)
diff --git a/tempest/manager.py b/tempest/manager.py
index 4137ec3..cb1e52d 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -55,7 +55,7 @@
 VolumesExtensionsClient = volumes_extensions_client.VolumesExtensionsClientJSON
 VolumesClient = volumes_client.VolumesClientJSON
 ConsoleOutputsClient = console_output_client.ConsoleOutputsClientJSON
-QuotasClient = quotas_client.QuotasClient
+QuotasClient = quotas_client.QuotasClientJSON
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/services/compute/admin/json/quotas_client.py b/tempest/services/compute/admin/json/quotas_client.py
index 625d4d4..0a4bd72 100644
--- a/tempest/services/compute/admin/json/quotas_client.py
+++ b/tempest/services/compute/admin/json/quotas_client.py
@@ -17,14 +17,14 @@
 
 import json
 
-from tempest.services.compute.json.quotas_client import QuotasClient
+from tempest.services.compute.json.quotas_client import QuotasClientJSON
 
 
-class AdminQuotasClient(QuotasClient):
+class AdminQuotasClientJSON(QuotasClientJSON):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(AdminQuotasClient, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
+        super(AdminQuotasClientJSON, self).__init__(config, username, password,
+                                                    auth_url, tenant_name)
 
     def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
diff --git a/tempest/services/compute/admin/xml/__init__.py b/tempest/services/compute/admin/xml/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/compute/admin/xml/__init__.py
diff --git a/tempest/services/compute/admin/xml/quotas_client.py b/tempest/services/compute/admin/xml/quotas_client.py
new file mode 100644
index 0000000..d567a9c
--- /dev/null
+++ b/tempest/services/compute/admin/xml/quotas_client.py
@@ -0,0 +1,88 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml.quotas_client import QuotasClientXML
+
+
+class AdminQuotasClientXML(QuotasClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(AdminQuotasClientXML, self).__init__(config, username, password,
+                                                   auth_url, tenant_name)
+
+    def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
+                         metadata_items=None, ram=None, floating_ips=None,
+                         key_pairs=None, instances=None,
+                         security_group_rules=None, injected_files=None,
+                         cores=None, injected_file_path_bytes=None,
+                         security_groups=None):
+        """
+        Updates the tenant's quota limits for one or more resources
+        """
+        post_body = Element("quota_set",
+                            xmlns=XMLNS_11)
+
+        if injected_file_content_bytes is not None:
+            post_body.add_attr('injected_file_content_bytes',
+                               injected_file_content_bytes)
+
+        if metadata_items is not None:
+            post_body.add_attr('metadata_items', metadata_items)
+
+        if ram is not None:
+            post_body.add_attr('ram', ram)
+
+        if floating_ips is not None:
+            post_body.add_attr('floating_ips', floating_ips)
+
+        if key_pairs is not None:
+            post_body.add_attr('key_pairs', key_pairs)
+
+        if instances is not None:
+            post_body.add_attr('instances', instances)
+
+        if security_group_rules is not None:
+            post_body.add_attr('security_group_rules', security_group_rules)
+
+        if injected_files is not None:
+            post_body.add_attr('injected_files', injected_files)
+
+        if cores is not None:
+            post_body.add_attr('cores', cores)
+
+        if injected_file_path_bytes is not None:
+            post_body.add_attr('injected_file_path_bytes',
+                               injected_file_path_bytes)
+
+        if security_groups is not None:
+            post_body.add_attr('security_groups', security_groups)
+
+        resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                              str(Document(post_body)),
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 543b015..a95ff1c 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -20,11 +20,11 @@
 from tempest.common.rest_client import RestClient
 
 
-class QuotasClient(RestClient):
+class QuotasClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(QuotasClient, self).__init__(config, username, password,
-                                           auth_url, tenant_name)
+        super(QuotasClientJSON, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
         self.service = self.config.compute.catalog_type
 
     def get_quota_set(self, tenant_id):
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
new file mode 100644
index 0000000..8978214
--- /dev/null
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+
+
+class QuotasClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(QuotasClientXML, self).__init__(config, username, password,
+                                              auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _format_quota(self, q):
+        quota = {}
+        for k, v in q.items():
+            try:
+                v = int(v)
+            except ValueError:
+                pass
+
+            quota[k] = v
+
+        return quota
+
+    def _parse_array(self, node):
+        return [self._format_quota(xml_to_json(x)) for x in node]
+
+    def get_quota_set(self, tenant_id):
+        """List the quota set for a tenant."""
+
+        url = 'os-quota-sets/%s' % str(tenant_id)
+        resp, body = self.get(url, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
diff --git a/tempest/test.py b/tempest/test.py
index dc480d1..7804e12 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -18,14 +18,14 @@
 import logging
 import time
 
-import unittest2 as unittest
+import testtools
 
 from tempest import manager
 
 LOG = logging.getLogger(__name__)
 
 
-class TestCase(unittest.TestCase):
+class TestCase(testtools.TestCase):
 
     """
     Base test case class for all Tempest tests
diff --git a/tempest/testboto.py b/tempest/testboto.py
index 29ac3ca..7031fe2 100644
--- a/tempest/testboto.py
+++ b/tempest/testboto.py
@@ -25,9 +25,8 @@
 from boto.exception import EC2ResponseError
 from boto.s3.bucket import Bucket
 from boto.s3.key import Key
-import nose
 import testresources
-import unittest2 as unittest
+import testtools
 
 from tempest.exceptions import TearDownException
 import tempest.tests.boto
@@ -123,11 +122,11 @@
     return string + ")"
 
 
-class BotoTestCase(unittest.TestCase,
+class BotoTestCase(testtools.TestCase,
                    testresources.ResourcedTestCase):
     """Recommended to use as base class for boto related test."""
 
-    resources = [('boto_init', tempest.tests.boto.generic_setup_package())]
+    resources = [('boto_init', tempest.tests.boto.BotoResource())]
 
     @classmethod
     def setUpClass(cls):
@@ -137,11 +136,11 @@
         cls._sequence = -1
         if (hasattr(cls, "EC2") and
             tempest.tests.boto.EC2_CAN_CONNECT_ERROR is not None):
-                raise nose.SkipTest("EC2 " + cls.__name__ + ": " +
+            raise cls.skipException("EC2 " + cls.__name__ + ": " +
                                     tempest.tests.boto.EC2_CAN_CONNECT_ERROR)
         if (hasattr(cls, "S3") and
             tempest.tests.boto.S3_CAN_CONNECT_ERROR is not None):
-                raise nose.SkipTest("S3 " + cls.__name__ + ": " +
+            raise cls.skipException("S3 " + cls.__name__ + ": " +
                                     tempest.tests.boto.S3_CAN_CONNECT_ERROR)
 
     @classmethod
diff --git a/tempest/tests/boto/__init__.py b/tempest/tests/boto/__init__.py
index 6d5149e..99dd8a9 100644
--- a/tempest/tests/boto/__init__.py
+++ b/tempest/tests/boto/__init__.py
@@ -26,6 +26,7 @@
 import tempest.clients
 from tempest.common.utils.file_utils import have_effective_read_access
 import tempest.config
+from testresources import TestResourceManager
 
 A_I_IMAGES_READY = False  # ari,ami,aki
 S3_CAN_CONNECT_ERROR = "Unknown Error"
@@ -96,3 +97,8 @@
     else:
         S3_CAN_CONNECT_ERROR = None
     boto_logger.setLevel(level)
+
+
+class BotoResource(TestResourceManager):
+    def make(self, dependency_resources=None):
+        return generic_setup_package()
diff --git a/tempest/tests/boto/test_ec2_instance_run.py b/tempest/tests/boto/test_ec2_instance_run.py
index 6a8778a..1adb5fb 100644
--- a/tempest/tests/boto/test_ec2_instance_run.py
+++ b/tempest/tests/boto/test_ec2_instance_run.py
@@ -20,9 +20,8 @@
 
 from boto.exception import EC2ResponseError
 from boto.s3.key import Key
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -44,8 +43,8 @@
     def setUpClass(cls):
         super(InstanceRunTest, cls).setUpClass()
         if not tempest.tests.boto.A_I_IMAGES_READY:
-            raise nose.SkipTest("".join(("EC2 ", cls.__name__,
-                                ": requires ami/aki/ari manifest")))
+            raise cls.skipException("".join(("EC2 ", cls.__name__,
+                                    ": requires ami/aki/ari manifest")))
         cls.os = clients.Manager()
         cls.s3_client = cls.os.s3_client
         cls.ec2_client = cls.os.ec2api_client
@@ -122,7 +121,7 @@
         self.cancelResourceCleanUp(rcuk)
 
     @attr(type='smoke')
-    @unittest.skip("Skipped until the Bug #1098891 is resolved")
+    @testtools.skip("Skipped until the Bug #1098891 is resolved")
     def test_run_terminate_instance(self):
         # EC2 run, terminate immediately
         image_ami = self.ec2_client.get_image(self.images["ami"]
diff --git a/tempest/tests/boto/test_ec2_keys.py b/tempest/tests/boto/test_ec2_keys.py
index fcec02d..540374a 100644
--- a/tempest/tests/boto/test_ec2_keys.py
+++ b/tempest/tests/boto/test_ec2_keys.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -47,7 +47,7 @@
                         self.client.get_key_pair(key_name)))
 
     @attr(type='smoke')
-    @unittest.skip("Skipped until the Bug #1072318 is resolved")
+    @testtools.skip("Skipped until the Bug #1072318 is resolved")
     def test_delete_ec2_keypair(self):
         # EC2 delete KeyPair
         key_name = rand_name("keypair-")
@@ -65,7 +65,7 @@
                         self.client.get_key_pair(key_name)))
 
     @attr(type='smoke')
-    @unittest.skip("Skipped until the Bug #1072762 is resolved")
+    @testtools.skip("Skipped until the Bug #1072762 is resolved")
     def test_duplicate_ec2_keypair(self):
         # EC2 duplicate KeyPair
         key_name = rand_name("keypair-")
diff --git a/tempest/tests/boto/test_ec2_network.py b/tempest/tests/boto/test_ec2_network.py
index 27649e6..76103c2 100644
--- a/tempest/tests/boto/test_ec2_network.py
+++ b/tempest/tests/boto/test_ec2_network.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.testboto import BotoTestCase
@@ -32,7 +32,7 @@
         cls.client = cls.os.ec2api_client
 
 #Note(afazekas): these tests for things duable without an instance
-    @unittest.skip("Skipped until the Bug #1080406 is resolved")
+    @testtools.skip("Skipped until the Bug #1080406 is resolved")
     @attr(type='smoke')
     def test_disassociate_not_associated_floating_ip(self):
         # EC2 disassociate not associated floating ip
diff --git a/tempest/tests/boto/test_ec2_security_groups.py b/tempest/tests/boto/test_ec2_security_groups.py
index 09da82c..ed7bedb 100644
--- a/tempest/tests/boto/test_ec2_security_groups.py
+++ b/tempest/tests/boto/test_ec2_security_groups.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/boto/test_ec2_volumes.py b/tempest/tests/boto/test_ec2_volumes.py
index ee7fa3f..7397cdb 100644
--- a/tempest/tests/boto/test_ec2_volumes.py
+++ b/tempest/tests/boto/test_ec2_volumes.py
@@ -19,7 +19,7 @@
 import time
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.testboto import BotoTestCase
diff --git a/tempest/tests/boto/test_s3_buckets.py b/tempest/tests/boto/test_s3_buckets.py
index beed28b..36aa319 100644
--- a/tempest/tests/boto/test_s3_buckets.py
+++ b/tempest/tests/boto/test_s3_buckets.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -33,7 +33,7 @@
         cls.client = cls.os.s3_client
         cls.config = cls.os.config
 
-    @unittest.skip("Skipped until the Bug #1076965 is resolved")
+    @testtools.skip("Skipped until the Bug #1076965 is resolved")
     @attr(type='smoke')
     def test_create_and_get_delete_bucket(self):
         # S3 Create, get and delete bucket
diff --git a/tempest/tests/boto/test_s3_ec2_images.py b/tempest/tests/boto/test_s3_ec2_images.py
index f14115a..e0dc124 100644
--- a/tempest/tests/boto/test_s3_ec2_images.py
+++ b/tempest/tests/boto/test_s3_ec2_images.py
@@ -19,9 +19,8 @@
 import os
 
 from boto.s3.key import Key
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -38,8 +37,8 @@
     def setUpClass(cls):
         super(S3ImagesTest, cls).setUpClass()
         if not tempest.tests.boto.A_I_IMAGES_READY:
-            raise nose.SkipTest("".join(("EC2 ", cls.__name__,
-                                ": requires ami/aki/ari manifest")))
+            raise cls.skipException("".join(("EC2 ", cls.__name__,
+                                    ": requires ami/aki/ari manifest")))
         cls.os = clients.Manager()
         cls.s3_client = cls.os.s3_client
         cls.images_client = cls.os.ec2api_client
@@ -88,7 +87,7 @@
         #TODO(afazekas): double deregister ?
         self.cancelResourceCleanUp(image["cleanUp"])
 
-    @unittest.skip("Skipped until the Bug #1074904 is resolved")
+    @testtools.skip("Skipped until the Bug #1074904 is resolved")
     def test_register_get_deregister_aki_image(self):
         # Register and deregister aki image
         image = {"name": rand_name("aki-name-"),
@@ -116,7 +115,7 @@
         self.assertIn(retrieved_image.state, self.valid_image_state)
         self.cancelResourceCleanUp(image["cleanUp"])
 
-    @unittest.skip("Skipped until the Bug #1074908 and #1074904 is resolved")
+    @testtools.skip("Skipped until the Bug #1074908 and #1074904 is resolved")
     def test_register_get_deregister_ari_image(self):
         # Register and deregister ari image
         image = {"name": rand_name("ari-name-"),
diff --git a/tempest/tests/boto/test_s3_objects.py b/tempest/tests/boto/test_s3_objects.py
index 6e89539..cacd99f 100644
--- a/tempest/tests/boto/test_s3_objects.py
+++ b/tempest/tests/boto/test_s3_objects.py
@@ -19,7 +19,7 @@
 
 from boto.s3.key import Key
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -37,7 +37,7 @@
         cls.client = cls.os.s3_client
         cls.config = cls.os.config
 
-    @unittest.skip("Skipped until the Bug #1076534 is resolved")
+    @testtools.skip("Skipped until the Bug #1076534 is resolved")
     @attr(type='smoke')
     def test_create_get_delete_object(self):
         # S3 Create, get and delete object
diff --git a/tempest/tests/boto/utils/wait.py b/tempest/tests/boto/utils/wait.py
index 77fe037..c2d4ea3 100644
--- a/tempest/tests/boto/utils/wait.py
+++ b/tempest/tests/boto/utils/wait.py
@@ -20,7 +20,7 @@
 import time
 
 from boto.exception import BotoServerError
-from unittest2 import TestCase
+from testtools import TestCase
 
 import tempest.config
 
diff --git a/tempest/tests/compute/__init__.py b/tempest/tests/compute/__init__.py
index 398f982..08e5091 100644
--- a/tempest/tests/compute/__init__.py
+++ b/tempest/tests/compute/__init__.py
@@ -17,11 +17,11 @@
 
 import logging
 
-import nose
 
 from tempest import clients
 from tempest import config
 from tempest.exceptions import InvalidConfiguration
+from testresources import TestResourceManager
 
 LOG = logging.getLogger(__name__)
 
@@ -80,3 +80,8 @@
                        % (user2_tenant_name, user2_password))
                 raise InvalidConfiguration(msg)
             MULTI_USER = True
+
+
+class ComputeResource(TestResourceManager):
+    def make(self, dependency_resources=None):
+        return generic_setup_package()
diff --git a/tempest/tests/compute/admin/test_flavors.py b/tempest/tests/compute/admin/test_flavors.py
index 4859308..eb2392c 100644
--- a/tempest/tests/compute/admin/test_flavors.py
+++ b/tempest/tests/compute/admin/test_flavors.py
@@ -15,9 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_int_id
 from tempest.common.utils.data_utils import rand_name
@@ -35,7 +34,7 @@
     def setUpClass(self, cls):
         if not compute.FLAVOR_EXTRA_DATA_ENABLED:
             msg = "FlavorExtraData extension not enabled."
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         cls.client = cls.os.flavors_client
         cls.flavor_name_prefix = 'test_flavor_'
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index 2c2e5da..b2b515a 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -18,23 +18,21 @@
 from nose.plugins.attrib import attr
 
 from tempest import exceptions
-from tempest.services.compute.admin.json import quotas_client as adm_quotas
-from tempest.tests.compute.base import BaseComputeTest
+from tempest.services.compute.admin.json \
+    import quotas_client as adm_quotas_json
+from tempest.services.compute.admin.xml import quotas_client as adm_quotas_xml
+from tempest.tests import compute
+from tempest.tests.compute import base
 
 
-class QuotasTest(BaseComputeTest):
+class QuotasAdminTestBase(object):
 
     @classmethod
     def setUpClass(cls):
-        super(QuotasTest, cls).setUpClass()
-        c_adm_user = cls.config.compute_admin.username
-        c_adm_pass = cls.config.compute_admin.password
-        c_adm_tenant = cls.config.compute_admin.tenant_name
-        auth_url = cls.config.identity.uri
-
-        cls.adm_client = adm_quotas.AdminQuotasClient(cls.config, c_adm_user,
-                                                      c_adm_pass, auth_url,
-                                                      c_adm_tenant)
+        cls.c_adm_user = cls.config.compute_admin.username
+        cls.c_adm_pass = cls.config.compute_admin.password
+        cls.c_adm_tenant = cls.config.compute_admin.tenant_name
+        cls.auth_url = cls.config.identity.uri
         cls.client = cls.os.quotas_client
         cls.identity_admin_client = cls._get_identity_admin_client()
         resp, tenants = cls.identity_admin_client.list_tenants()
@@ -57,7 +55,7 @@
                                  'cores': 20, 'security_groups': 10}
 
     @classmethod
-    def tearDown(cls):
+    def tearDownClass(cls):
         for server in cls.servers:
             try:
                 cls.servers_client.delete_server(server['id'])
@@ -154,3 +152,43 @@
         finally:
             self.adm_client.update_quota_set(self.demo_tenant_id,
                                              ram=default_mem_quota)
+
+
+class QuotasAdminTestJSON(QuotasAdminTestBase, base.BaseComputeAdminTestJSON,
+                          base.BaseComputeTest):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeAdminTestJSON.setUpClass()
+        base.BaseComputeTest.setUpClass()
+        super(QuotasAdminTestJSON, cls).setUpClass()
+
+        cls.adm_client = adm_quotas_json.AdminQuotasClientJSON(
+            cls.config, cls.c_adm_user, cls.c_adm_pass,
+            cls.auth_url, cls.c_adm_tenant)
+
+    @classmethod
+    def tearDownClass(cls):
+        super(QuotasAdminTestJSON, cls).tearDownClass()
+        base.BaseComputeTest.tearDownClass()
+
+
+class QuotasAdminTestXML(QuotasAdminTestBase, base.BaseComputeAdminTestXML,
+                         base.BaseComputeTest):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeAdminTestXML.setUpClass()
+        base.BaseComputeTest.setUpClass()
+        super(QuotasAdminTestXML, cls).setUpClass()
+
+        cls.adm_client = adm_quotas_xml.AdminQuotasClientXML(cls.config,
+                                                             cls.c_adm_user,
+                                                             cls.c_adm_pass,
+                                                             cls.auth_url,
+                                                             cls.c_adm_tenant)
+
+    @classmethod
+    def tearDownClass(cls):
+        super(QuotasAdminTestXML, cls).tearDownClass()
+        base.BaseComputeTest.tearDownClass()
diff --git a/tempest/tests/compute/base.py b/tempest/tests/compute/base.py
index 9e2e883..2312931 100644
--- a/tempest/tests/compute/base.py
+++ b/tempest/tests/compute/base.py
@@ -18,9 +18,8 @@
 import logging
 import time
 
-import nose
 import testresources
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -34,12 +33,11 @@
 LOG = logging.getLogger(__name__)
 
 
-class BaseCompTest(unittest.TestCase,
+class BaseCompTest(testtools.TestCase,
                    testresources.ResourcedTestCase):
-
     """Base test case class for all Compute API tests."""
 
-    resources = [('compute_init', compute.generic_setup_package())]
+    resources = [('compute_init', compute.ComputeResource())]
 
     @classmethod
     def setUpClass(cls):
@@ -249,7 +247,7 @@
         super(BaseComputeTestXML, cls).setUpClass()
 
 
-class BaseComputeAdminTest(unittest.TestCase):
+class BaseComputeAdminTest(testtools.TestCase):
 
     """Base test case class for all Compute Admin API tests."""
 
@@ -263,7 +261,7 @@
         if not cls.admin_username and cls.admin_password and cls.admin_tenant:
             msg = ("Missing Compute Admin API credentials "
                    "in configuration.")
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         cls.os = clients.ComputeAdminManager(interface=cls._interface)
 
diff --git a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
index 9a9914a..59faf66 100644
--- a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/compute/floating_ips/test_list_floating_ips.py b/tempest/tests/compute/floating_ips/test_list_floating_ips.py
index 9eec27c..ea99e89 100644
--- a/tempest/tests/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/tests/compute/floating_ips/test_list_floating_ips.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
diff --git a/tempest/tests/compute/images/test_image_metadata.py b/tempest/tests/compute/images/test_image_metadata.py
index cdf4249..94bdca7 100644
--- a/tempest/tests/compute/images/test_image_metadata.py
+++ b/tempest/tests/compute/images/test_image_metadata.py
@@ -53,6 +53,7 @@
         super(ImagesMetadataTest, cls).tearDownClass()
 
     def setUp(self):
+        super(ImagesMetadataTest, self).setUp()
         meta = {'key1': 'value1', 'key2': 'value2'}
         resp, _ = self.client.set_image_metadata(self.image_id, meta)
         self.assertEqual(resp.status, 200)
diff --git a/tempest/tests/compute/images/test_images.py b/tempest/tests/compute/images/test_images.py
index 2557f16..1fc03b8 100644
--- a/tempest/tests/compute/images/test_images.py
+++ b/tempest/tests/compute/images/test_images.py
@@ -15,9 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
@@ -113,7 +112,7 @@
         self.assertRaises(exceptions.Duplicate, self.client.create_image,
                           server['id'], snapshot_name)
 
-    @unittest.skip("Until Bug 1039739 is fixed")
+    @testtools.skip("Until Bug 1039739 is fixed")
     @attr(type='negative')
     def test_create_image_when_server_is_rebooting(self):
         # Return error when creating an image of server that is rebooting
@@ -217,6 +216,7 @@
                      ImagesTestBase):
     def tearDown(self):
         ImagesTestBase.tearDown(self)
+        base.BaseComputeTestJSON.tearDown(self)
 
     @classmethod
     def setUpClass(cls):
@@ -243,6 +243,7 @@
                     ImagesTestBase):
     def tearDown(self):
         ImagesTestBase.tearDown(self)
+        base.BaseComputeTestXML.tearDown(self)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/tests/compute/images/test_images_oneserver.py b/tempest/tests/compute/images/test_images_oneserver.py
index f8b560b..f3b1e01 100644
--- a/tempest/tests/compute/images/test_images_oneserver.py
+++ b/tempest/tests/compute/images/test_images_oneserver.py
@@ -15,9 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
@@ -43,7 +42,7 @@
             self.image_ids.remove(image_id)
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 1006725 is fixed")
+    @testtools.skip("Until Bug 1006725 is fixed")
     def test_create_image_specify_multibyte_character_image_name(self):
         # Return an error if the image name has multi-byte characters
         try:
@@ -56,7 +55,7 @@
                       " are used for image name")
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 1005423 is fixed")
+    @testtools.skip("Until Bug 1005423 is fixed")
     def test_create_image_specify_invalid_metadata(self):
         # Return an error when creating image with invalid metadata
         try:
@@ -69,7 +68,7 @@
             self.fail("Should raise 400 Bad Request if meta data is invalid")
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 1005423 is fixed")
+    @testtools.skip("Until Bug 1005423 is fixed")
     def test_create_image_specify_metadata_over_limits(self):
         # Return an error when creating image with meta data over 256 chars
         try:
@@ -82,8 +81,8 @@
             self.fail("Should raise 413 Over Limit if meta data was too long")
 
     @attr(type='negative')
-    @unittest.skipUnless(compute.MULTI_USER,
-                         'Need multiple users for this test.')
+    @testtools.skipUnless(compute.MULTI_USER,
+                          'Need multiple users for this test.')
     def test_delete_image_of_another_tenant(self):
         # Return an error while trying to delete another tenant's image
         self.servers_client.wait_for_server_status(self.server['id'], 'ACTIVE')
@@ -99,8 +98,8 @@
                           self.alt_client.delete_image, image_id)
 
     @attr(type='smoke')
-    @unittest.skipUnless(compute.CREATE_IMAGE_ENABLED,
-                         'Environment unable to create images.')
+    @testtools.skipUnless(compute.CREATE_IMAGE_ENABLED,
+                          'Environment unable to create images.')
     def test_create_delete_image(self):
 
         # Create a new image
@@ -123,8 +122,8 @@
         self.assertEqual(original_image['minDisk'], image['minDisk'])
 
     @attr(type='negative')
-    @unittest.skipUnless(compute.MULTI_USER,
-                         'Need multiple users for this test.')
+    @testtools.skipUnless(compute.MULTI_USER,
+                          'Need multiple users for this test.')
     def test_create_image_for_server_in_another_tenant(self):
         # Creating image of another tenant's server should be return error
 
@@ -157,7 +156,7 @@
                       "of the server is still being saved")
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 1004564 is fixed")
+    @testtools.skip("Until Bug 1004564 is fixed")
     def test_create_image_specify_name_over_256_chars(self):
         # Return an error if snapshot name over 256 characters is passed
 
@@ -192,6 +191,7 @@
 
     def tearDown(self):
         ImagesOneServerTestBase.tearDown(self)
+        base.BaseComputeTestJSON.tearDown(self)
 
     @classmethod
     def setUpClass(cls):
@@ -220,6 +220,7 @@
 
     def tearDown(self):
         ImagesOneServerTestBase.tearDown(self)
+        base.BaseComputeTestXML.tearDown(self)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/tests/compute/images/test_images_whitebox.py b/tempest/tests/compute/images/test_images_whitebox.py
index 2987534..b2419b4 100644
--- a/tempest/tests/compute/images/test_images_whitebox.py
+++ b/tempest/tests/compute/images/test_images_whitebox.py
@@ -50,7 +50,7 @@
             cls.image_ids.remove(image_id)
 
     @classmethod
-    def update_state(self, server_id, vm_state, task_state, deleted=False):
+    def update_state(self, server_id, vm_state, task_state, deleted=0):
         """Update states of an instance in database for validation."""
         if not task_state:
             task_state = "NULL"
@@ -63,7 +63,7 @@
 
         self.connection.execute(stmt, autocommit=True)
 
-    def _test_create_image_409_base(self, vm_state, task_state, deleted=False):
+    def _test_create_image_409_base(self, vm_state, task_state, deleted=0):
         """Base method for create image tests based on vm and task states."""
         try:
             self.update_state(self.shared_server['id'], vm_state,
diff --git a/tempest/tests/compute/keypairs/test_keypairs.py b/tempest/tests/compute/keypairs/test_keypairs.py
index 7d95a9b..45c9079 100644
--- a/tempest/tests/compute/keypairs/test_keypairs.py
+++ b/tempest/tests/compute/keypairs/test_keypairs.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -77,7 +77,7 @@
         self.assertEqual(202, resp.status)
 
     @attr(type='positive')
-    @unittest.skip("Skipped until the Bug #980688 is resolved")
+    @testtools.skip("Skipped until the Bug #980688 is resolved")
     def test_get_keypair_detail(self):
         # Keypair should be created, Got details by name and deleted
         k_name = rand_name('keypair-')
@@ -137,7 +137,7 @@
             self.fail('Expected BadRequest for invalid public key')
 
     @attr(type='negative')
-    @unittest.skip("Skipped until the Bug #1086980 is resolved")
+    @testtools.skip("Skipped until the Bug #1086980 is resolved")
     def test_keypair_delete_nonexistant_key(self):
         # Non-existant key deletion should throw a proper error
         k_name = rand_name("keypair-non-existant-")
diff --git a/tempest/tests/compute/limits/test_absolute_limits.py b/tempest/tests/compute/limits/test_absolute_limits.py
index 89c5b25..d520b92 100644
--- a/tempest/tests/compute/limits/test_absolute_limits.py
+++ b/tempest/tests/compute/limits/test_absolute_limits.py
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import unittest2 as unittest
+import testtools
 
 from tempest.tests.compute import base
 
@@ -26,7 +26,7 @@
     def setUpClass(cls):
         cls.client = cls.limits_client
 
-    @unittest.skip("Skipped until the Bug #1025294 is resolved")
+    @testtools.skip("Skipped until the Bug #1025294 is resolved")
     def test_absLimits_get(self):
         # To check if all limits are present in the response
         resp, absolute_limits = self.client.get_absolute_limits()
diff --git a/tempest/tests/compute/servers/test_console_output.py b/tempest/tests/compute/servers/test_console_output.py
index 3ad29a1..b26220b 100644
--- a/tempest/tests/compute/servers/test_console_output.py
+++ b/tempest/tests/compute/servers/test_console_output.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -63,7 +63,7 @@
             pass
 
     @attr(type='positive')
-    @unittest.skip('Until tempest bug 1014683 is fixed.')
+    @testtools.skip('Until tempest bug 1014683 is fixed.')
     def test_get_console_output_server_id_in_reboot_status(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id in reboot status
diff --git a/tempest/tests/compute/servers/test_create_server.py b/tempest/tests/compute/servers/test_create_server.py
index c5a54dc..0dcc79f 100644
--- a/tempest/tests/compute/servers/test_create_server.py
+++ b/tempest/tests/compute/servers/test_create_server.py
@@ -16,10 +16,9 @@
 #    under the License.
 
 import base64
-import nose
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 
 from tempest.common.utils.data_utils import rand_name
@@ -98,14 +97,14 @@
         self.assertTrue(found)
 
     @attr(type='positive')
-    @unittest.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
     def test_can_log_into_created_server(self):
         # Check that the user can authenticate with the generated password
         linux_client = RemoteClient(self.server, self.ssh_user, self.password)
         self.assertTrue(linux_client.can_authenticate())
 
     @attr(type='positive')
-    @unittest.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
     def test_verify_created_server_vcpus(self):
         # Verify that the number of vcpus reported by the instance matches
         # the amount stated by the flavor
@@ -114,7 +113,7 @@
         self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
 
     @attr(type='positive')
-    @unittest.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
     def test_host_name_is_same_as_server_name(self):
         # Verify the instance host name is the same as the server name
         linux_client = RemoteClient(self.server, self.ssh_user, self.password)
@@ -128,7 +127,7 @@
     def setUpClass(cls):
         if not compute.DISK_CONFIG_ENABLED:
             msg = "DiskConfig extension not enabled."
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
         super(ServersTestAutoDisk, cls).setUpClass()
         cls.disk_config = 'AUTO'
         ServersTest.setUpClass(cls)
@@ -146,7 +145,7 @@
     def setUpClass(cls):
         if not compute.DISK_CONFIG_ENABLED:
             msg = "DiskConfig extension not enabled."
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
         super(ServersTestManualDisk, cls).setUpClass()
         cls.disk_config = 'MANUAL'
         ServersTest.setUpClass(cls)
diff --git a/tempest/tests/compute/servers/test_disk_config.py b/tempest/tests/compute/servers/test_disk_config.py
index 490156b..c3a37ff 100644
--- a/tempest/tests/compute/servers/test_disk_config.py
+++ b/tempest/tests/compute/servers/test_disk_config.py
@@ -15,9 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -31,7 +30,7 @@
     def setUpClass(cls):
         if not compute.DISK_CONFIG_ENABLED:
             msg = "DiskConfig extension not enabled."
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
         super(TestServerDiskConfig, cls).setUpClass()
         cls.client = cls.os.servers_client
 
@@ -96,7 +95,7 @@
         resp, body = self.client.delete_server(server['id'])
 
     @attr(type='positive')
-    @unittest.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
+    @testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
     def test_resize_server_from_manual_to_auto(self):
         # A server should be resized from manual to auto disk config
         name = rand_name('server')
@@ -122,7 +121,7 @@
         resp, body = self.client.delete_server(server['id'])
 
     @attr(type='positive')
-    @unittest.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
+    @testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
     def test_resize_server_from_auto_to_manual(self):
         # A server should be resized from auto to manual disk config
         name = rand_name('server')
diff --git a/tempest/tests/compute/servers/test_list_server_filters.py b/tempest/tests/compute/servers/test_list_server_filters.py
index d943e5d..45ea3a0 100644
--- a/tempest/tests/compute/servers/test_list_server_filters.py
+++ b/tempest/tests/compute/servers/test_list_server_filters.py
@@ -16,10 +16,8 @@
 #    under the License.
 
 
-import nose
 from nose.plugins.attrib import attr
-import nose.plugins.skip
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
diff --git a/tempest/tests/compute/servers/test_list_servers_negative.py b/tempest/tests/compute/servers/test_list_servers_negative.py
index 035ffe8..eb4ea02 100644
--- a/tempest/tests/compute/servers/test_list_servers_negative.py
+++ b/tempest/tests/compute/servers/test_list_servers_negative.py
@@ -18,8 +18,7 @@
 import re
 import sys
 
-import nose
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -64,7 +63,7 @@
             tenant_name = cls.os.tenant_name
             msg = ("User/tenant %(username)s/%(tenant_name)s already have "
                    "existing server instances. Skipping test.") % locals()
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         resp, body = cls.alt_client.list_servers()
         servers = body['servers']
@@ -74,7 +73,7 @@
             tenant_name = cls.alt_manager.tenant_name
             msg = ("Alt User/tenant %(username)s/%(tenant_name)s already have "
                    "existing server instances. Skipping test.") % locals()
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         # The following servers are created for use
         # by the test methods in this class. These
diff --git a/tempest/tests/compute/servers/test_server_actions.py b/tempest/tests/compute/servers/test_server_actions.py
index 2fe8464..fd35461 100644
--- a/tempest/tests/compute/servers/test_server_actions.py
+++ b/tempest/tests/compute/servers/test_server_actions.py
@@ -19,7 +19,7 @@
 import time
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest.common.utils.linux.remote_client import RemoteClient
@@ -35,8 +35,8 @@
     run_ssh = tempest.config.TempestConfig().compute.run_ssh
 
     @attr(type='smoke')
-    @unittest.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
-                         'Change password not available.')
+    @testtools.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
+                          'Change password not available.')
     def test_change_server_password(self):
         # The server's password should be set to the provided password
         new_password = 'Newpass1234'
@@ -70,7 +70,7 @@
             self.assertGreater(new_boot_time, boot_time)
 
     @attr(type='smoke')
-    @unittest.skip('Until bug 1014647 is dealt with.')
+    @testtools.skip('Until bug 1014647 is dealt with.')
     def test_reboot_server_soft(self):
         # The server should be signaled to reboot gracefully
         if self.run_ssh:
@@ -123,7 +123,7 @@
             self.assertTrue(linux_client.can_authenticate())
 
     @attr(type='smoke')
-    @unittest.skipIf(not resize_available, 'Resize not available.')
+    @testtools.skipIf(not resize_available, 'Resize not available.')
     def test_resize_server_confirm(self):
         # The server's RAM and disk space should be modified to that of
         # the provided flavor
@@ -139,7 +139,7 @@
         self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
 
     @attr(type='positive')
-    @unittest.skipIf(not resize_available, 'Resize not available.')
+    @testtools.skipIf(not resize_available, 'Resize not available.')
     def test_resize_server_revert(self):
         # The server's RAM and disk space should return to its original
         # values after a resize is reverted
diff --git a/tempest/tests/compute/servers/test_server_advanced_ops.py b/tempest/tests/compute/servers/test_server_advanced_ops.py
index 4e85b04..f949f2e 100644
--- a/tempest/tests/compute/servers/test_server_advanced_ops.py
+++ b/tempest/tests/compute/servers/test_server_advanced_ops.py
@@ -17,7 +17,6 @@
 
 import logging
 
-import nose
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import test
@@ -39,13 +38,13 @@
 
         if not cls.config.compute.resize_available:
             msg = "Skipping test - resize not available on this host"
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         resize_flavor = cls.config.compute.flavor_ref_alt
 
         if resize_flavor == cls.config.compute.flavor_ref:
             msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/tests/compute/servers/test_server_metadata.py b/tempest/tests/compute/servers/test_server_metadata.py
index 6c44c3c..7db963e 100644
--- a/tempest/tests/compute/servers/test_server_metadata.py
+++ b/tempest/tests/compute/servers/test_server_metadata.py
@@ -44,6 +44,7 @@
         super(ServerMetadataTest, cls).tearDownClass()
 
     def setUp(self):
+        super(ServerMetadataTest, self).setUp()
         meta = {'key1': 'value1', 'key2': 'value2'}
         resp, _ = self.client.set_server_metadata(self.server_id, meta)
         self.assertEqual(resp.status, 200)
diff --git a/tempest/tests/compute/servers/test_servers.py b/tempest/tests/compute/servers/test_servers.py
index 8054c1f..e0d4d44 100644
--- a/tempest/tests/compute/servers/test_servers.py
+++ b/tempest/tests/compute/servers/test_servers.py
@@ -168,7 +168,6 @@
         # deletes are running slow we could very well overrun system
         # memory
         self.clear_servers()
-
         super(ServersTestJSON, self).tearDown()
 
 
@@ -184,5 +183,4 @@
         # deletes are running slow we could very well overrun system
         # memory
         self.clear_servers()
-
         super(ServersTestXML, self).tearDown()
diff --git a/tempest/tests/compute/servers/test_servers_negative.py b/tempest/tests/compute/servers/test_servers_negative.py
index f7624b3..ea63360 100644
--- a/tempest/tests/compute/servers/test_servers_negative.py
+++ b/tempest/tests/compute/servers/test_servers_negative.py
@@ -17,9 +17,8 @@
 
 import sys
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -31,7 +30,7 @@
 
     @classmethod
     def setUpClass(cls):
-        raise nose.SkipTest("Until Bug 1046870 is fixed")
+        raise cls.skipException("Until Bug 1046870 is fixed")
         super(ServersNegativeTest, cls).setUpClass()
         cls.client = cls.servers_client
         cls.img_client = cls.images_client
diff --git a/tempest/tests/compute/servers/test_servers_whitebox.py b/tempest/tests/compute/servers/test_servers_whitebox.py
index 33519b0..502f16b 100644
--- a/tempest/tests/compute/servers/test_servers_whitebox.py
+++ b/tempest/tests/compute/servers/test_servers_whitebox.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 from nose.plugins.attrib import attr
 
 from tempest import exceptions
@@ -28,7 +27,7 @@
 
     @classmethod
     def setUpClass(cls):
-        raise nose.SkipTest("Until Bug 1034129 is fixed")
+        raise cls.skipException("Until Bug 1034129 is fixed")
         super(ServersWhiteboxTest, cls).setUpClass()
         BaseIdentityAdminTest.setUpClass()
         cls.client = cls.servers_client
diff --git a/tempest/tests/compute/test_authorization.py b/tempest/tests/compute/test_authorization.py
index 78661d1..4d3b553 100644
--- a/tempest/tests/compute/test_authorization.py
+++ b/tempest/tests/compute/test_authorization.py
@@ -16,9 +16,8 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-from nose import SkipTest
 from nose.tools import raises
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
@@ -34,7 +33,7 @@
     def setUpClass(cls):
         if not compute.MULTI_USER:
             msg = "Need >1 user"
-            raise SkipTest(msg)
+            raise cls.skipException(msg)
 
         super(AuthorizationTest, cls).setUpClass()
 
@@ -225,7 +224,7 @@
 
     @raises(exceptions.NotFound)
     @attr(type='negative')
-    @unittest.skip("Skipped until the Bug #1086980 is resolved")
+    @testtools.skip("Skipped until the Bug #1086980 is resolved")
     def test_delete_keypair_of_alt_account_fails(self):
         # A DELETE request for another user's keypair should fail
         self.alt_keypairs_client.delete_keypair(self.keypairname)
diff --git a/tempest/tests/compute/test_live_block_migration.py b/tempest/tests/compute/test_live_block_migration.py
index eceaaba..1b651ab 100644
--- a/tempest/tests/compute/test_live_block_migration.py
+++ b/tempest/tests/compute/test_live_block_migration.py
@@ -18,9 +18,8 @@
 import random
 import string
 
-import nose
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.linux.remote_client import RemoteClient
 from tempest import config
@@ -101,12 +100,12 @@
             return server_id
 
     @attr(type='positive')
-    @unittest.skipIf(not live_migration_available,
-                     'Block Live migration not available')
+    @testtools.skipIf(not live_migration_available,
+                      'Block Live migration not available')
     def test_001_live_block_migration(self):
         # Live block migrate an instance to another host
         if len(self._get_compute_hostnames()) < 2:
-            raise nose.SkipTest(
+            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)
@@ -116,9 +115,9 @@
         self.assertEquals(target_host, self._get_host_for_server(server_id))
 
     @attr(type='positive', bug='lp1051881')
-    @unittest.skip('Until bug 1051881 is dealt with.')
-    @unittest.skipIf(not live_migration_available,
-                     'Block Live migration not available')
+    @testtools.skip('Until bug 1051881 is dealt with.')
+    @testtools.skipIf(not live_migration_available,
+                      'Block Live migration not available')
     def test_002_invalid_host_for_migration(self):
         # Migrating to an invalid host should not change the status
 
diff --git a/tempest/tests/compute/test_quotas.py b/tempest/tests/compute/test_quotas.py
index 3dc2515..9306351 100644
--- a/tempest/tests/compute/test_quotas.py
+++ b/tempest/tests/compute/test_quotas.py
@@ -17,14 +17,13 @@
 
 from nose.plugins.attrib import attr
 
-from tempest.tests.compute.base import BaseComputeTest
+from tempest.tests.compute import base
 
 
-class QuotasTest(BaseComputeTest):
+class QuotasTestBase(object):
 
     @classmethod
     def setUpClass(cls):
-        super(QuotasTest, cls).setUpClass()
         cls.client = cls.quotas_client
         cls.admin_client = cls._get_identity_admin_client()
         resp, tenants = cls.admin_client.list_tenants()
@@ -47,3 +46,19 @@
             self.assertSequenceEqual(expected_quota_set, quota_set)
         except Exception:
             self.fail("Quota set for tenant did not have default limits")
+
+
+class QuotasTestJSON(QuotasTestBase, base.BaseComputeTestJSON):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeTestJSON.setUpClass()
+        super(QuotasTestJSON, cls).setUpClass()
+
+
+class QuotasTestXML(QuotasTestBase, base.BaseComputeTestXML):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeTestXML.setUpClass()
+        super(QuotasTestXML, cls).setUpClass()
diff --git a/tempest/tests/compute/volumes/test_attach_volume.py b/tempest/tests/compute/volumes/test_attach_volume.py
index 9581026..0e0e4a5 100644
--- a/tempest/tests/compute/volumes/test_attach_volume.py
+++ b/tempest/tests/compute/volumes/test_attach_volume.py
@@ -16,7 +16,7 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -68,7 +68,7 @@
         return server, volume
 
     @attr(type='positive')
-    @unittest.skipIf(not run_ssh, 'SSH required for this test')
+    @testtools.skipIf(not run_ssh, 'SSH required for this test')
     def test_attach_detach_volume(self):
         # Stop and Start a server with an attached volume, ensuring that
         # the volume remains attached.
diff --git a/tempest/tests/compute/volumes/test_volumes_list.py b/tempest/tests/compute/volumes/test_volumes_list.py
index fef9c8d..cc690a5 100644
--- a/tempest/tests/compute/volumes/test_volumes_list.py
+++ b/tempest/tests/compute/volumes/test_volumes_list.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 
 from tempest.common.utils.data_utils import rand_name
 from tempest.tests.compute import base
@@ -96,7 +95,7 @@
                            "test. This typically means that the backing file "
                            "size of the nova-volumes group is too small to "
                            "create the 3 volumes needed by this test case")
-                    raise nose.SkipTest(msg)
+                    raise cls.skipException(msg)
                 raise
 
     @classmethod
@@ -142,7 +141,7 @@
                            "test. This typically means that the backing file "
                            "size of the nova-volumes group is too small to "
                            "create the 3 volumes needed by this test case")
-                    raise nose.SkipTest(msg)
+                    raise cls.skipException(msg)
                 raise
 
     @classmethod
diff --git a/tempest/tests/identity/admin/test_roles.py b/tempest/tests/identity/admin/test_roles.py
index f0dd8d9..2779b51 100644
--- a/tempest/tests/identity/admin/test_roles.py
+++ b/tempest/tests/identity/admin/test_roles.py
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import unittest2 as unittest
+import testtools
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
diff --git a/tempest/tests/identity/admin/test_services.py b/tempest/tests/identity/admin/test_services.py
index 30dfeb0..5261b9d 100644
--- a/tempest/tests/identity/admin/test_services.py
+++ b/tempest/tests/identity/admin/test_services.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -76,4 +75,4 @@
     @classmethod
     def setUpClass(cls):
         super(ServicesTestXML, cls).setUpClass()
-        raise nose.SkipTest("Skipping until Bug #1061738 resolved")
+        raise cls.skipException("Skipping until Bug #1061738 resolved")
diff --git a/tempest/tests/identity/admin/test_tenants.py b/tempest/tests/identity/admin/test_tenants.py
index 578af4a..54383f1 100644
--- a/tempest/tests/identity/admin/test_tenants.py
+++ b/tempest/tests/identity/admin/test_tenants.py
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import unittest2 as unittest
+import testtools
 
 from nose.plugins.attrib import attr
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/identity/admin/test_users.py b/tempest/tests/identity/admin/test_users.py
index 7ad932b..ef7d934 100644
--- a/tempest/tests/identity/admin/test_users.py
+++ b/tempest/tests/identity/admin/test_users.py
@@ -16,11 +16,11 @@
 #    under the License.
 
 from nose.plugins.attrib import attr
-import unittest2 as unittest
-
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.tests.identity import base
+import testtools
+from testtools.matchers._basic import Contains
 
 
 class UsersTestBase(object):
@@ -76,7 +76,7 @@
                           self.data.tenant['id'], self.data.test_email)
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug 999084 is fixed")
     def test_create_user_with_empty_password(self):
         # User with an empty password should not be created
         self.data.setup_test_tenant()
@@ -85,7 +85,7 @@
                           self.alt_email)
 
     @attr(type='nagative')
-    @unittest.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug 999084 is fixed")
     def test_create_user_with_long_password(self):
         # User having password exceeding max length should not be created
         self.data.setup_test_tenant()
@@ -94,7 +94,7 @@
                           self.alt_email)
 
     @attr(type='negative')
-    @unittest.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug 999084 is fixed")
     def test_create_user_with_invalid_email_format(self):
         # Email format should be validated while creating a user
         self.data.setup_test_tenant()
@@ -227,8 +227,9 @@
         # Get a list of users and find the test user
         self.data.setup_test_user()
         resp, users = self.client.get_users()
-        self.assertIn(self.data.test_user, [u['name'] for u in users],
-                      "Could not find %s" % self.data.test_user)
+        self.assertThat([u['name'] for u in users],
+                        Contains(self.data.test_user),
+                        "Could not find %s" % self.data.test_user)
 
     @attr(type='negative')
     def test_get_users_by_unauthorized_user(self):
diff --git a/tempest/tests/identity/base.py b/tempest/tests/identity/base.py
index 9c318cd..cbd943e 100644
--- a/tempest/tests/identity/base.py
+++ b/tempest/tests/identity/base.py
@@ -15,14 +15,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 
 
-class BaseIdAdminTest(unittest.TestCase):
+class BaseIdAdminTest(testtools.TestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -31,7 +30,7 @@
         cls.token_client = os.token_client
 
         if not cls.client.has_admin_extensions():
-            raise nose.SkipTest("Admin extensions disabled")
+            raise cls.skipException("Admin extensions disabled")
 
         cls.data = DataGenerator(cls.client)
 
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/test_images.py
index 2429a32..0a1a25f 100644
--- a/tempest/tests/image/test_images.py
+++ b/tempest/tests/image/test_images.py
@@ -18,10 +18,10 @@
 import cStringIO as StringIO
 import random
 
-import unittest2 as unittest
+import testtools
 
 from nose.plugins.attrib import attr
-from nose.plugins.skip import SkipTest
+
 
 GLANCE_INSTALLED = False
 try:
@@ -33,7 +33,7 @@
 from tempest import clients
 
 
-class CreateRegisterImagesTest(unittest.TestCase):
+class CreateRegisterImagesTest(testtools.TestCase):
 
     """
     Here we test the registration and creation of images
@@ -42,7 +42,7 @@
     @classmethod
     def setUpClass(cls):
         if not GLANCE_INSTALLED:
-            raise SkipTest('Glance not installed')
+            raise cls.skipException('Glance not installed')
         cls.os = clients.ServiceManager()
         cls.client = cls.os.images.get_client()
         cls.created_images = []
@@ -128,7 +128,7 @@
         self.assertEqual('active', results.status)
 
 
-class ListImagesTest(unittest.TestCase):
+class ListImagesTest(testtools.TestCase):
 
     """
     Here we test the listing of image information
@@ -137,7 +137,7 @@
     @classmethod
     def setUpClass(cls):
         if not GLANCE_INSTALLED:
-            raise SkipTest('Glance not installed')
+            raise cls.skipException('Glance not installed')
         cls.os = clients.ServiceManager()
         cls.client = cls.os.images.get_client()
         cls.created_images = []
diff --git a/tempest/tests/network/base.py b/tempest/tests/network/base.py
index 90b351d..01330cc 100644
--- a/tempest/tests/network/base.py
+++ b/tempest/tests/network/base.py
@@ -15,15 +15,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 
 
-class BaseNetworkTest(unittest.TestCase):
+class BaseNetworkTest(testtools.TestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -40,7 +39,7 @@
         except exceptions.EndpointNotFound:
             enabled = False
             skip_msg = "No OpenStack Network API endpoint"
-            raise nose.SkipTest(skip_msg)
+            raise cls.skipException(skip_msg)
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/tests/network/test_network_basic_ops.py b/tempest/tests/network/test_network_basic_ops.py
index 3c99f77..bdebced 100644
--- a/tempest/tests/network/test_network_basic_ops.py
+++ b/tempest/tests/network/test_network_basic_ops.py
@@ -19,7 +19,6 @@
 import subprocess
 
 import netaddr
-import nose
 
 from quantumclient.common import exceptions as exc
 
@@ -179,7 +178,7 @@
 
         cls.enabled = not bool(msg)
         if msg:
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
     @classmethod
     def setUpClass(cls):
@@ -458,7 +457,7 @@
 
     def test_005_create_servers(self):
         if not (self.keypairs or self.security_groups or self.networks):
-            raise nose.SkipTest('Necessary resources have not been defined')
+            raise self.skipTest('Necessary resources have not been defined')
         for i, network in enumerate(self.networks):
             tenant_id = network.tenant_id
             name = rand_name('server-smoke-%d-' % i)
@@ -471,9 +470,9 @@
     def test_006_check_tenant_network_connectivity(self):
         if not self.config.network.tenant_networks_reachable:
             msg = 'Tenant networks not configured to be reachable.'
-            raise nose.SkipTest(msg)
+            raise self.skipTest(msg)
         if not self.servers:
-            raise nose.SkipTest("No VM's have been created")
+            raise self.skipTest("No VM's have been created")
         for server in self.servers:
             for net_name, ip_addresses in server.networks.iteritems():
                 for ip_address in ip_addresses:
@@ -484,9 +483,9 @@
     def test_007_assign_floating_ips(self):
         public_network_id = self.config.network.public_network_id
         if not public_network_id:
-            raise nose.SkipTest('Public network not configured')
+            raise self.skipTest('Public network not configured')
         if not self.servers:
-            raise nose.SkipTest("No VM's have been created")
+            raise self.skipTest("No VM's have been created")
         for server in self.servers:
             floating_ip = self._create_floating_ip(server, public_network_id)
             self.floating_ips.setdefault(server, [])
@@ -494,7 +493,7 @@
 
     def test_008_check_public_network_connectivity(self):
         if not self.floating_ips:
-            raise nose.SkipTest('No floating ips have been allocated.')
+            raise self.skipTest('No floating ips have been allocated.')
         for server, floating_ips in self.floating_ips.iteritems():
             for floating_ip in floating_ips:
                 ip_address = floating_ip.floating_ip_address
diff --git a/tempest/tests/object_storage/base.py b/tempest/tests/object_storage/base.py
index 5e3d0bc..8c32ffc 100644
--- a/tempest/tests/object_storage/base.py
+++ b/tempest/tests/object_storage/base.py
@@ -15,8 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 import tempest.config
@@ -24,7 +23,7 @@
 from tempest.tests.identity.base import DataGenerator
 
 
-class BaseObjectTest(unittest.TestCase):
+class BaseObjectTest(testtools.TestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -50,4 +49,4 @@
         except exceptions.EndpointNotFound:
             enabled = False
             skip_msg = "No OpenStack Object Storage API endpoint"
-            raise nose.SkipTest(skip_msg)
+            raise cls.skipException(skip_msg)
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
index 3dea259..597fd86 100644
--- a/tempest/tests/object_storage/test_container_sync.py
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -19,7 +19,7 @@
 from tempest.common.utils.data_utils import arbitrary_string
 from tempest.common.utils.data_utils import rand_name
 from tempest.tests.object_storage import base
-import unittest2 as unittest
+import testtools
 
 
 class ContainerSyncTest(base.BaseObjectTest):
@@ -61,7 +61,7 @@
             #Attempt to delete the container
             resp, _ = client[0].delete_container(cont_name)
 
-    @unittest.skip('Until Bug 1093743 is resolved.')
+    @testtools.skip('Until Bug 1093743 is resolved.')
     @attr(type='positive')
     def test_container_synchronization(self):
         #Container to container synchronization
diff --git a/tempest/tests/object_storage/test_object_expiry.py b/tempest/tests/object_storage/test_object_expiry.py
index 099fc16..8e6b23b 100644
--- a/tempest/tests/object_storage/test_object_expiry.py
+++ b/tempest/tests/object_storage/test_object_expiry.py
@@ -20,8 +20,8 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.tests.object_storage import base
+import testtools
 from time import sleep
-import unittest2 as unittest
 
 
 class ObjectExpiryTest(base.BaseObjectTest):
@@ -54,7 +54,7 @@
         #Attempt to delete the container
         resp, _ = cls.container_client.delete_container(cls.container_name)
 
-    @unittest.skip('Until bug 1069849 is resolved.')
+    @testtools.skip('Until bug 1069849 is resolved.')
     @attr(type='regression')
     def test_get_object_after_expiry_time(self):
         # GET object after expiry time
diff --git a/tempest/tests/object_storage/test_object_services.py b/tempest/tests/object_storage/test_object_services.py
index a65401c..d5b6d5c 100644
--- a/tempest/tests/object_storage/test_object_services.py
+++ b/tempest/tests/object_storage/test_object_services.py
@@ -21,8 +21,8 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.tests.object_storage import base
+import testtools
 from time import time
-import unittest2 as unittest
 
 
 class ObjectTest(base.BaseObjectTest):
@@ -327,7 +327,7 @@
                 self.assertIn('x-container-read', resp)
                 self.assertEqual(resp['x-container-read'], 'x')
 
-    @unittest.skip('Until Bug 1091669  is resolved.')
+    @testtools.skip('Until Bug 1091669  is resolved.')
     @attr(type='smoke')
     def test_access_public_object_with_another_user_creds(self):
         #Make container public-readable, and access the object
@@ -382,7 +382,7 @@
                 self.assertIn('x-container-read', resp)
                 self.assertEqual(resp['x-container-read'], 'x')
 
-    @unittest.skip('Until Bug #1020722 is resolved.')
+    @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
@@ -433,7 +433,7 @@
                 self.assertIn('x-container-write', resp)
                 self.assertEqual(resp['x-container-write'], 'x')
 
-    @unittest.skip('Until Bug #1020722 is resolved.')
+    @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
@@ -592,7 +592,7 @@
                           self.container_name, object_name,
                           metadata=self.custom_headers)
 
-    @unittest.skip('Until bug 1097137 is resolved.')
+    @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
diff --git a/tempest/tests/utils.py b/tempest/tests/utils.py
index 571fc2a..0738201 100644
--- a/tempest/tests/utils.py
+++ b/tempest/tests/utils.py
@@ -17,41 +17,7 @@
 
 """Common utilities used in testing."""
 
-import nose.plugins.skip
-
-
-class skip_if(object):
-    """Decorator that skips a test if condition is true."""
-    def __init__(self, condition, msg):
-        self.condition = condition
-        self.message = msg
-
-    def __call__(self, func):
-        def _skipper(*args, **kw):
-            """Wrapped skipper function."""
-            if self.condition:
-                raise nose.SkipTest(self.message)
-            func(*args, **kw)
-        _skipper.__name__ = func.__name__
-        _skipper.__doc__ = func.__doc__
-        return _skipper
-
-
-class skip_unless(object):
-    """Decorator that skips a test if condition is not true."""
-    def __init__(self, condition, msg):
-        self.condition = condition
-        self.message = msg
-
-    def __call__(self, func):
-        def _skipper(*args, **kw):
-            """Wrapped skipper function."""
-            if not self.condition:
-                raise nose.SkipTest(self.message)
-            func(*args, **kw)
-        _skipper.__name__ = func.__name__
-        _skipper.__doc__ = func.__doc__
-        return _skipper
+from testtools import TestCase
 
 
 class skip_unless_attr(object):
@@ -66,7 +32,7 @@
             """Wrapped skipper function."""
             testobj = args[0]
             if not getattr(testobj, self.attr, False):
-                raise nose.SkipTest(self.message)
+                raise TestCase.skipException(self.message)
             func(*args, **kw)
         _skipper.__name__ = func.__name__
         _skipper.__doc__ = func.__doc__
diff --git a/tempest/tests/volume/admin/base.py b/tempest/tests/volume/admin/base.py
index 364be54..21425be 100644
--- a/tempest/tests/volume/admin/base.py
+++ b/tempest/tests/volume/admin/base.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import nose
-
 
 from tempest import config
 import tempest.services.volume.json.admin.volume_types_client \
@@ -40,7 +38,7 @@
         if not cls.adm_user and cls.adm_pass and cls.adm_tenant:
             msg = ("Missing Volume Admin API credentials "
                    "in configuration.")
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
     @classmethod
     def tearDownClass(cls):
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 d139425..e7fe701 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
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import unittest
+import testtools
 import uuid
 
 from nose.plugins.attrib import attr
@@ -42,7 +42,7 @@
     def tearDownClass(cls):
         cls.client.delete_volume_type(cls.volume_type['id'])
 
-    @unittest.skip('Until bug 1090320 is fixed')
+    @testtools.skip('Until bug 1090320 is fixed')
     @raises(exceptions.BadRequest)
     @attr(type='negative')
     def test_update_no_body(self):
@@ -88,7 +88,7 @@
         self.client.create_volume_type_extra_specs(str(uuid.uuid4()),
                                                    extra_specs)
 
-    @unittest.skip('Until bug 1090322 is fixed')
+    @testtools.skip('Until bug 1090322 is fixed')
     @raises(exceptions.BadRequest)
     @attr(type='negative')
     def test_create_none_body(self):
@@ -96,7 +96,7 @@
         self.client.create_volume_type_extra_specs(self.volume_type['id'],
                                                    None)
 
-    @unittest.skip('Until bug 1090322 is fixed')
+    @testtools.skip('Until bug 1090322 is fixed')
     @raises(exceptions.BadRequest)
     @attr(type='negative')
     def test_create_invalid_body(self):
diff --git a/tempest/tests/volume/admin/test_volume_types_negative.py b/tempest/tests/volume/admin/test_volume_types_negative.py
index c2daef9..f53e33c 100644
--- a/tempest/tests/volume/admin/test_volume_types_negative.py
+++ b/tempest/tests/volume/admin/test_volume_types_negative.py
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import unittest
+import testtools
 import uuid
 
 from nose.plugins.attrib import attr
@@ -40,7 +40,7 @@
                                           display_name=str(uuid.uuid4()),
                                           volume_type=str(uuid.uuid4()))
 
-    @unittest.skip('Until bug 1090356 is fixed')
+    @testtools.skip('Until bug 1090356 is fixed')
     @raises(exceptions.BadRequest)
     @attr(type='negative')
     def test_create_with_empty_name(self):
diff --git a/tempest/tests/volume/base.py b/tempest/tests/volume/base.py
index 33bae45..de78c99 100644
--- a/tempest/tests/volume/base.py
+++ b/tempest/tests/volume/base.py
@@ -19,7 +19,7 @@
 import time
 
 import nose
-import unittest2 as unittest
+import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
@@ -29,7 +29,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class BaseVolumeTest(unittest.TestCase):
+class BaseVolumeTest(testtools.TestCase):
 
     """Base test case class for all Cinder API tests."""
 
@@ -66,7 +66,7 @@
                                              cls.os.tenant_name)
         except exceptions.EndpointNotFound:
             cls.clear_isolated_creds()
-            raise nose.SkipTest(skip_msg)
+            raise cls.skipException(skip_msg)
 
     @classmethod
     def _get_identity_admin_client(cls):
diff --git a/tempest/tests/volume/test_volumes_list.py b/tempest/tests/volume/test_volumes_list.py
index 2fc1353..92d3d3f 100644
--- a/tempest/tests/volume/test_volumes_list.py
+++ b/tempest/tests/volume/test_volumes_list.py
@@ -94,7 +94,7 @@
                            "test. This typically means that the backing file "
                            "size of the nova-volumes group is too small to "
                            "create the 3 volumes needed by this test case")
-                    raise nose.SkipTest(msg)
+                    raise cls.skipException(msg)
                 raise
 
     @classmethod
@@ -141,7 +141,7 @@
                            "test. This typically means that the backing file "
                            "size of the nova-volumes group is too small to "
                            "create the 3 volumes needed by this test case")
-                    raise nose.SkipTest(msg)
+                    raise cls.skipException(msg)
                 raise
 
     @classmethod
diff --git a/tempest/whitebox.py b/tempest/whitebox.py
index d78b9e0..03ad63b 100644
--- a/tempest/whitebox.py
+++ b/tempest/whitebox.py
@@ -21,7 +21,6 @@
 import subprocess
 import sys
 
-import nose
 from sqlalchemy import create_engine, MetaData
 
 from tempest.common.ssh import Client
@@ -59,7 +58,7 @@
     def setUpClass(cls):
         if not compute.WHITEBOX_ENABLED:
             msg = "Whitebox testing disabled"
-            raise nose.SkipTest(msg)
+            raise cls.skipException(msg)
 
         super(ComputeWhiteboxTest, cls).setUpClass()
 
diff --git a/tools/pip-requires b/tools/pip-requires
index fcf1690..dcc859f 100644
--- a/tools/pip-requires
+++ b/tools/pip-requires
@@ -1,7 +1,7 @@
 anyjson
 nose
 httplib2>=0.7.0
-unittest2
+testtools
 lxml
 boto>=2.2.1
 paramiko