Merge "Add negative tests for network"
diff --git a/.testr.conf b/.testr.conf
index 05b12c4..c25ebec 100644
--- a/.testr.conf
+++ b/.testr.conf
@@ -2,7 +2,8 @@
 test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
              OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
              OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \
-             ${PYTHON:-python} -m subunit.run discover -t ./ ./tempest $LISTOPT $IDOPTION
+             OS_TEST_PATH=${OS_TEST_PATH:-./tempest} \
+             ${PYTHON:-python} -m subunit.run discover -t ./ $OS_TEST_PATH $LISTOPT $IDOPTION
 test_id_option=--load-list $IDFILE
 test_list_option=--list
 group_regex=([^\.]*\.)*
diff --git a/HACKING.rst b/HACKING.rst
index a74ff73..3fa1ff5 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -9,8 +9,8 @@
 ------------------------------
 
 - [T102] Cannot import OpenStack python clients in tempest/api tests
-- [T103] tempest/tests is deprecated
 - [T104] Scenario tests require a services decorator
+- [T105] Unit tests cannot use setUpClass
 
 Test Data/Configuration
 -----------------------
@@ -39,7 +39,7 @@
 when the additional operations leads to another exception.
 
 Just letting an exception to propagate, is not bad idea in a test case,
- at all.
+at all.
 
 Try to avoid using any exception handling construct which can hide the errors
 origin.
@@ -53,10 +53,10 @@
 test fails part way through.
 
 Use the ``self.assert*`` methods provided by the unit test framework
- the signal failures early.
+the signal failures early.
 
 Avoid using the ``self.fail`` alone, it's stack trace will signal
- the ``self.fail`` line as the origin of the error.
+the ``self.fail`` line as the origin of the error.
 
 Avoid constructing complex boolean expressions for assertion.
 The ``self.assertTrue`` or ``self.assertFalse`` without a ``msg`` argument,
@@ -192,3 +192,15 @@
 The sample config file is autogenerated using a script. If any changes are made
 to the config variables in tempest then the sample config file must be
 regenerated. This can be done running the script: tools/generate_sample.sh
+
+Unit Tests
+----------
+Unit tests are a separate class of tests in tempest. They verify tempest
+itself, and thus have a different set of guidelines around them:
+
+1. They can not require anything running externally. All you should need to
+   run the unit tests is the git tree, python and the dependencies installed.
+   This includes running services, a config file, etc.
+
+2. The unit tests cannot use setUpClass, instead fixtures and testresources
+   should be used for shared state between tests.
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 467a6f9..609d2c6 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -18,7 +18,6 @@
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -35,7 +34,6 @@
     def setUpClass(cls):
         super(AggregatesAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.aggregates_client
-        cls.user_client = cls.aggregates_client
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
 
@@ -141,54 +139,6 @@
                          (x['id'], x['name'], x['availability_zone']),
                           aggregates))
 
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_create_as_user(self):
-        # Regular user is not allowed to create an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.create_aggregate,
-                          aggregate_name)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_delete_as_user(self):
-        # Regular user is not allowed to delete an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.delete_aggregate,
-                          aggregate['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_list_as_user(self):
-        # Regular user is not allowed to list aggregates.
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.list_aggregates)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_get_details_as_user(self):
-        # Regular user is not allowed to get aggregate details.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.get_aggregate,
-                          aggregate['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_delete_with_invalid_id(self):
-        # Delete an aggregate with invalid id should raise exceptions.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.delete_aggregate, -1)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_get_details_with_invalid_id(self):
-        # Get aggregate details with invalid id should raise exceptions.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_aggregate, -1)
-
     @attr(type='gate')
     def test_aggregate_add_remove_host(self):
         # Add an host to the given aggregate and remove.
@@ -262,48 +212,6 @@
         resp, body = admin_servers_client.get_server(server['id'])
         self.assertEqual(self.host, body[self._host_key])
 
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_add_non_exist_host(self):
-        # Adding a non-exist host to an aggregate should raise exceptions.
-        resp, hosts_all = self.os_adm.hosts_client.list_hosts()
-        hosts = map(lambda x: x['host_name'], hosts_all)
-        while True:
-            non_exist_host = data_utils.rand_name('nonexist_host_')
-            if non_exist_host not in hosts:
-                break
-
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.NotFound, self.client.add_host,
-                          aggregate['id'], non_exist_host)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_add_host_as_user(self):
-        # Regular user is not allowed to add a host to an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.add_host,
-                          aggregate['id'], self.host)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_remove_host_as_user(self):
-        # Regular user is not allowed to remove a host from an aggregate.
-        self.useFixture(fixtures.LockFixture('availability_zone'))
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-        self.client.add_host(aggregate['id'], self.host)
-        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.remove_host,
-                          aggregate['id'], self.host)
-
 
 class AggregatesAdminTestXML(AggregatesAdminTestJSON):
     _host_key = (
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
new file mode 100644
index 0000000..8506206
--- /dev/null
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -0,0 +1,196 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AggregatesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Aggregates API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AggregatesAdminNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.aggregates_client
+        cls.user_client = cls.aggregates_client
+        cls.aggregate_name_prefix = 'test_aggregate_'
+        cls.az_name_prefix = 'test_az_'
+
+        resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+        hosts = map(lambda x: x['host_name'],
+                    filter(lambda y: y['service'] == 'compute', hosts_all))
+        cls.host = hosts[0]
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_as_user(self):
+        # Regular user is not allowed to create an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_aggregate_name_length_less_than_1(self):
+        # the length of aggregate name should >= 1 and <=255
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_aggregate,
+                          '')
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_aggregate_name_length_exceeds_255(self):
+        # the length of aggregate name should >= 1 and <=255
+        aggregate_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_with_existent_aggregate_name(self):
+        # creating an aggregate with existent aggregate name is forbidden
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Conflict,
+                          self.client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_delete_as_user(self):
+        # Regular user is not allowed to delete an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.delete_aggregate,
+                          aggregate['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_list_as_user(self):
+        # Regular user is not allowed to list aggregates.
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.list_aggregates)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_get_details_as_user(self):
+        # Regular user is not allowed to get aggregate details.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.get_aggregate,
+                          aggregate['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_delete_with_invalid_id(self):
+        # Delete an aggregate with invalid id should raise exceptions.
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_aggregate, -1)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_get_details_with_invalid_id(self):
+        # Get aggregate details with invalid id should raise exceptions.
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_aggregate, -1)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_non_exist_host(self):
+        # Adding a non-exist host to an aggregate should raise exceptions.
+        resp, hosts_all = self.os_adm.hosts_client.list_hosts()
+        hosts = map(lambda x: x['host_name'], hosts_all)
+        while True:
+            non_exist_host = data_utils.rand_name('nonexist_host_')
+            if non_exist_host not in hosts:
+                break
+
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.NotFound, self.client.add_host,
+                          aggregate['id'], non_exist_host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_host_as_user(self):
+        # Regular user is not allowed to add a host to an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.add_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_existent_host(self):
+        self.useFixture(fixtures.LockFixture('availability_zone'))
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        resp, body = self.client.add_host(aggregate['id'], self.host)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
+
+        self.assertRaises(exceptions.Conflict, self.client.add_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_remove_host_as_user(self):
+        # Regular user is not allowed to remove a host from an aggregate.
+        self.useFixture(fixtures.LockFixture('availability_zone'))
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+        resp, body = self.client.add_host(aggregate['id'], self.host)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.remove_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_remove_nonexistent_host(self):
+        non_exist_host = data_utils.rand_name('nonexist_host_')
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.NotFound, self.client.remove_host,
+                          aggregate['id'], non_exist_host)
+
+
+class AggregatesAdminNegativeTestXML(AggregatesAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index d6488c4..e1a1a5d 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -16,21 +16,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
-class AvailabilityZoneAdminTestJSON(base.BaseV2ComputeAdminTest):
+class AZAdminTestJSON(base.BaseV2ComputeAdminTest):
 
     """
-    Tests Availability Zone API List that require admin privileges
+    Tests Availability Zone API List
     """
 
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(AvailabilityZoneAdminTestJSON, cls).setUpClass()
+        super(AZAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.availability_zone_client
         cls.non_adm_client = cls.availability_zone_client
 
@@ -57,14 +56,6 @@
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_availability_zone_list_detail_with_non_admin_user(self):
-        # List of availability zones and available services with
-        # non-administrator user
-        self.assertRaises(
-            exceptions.Unauthorized,
-            self.non_adm_client.get_availability_zone_list_detail)
 
-
-class AvailabilityZoneAdminTestXML(AvailabilityZoneAdminTestJSON):
+class AZAdminTestXML(AZAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
new file mode 100644
index 0000000..6ba8d58
--- /dev/null
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -0,0 +1,45 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AZAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Availability Zone API List
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AZAdminNegativeTestJSON, cls).setUpClass()
+        cls.non_adm_client = cls.availability_zone_client
+
+    @attr(type=['negative', 'gate'])
+    def test_get_availability_zone_list_detail_with_non_admin_user(self):
+        # List of availability zones and available services with
+        # non-administrator user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_availability_zone_list_detail)
+
+
+class AZAdminNegativeTestXML(AZAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 427f728..4989d6f 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -16,7 +16,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -30,7 +29,6 @@
             msg = ("%s skipped as neutron is available" % cls.__name__)
             raise cls.skipException(msg)
         cls.client = cls.os_adm.fixed_ips_client
-        cls.non_admin_client = cls.fixed_ips_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         resp, server = cls.servers_client.get_server(server['id'])
         for ip_set in server['addresses']:
@@ -46,11 +44,6 @@
         resp, fixed_ip = self.client.get_fixed_ip_details(self.ip)
         self.assertEqual(fixed_ip['address'], self.ip)
 
-    @attr(type=['negative', 'gate'])
-    def test_list_fixed_ip_details_with_non_admin_user(self):
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.get_fixed_ip_details, self.ip)
-
     @attr(type='gate')
     def test_set_reserve(self):
         body = {"reserve": "None"}
@@ -63,36 +56,6 @@
         resp, body = self.client.reserve_fixed_ip(self.ip, body)
         self.assertEqual(resp.status, 202)
 
-    @attr(type=['negative', 'gate'])
-    def test_set_reserve_with_non_admin_user(self):
-        body = {"reserve": "None"}
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.reserve_fixed_ip,
-                          self.ip, body)
-
-    @attr(type=['negative', 'gate'])
-    def test_set_unreserve_with_non_admin_user(self):
-        body = {"unreserve": "None"}
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.reserve_fixed_ip,
-                          self.ip, body)
-
-    @attr(type=['negative', 'gate'])
-    def test_set_reserve_with_invalid_ip(self):
-        # NOTE(maurosr): since this exercises the same code snippet, we do it
-        # only for reserve action
-        body = {"reserve": "None"}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.reserve_fixed_ip,
-                          "my.invalid.ip", body)
-
-    @attr(type=['negative', 'gate'])
-    def test_fixed_ip_with_invalid_action(self):
-        body = {"invalid_action": "None"}
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.reserve_fixed_ip,
-                          self.ip, body)
-
 
 class FixedIPsTestXml(FixedIPsTestJson):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
new file mode 100644
index 0000000..cf48f0a
--- /dev/null
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -0,0 +1,80 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class FixedIPsNegativeTestJson(base.BaseV2ComputeAdminTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FixedIPsNegativeTestJson, cls).setUpClass()
+        if cls.config.service_available.neutron:
+            msg = ("%s skipped as neutron is available" % cls.__name__)
+            raise cls.skipException(msg)
+        cls.client = cls.os_adm.fixed_ips_client
+        cls.non_admin_client = cls.fixed_ips_client
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        resp, server = cls.servers_client.get_server(server['id'])
+        for ip_set in server['addresses']:
+            for ip in server['addresses'][ip_set]:
+                if ip['OS-EXT-IPS:type'] == 'fixed':
+                    cls.ip = ip['addr']
+                    break
+            if cls.ip:
+                break
+
+    @attr(type=['negative', 'gate'])
+    def test_list_fixed_ip_details_with_non_admin_user(self):
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.get_fixed_ip_details, self.ip)
+
+    @attr(type=['negative', 'gate'])
+    def test_set_reserve_with_non_admin_user(self):
+        body = {"reserve": "None"}
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.reserve_fixed_ip,
+                          self.ip, body)
+
+    @attr(type=['negative', 'gate'])
+    def test_set_unreserve_with_non_admin_user(self):
+        body = {"unreserve": "None"}
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.reserve_fixed_ip,
+                          self.ip, body)
+
+    @attr(type=['negative', 'gate'])
+    def test_set_reserve_with_invalid_ip(self):
+        # NOTE(maurosr): since this exercises the same code snippet, we do it
+        # only for reserve action
+        body = {"reserve": "None"}
+        self.assertRaises(exceptions.NotFound,
+                          self.client.reserve_fixed_ip,
+                          "my.invalid.ip", body)
+
+    @attr(type=['negative', 'gate'])
+    def test_fixed_ip_with_invalid_action(self):
+        body = {"invalid_action": "None"}
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.reserve_fixed_ip,
+                          self.ip, body)
+
+
+class FixedIPsNegativeTestXml(FixedIPsNegativeTestJson):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index cf72e49..0fb9460 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -130,40 +130,6 @@
                 flag = True
         self.assertTrue(flag)
 
-    @test.attr(type=['negative', 'gate'])
-    def test_get_flavor_details_for_deleted_flavor(self):
-        # Delete a flavor and ensure it is not listed
-        # Create a test flavor
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        resp, flavor = self.client.create_flavor(flavor_name,
-                                                 self.ram,
-                                                 self.vcpus, self.disk,
-                                                 new_flavor_id,
-                                                 ephemeral=self.ephemeral,
-                                                 swap=self.swap,
-                                                 rxtx=self.rxtx)
-        # Delete the flavor
-        new_flavor_id = flavor['id']
-        resp_delete, body = self.client.delete_flavor(new_flavor_id)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(202, resp_delete.status)
-
-        # Deleted flavors can be seen via detailed GET
-        resp, flavor = self.client.get_flavor_details(new_flavor_id)
-        self.assertEqual(resp.status, 200)
-        self.assertEqual(flavor['name'], flavor_name)
-
-        # Deleted flavors should not show up in a list however
-        resp, flavors = self.client.list_flavors_with_detail()
-        self.assertEqual(resp.status, 200)
-        flag = True
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = False
-        self.assertTrue(flag)
-
     @test.attr(type='gate')
     def test_create_list_flavor_without_extra_data(self):
         # Create a flavor and ensure it is listed
@@ -347,49 +313,6 @@
         self.assertEqual(flavor['ram'], int(ram))
         self.assertEqual(int(flavor['id']), new_flavor_id)
 
