Merge "Use built in cleanup for servers in test_large_ops"
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 85b03e6..ee262df 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 config
 from tempest import exceptions
 from tempest.test import attr
 
@@ -24,8 +23,6 @@
 class FixedIPsTestJson(base.BaseComputeAdminTest):
     _interface = 'json'
 
-    CONF = config.TempestConfig()
-
     @classmethod
     def setUpClass(cls):
         super(FixedIPsTestJson, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index e730d31..2029a2e 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -35,8 +35,11 @@
         cls.client = cls.os_adm.servers_client
         cls.flavors_client = cls.os_adm.flavors_client
 
-        cls.admin_client = cls._get_identity_admin_client()
-        tenant = cls.admin_client.get_tenant_by_name(
+        cls.non_adm_client = cls.servers_client
+        cls.flavors_client = cls.os_adm.flavors_client
+
+        cls.identity_client = cls._get_identity_admin_client()
+        tenant = cls.identity_client.get_tenant_by_name(
             cls.client.tenant_name)
         cls.tenant_id = tenant['id']
 
@@ -158,6 +161,24 @@
         self.assertRaises(exceptions.NotFound,
                           self.client.reset_state, '999')
 
+    @attr(type='gate')
+    def test_get_server_diagnostics_by_admin(self):
+        # Retrieve server diagnostics by admin user
+        resp, diagnostic = self.client.get_server_diagnostics(self.s1_id)
+        self.assertEqual(200, resp.status)
+        basic_attrs = ['rx_packets', 'rx_errors', 'rx_drop',
+                       'tx_packets', 'tx_errors', 'tx_drop',
+                       'read_req', 'write_req', 'cpu', 'memory']
+        for key in basic_attrs:
+            self.assertIn(key, str(diagnostic.keys()))
+
+    @attr(type=['negative', 'gate'])
+    def test_get_server_diagnostics_by_non_admin(self):
+        # Non-admin user can not view server diagnostics according to policy
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_adm_client.get_server_diagnostics,
+                          self.s1_id)
+
 
 class ServersAdminTestXML(ServersAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index e9defe5..6f646b2 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -118,7 +118,8 @@
         password = 'rebuildPassw0rd'
         resp, rebuilt_server = self.client.rebuild(self.server_id,
                                                    self.image_ref_alt,
-                                                   name=new_name, meta=meta,
+                                                   name=new_name,
+                                                   metadata=meta,
                                                    personality=personality,
                                                    adminPass=password)
 
@@ -226,7 +227,8 @@
         self.assertRaises(exceptions.NotFound,
                           self.client.rebuild,
                           999, self.image_ref_alt,
-                          name=new_name, meta=meta,
+                          name=new_name,
+                          metadata=meta,
                           personality=personality,
                           adminPass='rebuild')
 
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index a48cea2..3e2b6ad 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -38,19 +38,19 @@
         cls.client.wait_for_volume_status(cls.volume['id'], 'available')
         cls.mountpoint = "/dev/vdc"
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_volume_get_nonexistant_volume_id(self):
         # Should not be able to get a non-existant volume
         self.assertRaises(exceptions.NotFound, self.client.get_volume,
                           str(uuid.uuid4()))
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_volume_delete_nonexistant_volume_id(self):
         # Should not be able to delete a non-existant Volume
         self.assertRaises(exceptions.NotFound, self.client.delete_volume,
                           str(uuid.uuid4()))
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_invalid_size(self):
         # Should not be able to create volume with invalid size
         # in request
@@ -59,7 +59,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='#$%', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_out_passing_size(self):
         # Should not be able to create volume without passing size
         # in request
@@ -68,7 +68,7 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_volume_with_size_zero(self):
         # Should not be able to create volume with size zero
         v_name = rand_name('Volume-')
@@ -76,24 +76,56 @@
         self.assertRaises(exceptions.BadRequest, self.client.create_volume,
                           size='0', display_name=v_name, metadata=metadata)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
+    def test_create_volume_with_size_negative(self):
+        # Should not be able to create volume with size negative
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.BadRequest, self.client.create_volume,
+                          size='-1', display_name=v_name, metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_nonexistant_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id=str(uuid.uuid4()), display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_invalid_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id='#$%%&^&^', display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_volume_with_empty_volume_id(self):
+        v_name = rand_name('Volume-')
+        metadata = {'Type': 'work'}
+        self.assertRaises(exceptions.NotFound, self.client.update_volume,
+                          volume_id='', display_name=v_name,
+                          metadata=metadata)
+
+    @attr(type=['negative', 'gate'])
     def test_get_invalid_volume_id(self):
         # Should not be able to get volume with invalid id
         self.assertRaises(exceptions.NotFound, self.client.get_volume,
                           '#$%%&^&^')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_get_volume_without_passing_volume_id(self):
         # Should not be able to get volume when empty ID is passed
         self.assertRaises(exceptions.NotFound, self.client.get_volume, '')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_invalid_volume_id(self):
         # Should not be able to delete volume when invalid ID is passed
         self.assertRaises(exceptions.NotFound, self.client.delete_volume,
                           '!@#$%^&*()')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_volume_without_passing_volume_id(self):
         # Should not be able to delete volume when empty ID is passed
         self.assertRaises(exceptions.NotFound, self.client.delete_volume, '')
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/test_cinder.py
index 3ff997a..25157a4 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/test_cinder.py
@@ -84,6 +84,24 @@
         roles = self.parser.listing(self.cinder('list-extensions'))
         self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
 
+    def test_cinder_credentials(self):
+        self.cinder('credentials')
+
+    def test_cinder_availability_zone_list(self):
+        self.cinder('availability-zone-list')
+
+    def test_cinder_endpoints(self):
+        self.cinder('endpoints')
+
+    def test_cinder_service_list(self):
+        self.cinder('service-list')
+
+    def test_cinder_transfer_list(self):
+        self.cinder('transfer-list')
+
+    def test_cinder_bash_completion(self):
+        self.cinder('bash-completion')
+
     def test_admin_help(self):
         help_text = self.cinder('help')
         lines = help_text.split('\n')
diff --git a/tempest/cli/simple_read_only/test_compute.py b/tempest/cli/simple_read_only/test_compute.py
index 9b358e6..94415f0 100644
--- a/tempest/cli/simple_read_only/test_compute.py
+++ b/tempest/cli/simple_read_only/test_compute.py
@@ -167,6 +167,10 @@
     def test_admin_net_list(self):
         self.nova('net-list')
 
+    def test_agent_list(self):
+        self.nova('agent-list')
+        self.nova('agent-list', flags='--debug')
+
     # Optional arguments:
 
     def test_admin_version(self):
diff --git a/tempest/cli/simple_read_only/test_compute_manage.py b/tempest/cli/simple_read_only/test_compute_manage.py
index 523c65f..9a33556 100644
--- a/tempest/cli/simple_read_only/test_compute_manage.py
+++ b/tempest/cli/simple_read_only/test_compute_manage.py
@@ -81,3 +81,11 @@
 
     def test_db_version(self):
         self.assertNotEqual("", self.nova_manage('db version'))
+
+    def test_cell_list(self):
+        # make sure command doesn't error out
+        self.nova_manage('cell list')
+
+    def test_host_list(self):
+        # make sure command doesn't error out
+        self.nova_manage('host list')
diff --git a/tempest/common/tempest_fixtures.py b/tempest/common/tempest_fixtures.py
index 081b271..ebc9ad3 100644
--- a/tempest/common/tempest_fixtures.py
+++ b/tempest/common/tempest_fixtures.py
@@ -15,16 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import fixtures
-
 from tempest.openstack.common import lockutils
 
 
-class LockFixture(fixtures.Fixture):
+class LockFixture(lockutils.LockFixture):
     def __init__(self, name):
-        self.mgr = lockutils.lock(name, 'tempest-', True)
-
-    def setUp(self):
-        super(LockFixture, self).setUp()
-        self.addCleanup(self.mgr.__exit__, None, None, None)
-        self.mgr.__enter__()
+        super(LockFixture, self).__init__(name, 'tempest-')
diff --git a/tempest/openstack/common/lockutils.py b/tempest/openstack/common/lockutils.py
index 0abd1a7..a55fd94 100644
--- a/tempest/openstack/common/lockutils.py
+++ b/tempest/openstack/common/lockutils.py
@@ -24,6 +24,7 @@
 import time
 import weakref
 
+import fixtures
 from oslo.config import cfg
 
 from tempest.openstack.common import fileutils
@@ -275,3 +276,36 @@
     """
 
     return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
+
+
+class LockFixture(fixtures.Fixture):
+    """External locking fixture.
+
+    This fixture is basically an alternative to the synchronized decorator with
+    the external flag so that tearDowns and addCleanups will be included in
+    the lock context for locking between tests. The fixture is recommended to
+    be the first line in a test method, like so::
+
+        def test_method(self):
+            self.useFixture(LockFixture)
+                ...
+
+    or the first line in setUp if all the test methods in the class are
+    required to be serialized. Something like::
+
+        class TestCase(testtools.testcase):
+            def setUp(self):
+                self.useFixture(LockFixture)
+                super(TestCase, self).setUp()
+                    ...
+
+    This is because addCleanups are put on a LIFO queue that gets run after the
+    test method exits. (either by completing or raising an exception)
+    """
+    def __init__(self, name, lock_file_prefix=None):
+        self.mgr = lock(name, lock_file_prefix, True)
+
+    def setUp(self):
+        super(LockFixture, self).setUp()
+        self.addCleanup(self.mgr.__exit__, None, None, None)
+        self.mgr.__enter__()
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 990c986..eda0ede 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -366,6 +366,11 @@
         """Unrescue the provided server."""
         return self.action(server_id, 'unrescue', None)
 
+    def get_server_diagnostics(self, server_id):
+        """Get the usage data for a server."""
+        resp, body = self.get("servers/%s/diagnostics" % str(server_id))
+        return resp, json.loads(body)
+
     def list_instance_actions(self, server_id):
         """List the provided server action."""
         resp, body = self.get("servers/%s/os-instance-actions" %
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index c58c3ee..cb21c61 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -575,6 +575,13 @@
                                  (server_id, volume_id), headers)
         return resp, body
 
+    def get_server_diagnostics(self, server_id):
+        """Get the usage data for a server."""
+        resp, body = self.get("servers/%s/diagnostics" % server_id,
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
     def list_instance_actions(self, server_id):
         """List the provided server action."""
         resp, body = self.get("servers/%s/os-instance-actions" % server_id,