Merge "Remove quota whitebox tests"
diff --git a/HACKING.rst b/HACKING.rst
index eafa81b..1db1e26 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -1,3 +1,7 @@
+Tempest Coding Guide
+====================
+
+
 Test Data/Configuration
 -----------------------
 - Assume nothing about existing test data
diff --git a/doc/source/HACKING.rst b/doc/source/HACKING.rst
new file mode 120000
index 0000000..a2f06b7
--- /dev/null
+++ b/doc/source/HACKING.rst
@@ -0,0 +1 @@
+../../HACKING.rst
\ No newline at end of file
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1ca7344..e8fdf2c 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -3,9 +3,9 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-===================================
+=======================
 Tempest Testing Project
-===================================
+=======================
 
 Contents:
 
@@ -13,11 +13,11 @@
    :maxdepth: 2
 
    overview
+   HACKING
 
-
--------------------------------
+------------
 Field Guides
--------------------------------
+------------
 Tempest contains tests of many different types, the field guides
 attempt to explain these in a way that makes it easy to understand
 where your test contributions should go.
diff --git a/tempest/README.rst b/tempest/README.rst
index fa29fe2..892b0f8 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -75,8 +75,8 @@
 ------------
 
 Many openstack components include 3rdparty API support. It is
-completely legitmate for Tempest to include tests of 3rdparty APIs,
-but those should be kept seperate from the normal OpenStack
+completely legitimate for Tempest to include tests of 3rdparty APIs,
+but those should be kept separate from the normal OpenStack
 validation.
 
 
@@ -84,5 +84,5 @@
 ----------
 
 Whitebox tests are tests which require access to the database of the
-target OpenStack machine to verify internal state after opperations
+target OpenStack machine to verify internal state after operations
 are made. White box tests are allowed to use the python clients.
diff --git a/tempest/api/README.rst b/tempest/api/README.rst
index cf0aac7..617fda4 100644
--- a/tempest/api/README.rst
+++ b/tempest/api/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to API tests
-========
+==========================
 
 
 What are these tests?
---------
+---------------------
 
 One of Tempest's prime function is to ensure that your OpenStack cloud
 works with the OpenStack API as documented. The current largest
@@ -21,7 +21,7 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 
 This is one of the core missions for the Tempest project, and where it
 started. Many people use this bit of function in Tempest to ensure
@@ -34,7 +34,7 @@
 
 
 Scope of these tests