-    @test.attr(type=['negative', 'gate'])
-    def test_invalid_is_public_string(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.list_flavors_with_detail,
-                          {'is_public': 'invalid'})
-
-    @test.attr(type=['negative', 'gate'])
-    def test_create_flavor_as_user(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.create_flavor,
-                          flavor_name, self.ram, self.vcpus, self.disk,
-                          new_flavor_id, ephemeral=self.ephemeral,
-                          swap=self.swap, rxtx=self.rxtx)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_delete_flavor_as_user(self):
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.delete_flavor,
-                          self.flavor_ref_alt)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_create_flavor_using_invalid_ram(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_flavor,
-                          flavor_name, -1, self.vcpus,
-                          self.disk, new_flavor_id)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_create_flavor_using_invalid_vcpus(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_flavor,
-                          flavor_name, self.ram, 0,
-                          self.disk, new_flavor_id)
-
 
 class FlavorsAdminTestXML(FlavorsAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
new file mode 100644
index 0000000..1d9198a
--- /dev/null
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -0,0 +1,344 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class FlavorsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Flavors API Create and Delete that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsAdminNegativeTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        cls.user_client = cls.os.flavors_client
+        cls.flavor_name_prefix = 'test_flavor_'
+        cls.ram = 512
+        cls.vcpus = 1
+        cls.disk = 10
+        cls.ephemeral = 10
+        cls.swap = 1024
+        cls.rxtx = 2
+
+    def flavor_clean_up(self, flavor_id):
+        resp, body = self.client.delete_flavor(flavor_id)
+        self.assertEqual(resp.status, 202)
+        self.client.wait_for_resource_deletion(flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_get_flavor_details_for_deleted_flavor(self):
+        # Delete a flavor and ensure it is not listed
+        # Create a test flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+
+        # no need to specify flavor_id, we can get the flavor_id from a
+        # response of create_flavor() call.
+        resp, flavor = self.client.create_flavor(flavor_name,
+                                                 self.ram,
+                                                 self.vcpus, self.disk,
+                                                 '',
+                                                 ephemeral=self.ephemeral,
+                                                 swap=self.swap,
+                                                 rxtx=self.rxtx)
+        # Delete the flavor
+        new_flavor_id = flavor['id']
+        resp_delete, body = self.client.delete_flavor(new_flavor_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(202, resp_delete.status)
+
+        # Deleted flavors can be seen via detailed GET
+        resp, flavor = self.client.get_flavor_details(new_flavor_id)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(flavor['name'], flavor_name)
+
+        # Deleted flavors should not show up in a list however
+        resp, flavors = self.client.list_flavors_with_detail()
+        self.assertEqual(resp.status, 200)
+        flag = True
+        for flavor in flavors:
+            if flavor['name'] == flavor_name:
+                flag = False
+        self.assertTrue(flag)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_invalid_is_public_string(self):
+        # the 'is_public' parameter can be 'none/true/false' if it exists
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.list_flavors_with_detail,
+                          {'is_public': 'invalid'})
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_as_user(self):
+        # only admin user can create a flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.create_flavor,
+                          flavor_name, self.ram, self.vcpus, self.disk,
+                          new_flavor_id, ephemeral=self.ephemeral,
+                          swap=self.swap, rxtx=self.rxtx)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_delete_flavor_as_user(self):
+        # only admin user can delete a flavor
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.delete_flavor,
+                          self.flavor_ref_alt)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_using_invalid_ram(self):
+        # the 'ram' attribute must be positive integer
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          flavor_name, -1, self.vcpus,
+                          self.disk, new_flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_using_invalid_vcpus(self):
+        # the 'vcpu' attribute must be positive integer
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          flavor_name, self.ram, -1,
+                          self.disk, new_flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_name_length_less_than_1(self):
+        # ensure name length >= 1
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          '',
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_name_length_exceeds_255(self):
+        # ensure name do not exceed 255 characters
+        new_flavor_name = 'a' * 256
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_name(self):
+        # the regex of flavor_name is '^[\w\.\- ]*$'
+        invalid_flavor_name = data_utils.rand_name('invalid-!@#$%-')
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          invalid_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_flavor_id(self):
+        # the regex of flavor_id is '^[\w\.\- ]*$', and it cannot contain
+        # leading and/or trailing whitespace
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        invalid_flavor_id = '!@#$%'
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          invalid_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_id_length_exceeds_255(self):
+        # the length of flavor_id should not exceed 255 characters
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        invalid_flavor_id = 'a' * 256
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          invalid_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_root_gb(self):
+        # root_gb attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          -1,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_ephemeral_gb(self):
+        # ephemeral_gb attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=-1,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_swap(self):
+        # swap attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=-1,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_rxtx_factor(self):
+        # rxtx_factor attribute should be a positive float
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=-1.5,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_is_public(self):
+        # is_public attribute should be boolean
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='Invalid')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_already_exists(self):
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        resp, flavor = self.client.create_flavor(flavor_name,
+                                                 self.ram, self.vcpus,
+                                                 self.disk,
+                                                 new_flavor_id,
+                                                 ephemeral=self.ephemeral,
+                                                 swap=self.swap,
+                                                 rxtx=self.rxtx)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.flavor_clean_up, flavor['id'])
+
+        self.assertRaises(exceptions.Conflict,
+                          self.client.create_flavor,
+                          flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_delete_nonexistent_flavor(self):
+        nonexistent_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_flavor,
+                          nonexistent_flavor_id)
+
+
+class FlavorsAdminNegativeTestXML(FlavorsAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
new file mode 100644
index 0000000..5ed4823
--- /dev/null
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -0,0 +1,96 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 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 testtools
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest.test import attr
+
+
+class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(SecurityGroupsTestAdminJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.security_groups_client
+        cls.client = cls.security_groups_client
+
+    def _delete_security_group(self, securitygroup_id, admin=True):
+        if admin:
+            resp, _ = self.adm_client.delete_security_group(securitygroup_id)
+        else:
+            resp, _ = self.client.delete_security_group(securitygroup_id)
+
+        self.assertEqual(202, resp.status)
+
+    @testtools.skipIf(config.TempestConfig().service_available.neutron,
+                      "Skipped because neutron do not support all_tenants"
+                      "search filter.")
+    @attr(type='smoke')
+    def test_list_security_groups_list_all_tenants_filter(self):
+        # Admin can list security groups of all tenants
+        # List of all security groups created
+        security_group_list = []
+        # Create two security groups for a non-admin tenant
+        for i in range(2):
+            name = data_utils.rand_name('securitygroup-')
+            description = data_utils.rand_name('description-')
+            resp, securitygroup = (self.client
+                                   .create_security_group(name, description))
+            self.assertEqual(200, resp.status)
+            self.addCleanup(self._delete_security_group,
+                            securitygroup['id'], admin=False)
+            security_group_list.append(securitygroup)
+
+        client_tenant_id = securitygroup['tenant_id']
+        # Create two security groups for admin tenant
+        for i in range(2):
+            name = data_utils.rand_name('securitygroup-')
+            description = data_utils.rand_name('description-')
+            resp, adm_securitygroup = (self.adm_client
+                                       .create_security_group(name,
+                                                              description))
+            self.assertEqual(200, resp.status)
+            self.addCleanup(self._delete_security_group,
+                            adm_securitygroup['id'])
+            security_group_list.append(adm_securitygroup)
+
+        # Fetch all security groups based on 'all_tenants' search filter
+        param = {'all_tenants': 'true'}
+        resp, fetched_list = self.adm_client.list_security_groups(params=param)
+        self.assertEqual(200, resp.status)
+        sec_group_id_list = map(lambda sg: sg['id'], fetched_list)
+        # Now check if all created Security Groups are present in fetched list
+        for sec_group in security_group_list:
+            self.assertIn(sec_group['id'], sec_group_id_list)
+
+        # Fetch all security groups for non-admin user with 'all_tenants'
+        # search filter
+        resp, fetched_list = self.client.list_security_groups(params=param)
+        self.assertEqual(200, resp.status)
+        # Now check if all created Security Groups are present in fetched list
+        for sec_group in fetched_list:
+            self.assertEqual(sec_group['tenant_id'], client_tenant_id,
+                             "Failed to get all security groups for "
+                             "non admin user.")
+
+
+class SecurityGroupsTestAdminXML(SecurityGroupsTestAdminJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index 81e4f87..0b20e90 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -18,7 +18,6 @@
 import uuid
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest import exceptions
 from tempest.test import attr
 
@@ -31,14 +30,6 @@
         super(FlavorsNegativeTestJSON, cls).setUpClass()
         cls.client = cls.flavors_client
 
-        # Generating a nonexistent flavor id
-        resp, flavors = cls.client.list_flavors()
-        flavor_ids = [flavor['id'] for flavor in flavors]
-        while True:
-            cls.nonexistent_flavor_id = data_utils.rand_int_id(start=999)
-            if cls.nonexistent_flavor_id not in flavor_ids:
-                break
-
     @attr(type=['negative', 'gate'])
     def test_invalid_minRam_filter(self):
         self.assertRaises(exceptions.BadRequest,
@@ -52,17 +43,11 @@
                           {'minDisk': 'invalid'})
 
     @attr(type=['negative', 'gate'])
-    def test_get_flavor_details_for_invalid_flavor_id(self):
-        # Ensure 404 returned for invalid flavor ID
-        invalid_flavor_id = str(uuid.uuid4())
-        self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
-                          invalid_flavor_id)
-
-    @attr(type=['negative', 'gate'])
     def test_non_existent_flavor_id(self):
         # flavor details are not returned for non-existent flavors
+        nonexistent_flavor_id = str(uuid.uuid4())
         self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
-                          self.nonexistent_flavor_id)
+                          nonexistent_flavor_id)
 
 
 class FlavorsNegativeTestXML(FlavorsNegativeTestJSON):
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 6387f4e..e4d03ae 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -15,11 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import uuid
-
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -78,24 +74,6 @@
         finally:
             self.client.delete_floating_ip(floating_ip_id)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_nonexistant_floating_ip_details(self):
-        # Negative test:Should not be able to GET the details
-        # of non-existent floating IP
-        floating_ip_id = []
-        resp, body = self.client.list_floating_ips()
-        for i in range(len(body)):
-            floating_ip_id.append(body[i]['id'])
-        # Creating a non-existent floatingIP id
-        while True:
-            non_exist_id = data_utils.rand_int_id(start=999)
-            if self.config.service_available.neutron:
-                non_exist_id = str(uuid.uuid4())
-            if non_exist_id not in floating_ip_id:
-                break
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_floating_ip_details, non_exist_id)
-
     @attr(type='gate')
     def test_list_floating_ip_pools(self):
         # Positive test:Should return the list of floating IP Pools
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
new file mode 100644
index 0000000..e7dc8ee
--- /dev/null
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -0,0 +1,48 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FloatingIPDetailsNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.floating_ips_client
+
+    @attr(type=['negative', 'gate'])
+    def test_get_nonexistent_floating_ip_details(self):
+        # Negative test:Should not be able to GET the details
+        # of non-existent floating IP
+        # Creating a non-existent floatingIP id
+        if self.config.service_available.neutron:
+            non_exist_id = str(uuid.uuid4())
+        else:
+            non_exist_id = data_utils.rand_int_id(start=999)
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_floating_ip_details, non_exist_id)
+
+
+class FloatingIPDetailsNegativeTestXML(FloatingIPDetailsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index b0ff7ab..6e4c8cb 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -117,6 +117,20 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_resource_deletion(image_id)
 
+    @attr(type=['gate'])
+    def test_create_image_specify_multibyte_character_image_name(self):
+        if self.__class__._interface == "xml":
+            # NOTE(sdague): not entirely accurage, but we'd need a ton of work
+            # in our XML client to make this good
+            raise self.skipException("Not testable in XML")
+        # prefix character is:
+        # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
+        utf8_name = data_utils.rand_name(u'\xF0\x9F\x92\xA9')
+        resp, body = self.client.create_image(self.server_id, utf8_name)
+        image_id = data_utils.parse_image_id(resp['location'])
+        self.addCleanup(self.client.delete_image, image_id)
+        self.assertEqual('202', resp['status'])
+
 
 class ImagesOneServerTestXML(ImagesOneServerTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 2d27b81..b8a4304 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -86,11 +86,15 @@
     @skip_because(bug="1006725")
     @attr(type=['negative', 'gate'])
     def test_create_image_specify_multibyte_character_image_name(self):
-        # Return an error if the image name has multi-byte characters
-        snapshot_name = data_utils.rand_name('\xef\xbb\xbf')
+        if self.__class__._interface == "xml":
+            raise self.skipException("Not testable in XML")
+        # invalid multibyte sequence from:
+        # http://stackoverflow.com/questions/1301402/
+        #     example-invalid-utf8-string
+        invalid_name = data_utils.rand_name(u'\xc3\x28')
         self.assertRaises(exceptions.BadRequest,
                           self.client.create_image, self.server_id,
-                          snapshot_name)
+                          invalid_name)
 
     @attr(type=['negative', 'gate'])
     def test_create_image_specify_invalid_metadata(self):
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 50b6c77..b36595c 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -17,7 +17,7 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class KeyPairsTestJSON(base.BaseV2ComputeTest):
@@ -28,14 +28,23 @@
         super(KeyPairsTestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
-    @attr(type='gate')
+    def _delete_keypair(self, keypair_name):
+        resp, _ = self.client.delete_keypair(keypair_name)
+        self.assertEqual(202, resp.status)
+
+    def _create_keypair(self, keypair_name, pub_key=None):
+        resp, body = self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self._delete_keypair, keypair_name)
+        return resp, body
+
+    @test.attr(type='gate')
     def test_keypairs_create_list_delete(self):
         # Keypairs created should be available in the response list
         # Create 3 keypairs
         key_list = list()
         for i in range(3):
             k_name = data_utils.rand_name('keypair-')
-            resp, keypair = self.client.create_keypair(k_name)
+            resp, keypair = self._create_keypair(k_name)
             # Need to pop these keys so that our compare doesn't fail later,
             # as the keypair dicts from list API doesn't have them.
             keypair.pop('private_key')
@@ -57,16 +66,12 @@
         self.assertFalse(missing_kps,
                          "Failed to find keypairs %s in fetched list"
                          % ', '.join(m_key['name'] for m_key in missing_kps))
-        # Delete all the keypairs created
-        for keypair in key_list:
-            resp, _ = self.client.delete_keypair(keypair['name'])
-            self.assertEqual(202, resp.status)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_keypair_create_delete(self):
         # Keypair should be created, verified and deleted
         k_name = data_utils.rand_name('keypair-')
-        resp, keypair = self.client.create_keypair(k_name)
+        resp, keypair = self._create_keypair(k_name)
         self.assertEqual(200, resp.status)
         private_key = keypair['private_key']
         key_name = keypair['name']
@@ -75,15 +80,12 @@
                          "to the requested name")
         self.assertTrue(private_key is not None,
                         "Field private_key is empty or not found.")
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_get_keypair_detail(self):
         # Keypair should be created, Got details by name and deleted
         k_name = data_utils.rand_name('keypair-')
-        resp, keypair = self.client.create_keypair(k_name)
-        self.addCleanup(self.client.delete_keypair, k_name)
+        resp, keypair = self._create_keypair(k_name)
         resp, keypair_detail = self.client.get_keypair(k_name)
         self.assertEqual(200, resp.status)
         self.assertIn('name', keypair_detail)
@@ -95,7 +97,7 @@
         self.assertTrue(public_key is not None,
                         "Field public_key is empty or not found.")
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_keypair_create_with_pub_key(self):
         # Keypair should be created with a given public key
         k_name = data_utils.rand_name('keypair-')
@@ -108,7 +110,7 @@
                    "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
                    "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
                    "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
-        resp, keypair = self.client.create_keypair(k_name, pub_key)
+        resp, keypair = self._create_keypair(k_name, pub_key)
         self.assertEqual(200, resp.status)
         self.assertFalse('private_key' in keypair,
                          "Field private_key is not empty!")
@@ -116,8 +118,6 @@
         self.assertEqual(key_name, k_name,
                          "The created keypair name is not equal "
                          "to the requested name!")
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
 
 
 class KeyPairsTestXML(KeyPairsTestJSON):
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index fad985e..621487c 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -19,7 +19,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 KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
@@ -30,67 +30,71 @@
         super(KeyPairsNegativeTestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
-    @attr(type=['negative', 'gate'])
+    def _create_keypair(self, keypair_name, pub_key=None):
+        self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self.client.delete_keypair, keypair_name)
+
+    @test.attr(type=['negative', 'gate'])
     def test_keypair_create_with_invalid_pub_key(self):
         # Keypair should not be created with a non RSA public key
         k_name = data_utils.rand_name('keypair-')
         pub_key = "ssh-rsa JUNK nova@ubuntu"
         self.assertRaises(exceptions.BadRequest,
-                          self.client.create_keypair, k_name, pub_key)
+                          self._create_keypair, k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_keypair_delete_nonexistant_key(self):
         # Non-existant key deletion should throw a proper error
         k_name = data_utils.rand_name("keypair-non-existant-")
         self.assertRaises(exceptions.NotFound, self.client.delete_keypair,
                           k_name)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_empty_public_key(self):
         # Keypair should not be created with an empty public key
         k_name = data_utils.rand_name("keypair-")
         pub_key = ' '
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
         # Keypair should not be created when public key bits are too long
         k_name = data_utils.rand_name("keypair-")
         pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_duplicate_name(self):
         # Keypairs with duplicate names should not be created
         k_name = data_utils.rand_name('keypair-')
         resp, _ = self.client.create_keypair(k_name)
         self.assertEqual(200, resp.status)
         # Now try the same keyname to create another key
-        self.assertRaises(exceptions.Conflict, self.client.create_keypair,
+        self.assertRaises(exceptions.Conflict, self._create_keypair,
                           k_name)
         resp, _ = self.client.delete_keypair(k_name)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_empty_name_string(self):
         # Keypairs with name being an empty string should not be created
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           '')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_long_keynames(self):
         # Keypairs with name longer than 255 chars should not be created
         k_name = 'keypair-'.ljust(260, '0')
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_invalid_name(self):
         # Keypairs with name being an invalid name should not be created
         k_name = 'key_/.\@:'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name)
 
 
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 24ade96..cbd0eb1 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -93,13 +93,6 @@
 
     @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
     @attr(type='gate')
