Merge "Fix api_version filter for KeystoneV3AuthProvider"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 0f18f5e..1d571c0 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -165,6 +165,11 @@
 # value)
 #cli_dir=/usr/local/bin
 
+# Whether the tempest run location has access to the *-manage
+# commands. In a pure blackbox environment it will not.
+# (boolean value)
+#has_manage=true
+
 # Number of seconds to wait on a CLI timeout (integer value)
 #timeout=15
 
diff --git a/requirements.txt b/requirements.txt
index 8573a2e..a08a437 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,5 @@
 pbr>=0.5.21,<1.0
 anyjson>=0.3.3
-nose
 httplib2>=0.7.5
 jsonschema>=2.0.0,<3.0.0
 testtools>=0.9.34
diff --git a/run_tempest.sh b/run_tempest.sh
index f6c330d..bdd1f69 100755
--- a/run_tempest.sh
+++ b/run_tempest.sh
@@ -53,12 +53,12 @@
     -u|--update) update=1;;
     -d|--debug) debug=1;;
     -C|--config) config_file=$2; shift;;
-    -s|--smoke) testrargs+="smoke"; noseargs+="--attr=type=smoke";;
+    -s|--smoke) testrargs+="smoke";;
     -t|--serial) serial=1;;
     -l|--logging) logging=1;;
     -L|--logging-config) logging_config=$2; shift;;
     --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
+    *) testrargs+="$testrargs $1";;
   esac
   shift
 done
@@ -110,22 +110,6 @@
   fi
 }
 
-function run_tests_nose {
-    export NOSE_WITH_OPENSTACK=1
-    export NOSE_OPENSTACK_COLOR=1
-    export NOSE_OPENSTACK_RED=15.00
-    export NOSE_OPENSTACK_YELLOW=3.00
-    export NOSE_OPENSTACK_SHOW_ELAPSED=1
-    export NOSE_OPENSTACK_STDOUT=1
-    export TEMPEST_PY26_NOSE_COMPAT=1
-    if [[ "x$noseargs" =~ "tempest" ]]; then
-        noseargs="$testrargs"
-    else
-        noseargs="$noseargs tempest"
-    fi
-    ${wrapper} nosetests $noseargs
-}
-
 if [ $never_venv -eq 0 ]
 then
   # Remove the virtual environment if --force used
@@ -156,12 +140,7 @@
   fi
 fi
 
-py_version=`${wrapper} python --version 2>&1`
-if [[ $py_version =~ "2.6" ]] ; then
-    run_tests_nose
-else
-    run_tests
-fi
+run_tests
 retval=$?
 
 exit $retval
diff --git a/run_tests.sh b/run_tests.sh
index cb6a5df..a12bf46 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -54,7 +54,7 @@
     -c|--coverage) coverage=1;;
     -t|--serial) serial=1;;
     --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
+    *) testrargs="$testrargs $1";;
   esac
   shift
 done
@@ -84,6 +84,11 @@
       return $?
   fi
 