---------
+--------------------
 
 API tests should always use the Tempest implementation of the
 OpenStack API, as we want to ensure that bugs aren't hidden by the
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
new file mode 100644
index 0000000..00a5955
--- /dev/null
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -0,0 +1,112 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM 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 HypervisorAdminTestJSON(base.BaseComputeAdminTest):
+
+    """
+    Tests Hypervisors API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(HypervisorAdminTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.hypervisor_client
+        cls.non_adm_client = cls.hypervisor_client
+
+    def _list_hypervisors(self):
+        # List of hypervisors
+        resp, hypers = self.client.get_hypervisor_list()
+        self.assertEqual(200, resp.status)
+        return hypers
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_list(self):
+        # List of hypervisor and available hypervisors hostname
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_list_details(self):
+        # Display the details of the all hypervisor
+        resp, hypers = self.client.get_hypervisor_list_details()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypers) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_show_details(self):
+        # Display the details of the specified hypervisor
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        resp, details = (self.client.
+                         get_hypervisor_show_details(hypers[0]['id']))
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(details) > 0)
+        self.assertEqual(details['hypervisor_hostname'],
+                         hypers[0]['hypervisor_hostname'])
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_show_servers(self):
+        # Show instances about the specific hypervisors
+        hypers = self._list_hypervisors()
+        self.assertTrue(len(hypers) > 0)
+
+        hostname = hypers[0]['hypervisor_hostname']
+        resp, hypervisors = self.client.get_hypervisor_servers(hostname)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hypervisors) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_stats(self):
+        # Verify the stats of the all hypervisor
+        resp, stats = self.client.get_hypervisor_stats()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(stats) > 0)
+
+    @attr(type=['positive', 'gate'])
+    def test_get_hypervisor_uptime(self):
+        # Verify that GET shows the specified hypervisor uptime
+        hypers = self._list_hypervisors()
+
+        resp, uptime = self.client.get_hypervisor_uptime(hypers[0]['id'])
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(uptime) > 0)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_list_with_non_admin_user(self):
+        # List of hypervisor and available services with non admin user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_list)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_hypervisor_list_details_with_non_admin_user(self):
+        # List of hypervisor details and available services with non admin user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_hypervisor_list_details)
+
+
+class HypervisorAdminTestXML(HypervisorAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 1266405..a6b4e31 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -19,6 +19,7 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
+import testtools
 
 
 class QuotasAdminTestJSON(base.BaseComputeAdminTest):
@@ -70,12 +71,9 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(expected_quota_set, quota_set)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_update_all_quota_resources_for_tenant(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Admin can update all the resource quota limits for a tenant
         new_quota_set = {'force': True,
                          'injected_file_content_bytes': 20480,
@@ -125,12 +123,9 @@
             self.assertEqual(200, resp.status, "Failed to reset quota "
                              "defaults")
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_create_server_when_cpu_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's vcpu quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_vcpu_quota = quota_set['cores']
@@ -144,12 +139,9 @@
                         cores=default_vcpu_quota)
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type='gate')
     def test_create_server_when_memory_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         # Disallow server creation when tenant's memory quota is full
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_mem_quota = quota_set['ram']
@@ -165,12 +157,9 @@
 
 #TODO(afazekas): Add test that tried to update the quota_set as a regular user
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
-        self.skipTest("This test require the change in nova component "
-                      "https://review.openstack.org/#/c/25887/, the related "
-                      "bug is https://bugs.launchpad.net/nova/+bug/1160749 "
-                      "once the change is merged I will enable this testcase")
         #Once instances quota limit is reached, disallow server creation
         resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
         default_instances_quota = quota_set['instances']
@@ -183,6 +172,7 @@
                         instances=default_instances_quota)
         self.assertRaises(exceptions.OverLimit, self.create_server)
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_security_groups_exceed_limit(self):
         # Negative test: Creation Security Groups over limit should FAIL
@@ -204,6 +194,7 @@
                           self.sg_client.create_security_group,
                           "sg-overlimit", "sg-desc")
 
+    @testtools.skip("Skipped until the Bug #1160749 is resolved")
     @attr(type=['negative', 'gate'])
     def test_security_groups_rules_exceed_limit(self):
         # Negative test: Creation of Security Group Rules should FAIL
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 48ef296..0fa5a84 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -64,6 +64,7 @@
         cls.availability_zone_client = os.availability_zone_client
         cls.aggregates_client = os.aggregates_client
         cls.services_client = os.services_client
+        cls.hypervisor_client = os.hypervisor_client
         cls.build_interval = cls.config.compute.build_interval
         cls.build_timeout = cls.config.compute.build_timeout
         cls.ssh_user = cls.config.compute.ssh_user
diff --git a/tempest/tests/compute/test_auth_token.py b/tempest/api/compute/test_auth_token.py
similarity index 97%
rename from tempest/tests/compute/test_auth_token.py
rename to tempest/api/compute/test_auth_token.py
index ca319a1..bbe92ef 100644
--- a/tempest/tests/compute/test_auth_token.py
+++ b/tempest/api/compute/test_auth_token.py
@@ -15,8 +15,8 @@
 
 import testtools
 
+from tempest.api.compute import base
 import tempest.config as config
-from tempest.tests.compute import base
 
 
 class AuthTokenTestJSON(base.BaseComputeTest):
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index e0e40cb..8068284 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -73,6 +73,7 @@
         cidr = netaddr.IPNetwork(cls.network_cfg.tenant_network_cidr)
         mask_bits = cls.network_cfg.tenant_network_mask_bits
         # Find a cidr that is not in use yet and create a subnet with it
+        failure = None
         for subnet_cidr in cidr.subnet(mask_bits):
             try:
                 resp, body = cls.client.create_subnet(network['id'],
@@ -82,6 +83,12 @@
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
                 if not is_overlapping_cidr:
                     raise
+                # save the failure in case all of the CIDRs are overlapping
+                failure = e
+
+        if not body and failure:
+            raise failure
+
         subnet = body['subnet']
         cls.subnets.append(subnet)
         return subnet
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 3a0c802..602209a 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -12,8 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.volume import base
 from tempest.common import log as logging
 from tempest.common.utils.data_utils import rand_name
@@ -82,6 +80,5 @@
         self.clear_snapshots()
 
 
-@testtools.skip("Until Bug #1177610 is resolved.")
 class VolumesSnapshotTestXML(VolumesSnapshotTest):
     _interface = "xml"
diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst
index 4742d4a..76b05a3 100644
--- a/tempest/cli/README.rst
+++ b/tempest/cli/README.rst
@@ -1,16 +1,16 @@
 Tempest Guide to CLI tests
-========
+==========================
 
 
 What are these tests?
----------
+---------------------
 The cli tests test the various OpenStack command line interface tools
 to ensure that they minimally function. The current scope is read only
 operations on a cloud that are hard to test via unit tests.
 
 
 Why are these tests in tempest?
----------
+-------------------------------
 These tests exist here because it is extremely difficult to build a
 functional enough environment in the python-*client unit tests to
 provide this kind of testing. Because we already put up a cloud in the
@@ -20,14 +20,14 @@
 
 
 Scope of these tests
----------
+--------------------
 This should stay limited to the scope of testing the cli. Functional
 testing of the cloud should be elsewhere, this is about exercising the
 cli code.
 
 
 Example of a good test
----------
+----------------------
 Tests should be isolated to a single command in one of the python
 clients.
 
diff --git a/tempest/clients.py b/tempest/clients.py
index e85809f..e778dc1 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -30,6 +30,8 @@
 from tempest.services.compute.json.floating_ips_client import \
     FloatingIPsClientJSON
 from tempest.services.compute.json.hosts_client import HostsClientJSON
+from tempest.services.compute.json.hypervisor_client import \
+    HypervisorClientJSON
 from tempest.services.compute.json.images_client import ImagesClientJSON
 from tempest.services.compute.json.interfaces_client import \
     InterfacesClientJSON
@@ -52,6 +54,7 @@
 from tempest.services.compute.xml.flavors_client import FlavorsClientXML
 from tempest.services.compute.xml.floating_ips_client import \
     FloatingIPsClientXML
+from tempest.services.compute.xml.hypervisor_client import HypervisorClientXML
 from tempest.services.compute.xml.images_client import ImagesClientXML
 from tempest.services.compute.xml.interfaces_client import \
     InterfacesClientXML
@@ -231,6 +234,11 @@
     "xml": PolicyClientXML,
 }
 
+HYPERVISOR_CLIENT = {
+    "json": HypervisorClientJSON,
+    "xml": HypervisorClientXML,
+}
+
 
 class Manager(object):
 
@@ -317,6 +325,7 @@
             self.tenant_usages_client = \
                 TENANT_USAGES_CLIENT[interface](*client_args)
             self.policy_client = POLICY_CLIENT[interface](*client_args)
+            self.hypervisor_client = HYPERVISOR_CLIENT[interface](*client_args)
 
             if client_args_v3_auth:
                 self.servers_client_v3_auth = SERVERS_CLIENTS[interface](
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 353a9ac..93cf89d 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -53,6 +53,16 @@
                      " in tempest/api/* tests"))
 
 
+def import_no_files_in_tests(physical_line, filename):
+    """Check for merges that try to land into tempest/tests
+
+    T103: tempest/tests directory is deprecated
+    """
+
+    if "tempest/tests" in filename:
+        return (0, ("T103: tempest/tests is deprecated"))
+
+
 def factory(register):
     register(skip_bugs)
     register(import_no_clients_in_api)
diff --git a/tempest/manager.py b/tempest/manager.py
index 25e80ad..762bc18 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -22,6 +22,7 @@
 from tempest.services.compute.json import extensions_client
 from tempest.services.compute.json import flavors_client
 from tempest.services.compute.json import floating_ips_client
+from tempest.services.compute.json import hypervisor_client
 from tempest.services.compute.json import images_client
 from tempest.services.compute.json import keypairs_client
 from tempest.services.compute.json import limits_client
@@ -46,6 +47,7 @@
 VolumesClient = volumes_client.VolumesClientJSON
 SnapshotsClient = snapshots_client.SnapshotsClientJSON
 QuotasClient = quotas_client.QuotasClientJSON
+HypervisorClient = hypervisor_client.HypervisorClientJSON
 
 LOG = logging.getLogger(__name__)
 
@@ -132,6 +134,7 @@
         self.snapshots_client = SnapshotsClient(*client_args)
         self.quotas_client = QuotasClient(*client_args)
         self.network_client = NetworkClient(*client_args)
+        self.hypervisor_client = HypervisorClient(*client_args)
 
 
 class ComputeFuzzClientAltManager(Manager):
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
index c5fa0d3..98b74e4 100644
--- a/tempest/scenario/README.rst
+++ b/tempest/scenario/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to Scenario tests
-========
+===============================
 
 
 What are these tests?
---------
+---------------------
 
 Scenario tests are "through path" tests of OpenStack
 function. Complicated setups where one part might depend on completion
@@ -17,13 +17,13 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 This is one of tempests core purposes, testing the integration between
 projects.
 
 
 Scope of these tests
---------
+--------------------
 Scenario tests should always test at least 2 services in
 interaction. They should use the official python client libraries for
 OpenStack, as they provide a more realistic approach in how people
@@ -34,7 +34,7 @@
 
 
 Example of a good test
---------
+----------------------
 While we are looking for interaction of 2 or more services, be
 specific in your interactions. A giant "this is my data center" smoke
 test is hard to debug when it goes wrong.
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index b62e8bb..366ff43 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -25,13 +25,9 @@
 import keystoneclient.v2_0.client
 import netaddr
 import novaclient.client
-try:
-    # TODO(sdague): is there are reason this is still optional
-    from quantumclient.common import exceptions as exc
-    import quantumclient.v2_0.client
+from quantumclient.common import exceptions as exc
+import quantumclient.v2_0.client
 
-except ImportError:
-    pass
 
 from tempest.api.network import common as net_common
 from tempest.common import ssh
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
new file mode 100644
index 0000000..e2e5c7b
--- /dev/null
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -0,0 +1,65 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class HypervisorClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorClientJSON, self).__init__(config, username,
+                                                   password, auth_url,
+                                                   tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def get_hypervisor_list(self):
+        """List hypervisors information."""
+        resp, body = self.get('os-hypervisors')
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_list_details(self):
+        """Show detailed hypervisors information."""
+        resp, body = self.get('os-hypervisors/detail')
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_show_details(self, hyper_id):
+        """Display the details of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s' % hyper_id)
+        body = json.loads(body)
+        return resp, body['hypervisor']
+
+    def get_hypervisor_servers(self, hyper_name):
+        """List instances belonging to the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/servers' % hyper_name)
+        body = json.loads(body)
+        return resp, body['hypervisors']
+
+    def get_hypervisor_stats(self):
+        """Get hypervisor statistics over all compute nodes."""
+        resp, body = self.get('os-hypervisors/statistics')
+        body = json.loads(body)
+        return resp, body['hypervisor_statistics']
+
+    def get_hypervisor_uptime(self, hyper_id):
+        """Display the uptime of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id)
+        body = json.loads(body)
+        return resp, body['hypervisor']
diff --git a/tempest/services/compute/xml/hypervisor_client.py b/tempest/services/compute/xml/hypervisor_client.py
new file mode 100644
index 0000000..3c4f2b8
--- /dev/null
+++ b/tempest/services/compute/xml/hypervisor_client.py
@@ -0,0 +1,72 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class HypervisorClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(HypervisorClientXML, self).__init__(config, username,
+                                                  password, auth_url,
+                                                  tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _parse_array(self, node):
+        return [xml_to_json(x) for x in node]
+
+    def get_hypervisor_list(self):
+        """List hypervisors information."""
+        resp, body = self.get('os-hypervisors', self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_list_details(self):
+        """Show detailed hypervisors information."""
+        resp, body = self.get('os-hypervisors/detail', self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_show_details(self, hyper_id):
+        """Display the details of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s' % hyper_id,
+                              self.headers)
+        hypervisor = xml_to_json(etree.fromstring(body))
+        return resp, hypervisor
+
+    def get_hypervisor_servers(self, hyper_name):
+        """List instances belonging to the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/servers' % hyper_name,
+                              self.headers)
+        hypervisors = self._parse_array(etree.fromstring(body))
+        return resp, hypervisors
+
+    def get_hypervisor_stats(self):
+        """Get hypervisor statistics over all compute nodes."""
+        resp, body = self.get('os-hypervisors/statistics', self.headers)
+        stats = xml_to_json(etree.fromstring(body))
+        return resp, stats
+
+    def get_hypervisor_uptime(self, hyper_id):
+        """Display the uptime of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id,
+                              self.headers)
+        uptime = xml_to_json(etree.fromstring(body))
+        return resp, uptime
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index 410ed3e..b35c43e 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -48,7 +48,10 @@
 
         resp, body = self.get(url, self.headers)
         body = etree.fromstring(body)
-        return resp, xml_to_json(body)
+        snapshots = []
+        for snap in body:
+            snapshots.append(xml_to_json(snap))
+        return resp, snapshots
 
     def list_snapshots_with_detail(self, params=None):
         """List all the details of snapshot."""
@@ -60,7 +63,9 @@
         resp, body = self.get(url, self.headers)
         body = etree.fromstring(body)
         snapshots = []
-        return resp, snapshots(xml_to_json(body))
+        for snap in body:
+            snapshots.append(xml_to_json(snap))
+        return resp, snapshots
 
     def get_snapshot(self, snapshot_id):
         """Returns the details of a single snapshot."""
diff --git a/tempest/stress/README.rst b/tempest/stress/README.rst
index 2fcdf2e..661763c 100644
--- a/tempest/stress/README.rst
+++ b/tempest/stress/README.rst
@@ -1,5 +1,5 @@
 Tempest Field Guide to Stress Tests
-======================================================
+===================================
 
 Nova is a distributed, asynchronous system that is prone to race condition
 bugs. These bugs will not be easily found during
@@ -9,7 +9,7 @@
 
 
 Environment
-------------
+-----------
 This particular framework assumes your working Nova cluster understands Nova
 API 2.0. The stress tests can read the logs from the cluster. To enable this
 you have to provide the hostname to call 'nova-manage' and
diff --git a/tempest/whitebox/README.rst b/tempest/whitebox/README.rst
index dabf758..0e45421 100644
--- a/tempest/whitebox/README.rst
+++ b/tempest/whitebox/README.rst
@@ -1,9 +1,9 @@
 Tempest Guide to Whitebox tests
-========
+===============================
 
 
 What are these tests?
---------
+---------------------
 
 When you hit the OpenStack API, this causes internal state changes in
 the system. This might be database transitions, vm modifications,
@@ -20,7 +20,7 @@
 
 
 Why are these tests in tempest?
---------
+-------------------------------
 
 Especially when it comes to something like VM state changing, which is
 a coordination of numerous running daemons, and a functioning VM, it's
@@ -28,7 +28,7 @@
 
 
 Scope of these tests
---------
+--------------------
 
 White box tests should be limitted to tests where black box testing
 (using the OpenStack API to verify results) isn't sufficient.
@@ -40,7 +40,7 @@
 
 
 Example of a good test
---------
+----------------------
 
 Pushing VMs through a series of state transitions, and ensuring along
 the way the database state transitions match what's expected.
diff --git a/tempest/whitebox/test_images_whitebox.py b/tempest/whitebox/test_images_whitebox.py
index 096d3bf..dc68336 100644
--- a/tempest/whitebox/test_images_whitebox.py
+++ b/tempest/whitebox/test_images_whitebox.py
@@ -20,6 +20,10 @@
 from tempest import exceptions
 from tempest.whitebox import manager
 
+#TODO(afazekas): The whitebox tests are using complex testclass/manager
+# hierarchy, without a real need. It is difficult to maintain.
+# They could share more code with scenario tests.
+
 
 class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest):
     _interface = 'json'
@@ -34,7 +38,8 @@
 
     @classmethod
     def tearDownClass(cls):
-        """Delete images after a test is executed."""
+        """Delete images and server after a test is executed."""
+        cls.servers_client.delete_server(cls.shared_server['id'])
         for image_id in cls.image_ids:
             cls.client.delete_image(image_id)
             cls.image_ids.remove(image_id)