-    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())
-
-    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
-    @attr(type='gate')
     def test_verify_created_server_vcpus(self):
         # Verify that the number of vcpus reported by the instance matches
         # the amount stated by the flavor
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 5552d0b..e009888 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -67,7 +67,7 @@
             # Verify that the user can authenticate with the new password
             resp, server = self.client.get_server(self.server_id)
             linux_client = RemoteClient(server, self.ssh_user, new_password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     @attr(type='smoke')
     def test_reboot_server_hard(self):
@@ -141,7 +141,7 @@
         if self.run_ssh:
             # Verify that the user can authenticate with the provided password
             linux_client = RemoteClient(server, self.ssh_user, password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     @attr(type='gate')
     def test_rebuild_server_in_stop_state(self):
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 8f1e446..b0bffc4 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -17,18 +17,31 @@
 
 
 from tempest.api.compute import base
-from tempest.test import attr
+from tempest import test
+import testtools
 
 
 class ExtensionsTestJSON(base.BaseV2ComputeTest):
     _interface = 'json'
 
-    @attr(type='gate')
+    @testtools.skipIf(not test.is_extension_enabled('os-consoles', 'compute'),
+                      'os-consoles extension not enabled.')
+    @test.attr(type='gate')
     def test_list_extensions(self):
         # List of all extensions
         resp, extensions = self.extensions_client.list_extensions()
         self.assertIn("extensions", extensions)
         self.assertEqual(200, resp.status)
+        self.assertTrue(self.extensions_client.is_enabled("Consoles"))
+
+    @testtools.skipIf(not test.is_extension_enabled('os-consoles', 'compute'),
+                      'os-consoles extension not enabled.')
+    @test.attr(type='gate')
+    def test_get_extension(self):
+        # get the specified extensions
+        resp, extension = self.extensions_client.get_extension('os-consoles')
+        self.assertEqual(200, resp.status)
+        self.assertEqual('os-consoles', extension['alias'])
 
 
 class ExtensionsTestXML(ExtensionsTestJSON):
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index ff2765c..dca556f 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -16,21 +16,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
-class AvailabilityZoneAdminV3TestJSON(base.BaseV3ComputeAdminTest):
+class AZAdminV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
-    Tests Availability Zone API List that require admin privileges
+    Tests Availability Zone API List
     """
 
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(AvailabilityZoneAdminV3TestJSON, cls).setUpClass()
+        super(AZAdminV3TestJSON, cls).setUpClass()
         cls.client = cls.availability_zone_admin_client
         cls.non_adm_client = cls.availability_zone_client
 
@@ -57,14 +56,6 @@
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_availability_zone_list_detail_with_non_admin_user(self):
-        # List of availability zones and available services with
-        # non-administrator user
-        self.assertRaises(
-            exceptions.Unauthorized,
-            self.non_adm_client.get_availability_zone_list_detail)
 
-
-class AvailabilityZoneAdminV3TestXML(AvailabilityZoneAdminV3TestJSON):
+class AZAdminV3TestXML(AZAdminV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_availability_zone_negative.py b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
new file mode 100644
index 0000000..93a57e3
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
@@ -0,0 +1,47 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AZAdminNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
+
+    """
+    Tests Availability Zone API List
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AZAdminNegativeV3TestJSON, cls).setUpClass()
+        cls.client = cls.availability_zone_admin_client
+        cls.non_adm_client = cls.availability_zone_client
+
+    @attr(type=['negative', 'gate'])
+    def test_get_availability_zone_list_detail_with_non_admin_user(self):
+        # List of availability zones and available services with
+        # non-administrator user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_availability_zone_list_detail)
+
+
+class AZAdminNegativeV3TestXML(AZAdminNegativeV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/keypairs/__init__.py b/tempest/api/compute/v3/keypairs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/api/compute/v3/keypairs/__init__.py
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs.py b/tempest/api/compute/v3/keypairs/test_keypairs.py
new file mode 100644
index 0000000..b36595c
--- /dev/null
+++ b/tempest/api/compute/v3/keypairs/test_keypairs.py
@@ -0,0 +1,124 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class KeyPairsTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(KeyPairsTestJSON, cls).setUpClass()
+        cls.client = cls.keypairs_client
+
+    def _delete_keypair(self, keypair_name):
+        resp, _ = self.client.delete_keypair(keypair_name)
+        self.assertEqual(202, resp.status)
+
+    def _create_keypair(self, keypair_name, pub_key=None):
+        resp, body = self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self._delete_keypair, keypair_name)
+        return resp, body
+
+    @test.attr(type='gate')
+    def test_keypairs_create_list_delete(self):
+        # Keypairs created should be available in the response list
+        # Create 3 keypairs
+        key_list = list()
+        for i in range(3):
+            k_name = data_utils.rand_name('keypair-')
+            resp, keypair = self._create_keypair(k_name)
+            # Need to pop these keys so that our compare doesn't fail later,
+            # as the keypair dicts from list API doesn't have them.
+            keypair.pop('private_key')
+            keypair.pop('user_id')
+            self.assertEqual(200, resp.status)
+            key_list.append(keypair)
+        # Fetch all keypairs and verify the list
+        # has all created keypairs
+        resp, fetched_list = self.client.list_keypairs()
+        self.assertEqual(200, resp.status)
+        # We need to remove the extra 'keypair' element in the
+        # returned dict. See comment in keypairs_client.list_keypairs()
+        new_list = list()
+        for keypair in fetched_list:
+            new_list.append(keypair['keypair'])
+        fetched_list = new_list
+        # Now check if all the created keypairs are in the fetched list
+        missing_kps = [kp for kp in key_list if kp not in fetched_list]
+        self.assertFalse(missing_kps,
+                         "Failed to find keypairs %s in fetched list"
+                         % ', '.join(m_key['name'] for m_key in missing_kps))
+
+    @test.attr(type='gate')
+    def test_keypair_create_delete(self):
+        # Keypair should be created, verified and deleted
+        k_name = data_utils.rand_name('keypair-')
+        resp, keypair = self._create_keypair(k_name)
+        self.assertEqual(200, resp.status)
+        private_key = keypair['private_key']
+        key_name = keypair['name']
+        self.assertEqual(key_name, k_name,
+                         "The created keypair name is not equal "
+                         "to the requested name")
+        self.assertTrue(private_key is not None,
+                        "Field private_key is empty or not found.")
+
+    @test.attr(type='gate')
+    def test_get_keypair_detail(self):
+        # Keypair should be created, Got details by name and deleted
+        k_name = data_utils.rand_name('keypair-')
+        resp, keypair = self._create_keypair(k_name)
+        resp, keypair_detail = self.client.get_keypair(k_name)
+        self.assertEqual(200, resp.status)
+        self.assertIn('name', keypair_detail)
+        self.assertIn('public_key', keypair_detail)
+        self.assertEqual(keypair_detail['name'], k_name,
+                         "The created keypair name is not equal "
+                         "to requested name")
+        public_key = keypair_detail['public_key']
+        self.assertTrue(public_key is not None,
+                        "Field public_key is empty or not found.")
+
+    @test.attr(type='gate')
+    def test_keypair_create_with_pub_key(self):
+        # Keypair should be created with a given public key
+        k_name = data_utils.rand_name('keypair-')
+        pub_key = ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs"
+                   "Ne3/1ILNCqFyfYWDeTKLD6jEXC2OQHLmietMWW+/vd"
+                   "aZq7KZEwO0jhglaFjU1mpqq4Gz5RX156sCTNM9vRbw"
+                   "KAxfsdF9laBYVsex3m3Wmui3uYrKyumsoJn2g9GNnG1P"
+                   "I1mrVjZ61i0GY3khna+wzlTpCCmy5HNlrmbj3XLqBUpip"
+                   "TOXmsnr4sChzC53KCd8LXuwc1i/CZPvF+3XipvAgFSE53pCt"
+                   "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
+                   "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
+                   "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
+        resp, keypair = self._create_keypair(k_name, pub_key)
+        self.assertEqual(200, resp.status)
+        self.assertFalse('private_key' in keypair,
+                         "Field private_key is not empty!")
+        key_name = keypair['name']
+        self.assertEqual(key_name, k_name,
+                         "The created keypair name is not equal "
+                         "to the requested name!")
+
+
+class KeyPairsTestXML(KeyPairsTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
new file mode 100644
index 0000000..621487c
--- /dev/null
+++ b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
@@ -0,0 +1,102 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(KeyPairsNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.keypairs_client
+
+    def _create_keypair(self, keypair_name, pub_key=None):
+        self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self.client.delete_keypair, keypair_name)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_keypair_create_with_invalid_pub_key(self):
+        # Keypair should not be created with a non RSA public key
+        k_name = data_utils.rand_name('keypair-')
+        pub_key = "ssh-rsa JUNK nova@ubuntu"
+        self.assertRaises(exceptions.BadRequest,
+                          self._create_keypair, k_name, pub_key)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_keypair_delete_nonexistant_key(self):
+        # Non-existant key deletion should throw a proper error
+        k_name = data_utils.rand_name("keypair-non-existant-")
+        self.assertRaises(exceptions.NotFound, self.client.delete_keypair,
+                          k_name)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_with_empty_public_key(self):
+        # Keypair should not be created with an empty public key
+        k_name = data_utils.rand_name("keypair-")
+        pub_key = ' '
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
+                          k_name, pub_key)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
+        # Keypair should not be created when public key bits are too long
+        k_name = data_utils.rand_name("keypair-")
+        pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
+                          k_name, pub_key)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_with_duplicate_name(self):
+        # Keypairs with duplicate names should not be created
+        k_name = data_utils.rand_name('keypair-')
+        resp, _ = self.client.create_keypair(k_name)
+        self.assertEqual(200, resp.status)
+        # Now try the same keyname to create another key
+        self.assertRaises(exceptions.Conflict, self._create_keypair,
+                          k_name)
+        resp, _ = self.client.delete_keypair(k_name)
+        self.assertEqual(202, resp.status)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_with_empty_name_string(self):
+        # Keypairs with name being an empty string should not be created
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
+                          '')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_with_long_keynames(self):
+        # Keypairs with name longer than 255 chars should not be created
+        k_name = 'keypair-'.ljust(260, '0')
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
+                          k_name)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_keypair_invalid_name(self):
+        # Keypairs with name being an invalid name should not be created
+        k_name = 'key_/.\@:'
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
+                          k_name)
+
+
+class KeyPairsNegativeTestXML(KeyPairsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 090f4dd..ee37502 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -67,7 +67,7 @@
             # Verify that the user can authenticate with the new password
             resp, server = self.client.get_server(self.server_id)
             linux_client = RemoteClient(server, self.ssh_user, new_password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     @attr(type='smoke')
     def test_reboot_server_hard(self):
@@ -140,7 +140,7 @@
         if self.run_ssh:
             # Verify that the user can authenticate with the provided password
             linux_client = RemoteClient(server, self.ssh_user, password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     def _detect_server_image_flavor(self, server_id):
         # Detects the current server image flavor ref.
diff --git a/tempest/api/compute/v3/test_extensions.py b/tempest/api/compute/v3/test_extensions.py
index d7269d1..2affd86 100644
--- a/tempest/api/compute/v3/test_extensions.py
+++ b/tempest/api/compute/v3/test_extensions.py
@@ -17,18 +17,26 @@
 
 
 from tempest.api.compute import base
-from tempest.test import attr
+from tempest import test
 
 
 class ExtensionsV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_list_extensions(self):
         # List of all extensions
         resp, extensions = self.extensions_client.list_extensions()
         self.assertIn("extensions", extensions)
         self.assertEqual(200, resp.status)
+        self.assertTrue(self.extensions_client.is_enabled("Consoles"))
+
+    @test.attr(type='gate')
+    def test_get_extension(self):
+        # get the specified extensions
+        resp, extension = self.extensions_client.get_extension('servers')
+        self.assertEqual(200, resp.status)
+        self.assertEqual('servers', extension['alias'])
 
 
 class ExtensionsV3TestXML(ExtensionsV3TestJSON):
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index f54e9b3..b57dcfe 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -109,6 +109,65 @@
                          ', '.join(m_vol['displayName']
                                    for m_vol in missing_volumes))
 
+    @attr(type='gate')
+    def test_volume_list_param_limit(self):
+        # Return the list of volumes based on limit set
+        params = {'limit': 2}
+        resp, fetched_vol_list = self.client.list_volumes(params=params)
+        self.assertEqual(200, resp.status)
+
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volumes by limit set")
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_limit(self):
+        # Return the list of volumes with details based on limit set.
+        params = {'limit': 2}
+        resp, fetched_vol_list = \
+            self.client.list_volumes_with_detail(params=params)
+        self.assertEqual(200, resp.status)
+
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volume details by limit set")
+
+    @attr(type='gate')
+    def test_volume_list_param_offset_and_limit(self):
+        # Return the list of volumes based on offset and limit set.
+        # get all volumes list
+        response, all_vol_list = self.client.list_volumes()
+        params = {'offset': 1, 'limit': 1}
+        resp, fetched_vol_list = self.client.list_volumes(params=params)
+        self.assertEqual(200, resp.status)
+
+        # Validating length of the fetched volumes
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volumes by offset and limit")
+        # Validating offset of fetched volume
+        for index, volume in enumerate(fetched_vol_list):
+            self.assertEqual(volume['id'],
+                             all_vol_list[index + params['offset']]['id'],
+                             "Failed to list volumes by offset and limit")
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_offset_and_limit(self):
+        # Return the list of volumes details based on offset and limit set.
+        # get all volumes list
+        response, all_vol_list = self.client.list_volumes_with_detail()
+        params = {'offset': 1, 'limit': 1}
+        resp, fetched_vol_list = \
+            self.client.list_volumes_with_detail(params=params)
+        self.assertEqual(200, resp.status)
+
+        # Validating length of the fetched volumes
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volume details by offset and limit")
+        # Validating offset of fetched volume
+        for index, volume in enumerate(fetched_vol_list):
+            self.assertEqual(volume['id'],
+                             all_vol_list[index + params['offset']]['id'],
+                             "Failed to list volume details by "
+                             "offset and limit")
+
 
 class VolumesTestXML(VolumesTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
new file mode 100644
index 0000000..5e13a5a
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -0,0 +1,222 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.identity import base
+from tempest import clients
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+from tempest.test import attr
+
+
+class BaseTrustsV3Test(base.BaseIdentityAdminTest):
+
+    def setUp(self):
+        super(BaseTrustsV3Test, self).setUp()
+        # Use alt_username as the trustee
+        self.trustee_username = self.config.identity.alt_username
+
+        self.trust_id = None
+        self.create_trustor_and_roles()
+        self.addCleanup(self.cleanup_trust_user_and_roles)
+
+    def create_trustor_and_roles(self):
+        # Get trustor project ID, use the admin project
+        self.trustor_project_name = self.v3_client.tenant_name
+        self.trustor_project_id = self.get_tenant_by_name(
+            self.trustor_project_name)['id']
+        self.assertIsNotNone(self.trustor_project_id)
+
+        # Create a trustor User
+        self.trustor_username = rand_name('user-')
+        u_desc = self.trustor_username + 'description'
+        u_email = self.trustor_username + '@testmail.tm'
+        self.trustor_password = rand_name('pass-')
+        resp, user = self.v3_client.create_user(
+            self.trustor_username,
+            description=u_desc,
+            password=self.trustor_password,
+            email=u_email,
+            project_id=self.trustor_project_id)
+        self.assertEqual(resp['status'], '201')
+        self.trustor_user_id = user['id']
+
+        # And two roles, one we'll delegate and one we won't
+        self.delegated_role = rand_name('DelegatedRole-')
+        self.not_delegated_role = rand_name('NotDelegatedRole-')
+
+        resp, role = self.v3_client.create_role(self.delegated_role)
+        self.assertEqual(resp['status'], '201')
+        self.delegated_role_id = role['id']
+
+        resp, role = self.v3_client.create_role(self.not_delegated_role)
+        self.assertEqual(resp['status'], '201')
+        self.not_delegated_role_id = role['id']
+
+        # Assign roles to trustor
+        self.v3_client.assign_user_role(self.trustor_project_id,
+                                        self.trustor_user_id,
+                                        self.delegated_role_id)
+        self.v3_client.assign_user_role(self.trustor_project_id,
+                                        self.trustor_user_id,
+                                        self.not_delegated_role_id)
+
+        # Get trustee user ID, use the demo user
+        trustee_username = self.v3_non_admin_client.user
+        self.trustee_user_id = self.get_user_by_name(trustee_username)['id']
+        self.assertIsNotNone(self.trustee_user_id)
+
+        # Initialize a new client with the trustor credentials
+        os = clients.Manager(username=self.trustor_username,
+                             password=self.trustor_password,
+                             tenant_name=self.trustor_project_name,
+                             interface=self._interface)
+        self.trustor_v3_client = os.identity_v3_client
+
+    def cleanup_trust_user_and_roles(self):
+        if self.trust_id:
+            try:
+                self.trustor_v3_client.delete_trust(self.trust_id)
+            except exceptions.NotFound:
+                pass
+            self.trust_id = None
+
+        if self.trustor_user_id:
+            self.v3_client.delete_user(self.trustor_user_id)
+        if self.delegated_role_id:
+            self.v3_client.delete_role(self.delegated_role_id)
+        if self.not_delegated_role_id:
+            self.v3_client.delete_role(self.not_delegated_role_id)
+
+    def create_trust(self, impersonate=True, expires=None):
+
+        resp, trust_create = self.trustor_v3_client.create_trust(
+            trustor_user_id=self.trustor_user_id,
+            trustee_user_id=self.trustee_user_id,
+            project_id=self.trustor_project_id,
+            role_names=[self.delegated_role],
+            impersonation=impersonate,
+            expires_at=expires)
+        self.assertEqual('201', resp['status'])
+        self.trust_id = trust_create['id']
+        return trust_create
+
+    def validate_trust(self, trust, impersonate=True, expires=None,
+                       summary=False):
+        self.assertIsNotNone(trust['id'])
+        self.assertEqual(impersonate, trust['impersonation'])
+        self.assertEqual(expires, trust['expires_at'])
+        self.assertEqual(self.trustor_user_id, trust['trustor_user_id'])
+        self.assertEqual(self.trustee_user_id, trust['trustee_user_id'])
+        self.assertIn('v3/OS-TRUST/trusts', trust['links']['self'])
+        self.assertEqual(self.trustor_project_id, trust['project_id'])
+        if not summary:
+            self.assertEqual(self.delegated_role, trust['roles'][0]['name'])
+            self.assertEqual(1, len(trust['roles']))
+
+    def get_trust(self):
+        resp, trust_get = self.trustor_v3_client.get_trust(self.trust_id)
+        self.assertEqual('200', resp['status'])
+        return trust_get
+
+    def validate_role(self, role):
+        self.assertEqual(self.delegated_role_id, role['id'])
+        self.assertEqual(self.delegated_role, role['name'])
+        self.assertIn('v3/roles/%s' % self.delegated_role_id,
+                      role['links']['self'])
+        self.assertNotEqual(self.not_delegated_role_id, role['id'])
+        self.assertNotEqual(self.not_delegated_role, role['name'])
+        self.assertNotIn('v3/roles/%s' % self.not_delegated_role_id,
+                         role['links']['self'])
+
+    def check_trust_roles(self):
+        # Check we find the delegated role
+        resp, roles_get = self.trustor_v3_client.get_trust_roles(
+            self.trust_id)
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(1, len(roles_get))
+        self.validate_role(roles_get[0])
+
+        resp, role_get = self.trustor_v3_client.get_trust_role(
+            self.trust_id, self.delegated_role_id)
+        self.assertEqual('200', resp['status'])
+        self.validate_role(role_get)
+
+        resp, role_get = self.trustor_v3_client.check_trust_role(
+            self.trust_id, self.delegated_role_id)
+        self.assertEqual('204', resp['status'])
+
+        # And that we don't find not_delegated_role
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.get_trust_role,
+                          self.trust_id,
+                          self.not_delegated_role_id)
+
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.check_trust_role,
+                          self.trust_id,
+                          self.not_delegated_role_id)
+
+    def delete_trust(self):
+        resp, trust_delete = self.trustor_v3_client.delete_trust(self.trust_id)
+        self.assertEqual('204', resp['status'])
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.get_trust,
+                          self.trust_id)
+        self.trust_id = None
+
+
+class TrustsV3TestJSON(BaseTrustsV3Test):
+    _interface = 'json'
+
+    def setUp(self):
+        super(TrustsV3TestJSON, self).setUp()
+        self.create_trustor_and_roles()
+
+    @attr(type='smoke')
+    def test_trust_impersonate(self):
+        # Test case to check we can create, get and delete a trust
+        # updates are not supported for trusts
+        trust = self.create_trust()
+        self.validate_trust(trust)
+
+        trust_get = self.get_trust()
+        self.validate_trust(trust_get)
+
+        self.check_trust_roles()
+
+        self.delete_trust()
+
+    @attr(type='smoke')
+    def test_trust_noimpersonate(self):
+        # Test case to check we can create, get and delete a trust
+        # with impersonation=False
+        trust = self.create_trust(impersonate=False)
+        self.validate_trust(trust, impersonate=False)
+
+        trust_get = self.get_trust()
+        self.validate_trust(trust_get, impersonate=False)
+
+        self.check_trust_roles()
+
+        self.delete_trust()
+
+    @attr(type='smoke')
+    def test_trust_expire_invalid(self):
+        # Test case to check we can check an invlaid expiry time
+        # is rejected with the correct error
+        # with an expiry specified
+        expires_str = 'bad.123Z'
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_trust,
+                          expires=expires_str)
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
new file mode 100644
index 0000000..94659b2
--- /dev/null
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.network import base
+from tempest.common import tempest_fixtures as fixtures
+from tempest.test import attr
+
+
+class AgentManagementTestJSON(base.BaseAdminNetworkTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AgentManagementTestJSON, cls).setUpClass()
+        resp, body = cls.admin_client.list_agents()
+        agents = body['agents']
+        cls.agent = agents[0]
+
+    @attr(type='smoke')
+    def test_list_agent(self):
+        resp, body = self.admin_client.list_agents()
+        self.assertEqual('200', resp['status'])
+        agents = body['agents']
+        self.assertIn(self.agent, agents)
+
+    @attr(type='smoke')
+    def test_show_agent(self):
+        resp, body = self.admin_client.show_agent(self.agent['id'])
+        agent = body['agent']
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(agent['id'], self.agent['id'])
+
+    @attr(type='smoke')
+    def test_update_agent_status(self):
+        origin_status = self.agent['admin_state_up']
+        # Try to update the 'admin_state_up' to the original
+        # one to avoid the negative effect.
+        agent_status = {'admin_state_up': origin_status}
+        resp, body = self.admin_client.update_agent(agent_id=self.agent['id'],
+                                                    agent_info=agent_status)
+        updated_status = body['agent']['admin_state_up']
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(origin_status, updated_status)
+
+    @attr(type='smoke')
+    def test_update_agent_description(self):
+        self.useFixture(fixtures.LockFixture('agent_description'))
+        description = 'description for update agent.'
+        agent_description = {'description': description}
+        resp, body = self.admin_client.update_agent(
+            agent_id=self.agent['id'],
+            agent_info=agent_description)
+        self.assertEqual('200', resp['status'])
+        self.addCleanup(self._restore_agent)
+        updated_description = body['agent']['description']
+        self.assertEqual(updated_description, description)
+
+    def _restore_agent(self):
+        """
+        Restore the agent description after update test.
+        """
+        description = self.agent['description'] or ''
+        origin_agent = {'description': description}
+        self.admin_client.update_agent(agent_id=self.agent['id'],
+                                       agent_info=origin_agent)
+
+
+class AgentManagementTestXML(AgentManagementTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 9c187fd..64ab051 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -16,7 +16,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class L3AgentSchedulerJSON(base.BaseAdminNetworkTest):
@@ -36,8 +36,11 @@
     @classmethod
     def setUpClass(cls):
         super(L3AgentSchedulerJSON, cls).setUpClass()
+        if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
+            msg = "L3 Agent Scheduler Extension not enabled."
+            raise cls.skipException(msg)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_routers_on_l3_agent(self):
         resp, body = self.admin_client.list_agents()
         agents = body['agents']
@@ -48,7 +51,7 @@
             agent['id'])
         self.assertEqual('200', resp['status'])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_l3_agents_hosting_router(self):
         name = data_utils.rand_name('router-')
         resp, router = self.client.create_router(name)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 61af91f..064eaff 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -71,10 +71,10 @@
     def tearDownClass(cls):
         # Clean up ike policies
         for ikepolicy in cls.ikepolicies:
-            cls.client.delete_ike_policy(ikepolicy['id'])
+            cls.client.delete_ikepolicy(ikepolicy['id'])
         # Clean up vpn services
         for vpnservice in cls.vpnservices:
-            cls.client.delete_vpn_service(vpnservice['id'])
+            cls.client.delete_vpnservice(vpnservice['id'])
         # Clean up routers
         for router in cls.routers:
             resp, body = cls.client.list_router_interfaces(router['id'])
@@ -213,7 +213,7 @@
     @classmethod
     def create_vpnservice(cls, subnet_id, router_id):
         """Wrapper utility that returns a test vpn service."""
-        resp, body = cls.client.create_vpn_service(
+        resp, body = cls.client.create_vpnservice(
             subnet_id, router_id, admin_state_up=True,
             name=data_utils.rand_name("vpnservice-"))
         vpnservice = body['vpnservice']
@@ -221,9 +221,9 @@
         return vpnservice
 
     @classmethod
-    def create_ike_policy(cls, name):
+    def create_ikepolicy(cls, name):
         """Wrapper utility that returns a test ike policy."""
-        resp, body = cls.client.create_ike_policy(name)
+        resp, body = cls.client.create_ikepolicy(name)
         ikepolicy = body['ikepolicy']
         cls.ikepolicies.append(ikepolicy)
         return ikepolicy
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 1b27d1b..9d872f9 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -17,7 +17,7 @@
 
 
 from tempest.api.network import base
-from tempest.test import attr
+from tempest import test
 
 
 class ExtensionsTestJSON(base.BaseNetworkTest):
@@ -38,7 +38,7 @@
     def setUpClass(cls):
         super(ExtensionsTestJSON, cls).setUpClass()
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_show_extensions(self):
         # List available extensions for the tenant
         expected_alias = ['security-group', 'l3_agent_scheduler',
@@ -55,7 +55,7 @@
             ext_name = ext['name']
             ext_alias = ext['alias']
             actual_alias.append(ext['alias'])
-            resp, ext_details = self.client.show_extension_details(ext_alias)
+            resp, ext_details = self.client.show_extension(ext_alias)
             self.assertEqual('200', resp['status'])
             ext_details = ext_details['extension']
 
@@ -70,9 +70,11 @@
             self.assertEqual(ext_details['alias'], ext_alias)
             self.assertEqual(ext_details, ext)
         # Verify if expected extensions are present in the actual list
-        # of extensions returned
+        # of extensions returned, but only for those that have been
+        # enabled via configuration
         for e in expected_alias:
-            self.assertIn(e, actual_alias)
+            if test.is_extension_enabled(e, 'network'):
+                self.assertIn(e, actual_alias)
 
 
 class ExtensionsTestXML(ExtensionsTestJSON):
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 35d4fa8..3a41f4f 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -68,10 +68,10 @@
 
     def _delete_floating_ip(self, floating_ip_id):
         # Deletes a floating IP and verifies if it is deleted or not
-        resp, _ = self.client.delete_floating_ip(floating_ip_id)
+        resp, _ = self.client.delete_floatingip(floating_ip_id)
         self.assertEqual(204, resp.status)
         # Asserting that the floating_ip is not found in list after deletion
-        resp, floating_ips = self.client.list_floating_ips()
+        resp, floating_ips = self.client.list_floatingips()
         floatingip_id_list = list()
         for f in floating_ips['floatingips']:
             floatingip_id_list.append(f['id'])
@@ -106,7 +106,7 @@
         self.assertEqual(show_floating_ip['port_id'], self.port[0]['id'])
 
         # Verify the floating ip exists in the list of all floating_ips
-        resp, floating_ips = self.client.list_floating_ips()
+        resp, floating_ips = self.client.list_floatingips()
         self.assertEqual('200', resp['status'])
         floatingip_id_list = list()
         for f in floating_ips['floatingips']:
diff --git a/tempest/api/network/test_quotas.py b/tempest/api/network/test_quotas.py
index f7ba3cb..8b77637 100644
--- a/tempest/api/network/test_quotas.py
+++ b/tempest/api/network/test_quotas.py
@@ -74,12 +74,13 @@
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
         found = False
-        for qs in non_default_quotas:
+        for qs in non_default_quotas['quotas']:
             if qs['tenant_id'] == tenant_id:
                 found = True
         self.assertTrue(found)
         # Confirm from APi quotas were changed as requested for tenant
         resp, quota_set = self.admin_client.show_quotas(tenant_id)
+        quota_set = quota_set['quota']
         self.assertEqual('200', resp['status'])
         self.assertEqual(0, quota_set['network'])
         self.assertEqual(0, quota_set['security_group'])
@@ -88,5 +89,5 @@
         self.assertEqual('204', resp['status'])
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
-        for q in non_default_quotas:
+        for q in non_default_quotas['quotas']:
             self.assertNotEqual(tenant_id, q['tenant_id'])
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 63a8e24..fc3b1d9 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -46,20 +46,20 @@
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.vpnservice = cls.create_vpnservice(cls.subnet['id'],
                                                cls.router['id'])
-        cls.ikepolicy = cls.create_ike_policy(data_utils.rand_name(
-                                              "ike-policy-"))
+        cls.ikepolicy = cls.create_ikepolicy(
+            data_utils.rand_name("ike-policy-"))
 
     def _delete_ike_policy(self, ike_policy_id):
         # Deletes a ike policy and verifies if it is deleted or not
         ike_list = list()
-        resp, all_ike = self.client.list_ike_policies()
+        resp, all_ike = self.client.list_ikepolicies()
         for ike in all_ike['ikepolicies']:
             ike_list.append(ike['id'])
         if ike_policy_id in ike_list:
-            resp, _ = self.client.delete_ike_policy(ike_policy_id)
+            resp, _ = self.client.delete_ikepolicy(ike_policy_id)
             self.assertEqual(204, resp.status)
             # Asserting that the policy is not found in list after deletion
-            resp, ikepolicies = self.client.list_ike_policies()
+            resp, ikepolicies = self.client.list_ikepolicies()
             ike_id_list = list()
             for i in ikepolicies['ikepolicies']:
                 ike_id_list.append(i['id'])
@@ -68,7 +68,7 @@
     @attr(type='smoke')
     def test_list_vpn_services(self):
         # Verify the VPN service exists in the list of all VPN services
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         self.assertEqual('200', resp['status'])
         vpnservices = body['vpnservices']
         self.assertIn(self.vpnservice['id'], [v['id'] for v in vpnservices])
@@ -77,14 +77,14 @@
     def test_create_update_delete_vpn_service(self):
         # Creates a VPN service
         name = data_utils.rand_name('vpn-service-')
-        resp, body = self.client.create_vpn_service(self.subnet['id'],
-                                                    self.router['id'],
-                                                    name=name,
-                                                    admin_state_up=True)
+        resp, body = self.client.create_vpnservice(self.subnet['id'],
+                                                   self.router['id'],
+                                                   name=name,
+                                                   admin_state_up=True)
         self.assertEqual('201', resp['status'])
         vpnservice = body['vpnservice']
         # Assert if created vpnservices are not found in vpnservices list
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
         self.assertIsNotNone(vpnservice['id'])
         self.assertIn(vpnservice['id'], vpn_services)
@@ -95,17 +95,17 @@
         # should be "ACTIVE" not "PENDING*"
 
         # Verification of vpn service delete
-        resp, body = self.client.delete_vpn_service(vpnservice['id'])
+        resp, body = self.client.delete_vpnservice(vpnservice['id'])
         self.assertEqual('204', resp['status'])
         # Asserting if vpn service is found in the list after deletion
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
         self.assertNotIn(vpnservice['id'], vpn_services)
 
     @attr(type='smoke')
     def test_show_vpn_service(self):
         # Verifies the details of a vpn service
-        resp, body = self.client.show_vpn_service(self.vpnservice['id'])
+        resp, body = self.client.show_vpnservice(self.vpnservice['id'])
         self.assertEqual('200', resp['status'])
         vpnservice = body['vpnservice']
         self.assertEqual(self.vpnservice['id'], vpnservice['id'])
@@ -119,7 +119,7 @@
     @attr(type='smoke')
     def test_list_ike_policies(self):
         # Verify the ike policy exists in the list of all IKE policies
-        resp, body = self.client.list_ike_policies()
+        resp, body = self.client.list_ikepolicies()
         self.assertEqual('200', resp['status'])
         ikepolicies = body['ikepolicies']
         self.assertIn(self.ikepolicy['id'], [i['id'] for i in ikepolicies])
@@ -128,7 +128,7 @@
     def test_create_update_delete_ike_policy(self):
         # Creates a IKE policy
         name = data_utils.rand_name('ike-policy-')
-        resp, body = (self.client.create_ike_policy(
+        resp, body = (self.client.create_ikepolicy(
                       name,
                       ike_version="v1",
                       encryption_algorithm="aes-128",
@@ -140,19 +140,19 @@
         description = "Updated ike policy"
         new_ike = {'description': description, 'pfs': 'group5',
                    'name': data_utils.rand_name("New-IKE-")}
-        resp, body = self.client.update_ike_policy(ikepolicy['id'],
-                                                   **new_ike)
+        resp, body = self.client.update_ikepolicy(ikepolicy['id'],
+                                                  **new_ike)
         self.assertEqual('200', resp['status'])
         updated_ike_policy = body['ikepolicy']
         self.assertEqual(updated_ike_policy['description'], description)
         # Verification of ike policy delete
-        resp, body = self.client.delete_ike_policy(ikepolicy['id'])
+        resp, body = self.client.delete_ikepolicy(ikepolicy['id'])
         self.assertEqual('204', resp['status'])
 
     @attr(type='smoke')
     def test_show_ike_policy(self):
         # Verifies the details of a ike policy
-        resp, body = self.client.show_ike_policy(self.ikepolicy['id'])
+        resp, body = self.client.show_ikepolicy(self.ikepolicy['id'])
         self.assertEqual('200', resp['status'])
         ikepolicy = body['ikepolicy']
         self.assertEqual(self.ikepolicy['id'], ikepolicy['id'])
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 35a7326..b19344d 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -28,75 +28,57 @@
     template = """
 HeatTemplateFormatVersion: '2012-12-12'
 Description: |
-  Template which creates single EC2 instance
+  Template which creates some simple resources
 Parameters:
-  KeyName:
+  trigger:
     Type: String
-  InstanceType:
-    Type: String
-  ImageId:
-    Type: String
-  Subnet:
-    Type: String
+    Default: not_yet
 Resources:
-  SmokeServer:
-    Type: AWS::EC2::Instance
+  fluffy:
+    Type: AWS::AutoScaling::LaunchConfiguration
     Metadata:
-      Name: SmokeServer
+      kittens:
+      - Tom
+      - Stinky
     Properties:
-      ImageId: {Ref: ImageId}
-      InstanceType: {Ref: InstanceType}
-      KeyName: {Ref: KeyName}
-      SubnetId: {Ref: Subnet}
+      ImageId: not_used
+      InstanceType: not_used
       UserData:
-        Fn::Base64:
-          Fn::Join:
-          - ''
-          - - '#!/bin/bash -v
-
-              '
-            - /opt/aws/bin/cfn-signal -e 0 -r "SmokeServer created" '
-            - {Ref: WaitHandle}
-            - '''
-
-              '
-  WaitHandle:
-    Type: AWS::CloudFormation::WaitConditionHandle
-  WaitCondition:
-    Type: AWS::CloudFormation::WaitCondition
-    DependsOn: SmokeServer
-    Properties:
-      Handle: {Ref: WaitHandle}
-      Timeout: '600'
+        Fn::Replace:
+        - variable_a: {Ref: trigger}
+          variable_b: bee
+        - |
+          A == variable_a
+          B == variable_b
+Outputs:
+  fluffy:
+    Description: "fluffies irc nick"
+    Value:
+      Fn::Replace:
+      - nick: {Ref: fluffy}
+      - |
+        #nick
 """
 
     @classmethod
     def setUpClass(cls):
         super(StacksTestJSON, cls).setUpClass()
-        if not cls.orchestration_cfg.image_ref:
-            raise cls.skipException("No image available to test")
         cls.client = cls.orchestration_client
         cls.stack_name = data_utils.rand_name('heat')
-        keypair_name = (cls.orchestration_cfg.keypair_name or
-                        cls._create_keypair()['name'])
 
         # create the stack
-        subnet = cls._get_default_network()['subnets'][0]
         cls.stack_identifier = cls.create_stack(
             cls.stack_name,
             cls.template,
             parameters={
-                'KeyName': keypair_name,
-                'InstanceType': cls.orchestration_cfg.instance_type,
-                'ImageId': cls.orchestration_cfg.image_ref,
-                'Subnet': subnet
+                'trigger': 'start'
             })
         cls.stack_id = cls.stack_identifier.split('/')[1]
-        cls.resource_name = 'SmokeServer'
-        cls.resource_type = 'AWS::EC2::Instance'
+        cls.resource_name = 'fluffy'
+        cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
         cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_stack_list(self):
         """Created stack should be on the list of existing stacks."""
         resp, stacks = self.client.list_stacks()
@@ -105,7 +87,7 @@
         stacks_names = map(lambda stack: stack['stack_name'], stacks)
         self.assertIn(self.stack_name, stacks_names)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_stack_show(self):
         """Getting details about created stack should be possible."""
         resp, stack = self.client.get_stack(self.stack_name)
@@ -114,7 +96,7 @@
         self.assertEqual(self.stack_name, stack['stack_name'])
         self.assertEqual(self.stack_id, stack['id'])
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_list_resources(self):
         """Getting list of created resources for the stack should be possible.
         """
@@ -128,7 +110,7 @@
                               resources)
         self.assertIn(self.resource_type, resources_types)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_show_resource(self):
         """Getting details about created resource should be possible."""
         resp, resource = self.client.get_resource(self.stack_identifier,
@@ -137,7 +119,7 @@
         self.assertEqual(self.resource_name, resource['logical_resource_id'])
         self.assertEqual(self.resource_type, resource['resource_type'])
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_resource_metadata(self):
         """Getting metadata for created resource should be possible."""
         resp, metadata = self.client.show_resource_metadata(
@@ -145,9 +127,9 @@
             self.resource_name)
         self.assertEqual('200', resp['status'])
         self.assertIsInstance(metadata, dict)
-        self.assertEqual(self.resource_name, metadata.get('Name', None))
+        self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_list_events(self):
         """Getting list of created events for the stack should be possible."""
         resp, events = self.client.list_events(self.stack_identifier)
@@ -157,7 +139,7 @@
         self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
         self.assertIn('CREATE_COMPLETE', resource_statuses)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_show_event(self):
         """Getting details about existing event should be possible."""
         resp, events = self.client.list_resource_events(self.stack_identifier,
@@ -168,7 +150,7 @@
         resp, event = self.client.show_event(self.stack_identifier,
                                              self.resource_name, event_id)
         self.assertEqual('200', resp['status'])
-        self.assertEqual('CREATE_IN_PROGRESS', event['resource_status'])
+        self.assertIsInstance(event, dict)
+        self.assertEqual(self.resource_name, event['resource_name'])
         self.assertEqual('state changed', event['resource_status_reason'])
         self.assertEqual(self.resource_name, event['logical_resource_id'])
-        self.assertIsInstance(event, dict)
diff --git a/tempest/api/orchestration/stacks/test_server_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
index 3c2a2d2..0480570 100644
--- a/tempest/api/orchestration/stacks/test_server_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -169,9 +169,9 @@
             body['physical_resource_id'])
 
         # Check that the user can authenticate with the generated password
-        linux_client = RemoteClient(
-            server, 'ec2-user', pkey=self.keypair['private_key'])
-        self.assertTrue(linux_client.can_authenticate())
+        linux_client = RemoteClient(server, 'ec2-user',
+                                    pkey=self.keypair['private_key'])
+        linux_client.validate_authentication()
 
     @attr(type='slow')
     def test_stack_wait_condition_data(self):
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 4dbc88a..def330e 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -57,13 +57,13 @@
         # Create 3 test volumes
         cls.volume_list = []
         cls.volume_id_list = []
+        cls.metadata = {'Type': 'work'}
         for i in range(3):
             v_name = data_utils.rand_name('volume')
-            metadata = {'Type': 'work'}
             try:
                 resp, volume = cls.client.create_volume(size=1,
                                                         display_name=v_name,
-                                                        metadata=metadata)
+                                                        metadata=cls.metadata)
                 cls.client.wait_for_volume_status(volume['id'], 'available')
                 resp, volume = cls.client.get_volume(volume['id'])
                 cls.volume_list.append(volume)
@@ -88,6 +88,25 @@
             cls.client.wait_for_resource_deletion(volid)
         super(VolumesListTest, cls).tearDownClass()
 
+    def _list_by_param_value_and_assert(self, params, with_detail=False):
+        """
+        Perform list or list_details action with given params
+        and validates result.
+        """
+        if with_detail:
+            resp, fetched_vol_list = \
+                self.client.list_volumes_with_detail(params=params)
+        else:
+            resp, fetched_vol_list = self.client.list_volumes(params=params)
+
+        self.assertEqual(200, resp.status)
+        # Validating params of fetched volumes
+        for volume in fetched_vol_list:
+            for key in params:
+                msg = "Failed to list volumes %s by %s" % \
+                      ('details' if with_detail else '', key)
+                self.assertEqual(params[key], volume[key], msg)
+
     @attr(type='smoke')
     def test_volume_list(self):
         # Get a list of Volumes
@@ -164,6 +183,34 @@
             self.assertEqual(zone, volume['availability_zone'])
         self.assertVolumesIn(fetched_list, self.volume_list)
 
+    @attr(type='gate')
+    def test_volume_list_with_param_metadata(self):
+        # Test to list volumes when metadata param is given
+        params = {'metadata': self.metadata}
+        self._list_by_param_value_and_assert(params)
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_metadata(self):
+        # Test to list volumes details when metadata param is given
+        params = {'metadata': self.metadata}
+        self._list_by_param_value_and_assert(params, with_detail=True)
+
+    @attr(type='gate')
+    def test_volume_list_param_display_name_and_status(self):
+        # Test to list volume when display name and status param is given
+        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name'],
+                  'status': 'available'}
+        self._list_by_param_value_and_assert(params)
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_display_name_and_status(self):
+        # Test to list volume when name and status param is given
+        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name'],
+                  'status': 'available'}
+        self._list_by_param_value_and_assert(params, with_detail=True)
+
 
 class VolumeListTestXML(VolumesListTest):
     _interface = 'xml'
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 99e8de7..6c45c3d 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -37,6 +37,27 @@
     def tearDownClass(cls):
         super(VolumesSnapshotTest, cls).tearDownClass()
 
+    def _list_by_param_values_and_assert(self, params, with_detail=False):
+        """
+        Perform list or list_details action with given params
+        and validates result.
+        """
+        if with_detail:
+            resp, fetched_snap_list = \
+                self.snapshots_client.\
+                list_snapshots_with_detail(params=params)
+        else:
+            resp, fetched_snap_list = \
+                self.snapshots_client.list_snapshots(params=params)
+
+        self.assertEqual(200, resp.status)
+        # Validating params of fetched snapshots
+        for snap in fetched_snap_list:
+            for key in params:
+                msg = "Failed to list snapshots %s by %s" % \
+                      ('details' if with_detail else '', key)
+                self.assertEqual(params[key], snap[key], msg)
+
     @attr(type='gate')
     def test_snapshot_create_get_list_update_delete(self):
         # Create a snapshot
@@ -83,6 +104,46 @@
         self.snapshots.remove(snapshot)
 
     @attr(type='gate')
+    def test_snapshots_list_with_params(self):
+        """list snapshots with params."""
+        # Create a snapshot
+        display_name = data_utils.rand_name('snap')
+        snapshot = self.create_snapshot(self.volume_origin['id'],
+                                        display_name=display_name)
+
+        # Verify list snapshots by display_name filter
+        params = {'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params)
+
+        # Verify list snapshots by status filter
+        params = {'status': 'available'}
+        self._list_by_param_values_and_assert(params)
+
+        # Verify list snapshots by status and display name filter
+        params = {'status': 'available',
+                  'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params)
+
+    @attr(type='gate')
+    def test_snapshots_list_details_with_params(self):
+        """list snapshot details with params."""
+        # Create a snapshot
+        display_name = data_utils.rand_name('snap')
+        snapshot = self.create_snapshot(self.volume_origin['id'],
+                                        display_name=display_name)
+
+        # Verify list snapshot details by display_name filter
+        params = {'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+        # Verify list snapshot details by status filter
+        params = {'status': 'available'}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+        # Verify list snapshot details by status and display name filter
+        params = {'status': 'available',
+                  'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+
+    @attr(type='gate')
     def test_volume_from_snapshot(self):
         # Create a temporary snap using wrapper method from base, then
         # create a snap based volume, check resp code and deletes it
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index 047b17d..80376ab 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -44,35 +44,43 @@
             raise cls.skipException(msg)
         super(SimpleReadOnlyNeutronClientTest, cls).setUpClass()
 
+    @test.attr(type='smoke')
     def test_neutron_fake_action(self):
         self.assertRaises(subprocess.CalledProcessError,
                           self.neutron,
                           'this-does-not-exist')
 
+    @test.attr(type='smoke')
     def test_neutron_net_list(self):
         self.neutron('net-list')
 
+    @test.attr(type='smoke')
     def test_neutron_ext_list(self):
         ext = self.parser.listing(self.neutron('ext-list'))
         self.assertTableStruct(ext, ['alias', 'name'])
 
+    @test.attr(type='smoke')
     def test_neutron_dhcp_agent_list_hosting_net(self):
         self.neutron('dhcp-agent-list-hosting-net',
                      params=CONF.compute.fixed_network_name)
 
+    @test.attr(type='smoke')
     def test_neutron_agent_list(self):
         agents = self.parser.listing(self.neutron('agent-list'))
         field_names = ['id', 'agent_type', 'host', 'alive', 'admin_state_up']
         self.assertTableStruct(agents, field_names)
 
+    @test.attr(type='smoke')
     def test_neutron_floatingip_list(self):
         self.neutron('floatingip-list')
 
     @test.skip_because(bug="1240694")
+    @test.attr(type='smoke')
     def test_neutron_meter_label_list(self):
         self.neutron('meter-label-list')
 
     @test.skip_because(bug="1240694")
+    @test.attr(type='smoke')
     def test_neutron_meter_label_rule_list(self):
         self.neutron('meter-label-rule-list')
 
@@ -83,40 +91,52 @@
             if '404 Not Found' not in e.stderr:
                 self.fail('%s: Unexpected failure.' % command)
 
+    @test.attr(type='smoke')
     def test_neutron_lb_healthmonitor_list(self):
         self._test_neutron_lbaas_command('lb-healthmonitor-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_member_list(self):
         self._test_neutron_lbaas_command('lb-member-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_pool_list(self):
         self._test_neutron_lbaas_command('lb-pool-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_vip_list(self):
         self._test_neutron_lbaas_command('lb-vip-list')
 
+    @test.attr(type='smoke')
     def test_neutron_net_external_list(self):
         self.neutron('net-external-list')
 
+    @test.attr(type='smoke')
     def test_neutron_port_list(self):
         self.neutron('port-list')
 
+    @test.attr(type='smoke')
     def test_neutron_quota_list(self):
         self.neutron('quota-list')
 
+    @test.attr(type='smoke')
     def test_neutron_router_list(self):
         self.neutron('router-list')
 
+    @test.attr(type='smoke')
     def test_neutron_security_group_list(self):
         security_grp = self.parser.listing(self.neutron('security-group-list'))
         self.assertTableStruct(security_grp, ['id', 'name', 'description'])
 
+    @test.attr(type='smoke')
     def test_neutron_security_group_rule_list(self):
         self.neutron('security-group-rule-list')
 
+    @test.attr(type='smoke')
     def test_neutron_subnet_list(self):
         self.neutron('subnet-list')
 
+    @test.attr(type='smoke')
     def test_neutron_help(self):
         help_text = self.neutron('help')
         lines = help_text.split('\n')
@@ -136,11 +156,14 @@
 
      # Optional arguments:
 
+    @test.attr(type='smoke')
     def test_neutron_version(self):
         self.neutron('', flags='--version')
 
+    @test.attr(type='smoke')
     def test_neutron_debug_net_list(self):
         self.neutron('net-list', flags='--debug')
 
+    @test.attr(type='smoke')
     def test_neutron_quiet_net_list(self):
         self.neutron('net-list', flags='--quiet')
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index c397b7c..bca2f9e 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -23,6 +23,7 @@
 import warnings
 
 from tempest import exceptions
+from tempest.openstack.common import log as logging
 
 
 with warnings.catch_warnings():
@@ -30,6 +31,9 @@
     import paramiko
 
 
+LOG = logging.getLogger(__name__)
+
+
 class Client(object):
 
     def __init__(self, host, username, password=None, timeout=300, pkey=None,
@@ -49,33 +53,44 @@
 
     def _get_ssh_connection(self, sleep=1.5, backoff=1.01):
         """Returns an ssh connection to the specified host."""
-        _timeout = True
         bsleep = sleep
         ssh = paramiko.SSHClient()
         ssh.set_missing_host_key_policy(
             paramiko.AutoAddPolicy())
         _start_time = time.time()
-
-        while not self._is_timed_out(_start_time):
+        if self.pkey is not None:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with public key authentication",
+                     self.host, self.username)
+        else:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with password %s",
+                     self.host, self.username, str(self.password))
+        attempts = 0
+        while True:
             try:
                 ssh.connect(self.host, username=self.username,
                             password=self.password,
                             look_for_keys=self.look_for_keys,
                             key_filename=self.key_filename,
                             timeout=self.channel_timeout, pkey=self.pkey)
-                _timeout = False
-                break
+                LOG.info("ssh connection to %s@%s sucessfuly created",
+                         self.username, self.host)
+                return ssh
             except (socket.error,
-                    paramiko.AuthenticationException,
                     paramiko.SSHException):
+                attempts += 1
                 time.sleep(bsleep)
                 bsleep *= backoff
-                continue
-        if _timeout:
-            raise exceptions.SSHTimeout(host=self.host,
-                                        user=self.username,
-                                        password=self.password)
-        return ssh
+                if not self._is_timed_out(_start_time):
+                    continue
+                else:
+                    LOG.exception("Failed to establish authenticated ssh"
+                                  " connection to %s@%s after %d attempts",
+                                  self.username, self.host, attempts)
+                    raise exceptions.SSHTimeout(host=self.host,
+                                                user=self.username,
+                                                password=self.password)
 
     def _is_timed_out(self, start_time):
         return (time.time() - self.timeout) > start_time
@@ -144,11 +159,6 @@
         return ''.join(out_data)
 
     def test_connection_auth(self):
-        """Returns true if ssh can connect to server."""
-        try:
-            connection = self._get_ssh_connection()
-            connection.close()
-        except paramiko.AuthenticationException:
-            return False
-
-        return True
+        """Raises an exception when we can not connect to server via ssh."""
+        connection = self._get_ssh_connection()
+        connection.close()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 0d0e794..144536a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -19,7 +19,6 @@
 from tempest.common import utils
 from tempest.config import TempestConfig
 from tempest.exceptions import ServerUnreachable
-from tempest.exceptions import SSHTimeout
 
 
 class RemoteClient():
@@ -40,16 +39,15 @@
                     break
             else:
                 raise ServerUnreachable()
-
         self.ssh_client = Client(ip_address, username, password, ssh_timeout,
                                  pkey=pkey,
                                  channel_timeout=ssh_channel_timeout)
-        if not self.ssh_client.test_connection_auth():
-            raise SSHTimeout()
 
-    def can_authenticate(self):
-        # Re-authenticate
-        return self.ssh_client.test_connection_auth()
+    def validate_authentication(self):
+        """Validate ssh connection and authentication
+           This method raises an Exception when the validation fails.
+        """
+        self.ssh_client.test_connection_auth()
 
     def hostname_equals_servername(self, expected_hostname):
         # Get host name using command "hostname"
@@ -89,3 +87,11 @@
         # usually to /dev/ttyS0
         cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
         return self.ssh_client.exec_command(cmd)
+
+    def ping_host(self, host):
+        cmd = 'ping -c1 -w1 %s' % host
+        return self.ssh_client.exec_command(cmd)
+
+    def get_mac_address(self):
+        cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
+        return self.ssh_client.exec_command(cmd)
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 44198f0..d2b40c9 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -88,3 +88,34 @@
             raise exceptions.TimeoutException(message)
         old_status = server_status
         old_task_state = task_state
+
+
+def wait_for_image_status(client, image_id, status):
+    """Waits for an image to reach a given status.
+
+    The client should have a get_image(image_id) method to get the image.
+    The client should also have build_interval and build_timeout attributes.
+    """
+    resp, image = client.get_image(image_id)
+    start = int(time.time())
+
+    while image['status'] != status:
+        time.sleep(client.build_interval)
+        resp, image = client.get_image(image_id)
+        if image['status'] == 'ERROR':
+            raise exceptions.AddImageException(image_id=image_id)
+
+        # check the status again to avoid a false negative where we hit
+        # the timeout at the same time that the image reached the expected
+        # status
+        if image['status'] == status:
+            return
+
+        if int(time.time()) - start >= client.build_timeout:
+            message = ('Image %(image_id)s failed to reach %(status)s '
+                       'status within the required time (%(timeout)s s).' %
+                       {'image_id': image_id,
+                        'status': status,
+                        'timeout': client.build_timeout})
+            message += ' Current status: %s.' % image['status']
+            raise exceptions.TimeoutException(message)
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4c1c107..2adc98e 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -21,6 +21,7 @@
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
+SETUPCLASS_DEFINITION = re.compile(r'^\s*def setUpClass')
 SCENARIO_DECORATOR = re.compile(r'\s*@.*services\(')
 
 
@@ -52,6 +53,14 @@
                         "T104: Scenario tests require a service decorator")
 
 
+def no_setupclass_for_unit_tests(physical_line, filename):
+    if 'tempest/tests' in filename:
+        if SETUPCLASS_DEFINITION.match(physical_line):
+            return (physical_line.find('def'),
+                    "T105: setUpClass can not be used with unit tests")
+
+
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
+    register(no_setupclass_for_unit_tests)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index e839d20..9f97964 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -33,7 +33,6 @@
 
 from tempest.api.network import common as net_common
 from tempest.common import isolated_creds
-from tempest.common import ssh
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux.remote_client import RemoteClient
 from tempest import exceptions
@@ -248,7 +247,8 @@
                 thing.delete()
             except Exception as e:
                 # If the resource is already missing, mission accomplished.
-                if e.__class__.__name__ == 'NotFound':
+                # add status code as workaround for bug 1247568
+                if e.__class__.__name__ == 'NotFound' or e.status_code == 404:
                     continue
                 raise
 
@@ -649,13 +649,6 @@
         return tempest.test.call_until_true(
             ping, self.config.compute.ping_timeout, 1)
 
-    def _is_reachable_via_ssh(self, ip_address, username, private_key,
-                              timeout):
-        ssh_client = ssh.Client(ip_address, username,
-                                pkey=private_key,
-                                timeout=timeout)
-        return ssh_client.test_connection_auth()
-
     def _check_vm_connectivity(self, ip_address,
                                username=None,
                                private_key=None,
@@ -680,13 +673,9 @@
                         msg=msg)
         if should_connect:
             # no need to check ssh for negative connectivity
-            self.assertTrue(self._is_reachable_via_ssh(
-                ip_address,
-                username,
-                private_key,
-                timeout=self.config.compute.ssh_timeout),
-                'Auth failure in connecting to %s@%s via ssh' %
-                (username, ip_address))
+            linux_client = self.get_remote_client(ip_address, username,
+                                                  private_key)
+            linux_client.validate_authentication()
 
     def _create_security_group_nova(self, client=None,
                                     namestart='secgroup-smoke-',
@@ -853,6 +842,12 @@
 
         return rules
 
+    def _ssh_to_server(self, server, private_key):
+        ssh_login = self.config.compute.image_ssh_user
+        return self.get_remote_client(server,
+                                      username=ssh_login,
+                                      private_key=private_key)
+
     def _show_quota_network(self, tenant_id):
         quota = self.network_client.show_quota(tenant_id)
         return quota['quota']['network']
@@ -865,6 +860,60 @@
         quota = self.network_client.show_quota(tenant_id)
         return quota['quota']['port']
 
+    def _get_router(self, tenant_id):
+        """Retrieve a router for the given tenant id.
+
+        If a public router has been configured, it will be returned.
+
+        If a public router has not been configured, but a public
+        network has, a tenant router will be created and returned that
+        routes traffic to the public network.
+        """
+        router_id = self.config.network.public_router_id
+        network_id = self.config.network.public_network_id
+        if router_id:
+            result = self.network_client.show_router(router_id)
+            return net_common.AttributeDict(**result['router'])
+        elif network_id:
+            router = self._create_router(tenant_id)
+            router.add_gateway(network_id)
+            return router
+        else:
+            raise Exception("Neither of 'public_router_id' or "
+                            "'public_network_id' has been defined.")
+
+    def _create_router(self, tenant_id, namestart='router-smoke-'):
+        name = data_utils.rand_name(namestart)
+        body = dict(
+            router=dict(
+                name=name,
+                admin_state_up=True,
+                tenant_id=tenant_id,
+            ),
+        )
+        result = self.network_client.create_router(body=body)
+        router = net_common.DeletableRouter(client=self.network_client,
+                                            **result['router'])
+        self.assertEqual(router.name, name)
+        self.set_resource(name, router)
+        return router
+
+    def _create_networks(self, tenant_id=None):
+        """Create a network with a subnet connected to a router.
+
+        :returns: network, subnet, router
+        """
+        if tenant_id is None:
+            tenant_id = self.tenant_id
+        network = self._create_network(tenant_id)
+        router = self._get_router(tenant_id)
+        subnet = self._create_subnet(network)
+        subnet.add_to_router(router.id)
+        self.networks.append(network)
+        self.subnets.append(subnet)
+        self.routers.append(router)
+        return network, subnet, router
+
 
 class OrchestrationScenarioTest(OfficialClientTest):
     """
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_cross_tenant_connectivity.py
new file mode 100644
index 0000000..ad2c271
--- /dev/null
+++ b/tempest/scenario/test_cross_tenant_connectivity.py
@@ -0,0 +1,494 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Red Hat, Inc.
+# 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.common import debug
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest.scenario.manager import OfficialClientManager
+from tempest.test import attr
+from tempest.test import call_until_true
+from tempest.test import services
+
+LOG = logging.getLogger(__name__)
+
+
+class TestNetworkCrossTenant(manager.NetworkScenarioTest):
+
+    """
+    This test suite assumes that Nova has been configured to
+    boot VM's with Neutron-managed networking, and attempts to
+    verify cross tenant connectivity as follows
+
+    ssh:
+        in order to overcome "ip namespace", each tenant has an "access point"
+        VM with floating-ip open to incoming ssh connection allowing network
+        commands (ping/ssh) to be executed from within the
+        tenant-network-namespace
+        Tempest host performs key-based authentication to the ssh server via
+        floating IP address
+
+    connectivity test is done by pinging destination server via source server
+    ssh connection.
+    success - ping returns
+    failure - ping_timeout reached
+
+    setup:
+        for each tenant (demo and alt):
+            1. create a network&subnet
+            2. create a router (if public router isn't configured)
+            3. connect tenant network to public network via router
+            4. create an access point:
+                a. a security group open to incoming ssh connection
+                b. a VM with a floating ip
+            5. create a general empty security group (same as "default", but
+            without rules allowing in-tenant traffic)
+            6. for demo tenant - create another server to test in-tenant
+            connections
+
+    tests:
+        1. _verify_network_details
+        2. _verify_mac_addr: for each access point verify that
+        (subnet, fix_ip, mac address) are as defined in the port list
+        3. _test_in_tenant_block: test that in-tenant traffic is disabled
+        without rules allowing it
+        4. _test_in_tenant_allow: test that in-tenant traffic is enabled
+        once an appropriate rule has been created
+        5. _test_cross_tenant_block: test that cross-tenant traffic is disabled
+        without a rule allowing it on destination tenant
+        6. _test_cross_tenant_allow:
+            * test that cross-tenant traffic is enabled once an appropriate
+            rule has been created on destination tenant.
+            * test that reverse traffic is still blocked
+            * test than revesre traffic is enabled once an appropriate rule has
+            been created on source tenant
+
+    assumptions:
+        1. alt_tenant/user existed and is different from demo_tenant/user
+        2. Public network is defined and reachable from the Tempest host
+        3. Public router can either be:
+            * defined, in which case all tenants networks can connect directly
+            to it, and cross tenant check will be done on the private IP of the
+            destination tenant
+            or
+            * not defined (empty string), in which case each tanant will have
+            its own router connected to the public network
+    """
+
+    class TenantProperties():
+        '''
+        helper class to save tenant details
+            id
+            credentials
+            network
+            subnet
+            security groups
+            servers
+            access point
+        '''
+
+        def __init__(self, tenant_id, tenant_user, tenant_pass, tenant_name):
+            self.manager = OfficialClientManager(
+                tenant_user,
+                tenant_pass,
+                tenant_name
+            )
+            self.tenant_id = tenant_id
+            self.tenant_name = tenant_name
+            self.tenant_user = tenant_user
+            self.tenant_pass = tenant_pass
+            self.network = None
+            self.subnet = None
+            self.router = None
+            self.security_groups = {}
+            self.servers = list()
+
+        def _set_network(self, network, subnet, router):
+            self.network = network
+            self.subnet = subnet
+            self.router = router
+
+        def _get_tenant_credentials(self):
+            return self.tenant_user, self.tenant_pass, self.tenant_name
+
+    @classmethod
+    def check_preconditions(cls):
+        super(TestNetworkCrossTenant, cls).check_preconditions()
+        if (cls.alt_tenant_id is None) or (cls.tenant_id is cls.alt_tenant_id):
+            msg = 'No alt_tenant defined'
+            cls.enabled = False
+            raise cls.skipException(msg)
+        cfg = cls.config.network
+        if not (cfg.tenant_networks_reachable or cfg.public_network_id):
+            msg = ('Either tenant_networks_reachable must be "true", or '
+                   'public_network_id must be defined.')
+            cls.enabled = False
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestNetworkCrossTenant, cls).setUpClass()
+        cls.alt_tenant_id = cls.manager._get_identity_client(
+            cls.config.identity.alt_username,
+            cls.config.identity.alt_password,
+            cls.config.identity.alt_tenant_name
+        ).tenant_id
+        cls.check_preconditions()
+        # TODO(mnewby) Consider looking up entities as needed instead
+        # of storing them as collections on the class.
+        cls.keypairs = {}
+        cls.security_groups = {}
+        cls.networks = []
+        cls.subnets = []
+        cls.routers = []
+        cls.servers = []
+        cls.floating_ips = {}
+        cls.tenants = {}
+        cls.demo_tenant = cls.TenantProperties(
+            cls.tenant_id,
+            cls.config.identity.username,
+            cls.config.identity.password,
+            cls.config.identity.tenant_name
+        )
+        cls.alt_tenant = cls.TenantProperties(
+            cls.alt_tenant_id,
+            cls.config.identity.alt_username,
+            cls.config.identity.alt_password,
+            cls.config.identity.alt_tenant_name
+        )
+        for tenant in [cls.demo_tenant, cls.alt_tenant]:
+            cls.tenants[tenant.tenant_id] = tenant
+        if not cls.config.network.public_router_id:
+            cls.floating_ip_access = True
+        else:
+            cls.floating_ip_access = False
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestNetworkCrossTenant, cls).tearDownClass()
+
+    def _create_tenant_keypairs(self, tenant_id):
+        self.keypairs[tenant_id] = self.create_keypair(
+            name=data_utils.rand_name('keypair-smoke-'))
+
+    def _create_tenant_security_groups(self, tenant):
+        self.security_groups.setdefault(self.tenant_id, [])
+        access_sg = self._create_empty_security_group(
+            namestart='secgroup_access-',
+            tenant_id=tenant.tenant_id
+        )
+        # don't use default secgroup since it allows in-tenant traffic
+        def_sg = self._create_empty_security_group(
+            namestart='secgroup_general-',
+            tenant_id=tenant.tenant_id
+        )
+        tenant.security_groups.update(access=access_sg, default=def_sg)
+        ssh_rule = dict(
+            protocol='tcp',
+            port_range_min=22,
+            port_range_max=22,
+            direction='ingress',
+        )
+        self._create_security_group_rule(secgroup=access_sg,
+                                         **ssh_rule
+                                         )
+
+    def _verify_network_details(self, tenant):
+        # Checks that we see the newly created network/subnet/router via
+        # checking the result of list_[networks,routers,subnets]
+        # Check that (router, subnet) couple exist in port_list
+        seen_nets = self._list_networks()
+        seen_names = [n['name'] for n in seen_nets]
+        seen_ids = [n['id'] for n in seen_nets]
+
+        self.assertIn(tenant.network.name, seen_names)
+        self.assertIn(tenant.network.id, seen_ids)
+
+        seen_subnets = [(n['id'], n['cidr'], n['network_id'])
+                        for n in self._list_subnets()]
+        mysubnet = (tenant.subnet.id, tenant.subnet.cidr, tenant.network.id)
+        self.assertIn(mysubnet, seen_subnets)
+
+        seen_routers = self._list_routers()
+        seen_router_ids = [n['id'] for n in seen_routers]
+        seen_router_names = [n['name'] for n in seen_routers]
+
+        self.assertIn(tenant.router.name, seen_router_names)
+        self.assertIn(tenant.router.id, seen_router_ids)
+
+        myport = (tenant.router.id, tenant.subnet.id)
+        router_ports = [(i['device_id'], i['fixed_ips'][0]['subnet_id']) for i
+                        in self.network_client.list_ports()['ports']
+                        if i['device_owner'] == 'network:router_interface']
+
+        self.assertIn(myport, router_ports)
+
+    def _create_server(self, name, tenant, security_groups=None):
+        """
+        creates a server and assigns to security group
+        """
+        self._set_compute_context(tenant)
+        if security_groups is None:
+            security_groups = [tenant.security_groups['default'].name]
+        create_kwargs = {
+            'nics': [
+                {'net-id': tenant.network.id},
+            ],
+            'key_name': self.keypairs[tenant.tenant_id].name,
+            'security_groups': security_groups,
+            'tenant_id': tenant.tenant_id
+        }
+        server = self.create_server(name=name, create_kwargs=create_kwargs)
+        return server
+
+    def _create_tenant_servers(self, tenant, num=1):
+        for i in range(num):
+            name = 'server-{tenant}-gen-{num}-'.format(
+                   tenant=tenant.tenant_name,
+                   num=i
+            )
+            name = data_utils.rand_name(name)
+            server = self._create_server(name, tenant)
+            self.servers.append(server)
+            tenant.servers.append(server)
+
+    def _set_access_point(self, tenant):
+        """
+        creates a server in a secgroup with rule allowing external ssh
+        in order to access tenant internal network
+        workaround ip namespace
+        """
+        secgroups = [sg.name for sg in tenant.security_groups.values()]
+        name = 'server-{tenant}-access_point-'.format(tenant=tenant.tenant_name
+                                                      )
+        name = data_utils.rand_name(name)
+        server = self._create_server(name, tenant,
+                                     security_groups=secgroups)
+        self.servers.append(server)
+        tenant.access_point = server
+        self._assign_floating_ips(server)
+
+    def _assign_floating_ips(self, server):
+        public_network_id = self.config.network.public_network_id
+        floating_ip = self._create_floating_ip(server, public_network_id)
+        self.floating_ips.setdefault(server, floating_ip)
+
+    def _create_tenant_network(self, tenant):
+        tenant._set_network(*self._create_networks(tenant.tenant_id))
+
+    def _set_compute_context(self, tenant):
+        self.compute_client = tenant.manager.compute_client
+        return self.compute_client
+
+    def _deploy_tenant(self, tenant_or_id):
+        """
+        creates:
+            network
+            subnet
+            router (if public not defined)
+            access security group
+            access-point server
+            for demo_tenant:
+                creates general server to test against
+        """
+        if not isinstance(tenant_or_id, self.TenantProperties):
+            tenant = self.tenants[tenant_or_id]
+            tenant_id = tenant_or_id
+        else:
+            tenant = tenant_or_id
+            tenant_id = tenant.tenant_id
+        self._set_compute_context(tenant)
+        self._create_tenant_keypairs(tenant_id)
+        self._create_tenant_network(tenant)
+        self._create_tenant_security_groups(tenant)
+        if tenant is self.demo_tenant:
+            self._create_tenant_servers(tenant, num=1)
+        self._set_access_point(tenant)
+
+    def _get_server_ip(self, server, floating=False):
+        '''
+        returns the ip (floating/internal) of a server
+        '''
+        if floating:
+            return self.floating_ips[server].floating_ip_address
+        else:
+            network_name = self.tenants[server.tenant_id].network.name
+            return server.networks[network_name][0]
+
+    def _connect_to_access_point(self, tenant):
+        """
+        create ssh connection to tenant access point
+        """
+        access_point_ssh = \
+            self.floating_ips[tenant.access_point].floating_ip_address
+        private_key = self.keypairs[tenant.tenant_id].private_key
+        access_point_ssh = self._ssh_to_server(access_point_ssh,
+                                               private_key=private_key)
+        return access_point_ssh
+
+    def _test_remote_connectivity(self, source, dest, should_succeed=True):
+        """
+        check ping server via source ssh connection
+
+        :param source: RemoteClient: an ssh connection from which to ping
+        :param dest: and IP to ping against
+        :param should_succeed: boolean should ping succeed or not
+        :returns: boolean -- should_succeed == ping
+        :returns: ping is false if ping failed
+        """
+        def ping_remote():
+            try:
+                source.ping_host(dest)
+            except exceptions.SSHExecCommandFailed as ex:
+                LOG.debug(ex)
+                return not should_succeed
+            return should_succeed
+
+        return call_until_true(ping_remote,
+                               self.config.compute.ping_timeout,
+                               1)
+
+    def _check_connectivity(self, access_point, ip, should_succeed=True):
+        if should_succeed:
+            msg = "Timed out waiting for %s to become reachable" % ip
+        else:
+            # todo(yfried): remove this line when bug 1252620 is fixed
+            return True
+            msg = "%s is reachable" % ip
+        try:
+            self.assertTrue(self._test_remote_connectivity(access_point, ip,
+                                                           should_succeed),
+                            msg)
+        except Exception:
+            debug.log_ip_ns()
+            raise
+
+    def _test_in_tenant_block(self, tenant):
+        access_point_ssh = self._connect_to_access_point(tenant)
+        for server in tenant.servers:
+            self._check_connectivity(access_point=access_point_ssh,
+                                     ip=self._get_server_ip(server),
+                                     should_succeed=False)
+
+    def _test_in_tenant_allow(self, tenant):
+        ruleset = dict(
+            protocol='icmp',
+            remote_group_id=tenant.security_groups['default'].id,
+            direction='ingress'
+        )
+        rule = self._create_security_group_rule(
+            secgroup=tenant.security_groups['default'],
+            **ruleset
+        )
+        access_point_ssh = self._connect_to_access_point(tenant)
+        for server in tenant.servers:
+            self._check_connectivity(access_point=access_point_ssh,
+                                     ip=self._get_server_ip(server))
+        rule.delete()
+
+    def _test_cross_tenant_block(self, source_tenant, dest_tenant):
+        '''
+        if public router isn't defined, then dest_tenant access is via
+        floating-ip
+        '''
+        access_point_ssh = self._connect_to_access_point(source_tenant)
+        ip = self._get_server_ip(dest_tenant.access_point,
+                                 floating=self.floating_ip_access)
+        self._check_connectivity(access_point=access_point_ssh, ip=ip,
+                                 should_succeed=False)
+
+    def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
+        '''
+        check for each direction:
+        creating rule for tenant incoming traffic enables only 1way traffic
+        '''
+        ruleset = dict(
+            protocol='icmp',
+            direction='ingress'
+        )
+        rule_s2d = self._create_security_group_rule(
+            secgroup=dest_tenant.security_groups['default'],
+            **ruleset
+        )
+        try:
+            access_point_ssh = self._connect_to_access_point(source_tenant)
+            ip = self._get_server_ip(dest_tenant.access_point,
+                                     floating=self.floating_ip_access)
+            self._check_connectivity(access_point_ssh, ip)
+
+            # test that reverse traffic is still blocked
+            self._test_cross_tenant_block(dest_tenant, source_tenant)
+
+            # allow reverse traffic and check
+            rule_d2s = self._create_security_group_rule(
+                secgroup=source_tenant.security_groups['default'],
+                **ruleset
+            )
+            try:
+                access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
+                ip = self._get_server_ip(source_tenant.access_point,
+                                         floating=self.floating_ip_access)
+                self._check_connectivity(access_point_ssh_2, ip)
+
+                # clean_rules
+                rule_s2d.delete()
+                rule_d2s.delete()
+
+            except Exception as e:
+                rule_d2s.delete()
+                raise e
+
+        except Exception as e:
+            rule_s2d.delete()
+            raise e
+
+    def _verify_mac_addr(self, tenant):
+        """
+        verify that VM (tenant's access point) has the same ip,mac as listed in
+        port list
+        """
+        access_point_ssh = self._connect_to_access_point(tenant)
+        mac_addr = access_point_ssh.get_mac_address()
+        mac_addr = mac_addr.strip().lower()
+        port_list = self.network_client.list_ports()['ports']
+        port_detail_list = [
+            (port['fixed_ips'][0]['subnet_id'],
+             port['fixed_ips'][0]['ip_address'],
+             port['mac_address'].lower()) for port in port_list
+        ]
+        server_ip = self._get_server_ip(tenant.access_point)
+        subnet_id = tenant.subnet.id
+        self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list)
+
+    @attr(type='smoke')
+    @services('compute', 'network')
+    def test_cross_tenant_traffic(self):
+        for tenant_id in self.tenants.keys():
+            self._deploy_tenant(tenant_id)
+            self._verify_network_details(self.tenants[tenant_id])
+            self._verify_mac_addr(self.tenants[tenant_id])
+
+        # in-tenant check
+        self._test_in_tenant_block(self.demo_tenant)
+        self._test_in_tenant_allow(self.demo_tenant)
+
+        # cross tenant check
+        source_tenant = self.demo_tenant
+        dest_tenant = self.alt_tenant
+        self._test_cross_tenant_block(source_tenant, dest_tenant)
+        self._test_cross_tenant_allow(source_tenant, dest_tenant)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index d605dff..54517ab 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -16,7 +16,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.network import common as net_common
 from tempest.common import debug
 from tempest.common.utils import data_utils
 from tempest import config
@@ -165,45 +164,6 @@
         cls.servers = []
         cls.floating_ips = {}
 
-    def _get_router(self, tenant_id):
-        """Retrieve a router for the given tenant id.
-
-        If a public router has been configured, it will be returned.
-
-        If a public router has not been configured, but a public
-        network has, a tenant router will be created and returned that
-        routes traffic to the public network.
-
-        """
-        router_id = self.config.network.public_router_id
-        network_id = self.config.network.public_network_id
-        if router_id:
-            result = self.network_client.show_router(router_id)
-            return net_common.AttributeDict(**result['router'])
-        elif network_id:
-            router = self._create_router(tenant_id)
-            router.add_gateway(network_id)
-            return router
-        else:
-            raise Exception("Neither of 'public_router_id' or "
-                            "'public_network_id' has been defined.")
-
-    def _create_router(self, tenant_id, namestart='router-smoke-'):
-        name = data_utils.rand_name(namestart)
-        body = dict(
-            router=dict(
-                name=name,
-                admin_state_up=True,
-                tenant_id=tenant_id,
-            ),
-        )
-        result = self.network_client.create_router(body=body)
-        router = net_common.DeletableRouter(client=self.network_client,
-                                            **result['router'])
-        self.assertEqual(router.name, name)
-        self.set_resource(name, router)
-        return router
-
     def _create_keypairs(self):
         self.keypairs[self.tenant_id] = self.create_keypair(
             name=data_utils.rand_name('keypair-smoke-'))
@@ -212,15 +172,6 @@
         self.security_groups[self.tenant_id] =\
             self._create_security_group_neutron(tenant_id=self.tenant_id)
 
-    def _create_networks(self):
-        network = self._create_network(self.tenant_id)
-        router = self._get_router(self.tenant_id)
-        subnet = self._create_subnet(network)
-        subnet.add_to_router(router.id)
-        self.networks.append(network)
-        self.subnets.append(subnet)
-        self.routers.append(router)
-
     def _check_networks(self):
         # Checks that we see the newly created network/subnet/router via
         # checking the result of list_[networks,routers,subnets]
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index ce46a9b..ad5354c 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -37,3 +37,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias)
+        body = json.loads(body)
+        return resp, body['extension']
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 5f17894..c05571a 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,10 +16,10 @@
 #    under the License.
 
 import json
-import time
 import urllib
 
 from tempest.common.rest_client import RestClient
+from tempest.common import waiters
 from tempest import exceptions
 
 
@@ -82,18 +82,7 @@
 
     def wait_for_image_status(self, image_id, status):
         """Waits for an image to reach a given status."""
-        resp, image = self.get_image(image_id)
-        start = int(time.time())
-
-        while image['status'] != status:
-            time.sleep(self.build_interval)
-            resp, image = self.get_image(image_id)
-
-            if image['status'] == 'ERROR':
-                raise exceptions.AddImageException(image_id=image_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                raise exceptions.TimeoutException
+        waiters.wait_for_image_status(self, image_id, status)
 
     def list_image_metadata(self, image_id):
         """Lists all metadata items for an image."""
diff --git a/tempest/services/compute/v3/json/extensions_client.py b/tempest/services/compute/v3/json/extensions_client.py
index 60c0217..6e0dc9d 100644
--- a/tempest/services/compute/v3/json/extensions_client.py
+++ b/tempest/services/compute/v3/json/extensions_client.py
@@ -38,3 +38,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias)
+        body = json.loads(body)
+        return resp, body['extension']
diff --git a/tempest/services/compute/v3/json/keypairs_client.py b/tempest/services/compute/v3/json/keypairs_client.py
new file mode 100644
index 0000000..5e1900c
--- /dev/null
+++ b/tempest/services/compute/v3/json/keypairs_client.py
@@ -0,0 +1,56 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class KeyPairsClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(KeyPairsClientJSON, self).__init__(config, username, password,
+                                                 auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_keypairs(self):
+        resp, body = self.get("os-keypairs")
+        body = json.loads(body)
+        # Each returned keypair is embedded within an unnecessary 'keypair'
+        # element which is a deviation from other resources like floating-ips,
+        # servers, etc. A bug?
+        # For now we shall adhere to the spec, but the spec for keypairs
+        # is yet to be found
+        return resp, body['keypairs']
+
+    def get_keypair(self, key_name):
+        resp, body = self.get("os-keypairs/%s" % str(key_name))
+        body = json.loads(body)
+        return resp, body['keypair']
+
+    def create_keypair(self, name, pub_key=None):
+        post_body = {'keypair': {'name': name}}
+        if pub_key:
+            post_body['keypair']['public_key'] = pub_key
+        post_body = json.dumps(post_body)
+        resp, body = self.post("os-keypairs",
+                               headers=self.headers, body=post_body)
+        body = json.loads(body)
+        return resp, body['keypair']
+
+    def delete_keypair(self, key_name):
+        return self.delete("os-keypairs/%s" % str(key_name))
diff --git a/tempest/services/compute/v3/xml/extensions_client.py b/tempest/services/compute/v3/xml/extensions_client.py
index e03251c..8f97692 100644
--- a/tempest/services/compute/v3/xml/extensions_client.py
+++ b/tempest/services/compute/v3/xml/extensions_client.py
@@ -43,3 +43,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/compute/v3/xml/keypairs_client.py b/tempest/services/compute/v3/xml/keypairs_client.py
new file mode 100644
index 0000000..0157245
--- /dev/null
+++ b/tempest/services/compute/v3/xml/keypairs_client.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 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 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 Text
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class KeyPairsClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(KeyPairsClientXML, self).__init__(config, username, password,
+                                                auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_keypairs(self):
+        resp, body = self.get("os-keypairs", self.headers)
+        node = etree.fromstring(body)
+        body = [{'keypair': xml_to_json(x)} for x in node.getchildren()]
+        return resp, body
+
+    def get_keypair(self, key_name):
+        resp, body = self.get("os-keypairs/%s" % str(key_name), self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def create_keypair(self, name, pub_key=None):
+        doc = Document()
+
+        keypair_element = Element("keypair")
+
+        if pub_key:
+            public_key_element = Element("public_key")
+            public_key_text = Text(pub_key)
+            public_key_element.append(public_key_text)
+            keypair_element.append(public_key_element)
+
+        name_element = Element("name")
+        name_text = Text(name)
+        name_element.append(name_text)
+        keypair_element.append(name_element)
+
+        doc.append(keypair_element)
+
+        resp, body = self.post("os-keypairs",
+                               headers=self.headers, body=str(doc))
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def delete_keypair(self, key_name):
+        return self.delete("os-keypairs/%s" % str(key_name))
diff --git a/tempest/services/compute/xml/extensions_client.py b/tempest/services/compute/xml/extensions_client.py
index 1395b5a..b17fc4f 100644
--- a/tempest/services/compute/xml/extensions_client.py
+++ b/tempest/services/compute/xml/extensions_client.py
@@ -43,3 +43,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index b17ae78..20fcc9b 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -15,12 +15,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
 import urllib
 
 from lxml import etree
 
 from tempest.common.rest_client import RestClientXML
+from tempest.common import waiters
 from tempest import exceptions
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
@@ -140,17 +140,7 @@
 
     def wait_for_image_status(self, image_id, status):
         """Waits for an image to reach a given status."""
-        resp, image = self.get_image(image_id)
-        start = int(time.time())
-
-        while image['status'] != status:
-            time.sleep(self.build_interval)
-            resp, image = self.get_image(image_id)
-            if image['status'] == 'ERROR':
-                raise exceptions.AddImageException(image_id=image_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                raise exceptions.TimeoutException
+        waiters.wait_for_image_status(self, image_id, status)
 
     def _metadata_body(self, meta):
         post_body = Element('metadata')
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index ec99d37..e457c1f 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -359,6 +359,66 @@
                                  (domain_id, group_id, role_id))
         return resp, body
 
+    def create_trust(self, trustor_user_id, trustee_user_id, project_id,
+                     role_names, impersonation, expires_at):
+        """Creates a trust."""
+        roles = [{'name': n} for n in role_names]
+        post_body = {
+            'trustor_user_id': trustor_user_id,
+            'trustee_user_id': trustee_user_id,
+            'project_id': project_id,
+            'impersonation': impersonation,
+            'roles': roles,
+            'expires_at': expires_at
+        }
+        post_body = json.dumps({'trust': post_body})
+        resp, body = self.post('OS-TRUST/trusts', post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['trust']
+
+    def delete_trust(self, trust_id):
+        """Deletes a trust."""
+        resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id)
+        return resp, body
+
+    def get_trusts(self, trustor_user_id=None, trustee_user_id=None):
+        """GET trusts."""
+        if trustor_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustor_user_id=%s"
+                                  % trustor_user_id)
+        elif trustee_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustee_user_id=%s"
+                                  % trustee_user_id)
+        else:
+            resp, body = self.get("OS-TRUST/trusts")
+        body = json.loads(body)
+        return resp, body['trusts']
+
+    def get_trust(self, trust_id):
+        """GET trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s" % trust_id)
+        body = json.loads(body)
+        return resp, body['trust']
+
+    def get_trust_roles(self, trust_id):
+        """GET roles delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id)
+        body = json.loads(body)
+        return resp, body['roles']
+
+    def get_trust_role(self, trust_id, role_id):
+        """GET role delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles/%s"
+                              % (trust_id, role_id))
+        body = json.loads(body)
+        return resp, body['role']
+
+    def check_trust_role(self, trust_id, role_id):
+        """HEAD Check if role is delegated by a trust."""
+        resp, body = self.head("OS-TRUST/trusts/%s/roles/%s"
+                               % (trust_id, role_id))
+        return resp, body
+
 
 class V3TokenClientJSON(RestClient):
 
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index f5fb2bd..b323dc6 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -15,9 +15,10 @@
 import json
 
 from tempest.common.rest_client import RestClient
+from tempest.services.network import network_client_base
 
 
-class NetworkClientJSON(RestClient):
+class NetworkClientJSON(network_client_base.NetworkClientBase):
 
     """
     Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
@@ -32,25 +33,25 @@
     quotas
     """
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(NetworkClientJSON, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
-        self.service = self.config.network.catalog_type
-        self.version = '2.0'
-        self.uri_prefix = "v%s" % (self.version)
+    def get_rest_client(self, config, username,
+                        password, auth_url, tenant_name=None):
+        return RestClient(config, username, password, auth_url, tenant_name)
 
-    def list_networks(self):
-        uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
+    def deserialize_single(self, body):
+        return json.loads(body)
+
+    def deserialize_list(self, body):
+        res = json.loads(body)
+        # expecting response in form
+        # {'resources': [ res1, res2] }
+        return res[res.keys()[0]]
 
     def create_network(self, name, **kwargs):
         post_body = {'network': kwargs}
         post_body['network']['name'] = name
         body = json.dumps(post_body)
         uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -61,21 +62,10 @@
         post_body = {'networks': network_list}
         body = json.dumps(post_body)
         uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def create_subnet(self, net_uuid, cidr, ip_version=4, **kwargs):
         post_body = {'subnet': kwargs}
         post_body['subnet']['ip_version'] = ip_version
@@ -83,24 +73,7 @@
         post_body['subnet']['cidr'] = cidr
         body = json.dumps(post_body)
         uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def list_subnets(self):
-        uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -114,28 +87,7 @@
             post_body['port'][key] = val
         body = json.dumps(post_body)
         uri = '%s/ports' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def list_ports(self, **filters):
-        uri = '%s/ports' % (self.uri_prefix)
-        filter_items = ["%s=%s" % (k, v) for (k, v) in filters.iteritems()]
-        querystring = "&".join(filter_items)
-        if querystring:
-            uri = "%s?%s" % (uri, querystring)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -143,27 +95,15 @@
         put_body = {'quota': kwargs}
         body = json.dumps(put_body)
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.put(uri, body, self.headers)
-        body = json.loads(body)
-        return resp, body['quota']
-
-    def show_quotas(self, tenant_id):
-        uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body['quota']
 
     def reset_quotas(self, tenant_id):
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.delete(uri, self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
-    def list_quotas(self):
-        uri = '%s/quotas' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body['quotas']
-
     def update_subnet(self, subnet_id, new_name):
         put_body = {
             'subnet': {
@@ -172,7 +112,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/subnets/%s' % (self.uri_prefix, subnet_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -184,7 +124,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -196,13 +136,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/networks/%s' % (self.uri_prefix, network_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_routers(self):
-        uri = '%s/routers' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -212,24 +146,13 @@
         post_body['router']['admin_state_up'] = admin_state_up
         body = json.dumps(post_body)
         uri = '%s/routers' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
     def _update_router(self, router_id, set_enable_snat, **kwargs):
         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         update_body = {}
         update_body['name'] = kwargs.get('name', body['router']['name'])
@@ -242,7 +165,7 @@
             'external_gateway_info', body['router']['external_gateway_info'])
         update_body = dict(router=update_body)
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -268,7 +191,7 @@
               router_id)
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -277,7 +200,7 @@
               router_id)
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -286,7 +209,7 @@
               router_id)
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -295,7 +218,7 @@
               router_id)
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -305,21 +228,10 @@
         post_body['floatingip']['floating_network_id'] = ext_network_id
         body = json.dumps(post_body)
         uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body=body)
         body = json.loads(body)
         return resp, body
 
-    def list_security_groups(self):
-        uri = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, secgroup_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def create_security_group(self, name, **kwargs):
         post_body = {
             'security_group': {
@@ -330,45 +242,16 @@
             post_body['security_group'][str(key)] = value
         body = json.dumps(post_body)
         uri = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, secgroup_id)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_floating_ips(self):
-        uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_security_group_rules(self):
-        uri = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_floating_ip(self, floating_ip_id, **kwargs):
         post_body = {
             'floatingip': kwargs}
         body = json.dumps(post_body)
         uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.put(uri, headers=self.headers, body=body)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -384,7 +267,7 @@
             post_body['security_group_rule'][str(key)] = value
         body = json.dumps(post_body)
         uri = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -392,18 +275,7 @@
         post_body = {'subnets': subnet_list}
         body = json.dumps(post_body)
         uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, rule_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, rule_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -411,13 +283,7 @@
         post_body = {'ports': port_list}
         body = json.dumps(post_body)
         uri = '%s/ports' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def list_vips(self):
-        uri = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -433,7 +299,7 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -448,26 +314,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_vip(self, uuid):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_vip(self, uuid):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def delete_pool(self, uuid):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_vip(self, vip_id, new_name):
         put_body = {
             "vip": {
@@ -476,7 +326,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/vips/%s' % (self.uri_prefix, vip_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -488,25 +338,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/pools/%s' % (self.uri_prefix, pool_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_pools(self):
-        uri = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_pool(self, uuid):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_members(self):
-        uri = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -520,21 +352,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_member(self, uuid):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_member(self, uuid):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_member(self, admin_state_up, member_id):
         put_body = {
             "member": {
@@ -543,13 +364,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/members/%s' % (self.uri_prefix, member_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_health_monitors(self):
-        uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -564,21 +379,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_health_monitor(self, admin_state_up, uuid):
         put_body = {
             "health_monitor": {
@@ -587,7 +391,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -601,7 +405,7 @@
         body = json.dumps(post_body)
         uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
                                                   pool_id)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -609,28 +413,10 @@
                                               pool_id):
         uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
                                                      health_monitor_id)
-        resp, body = self.delete(uri, headers=self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
-    def list_extensions(self):
-        uri = '%s/extensions' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_extension_details(self, ext_alias):
-        uri = '%s/extensions/%s' % (self.uri_prefix, ext_alias)
-        resp, body = self.get(uri, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_vpn_services(self):
-        uri = '%s/vpn/vpnservices' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def create_vpn_service(self, subnet_id, router_id, **kwargs):
+    def create_vpnservice(self, subnet_id, router_id, **kwargs):
         post_body = {
             "vpnservice": {
                 "subnet_id": subnet_id,
@@ -641,22 +427,11 @@
             post_body['vpnservice'][key] = val
         body = json.dumps(post_body)
         uri = '%s/vpn/vpnservices' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_vpn_service(self, uuid):
-        uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_vpn_service(self, uuid):
-        uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def update_vpn_service(self, uuid, description):
+    def update_vpnservice(self, uuid, description):
         put_body = {
             "vpnservice": {
                 "description": description
@@ -664,65 +439,59 @@
         }
         body = json.dumps(put_body)
         uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
     def list_router_interfaces(self, uuid):
         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
-    def list_agents(self):
-        uri = '%s/agents' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
+    def update_agent(self, agent_id, agent_info):
+        """
+        :param agent_info: Agent update information.
+        E.g {"admin_state_up": True}
+        """
+        uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
+        agent = {"agent": agent_info}
+        body = json.dumps(agent)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
     def list_routers_on_l3_agent(self, agent_id):
         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
     def list_l3_agents_hosting_router(self, router_id):
         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_service_providers(self):
-        uri = '%s/service-providers' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
     def list_dhcp_agent_hosting_network(self, network_id):
         uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
     def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
     def remove_network_from_dhcp_agent(self, agent_id, network_id):
         uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
                                                  network_id)
-        resp, body = self.delete(uri, self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
-    def list_ike_policies(self):
-        uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def create_ike_policy(self, name, **kwargs):
+    def create_ikepolicy(self, name, **kwargs):
         post_body = {
             "ikepolicy": {
                 "name": name,
@@ -732,26 +501,15 @@
             post_body['ikepolicy'][key] = val
         body = json.dumps(post_body)
         uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_ike_policy(self, uuid):
-        uri = '%s/vpn/ikepolicies/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_ike_policy(self, uuid):
-        uri = '%s/vpn/ikepolicies/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def update_ike_policy(self, uuid, **kwargs):
+    def update_ikepolicy(self, uuid, **kwargs):
         put_body = {'ikepolicy': kwargs}
         body = json.dumps(put_body)
         uri = '%s/vpn/ikepolicies/%s' % (self.uri_prefix, uuid)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -764,7 +522,7 @@
             }
         }
         body = json.dumps(put_body)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -777,6 +535,6 @@
             }
         }
         body = json.dumps(put_body)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
new file mode 100644
index 0000000..b48dd34
--- /dev/null
+++ b/tempest/services/network/network_client_base.py
@@ -0,0 +1,136 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+#    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
+
+# the folliwing map is used to construct proper URI
+# for the given neutron resource
+service_resource_prefix_map = {
+    'networks': '',
+    'subnets': '',
+    'ports': '',
+    'pools': 'lb',
+    'vips': 'lb',
+    'health_monitors': 'lb',
+    'members': 'lb',
+    'vpnservices': 'vpn',
+    'ikepolicies': 'vpn'
+}
+
+# The following list represents resource names that do not require
+# changing underscore to a hyphen
+hyphen_exceptions = ["health_monitors"]
+
+# map from resource name to a plural name
+# needed only for those which can't be constructed as name + 's'
+resource_plural_map = {
+    'security_groups': 'security_groups',
+    'security_group_rules': 'security_group_rules',
+    'ikepolicy': 'ikepolicies',
+    'floating_ip': 'floatingips',
+    'quotas': 'quotas'
+}
+
+
+class NetworkClientBase(object):
+    def __init__(self, config, username, password,
+                 auth_url, tenant_name=None):
+        self.rest_client = self.get_rest_client(
+            config, username, password, auth_url, tenant_name)
+        self.rest_client.service = self.rest_client.config.network.catalog_type
+        self.version = '2.0'
+        self.uri_prefix = "v%s" % (self.version)
+
+    def get_rest_client(self, config, username, password,
+                        auth_url, tenant_name):
+        raise NotImplementedError
+
+    def post(self, uri, body, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.post(uri, body, headers)
+
+    def put(self, uri, body, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.put(uri, body, headers)
+
+    def get(self, uri, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.get(uri, headers)
+
+    def delete(self, uri, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.delete(uri, headers)
+
+    def deserialize_list(self, body):
+        raise NotImplementedError
+
+    def deserialize_single(self, body):
+        raise NotImplementedError
+
+    def get_uri(self, plural_name):
+        # get service prefix from resource name
+        service_prefix = service_resource_prefix_map.get(
+            plural_name)
+        if plural_name not in hyphen_exceptions:
+            plural_name = plural_name.replace("_", "-")
+        if service_prefix:
+            uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
+                                plural_name)
+        else:
+            uri = '%s/%s' % (self.uri_prefix, plural_name)
+        return uri
+
+    def pluralize(self, resource_name):
+        # get plural from map or just add 's'
+        return resource_plural_map.get(resource_name, resource_name + 's')
+
+    def _lister(self, plural_name):
+        def _list(**filters):
+            uri = self.get_uri(plural_name)
+            if filters:
+                uri += '?' + urllib.urlencode(filters)
+            resp, body = self.get(uri)
+            result = {plural_name: self.deserialize_list(body)}
+            return resp, result
+
+        return _list
+
+    def _deleter(self, resource_name):
+        def _delete(resource_id):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            return self.delete(uri)
+
+        return _delete
+
+    def _shower(self, resource_name):
+        def _show(resource_id):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            resp, body = self.get(uri)
+            body = self.deserialize_single(body)
+            return resp, body
+
+        return _show
+
+    def __getattr__(self, name):
+        method_prefixes = ["list_", "delete_", "show_"]
+        method_functors = [self._lister,
+                           self._deleter,
+                           self._shower]
+        for index, prefix in enumerate(method_prefixes):
+            prefix_len = len(prefix)
+            if name[:prefix_len] == prefix:
+                return method_functors[index](name[prefix_len:])
+        raise AttributeError(name)
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
old mode 100755
new mode 100644
index e11d4c1..a999e31
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -20,30 +20,28 @@
 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.network import network_client_base as client_base
 
 
-class NetworkClientXML(RestClientXML):
+class NetworkClientXML(client_base.NetworkClientBase):
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(NetworkClientXML, self).__init__(config, username, password,
-                                               auth_url, tenant_name)
-        self.service = self.config.network.catalog_type
-        self.version = '2.0'
-        self.uri_prefix = "v%s" % (self.version)
+    def get_rest_client(self, config, username, password,
+                        auth_url, tenant_name=None):
+        return RestClientXML(config, username, password,
+                             auth_url, tenant_name)
 
-    def list_networks(self):
-        uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        networks = self._parse_array(etree.fromstring(body))
-        networks = {"networks": networks}
-        return resp, networks
+    def deserialize_list(self, body):
+        return self._parse_array(etree.fromstring(body))
+
+    def deserialize_single(self, body):
+        return _root_tag_fetcher_and_xml_to_json_parse(body)
 
     def create_network(self, name):
         uri = '%s/networks' % (self.uri_prefix)
         post_body = Element("network")
         p2 = Element("name", name)
         post_body.append(p2)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -55,21 +53,11 @@
                 p2 = Element("name", names[i])
                 p1.append(p2)
                 post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         networks = self._parse_array(etree.fromstring(body))
         networks = {"networks": networks}
         return resp, networks
 
-    def delete_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, str(uuid))
-        return self.delete(uri, self.headers)
-
-    def show_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
     def create_subnet(self, net_uuid, cidr):
         uri = '%s/subnets' % (self.uri_prefix)
         subnet = Element("subnet")
@@ -79,24 +67,7 @@
         subnet.append(p2)
         subnet.append(p3)
         subnet.append(p4)
-        resp, body = self.post(uri, str(Document(subnet)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_subnet(self, subnet_id):
-        uri = '%s/subnets/%s' % (self.uri_prefix, str(subnet_id))
-        return self.delete(uri, self.headers)
-
-    def list_subnets(self):
-        uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        subnets = self._parse_array(etree.fromstring(body))
-        subnets = {"subnets": subnets}
-        return resp, subnets
-
-    def show_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -108,39 +79,22 @@
         for key, val in kwargs.items():
             key = Element(key, val)
             port.append(key)
-        resp, body = self.post(uri, str(Document(port)), self.headers)
+        resp, body = self.post(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def delete_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
-        return self.delete(uri, self.headers)
-
     def _parse_array(self, node):
         array = []
         for child in node.getchildren():
             array.append(xml_to_json(child))
         return array
 
-    def list_ports(self):
-        url = '%s/ports' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        ports = self._parse_array(etree.fromstring(body))
-        ports = {"ports": ports}
-        return resp, ports
-
-    def show_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
     def update_port(self, port_id, name):
         uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
         port = Element("port")
         p2 = Element("name", name)
         port.append(p2)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -149,7 +103,7 @@
         subnet = Element("subnet")
         p2 = Element("name", name)
         subnet.append(p2)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -158,7 +112,7 @@
         network = Element("network")
         p2 = Element("name", name)
         network.append(p2)
-        resp, body = self.put(uri, str(Document(network)), self.headers)
+        resp, body = self.put(uri, str(Document(network)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -167,34 +121,10 @@
         post_body = Element("security_group")
         p2 = Element("name", name)
         post_body.append(p2)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_security_groups(self):
-        url = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        secgroups = self._parse_array(etree.fromstring(body))
-        secgroups = {"security_groups": secgroups}
-        return resp, secgroups
-
-    def delete_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, str(secgroup_id))
-        return self.delete(uri, self.headers)
-
-    def show_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, str(secgroup_id))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def list_security_group_rules(self):
-        url = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        rules = self._parse_array(etree.fromstring(body))
-        rules = {"security_group_rules": rules}
-        return resp, rules
-
     def create_security_group_rule(self, secgroup_id,
                                    direction='ingress', **kwargs):
         uri = '%s/security-group-rules' % (self.uri_prefix)
@@ -206,17 +136,7 @@
         for key, val in kwargs.items():
             key = Element(key, val)
             rule.append(key)
-        resp, body = self.post(uri, str(Document(rule)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, str(rule_id))
-        return self.delete(uri, self.headers)
-
-    def show_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, str(rule_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(rule)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -230,7 +150,7 @@
                 p2 = Element(k, kv)
                 p1.append(p2)
             post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         subnets = self._parse_array(etree.fromstring(body))
         subnets = {"subnets": subnets}
         return resp, subnets
@@ -245,18 +165,11 @@
                 p2 = Element(k, kv)
                 p1.append(p2)
             post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         ports = self._parse_array(etree.fromstring(body))
         ports = {"ports": ports}
         return resp, ports
 
-    def list_vips(self):
-        url = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        vips = self._parse_array(etree.fromstring(body))
-        vips = {"vips": vips}
-        return resp, vips
-
     def create_vip(self, name, protocol, protocol_port, subnet_id, pool_id):
         uri = '%s/lb/vips' % (self.uri_prefix)
         post_body = Element("vip")
@@ -270,17 +183,7 @@
         post_body.append(p3)
         post_body.append(p4)
         post_body.append(p5)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_vip(self, vip_id):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
-        return self.delete(uri, self.headers)
-
-    def show_vip(self, vip_id):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -289,17 +192,10 @@
         put_body = Element("vip")
         p2 = Element("name", new_name)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_pools(self):
-        url = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        pools = self._parse_array(etree.fromstring(body))
-        pools = {"pools": pools}
-        return resp, pools
-
     def create_pool(self, name, lb_method, protocol, subnet_id):
         uri = '%s/lb/pools' % (self.uri_prefix)
         post_body = Element("pool")
@@ -309,17 +205,7 @@
         post_body.append(p1)
         post_body.append(p2)
         post_body.append(p3)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_pool(self, pool_id):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
-        return self.delete(uri, self.headers)
-
-    def show_pool(self, pool_id):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -328,17 +214,10 @@
         put_body = Element("pool")
         p2 = Element("name", new_name)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_members(self):
-        url = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        members = self._parse_array(etree.fromstring(body))
-        members = {"members": members}
-        return resp, members
-
     def create_member(self, address, protocol_port, pool_id):
         uri = '%s/lb/members' % (self.uri_prefix)
         post_body = Element("member")
@@ -348,17 +227,7 @@
         post_body.append(p1)
         post_body.append(p2)
         post_body.append(p3)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_member(self, member_id):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
-        return self.delete(uri, self.headers)
-
-    def show_member(self, member_id):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -367,17 +236,10 @@
         put_body = Element("member")
         p2 = Element("admin_state_up", admin_state_up)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_health_monitors(self):
-        uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = self._parse_array(etree.fromstring(body))
-        body = {"health_monitors": body}
-        return resp, body
-
     def create_health_monitor(self, delay, max_retries, Type, timeout):
         uri = '%s/lb/health_monitors' % (self.uri_prefix)
         post_body = Element("health_monitor")
@@ -389,17 +251,7 @@
         post_body.append(p2)
         post_body.append(p3)
         post_body.append(p4)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, str(uuid))
-        return self.delete(uri, self.headers)
-
-    def show_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -408,7 +260,7 @@
         put_body = Element("health_monitor")
         p2 = Element("admin_state_up", admin_state_up)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -419,7 +271,7 @@
         post_body = Element("health_monitor")
         p1 = Element("id", health_monitor_id,)
         post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -427,18 +279,11 @@
                                               pool_id):
         uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
                                                      health_monitor_id)
-        return self.delete(uri, self.headers)
-
-    def list_extensions(self):
-        url = '%s/extensions' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        extensions = self._parse_array(etree.fromstring(body))
-        extensions = {"extensions": extensions}
-        return resp, extensions
+        return self.delete(uri)
 
     def show_extension_details(self, ext_alias):
         uri = '%s/extensions/%s' % (self.uri_prefix, str(ext_alias))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -447,18 +292,7 @@
         router = Element("router")
         router.append(Element("name", name))
         deep_dict_to_xml(router, kwargs)
-        resp, body = self.post(uri, str(Document(router)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(router)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -467,7 +301,7 @@
         router = Element("router")
         for element, content in kwargs.iteritems():
             router.append(Element(element, content))
-        resp, body = self.put(uri, str(Document(router)), self.headers)
+        resp, body = self.put(uri, str(Document(router)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -475,7 +309,7 @@
         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
               router_id)
         subnet = Element("subnet_id", subnet_id)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -483,7 +317,7 @@
         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
               router_id)
         port = Element("port_id", port_id)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -491,7 +325,7 @@
         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
               router_id)
         subnet = Element("subnet_id", subnet_id)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -499,7 +333,7 @@
         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
               router_id)
         port = Element("port_id", port_id)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -509,28 +343,10 @@
         floatingip.append(Element("floating_network_id", ext_network_id))
         for element, content in kwargs.iteritems():
             floatingip.append(Element(element, content))
-        resp, body = self.post(uri, str(Document(floatingip)), self.headers)
+        resp, body = self.post(uri, str(Document(floatingip)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def show_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def list_floating_ips(self):
-        uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        floatingips = self._parse_array(etree.fromstring(body))
-        floatingips = {"floatingips": floatingips}
-        return resp, floatingips
-
-    def delete_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_floating_ip(self, floating_ip_id, **kwargs):
         uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
         floatingip = Element('floatingip')
@@ -543,53 +359,49 @@
                 floatingip.append(xml_elem)
             else:
                 floatingip.append(Element(element, content))
-        resp, body = self.put(uri, str(Document(floatingip)), self.headers)
+        resp, body = self.put(uri, str(Document(floatingip)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
     def list_router_interfaces(self, uuid):
         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         ports = self._parse_array(etree.fromstring(body))
         ports = {"ports": ports}
         return resp, ports
 
-    def list_agents(self):
-        uri = '%s/agents' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
-        agents = self._parse_array(etree.fromstring(body))
-        agents = {'agents': agents}
-        return resp, agents
+    def update_agent(self, agent_id, agent_info):
+        uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
+        agent = Element('agent')
+        for (key, value) in agent_info.items():
+            p = Element(key, value)
+            agent.append(p)
+        resp, body = self.put(uri, str(Document(agent)))
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
 
     def list_routers_on_l3_agent(self, agent_id):
         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
     def list_l3_agents_hosting_router(self, router_id):
         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_service_providers(self):
-        uri = '%s/service-providers' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
-        providers = self._parse_array(etree.fromstring(body))
-        body = {'service_providers': providers}
-        return resp, body
-
     def list_dhcp_agent_hosting_network(self, network_id):
         uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         agents = self._parse_array(etree.fromstring(body))
         body = {'agents': agents}
         return resp, body
 
     def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         networks = self._parse_array(etree.fromstring(body))
         body = {'networks': networks}
         return resp, body
@@ -597,7 +409,7 @@
     def remove_network_from_dhcp_agent(self, agent_id, network_id):
         uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
                                                  network_id)
-        resp, body = self.delete(uri, self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
 
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 5d980eb..9435122 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -44,7 +44,7 @@
         body = json.loads(body)
         return resp, body['snapshots']
 
-    def list_snapshot_with_detail(self, params=None):
+    def list_snapshots_with_detail(self, params=None):
         """List the details of all snapshots."""
         url = 'snapshots/detail'
         if params:
diff --git a/tempest/test_discover/__init__.py b/tempest/test_discover/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/test_discover/__init__.py
diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py
new file mode 100644
index 0000000..2e19bf2
--- /dev/null
+++ b/tempest/test_discover/test_discover.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import os
+import unittest
+
+
+def load_tests(loader, tests, pattern):
+    suite = unittest.TestSuite()
+    base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
+    base_path = os.path.split(base_path)[0]
+    for test_dir in ['./tempest/api', './tempest/cli', './tempest/scenario',
+                     './tempest/thirdparty']:
+        if not pattern:
+            suite.addTests(loader.discover(test_dir, top_level_dir=base_path))
+        else:
+            suite.addTests(loader.discover(test_dir, pattern=pattern,
+                           top_level_dir=base_path))
+    return suite
diff --git a/tox.ini b/tox.ini
index 1d7e1b7..b44b3e0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,16 +8,20 @@
          LANG=en_US.UTF-8
          LANGUAGE=en_US:en
          LC_ALL=C
+         OS_TEST_PATH=./tempest/test_discover
 usedevelop = True
 install_command = pip install -U {opts} {packages}
 
 [testenv:py26]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py33]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py27]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]