+  if [ $coverage -eq 1 ]; then
+      ${wrapper} python setup.py test --coverage
+      return $?
+  fi
+
   if [ $serial -eq 1 ]; then
       ${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
   else
@@ -137,10 +142,6 @@
     exit
 fi
 
-if [ $coverage -eq 1 ]; then
-    $testrargs = "--coverage $testrargs"
-fi
-
 run_tests
 retval=$?
 
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 0bf604c..826317d 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -15,8 +15,7 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class ServerRescueTestJSON(base.BaseV2ComputeTest):
@@ -26,7 +25,6 @@
     def setUpClass(cls):
         cls.set_network_resources(network=True, subnet=True, router=True)
         super(ServerRescueTestJSON, cls).setUpClass()
-        cls.device = 'vdf'
 
         # Floating IP creation
         resp, body = cls.floating_ips_client.create_floating_ip()
@@ -54,14 +52,6 @@
         cls.password = server['adminPass']
         cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
 
-        # Server for negative tests
-        cls.rescue_id = resc_server['id']
-        cls.rescue_password = resc_server['adminPass']
-
-        cls.servers_client.rescue_server(
-            cls.rescue_id, adminPass=cls.rescue_password)
-        cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
-
     def setUp(self):
         super(ServerRescueTestJSON, self).setUp()
 
@@ -77,22 +67,12 @@
     def tearDown(self):
         super(ServerRescueTestJSON, self).tearDown()
 
-    def _detach(self, server_id, volume_id):
-        self.servers_client.detach_volume(server_id, volume_id)
-        self.volumes_extensions_client.wait_for_volume_status(volume_id,
-                                                              'available')
-
     def _unrescue(self, server_id):
         resp, body = self.servers_client.unrescue_server(server_id)
         self.assertEqual(202, resp.status)
         self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
 
-    def _unpause(self, server_id):
-        resp, body = self.servers_client.unpause_server(server_id)
-        self.assertEqual(202, resp.status)
-        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
-
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_rescue_unrescue_instance(self):
         resp, body = self.servers_client.rescue_server(
             self.server_id, adminPass=self.password)
@@ -102,76 +82,7 @@
         self.assertEqual(202, resp.status)
         self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
 
-    @attr(type=['negative', 'gate'])
-    def test_rescue_paused_instance(self):
-        # Rescue a paused server
-        resp, body = self.servers_client.pause_server(
-            self.server_id)
-        self.addCleanup(self._unpause, self.server_id)
-        self.assertEqual(202, resp.status)
-        self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
-        self.assertRaises(exceptions.Conflict,
-                          self.servers_client.rescue_server,
-                          self.server_id)
-
-    @attr(type=['negative', 'gate'])
-    def test_rescued_vm_reboot(self):
-        self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
-                          self.rescue_id, 'HARD')
-
-    @attr(type=['negative', 'gate'])
-    def test_rescue_non_existent_server(self):
-        # Rescue a non-existing server
-        self.assertRaises(exceptions.NotFound,
-                          self.servers_client.rescue_server,
-                          '999erra43')
-
-    @attr(type=['negative', 'gate'])
-    def test_rescued_vm_rebuild(self):
-        self.assertRaises(exceptions.Conflict,
-                          self.servers_client.rebuild,
-                          self.rescue_id,
-                          self.image_ref_alt)
-
-    @attr(type=['negative', 'gate'])
-    def test_rescued_vm_attach_volume(self):
-        # Rescue the server
-        self.servers_client.rescue_server(self.server_id,
-                                          adminPass=self.password)
-        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
-        self.addCleanup(self._unrescue, self.server_id)
-
-        # Attach the volume to the server
-        self.assertRaises(exceptions.Conflict,
-                          self.servers_client.attach_volume,
-                          self.server_id,
-                          self.volume['id'],
-                          device='/dev/%s' % self.device)
-
-    @attr(type=['negative', 'gate'])
-    def test_rescued_vm_detach_volume(self):
-        # Attach the volume to the server
-        self.servers_client.attach_volume(self.server_id,
-                                          self.volume['id'],
-                                          device='/dev/%s' % self.device)
-        self.volumes_extensions_client.wait_for_volume_status(
-            self.volume['id'], 'in-use')
-
-        # Rescue the server
-        self.servers_client.rescue_server(self.server_id,
-                                          adminPass=self.password)
-        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
-        # addCleanup is a LIFO queue
-        self.addCleanup(self._detach, self.server_id, self.volume['id'])
-        self.addCleanup(self._unrescue, self.server_id)
-
-        # Detach the volume from the server expecting failure
-        self.assertRaises(exceptions.Conflict,
-                          self.servers_client.detach_volume,
-                          self.server_id,
-                          self.volume['id'])
-
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_rescued_vm_associate_dissociate_floating_ip(self):
         # Rescue the server
         self.servers_client.rescue_server(
@@ -191,7 +102,7 @@
                                                         self.server_id)
         self.assertEqual(202, resp.status)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_rescued_vm_add_remove_security_group(self):
         # Rescue the server
         self.servers_client.rescue_server(
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
new file mode 100644
index 0000000..ffd79fa
--- /dev/null
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -0,0 +1,135 @@
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright 2014 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.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        cls.set_network_resources(network=True, subnet=True, router=True)
+        super(ServerRescueNegativeTestJSON, cls).setUpClass()
+        cls.device = 'vdf'
+
+        # Create a volume and wait for it to become ready for attach
+        resp, cls.volume = cls.volumes_extensions_client.create_volume(
+            1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
+        cls.volumes_extensions_client.wait_for_volume_status(
+            cls.volume['id'], 'available')
+
+        # Server for negative tests
+        resp, server = cls.create_test_server(wait_until='BUILD')
+        resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
+        cls.password = server['adminPass']
+        cls.rescue_id = resc_server['id']
+        rescue_password = resc_server['adminPass']
+
+        cls.servers_client.rescue_server(
+            cls.rescue_id, adminPass=rescue_password)
+        cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
+
+    def _detach(self, server_id, volume_id):
+        self.servers_client.detach_volume(server_id, volume_id)
+        self.volumes_extensions_client.wait_for_volume_status(volume_id,
+                                                              'available')
+
+    def _unrescue(self, server_id):
+        resp, body = self.servers_client.unrescue_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+    def _unpause(self, server_id):
+        resp, body = self.servers_client.unpause_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescue_paused_instance(self):
+        # Rescue a paused server
+        resp, body = self.servers_client.pause_server(self.server_id)
+        self.addCleanup(self._unpause, self.server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.rescue_server,
+                          self.server_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescued_vm_reboot(self):
+        self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
+                          self.rescue_id, 'HARD')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescue_non_existent_server(self):
+        # Rescue a non-existing server
+        non_existent_server = data_utils.rand_uuid()
+        self.assertRaises(exceptions.NotFound,
+                          self.servers_client.rescue_server,
+                          non_existent_server)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescued_vm_rebuild(self):
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.rebuild,
+                          self.rescue_id,
+                          self.image_ref_alt)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescued_vm_attach_volume(self):
+        # Rescue the server
+        self.servers_client.rescue_server(self.server_id,
+                                          adminPass=self.password)
+        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        self.addCleanup(self._unrescue, self.server_id)
+
+        # Attach the volume to the server
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.attach_volume,
+                          self.server_id,
+                          self.volume['id'],
+                          device='/dev/%s' % self.device)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_rescued_vm_detach_volume(self):
+        # Attach the volume to the server
+        self.servers_client.attach_volume(self.server_id,
+                                          self.volume['id'],
+                                          device='/dev/%s' % self.device)
+        self.volumes_extensions_client.wait_for_volume_status(
+            self.volume['id'], 'in-use')
+
+        # Rescue the server
+        self.servers_client.rescue_server(self.server_id,
+                                          adminPass=self.password)
+        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        # addCleanup is a LIFO queue
+        self.addCleanup(self._detach, self.server_id, self.volume['id'])
+        self.addCleanup(self._unrescue, self.server_id)
+
+        # Detach the volume from the server expecting failure
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.detach_volume,
+                          self.server_id,
+                          self.volume['id'])
+
+
+class ServerRescueNegativeTestXML(ServerRescueNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index da0e4c4..e1a264e 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -38,7 +38,7 @@
     def _migrate_server_to(self, server_id, dest_host):
         _resp, body = self.admin_servers_client.live_migrate_server(
             server_id, dest_host,
-            self.config.compute_feature_enabled.
+            CONF.compute_feature_enabled.
             block_migration_for_live_migration)
         return body
 
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index c4f6e14..5a8465c 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -25,7 +25,7 @@
         super(InstanceActionsV3Test, cls).setUpClass()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
-        cls.request_id = resp['x-compute-request-id']
+        cls.resp = resp
         cls.server_id = server['id']
 
     @test.attr(type='gate')
@@ -41,10 +41,12 @@
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
     @test.attr(type='gate')
+    @test.skip_because(bug="1281915")
     def test_get_instance_action(self):
         # Get the action details of the provided server
+        request_id = self.resp['x-compute-request-id']
         resp, body = self.client.get_instance_action(self.server_id,
-                                                     self.request_id)
+                                                     request_id)
         self.assertEqual(200, resp.status)
         self.assertEqual(self.server_id, body['instance_uuid'])
         self.assertEqual('create', body['action'])
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
index f1ae5f8..dee4407 100644
--- a/tempest/api/compute/v3/servers/test_multiple_create.py
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -15,7 +15,6 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest import test
 
 
@@ -47,38 +46,6 @@
         self.assertEqual('202', resp['status'])
         self.assertNotIn('reservation_id', body)
 
-    @test.attr(type=['negative', 'gate'])
-    def test_min_count_less_than_one(self):
-        invalid_min_count = 0
-        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
-                          min_count=invalid_min_count)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_min_count_non_integer(self):
-        invalid_min_count = 2.5
-        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
-                          min_count=invalid_min_count)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_max_count_less_than_one(self):
-        invalid_max_count = 0
-        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
-                          max_count=invalid_max_count)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_max_count_non_integer(self):
-        invalid_max_count = 2.5
-        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
-                          max_count=invalid_max_count)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_max_count_less_than_min_count(self):
-        min_count = 3
-        max_count = 2
-        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
-                          min_count=min_count,
-                          max_count=max_count)
-
     @test.attr(type='gate')
     def test_multiple_create_with_reservation_return(self):
         resp, body = self._create_multiple_servers(wait_until='ACTIVE',
diff --git a/tempest/api/compute/v3/servers/test_multiple_create_negative.py b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
new file mode 100644
index 0000000..57bb807
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
@@ -0,0 +1,69 @@
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class MultipleCreateV3NegativeTest(base.BaseV3ComputeTest):
+    _interface = 'json'
+    _name = 'multiple-create-negative-test'
+
+    def _generate_name(self):
+        return data_utils.rand_name(self._name)
+
+    def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
+        """
+        This is the right way to create_multiple servers and manage to get the
+        created servers into the servers list to be cleaned up after all.
+        """
+        kwargs['name'] = kwargs.get('name', self._generate_name())
+        resp, body = self.create_test_server(**kwargs)
+
+        return resp, body
+
+    @test.attr(type=['negative', 'gate'])
+    def test_min_count_less_than_one(self):
+        invalid_min_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_min_count_non_integer(self):
+        invalid_min_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_max_count_less_than_one(self):
+        invalid_max_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_max_count_non_integer(self):
+        invalid_max_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_max_count_less_than_min_count(self):
+        min_count = 3
+        max_count = 2
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=min_count,
+                          max_count=max_count)
diff --git a/tempest/api/compute/v3/test_live_block_migration_negative.py b/tempest/api/compute/v3/test_live_block_migration_negative.py
index 4d820d8..9e07478 100644
--- a/tempest/api/compute/v3/test_live_block_migration_negative.py
+++ b/tempest/api/compute/v3/test_live_block_migration_negative.py
@@ -39,7 +39,7 @@
     def _migrate_server_to(self, server_id, dest_host):
         _resp, body = self.admin_servers_client.live_migrate_server(
             server_id, dest_host,
-            self.config.compute_feature_enabled.
+            CONF.compute_feature_enabled.
             block_migration_for_live_migration)
         return body
 
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d552c70..0ff91ab 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -16,6 +16,7 @@
 import netaddr
 
 from tempest.api.network import base_routers as base
+from tempest import clients
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import test
@@ -32,6 +33,8 @@
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
+        admin_manager = clients.AdminManager()
+        cls.identity_admin_client = admin_manager.identity_client
 
     @test.attr(type='smoke')
     def test_create_show_list_update_delete_router(self):
@@ -77,6 +80,25 @@
         self.assertEqual(show_body['router']['name'], updated_name)
 
     @test.attr(type='smoke')
+    def test_create_router_setting_tenant_id(self):
+        # Test creating router from admin user setting tenant_id.
+        test_tenant = data_utils.rand_name('test_tenant_')
+        test_description = data_utils.rand_name('desc_')
+        _, tenant = self.identity_admin_client.create_tenant(
+            name=test_tenant,
+            description=test_description)
+        tenant_id = tenant['id']
+        self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+
+        name = data_utils.rand_name('router-')
+        resp, create_body = self.admin_client.create_router(
+            name, tenant_id=tenant_id)
+        self.assertEqual('201', resp['status'])
+        self.addCleanup(self.admin_client.delete_router,
+                        create_body['router']['id'])
+        self.assertEqual(tenant_id, create_body['router']['tenant_id'])
+
+    @test.attr(type='smoke')
     def test_add_remove_router_interface_with_subnet_id(self):
         network = self.create_network()
         subnet = self.create_subnet(network)
diff --git a/tempest/cli/simple_read_only/test_nova_manage.py b/tempest/cli/simple_read_only/test_nova_manage.py
index 13a1589..f1fee2e 100644
--- a/tempest/cli/simple_read_only/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/test_nova_manage.py
@@ -41,6 +41,10 @@
         if not CONF.service_available.nova:
             msg = ("%s skipped as Nova is not available" % cls.__name__)
             raise cls.skipException(msg)
+        if not CONF.cli.has_manage:
+            msg = ("%s skipped as *-manage commands not available"
+                   % cls.__name__)
+            raise cls.skipException(msg)
         super(SimpleReadOnlyNovaManageTest, cls).setUpClass()
 
     def test_admin_fake_action(self):
diff --git a/tempest/config.py b/tempest/config.py
index 4380608..ad91494 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -772,6 +772,11 @@
     cfg.StrOpt('cli_dir',
                default='/usr/local/bin',
                help="directory where python client binaries are located"),
+    cfg.BoolOpt('has_manage',
+                default=True,
+                help=("Whether the tempest run location has access to the "
+                      "*-manage commands. In a pure blackbox environment "
+                      "it will not.")),
     cfg.IntOpt('timeout',
                default=15,
                help="Number of seconds to wait on a CLI timeout"),
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 1763808..4c3a01c 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -225,8 +225,9 @@
             # so case sensitive comparisons can really mess things
             # up.
             if new_status.lower() == error_status.lower():
-                message = ("%s failed to get to expected status. "
-                           "In %s state.") % (thing, new_status)
+                message = ("%s failed to get to expected status (%s). "
+                           "In %s state.") % (thing, expected_status,
+                                              new_status)
                 raise exceptions.BuildErrorException(message,
                                                      server_id=thing_id)
             elif new_status == expected_status and expected_status is not None:
@@ -290,6 +291,27 @@
             image = CONF.compute.image_ref
         if flavor is None:
             flavor = CONF.compute.flavor_ref
+
+        fixed_network_name = CONF.compute.fixed_network_name
+        if 'nics' not in create_kwargs and fixed_network_name:
+            networks = client.networks.list()
+            # If several networks found, set the NetID on which to connect the
+            # server to avoid the following error "Multiple possible networks
+            # found, use a Network ID to be more specific."
+            # See Tempest #1250866
+            if len(networks) > 1:
+                for network in networks:
+                    if network.label == fixed_network_name:
+                        create_kwargs['nics'] = [{'net-id': network.id}]
+                        break
+                # If we didn't find the network we were looking for :
+                else:
+                    msg = ("The network on which the NIC of the server must "
+                           "be connected can not be found : "
+                           "fixed_network_name=%s. Starting instance without "
+                           "specifying a network.") % fixed_network_name
+                    LOG.info(msg)
+
         LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
                   name, image, flavor)
         server = client.servers.create(name, image, flavor, **create_kwargs)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 1144414..d369f12 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -26,10 +26,6 @@
 
 LOG = logging.getLogger(__name__)
 
-# NOTE(andreaf) - nose does not honour the load_tests protocol
-# however it's test discovery regex will match anything
-# which includes _tests. So nose would require some further
-# investigation to be supported with this
 load_tests = testscenarios.load_tests_apply_scenarios
 
 
diff --git a/tempest/test.py b/tempest/test.py
index 22aa3f2..c6e3d6e 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -23,7 +23,6 @@
 import uuid
 
 import fixtures
-import nose.plugins.attrib
 import testresources
 import testtools
 
@@ -43,11 +42,10 @@
 
 
 def attr(*args, **kwargs):
-    """A decorator which applies the nose and testtools attr decorator
+    """A decorator which applies the  testtools attr decorator
 
-    This decorator applies the nose attr decorator as well as the
-    the testtools.testcase.attr if it is in the list of attributes
-    to testtools we want to apply.
+    This decorator applies the testtools.testcase.attr if it is in the list of
+    attributes to testtools we want to apply.
     """
 
     def decorator(f):
@@ -60,7 +58,7 @@
                 f = testtools.testcase.attr(attr)(f)
                 if attr == 'smoke':
                     f = testtools.testcase.attr('gate')(f)
-        return nose.plugins.attrib.attr(*args, **kwargs)(f)
+        return f
 
     return decorator
 
@@ -194,40 +192,6 @@
         return True
     return False
 
-# there is a mis-match between nose and testtools for older pythons.
-# testtools will set skipException to be either
-# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
-# exception, depending on what it can find. Python <2.7 doesn't have
-# unittest.case.SkipTest; so if unittest2 is not installed it falls
-# back to the internal class.
-#
-# The current nose skip plugin will decide to raise either
-# unittest.case.SkipTest or its own internal exception; it does not
-# look for unittest2 or the internal unittest exception.  Thus we must
-# monkey-patch testtools.TestCase.skipException to be the exception
-# the nose skip plugin expects.
-#
-# However, with the switch to testr nose may not be available, so we
-# require you to opt-in to this fix with an environment variable.
-#
-# This is temporary until upstream nose starts looking for unittest2
-# as testtools does; we can then remove this and ensure unittest2 is
-# available for older pythons; then nose and testtools will agree
-# unittest2.case.SkipTest is the one-true skip test exception.
-#
-#   https://review.openstack.org/#/c/33056
-#   https://github.com/nose-devs/nose/pull/699
-if 'TEMPEST_PY26_NOSE_COMPAT' in os.environ:
-    try:
-        import unittest.case.SkipTest
-        # convince pep8 we're using the import...
-        if unittest.case.SkipTest:
-            pass
-        raise RuntimeError("You have unittest.case.SkipTest; "
-                           "no need to override")
-    except ImportError:
-        LOG.info("Overriding skipException to nose SkipTest")
-        testtools.TestCase.skipException = nose.plugins.skip.SkipTest
 
 at_exit_set = set()
 
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 88920dc..aa3c8fc 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -41,10 +41,6 @@
             self.assertEqual(getattr(foo, '__testtools_attrs'),
                              set(expected_attrs))
 
-        # nose sets it anyway
-        for arg, value in decorator_args.items():
-            self.assertEqual(getattr(foo, arg), value)
-
     def test_attr_without_type(self):
         self._test_attr_helper(expected_attrs='baz', bar='baz')
 
@@ -74,7 +70,6 @@
         t = TestFoo('test_bar')
         self.assertEqual(set(decorator_args), getattr(t.test_bar,
                                                       '__testtools_attrs'))
-        self.assertEqual(list(decorator_args), t.test_bar.type)
         self.assertEqual(t.test_bar(), 0)
 
     def test_services_decorator_with_single_service(self):
@@ -110,7 +105,6 @@
                          expected_frequency)
         self.assertEqual(getattr(foo, 'st_allow_inheritance'),
                          expected_inheritance)
-        self.assertEqual(foo.type, 'stress')
         self.assertEqual(set(['stress']), getattr(foo, '__testtools_attrs'))
 
     def test_stresstest_decorator_default(self):
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index b36e8c7..6a9836b 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -26,14 +26,12 @@
 import keystoneclient.exceptions
 
 import tempest.clients
-from tempest.common.utils.file_utils import have_effective_read_access
+from tempest.common.utils import file_utils
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
 import tempest.test
-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
+from tempest.thirdparty.boto.utils import wait
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -47,7 +45,7 @@
     id_matcher = re.compile("[A-Za-z0-9]{20,}")
 
     def all_read(*args):
-        return all(map(have_effective_read_access, args))
+        return all(map(file_utils.have_effective_read_access, args))
 
     materials_path = CONF.boto.s3_materials_path
     ami_path = materials_path + os.sep + CONF.boto.ami_manifest
@@ -327,7 +325,7 @@
             final_set = set((final_set,))
         final_set |= self.gone_set
         lfunction = self.get_lfunction_gone(lfunction)
-        state = state_wait(lfunction, final_set, valid_set)
+        state = wait.state_wait(lfunction, final_set, valid_set)
         self.assertIn(state, valid_set | self.gone_set)
         return state
 
@@ -377,8 +375,8 @@
                 return "ASSOCIATED"
             return "DISASSOCIATED"
 
-        state = state_wait(_disassociate, "DISASSOCIATED",
-                           set(("ASSOCIATED", "DISASSOCIATED")))
+        state = wait.state_wait(_disassociate, "DISASSOCIATED",
+                                set(("ASSOCIATED", "DISASSOCIATED")))
         self.assertEqual(state, "DISASSOCIATED")
 
     def assertAddressReleasedWait(self, address):
@@ -391,7 +389,7 @@
                     return "DELETED"
             return "NOTDELETED"
 
-        state = state_wait(_address_delete, "DELETED")
+        state = wait.state_wait(_address_delete, "DELETED")
         self.assertEqual(state, "DELETED")
 
     def assertReSearch(self, regexp, string):
@@ -462,7 +460,7 @@
         for instance in reservation.instances:
             try:
                 instance.terminate()
-                re_search_wait(_instance_state, "_GONE")
+                wait.re_search_wait(_instance_state, "_GONE")
             except BaseException:
                 LOG.exception("Failed to terminate instance %s " % instance)
                 exc_num += 1
@@ -503,7 +501,8 @@
             return volume.status
 
         try:
-            re_search_wait(_volume_state, "available")  # not validates status
+            wait.re_search_wait(_volume_state, "available")
+            # not validates status
             LOG.info(_volume_state())
             volume.delete()
         except BaseException:
@@ -520,7 +519,7 @@
         def _update():
             snapshot.update(validate=True)
 
-        wait_exception(_update)
+        wait.wait_exception(_update)
 
 
 # you can specify tuples if you want to specify the status pattern
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 54861be..bbfbb79 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -16,23 +16,21 @@
 from boto import exception
 
 from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.test import skip_because
-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
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
+from tempest.thirdparty.boto.utils import wait
 
 CONF = config.CONF
 
 LOG = logging.getLogger(__name__)
 
 
-class InstanceRunTest(BotoTestCase):
+class InstanceRunTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -57,7 +55,7 @@
         cls.addResourceCleanUp(cls.destroy_bucket,
                                cls.s3_client.connection_data,
                                cls.bucket_name)
-        s3_upload_dir(bucket, cls.materials_path)
+        s3.s3_upload_dir(bucket, cls.materials_path)
         cls.images = {"ami":
                       {"name": data_utils.rand_name("ami-name-"),
                        "location": cls.bucket_name + "/" + ami_manifest},
@@ -78,14 +76,14 @@
             def _state():
                 retr = cls.ec2_client.get_image(image["image_id"])
                 return retr.state
-            state = state_wait(_state, "available")
+            state = wait.state_wait(_state, "available")
             if state != "available":
                 for _image in cls.images.itervalues():
                     cls.ec2_client.deregister_image(_image["image_id"])
                 raise exceptions.EC2RegisterImageException(image_id=
                                                            image["image_id"])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_run_idempotent_instances(self):
         # EC2 run instances idempotently
 
@@ -123,7 +121,7 @@
         _terminate_reservation(reservation_1, rcuk_1)
         _terminate_reservation(reservation_2, rcuk_2)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_run_stop_terminate_instance(self):
         # EC2 run, stop and terminate instance
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -148,7 +146,7 @@
             instance.terminate()
         self.cancelResourceCleanUp(rcuk)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_run_stop_terminate_instance_with_tags(self):
         # EC2 run, stop and terminate instance with tags
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -195,8 +193,8 @@
             instance.terminate()
         self.cancelResourceCleanUp(rcuk)
 
-    @skip_because(bug="1098891")
-    @attr(type='smoke')
+    @test.skip_because(bug="1098891")
+    @test.attr(type='smoke')
     def test_run_terminate_instance(self):
         # EC2 run, terminate immediately
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -222,8 +220,8 @@
 
     # NOTE(afazekas): doctored test case,
     # with normal validation it would fail
-    @skip_because(bug="1182679")
-    @attr(type='smoke')
+    @test.skip_because(bug="1182679")
+    @test.attr(type='smoke')
     def test_integration_1(self):
         # EC2 1. integration test (not strict)
         image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
@@ -271,9 +269,9 @@
         self.assertVolumeStatusWait(volume, "available")
         # NOTE(afazekas): it may be reports available before it is available
 
-        ssh = RemoteClient(address.public_ip,
-                           CONF.compute.ssh_user,
-                           pkey=self.keypair.material)
+        ssh = remote_client.RemoteClient(address.public_ip,
+                                         CONF.compute.ssh_user,
+                                         pkey=self.keypair.material)
         text = data_utils.rand_name("Pattern text for console output -")
         resp = ssh.write_to_console(text)
         self.assertFalse(resp)
@@ -282,7 +280,7 @@
             output = instance.get_console_output()
             return output.output
 
-        re_search_wait(_output, text)
+        wait.re_search_wait(_output, text)
         part_lines = ssh.get_partitions().split('\n')
         volume.attach(instance.id, "/dev/vdh")
 
@@ -291,7 +289,7 @@
             return volume.status
 
         self.assertVolumeStatusWait(_volume_state, "in-use")
-        re_search_wait(_volume_state, "in-use")
+        wait.re_search_wait(_volume_state, "in-use")
 
         # NOTE(afazekas):  Different Hypervisor backends names
         # differently the devices,
@@ -305,7 +303,7 @@
                 return 'DECREASE'
             return 'EQUAL'
 
-        state_wait(_part_state, 'INCREASE')
+        wait.state_wait(_part_state, 'INCREASE')
         part_lines = ssh.get_partitions().split('\n')
 
         # TODO(afazekas): Resource compare to the flavor settings
@@ -313,10 +311,10 @@
         volume.detach()
 
         self.assertVolumeStatusWait(_volume_state, "available")
-        re_search_wait(_volume_state, "available")
+        wait.re_search_wait(_volume_state, "available")
         LOG.info("Volume %s state: %s", volume.id, volume.status)
 
-        state_wait(_part_state, 'DECREASE')
+        wait.state_wait(_part_state, 'DECREASE')
 
         instance.stop()
         address.disassociate()
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 329ace3..37484cf 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -14,9 +14,8 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
 
 def compare_key_pairs(a, b):
@@ -24,7 +23,7 @@
             a.fingerprint == b.fingerprint)
 
 
-class EC2KeysTest(BotoTestCase):
+class EC2KeysTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -33,7 +32,7 @@
         cls.ec = cls.ec2_error_code
 
 # TODO(afazekas): merge create, delete, get test cases
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_ec2_keypair(self):
         # EC2 create KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -42,8 +41,8 @@
         self.assertTrue(compare_key_pairs(keypair,
                         self.client.get_key_pair(key_name)))
 
-    @skip_because(bug="1072318")
-    @attr(type='smoke')
+    @test.skip_because(bug="1072318")
+    @test.attr(type='smoke')
     def test_delete_ec2_keypair(self):
         # EC2 delete KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -51,7 +50,7 @@
         self.client.delete_key_pair(key_name)
         self.assertEqual(None, self.client.get_key_pair(key_name))
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_get_ec2_keypair(self):
         # EC2 get KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -60,7 +59,7 @@
         self.assertTrue(compare_key_pairs(keypair,
                         self.client.get_key_pair(key_name)))
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_duplicate_ec2_keypair(self):
         # EC2 duplicate KeyPair
         key_name = data_utils.rand_name("keypair-")
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index 4b2f01f..d508c07 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -13,12 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
 
-class EC2NetworkTest(BotoTestCase):
+class EC2NetworkTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -26,8 +25,8 @@
         cls.client = cls.os.ec2api_client
 
     # Note(afazekas): these tests for things duable without an instance
-    @skip_because(bug="1080406")
-    @attr(type='smoke')
+    @test.skip_because(bug="1080406")
+    @test.attr(type='smoke')
     def test_disassociate_not_associated_floating_ip(self):
         # EC2 disassociate not associated floating ip
         ec2_codes = self.ec2_error_code
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 9b58603..86140ec 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -14,18 +14,18 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
 
-class EC2SecurityGroupTest(BotoTestCase):
+class EC2SecurityGroupTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
         super(EC2SecurityGroupTest, cls).setUpClass()
         cls.client = cls.os.ec2api_client
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_authorize_security_group(self):
         # EC2 Create, authorize/revoke security group
         group_name = data_utils.rand_name("securty_group-")
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index 04671c5..6a771e5 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -13,10 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest import config
 from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -25,15 +27,20 @@
             a.size == b.size)
 
 
-class EC2VolumesTest(BotoTestCase):
+class EC2VolumesTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
         super(EC2VolumesTest, cls).setUpClass()
+
+        if not CONF.service_available.cinder:
+            skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
+            raise cls.skipException(skip_msg)
+
         cls.client = cls.os.ec2api_client
         cls.zone = cls.client.get_good_zone()
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_get_delete(self):
         # EC2 Create, get, delete Volume
         volume = self.client.create_volume(1, self.zone)
@@ -46,7 +53,7 @@
         self.client.delete_volume(volume.id)
         self.cancelResourceCleanUp(cuk)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_volume_from_snapshot(self):
         # EC2 Create volume from snapshot
         volume = self.client.create_volume(1, self.zone)
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index f34faac..af6aa8b 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -14,20 +14,19 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
 
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
         super(S3BucketsTest, cls).setUpClass()
         cls.client = cls.os.s3_client
 
-    @skip_because(bug="1076965")
-    @attr(type='smoke')
+    @test.skip_because(bug="1076965")
+    @test.attr(type='smoke')
     def test_create_and_get_delete_bucket(self):
         # S3 Create, get and delete bucket
         bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index 9607a92..d2300ee 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -17,14 +17,14 @@
 
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
-from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
 
 CONF = config.CONF
 
 
-class S3ImagesTest(BotoTestCase):
+class S3ImagesTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
@@ -46,9 +46,9 @@
         cls.addResourceCleanUp(cls.destroy_bucket,
                                cls.s3_client.connection_data,
                                cls.bucket_name)
-        s3_upload_dir(bucket, cls.materials_path)
+        s3.s3_upload_dir(bucket, cls.materials_path)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_register_get_deregister_ami_image(self):
         # Register and deregister ami image
         image = {"name": data_utils.rand_name("ami-name-"),
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index a102a22..1ae46de 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -18,18 +18,18 @@
 import boto.s3.key
 
 from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
 
 
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
 
     @classmethod
     def setUpClass(cls):
         super(S3BucketsTest, cls).setUpClass()
         cls.client = cls.os.s3_client
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_get_delete_object(self):
         # S3 Create, get and delete object
         bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/utils/wait.py b/tempest/thirdparty/boto/utils/wait.py
index eed0a92..752ed0f 100644
--- a/tempest/thirdparty/boto/utils/wait.py
+++ b/tempest/thirdparty/boto/utils/wait.py
@@ -17,7 +17,7 @@
 import time
 
 import boto.exception
-from testtools import TestCase
+import testtools
 
 from tempest import config
 from tempest.openstack.common import log as logging
@@ -44,10 +44,11 @@
             return status
         dtime = time.time() - start_time
         if dtime > CONF.boto.build_timeout:
-            raise TestCase.failureException("State change timeout exceeded!"
-                                            '(%ds) While waiting'
-                                            'for %s at "%s"' %
-                                            (dtime, final_set, status))
+            raise testtools.TestCase\
+                .failureException("State change timeout exceeded!"
+                                  '(%ds) While waiting'
+                                  'for %s at "%s"' %
+                                  (dtime, final_set, status))
         time.sleep(CONF.boto.build_interval)
         old_status = status
         status = lfunction()
@@ -67,10 +68,11 @@
             return result
         dtime = time.time() - start_time
         if dtime > CONF.boto.build_timeout:
-            raise TestCase.failureException('Pattern find timeout exceeded!'
-                                            '(%ds) While waiting for'
-                                            '"%s" pattern in "%s"' %
-                                            (dtime, regexp, text))
+            raise testtools.TestCase\
+                .failureException('Pattern find timeout exceeded!'
+                                  '(%ds) While waiting for'
+                                  '"%s" pattern in "%s"' %
+                                  (dtime, regexp, text))
         time.sleep(CONF.boto.build_interval)
 
 
@@ -98,8 +100,8 @@
         # Let the other exceptions propagate
         dtime = time.time() - start_time
         if dtime > CONF.boto.build_timeout:
-            raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
-                                            dtime)
+            raise testtools.TestCase\
+                .failureException("Wait timeout exceeded! (%ds)" % dtime)
         time.sleep(CONF.boto.build_interval)
 
 
@@ -116,8 +118,8 @@
             return exc
         dtime = time.time() - start_time
         if dtime > CONF.boto.build_timeout:
-            raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
-                                            dtime)
+            raise testtools.TestCase\
+                .failureException("Wait timeout exceeded! (%ds)" % dtime)
         time.sleep(CONF.boto.build_interval)
 
 # TODO(afazekas): consider strategy design pattern..
diff --git a/tox.ini b/tox.ini
index 1580b14..69e9d57 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,11 +4,10 @@
 skipsdist = True
 
 [testenv]
-sitepackages = True
 setenv = VIRTUAL_ENV={envdir}
          OS_TEST_PATH=./tempest/test_discover
 usedevelop = True
-install_command = pip install {opts} {packages}
+install_command = pip install -U {opts} {packages}
 
 [testenv:py26]
 setenv = OS_TEST_PATH=./tempest/tests
@@ -27,11 +26,13 @@
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
+sitepackages = True
 setenv = VIRTUAL_ENV={envdir}
 commands =
   python setup.py testr --slowest --testr-args='{posargs}'
 
 [testenv:full]
+sitepackages = True
 # The regex below is used to select which tests to run and exclude the slow tag:
 # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
@@ -44,49 +45,29 @@
   bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:testr-full]
+sitepackages = True
 commands =
   bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:heat-slow]
+sitepackages = True
 setenv = OS_TEST_TIMEOUT=1200
 # The regex below is used to select heat api/scenario tests tagged as slow.
 commands =
   bash tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
 
 [testenv:large-ops]
+sitepackages = True
 commands =
   python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
 
-
-[testenv:py26-full]
-setenv = VIRTUAL_ENV={envdir}
-         NOSE_WITH_OPENSTACK=1
-         NOSE_OPENSTACK_COLOR=1
-         NOSE_OPENSTACK_RED=15
-         NOSE_OPENSTACK_YELLOW=3
-         NOSE_OPENSTACK_SHOW_ELAPSED=1
-         NOSE_OPENSTACK_STDOUT=1
-         TEMPEST_PY26_NOSE_COMPAT=1
-commands =
-  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli {posargs}
-
-[testenv:py26-smoke]
-setenv = VIRTUAL_ENV={envdir}
-NOSE_WITH_OPENSTACK=1
-         NOSE_OPENSTACK_COLOR=1
-         NOSE_OPENSTACK_RED=15
-         NOSE_OPENSTACK_YELLOW=3
-         NOSE_OPENSTACK_SHOW_ELAPSED=1
-         NOSE_OPENSTACK_STDOUT=1
-         TEMPEST_PY26_NOSE_COMPAT=1
-commands =
-  nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --attr=type=smoke --xunit-file=nosetests-smoke.xml tempest {posargs}
-
 [testenv:smoke]
+sitepackages = True
 commands =
    bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:smoke-serial]
+sitepackages = True
 # This is still serial because neutron doesn't work with parallel. See:
 # https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
 # job would fail if we moved it to parallel.
@@ -94,6 +75,7 @@
    bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:stress]
+sitepackages = True
 commands =
     python -m tempest/stress/run_stress -a -d 3600 -S