Merge "Refactor of test_network_basic_ops -prep new tests"
diff --git a/HACKING.rst b/HACKING.rst
index a546f8c..eafa81b 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -153,6 +153,19 @@
                              kwarg2=dict_of_numbers)
 
 
+Test Skips
+----------
+If a test is broken because of a bug it is appropriate to skip the test until
+bug has been fixed. However, the skip message should be formatted so that
+Tempest's skip tracking tool can watch the bug status. The skip message should
+contain the string 'Bug' immediately followed by a space. Then the bug number
+should be included in the message '#' in front of the number.
+
+Example::
+
+  @testtools.skip("Skipped until the Bug #980688 is resolved")
+
+
 openstack-common
 ----------------
 
diff --git a/cli/__init__.py b/cli/__init__.py
index 6ffe229..5d986c0 100644
--- a/cli/__init__.py
+++ b/cli/__init__.py
@@ -60,10 +60,11 @@
         return self.cmd_with_auth(
             'nova', action, flags, params, admin, fail_ok)
 
-    def nova_manage(self, action, flags='', params='', fail_ok=False):
+    def nova_manage(self, action, flags='', params='', fail_ok=False,
+                    merge_stderr=False):
         """Executes nova-manage command for the given action."""
         return self.cmd(
-            'nova-manage', action, flags, params, fail_ok)
+            'nova-manage', action, flags, params, fail_ok, merge_stderr)
 
     def keystone(self, action, flags='', params='', admin=True, fail_ok=False):
         """Executes keystone command for the given action."""
@@ -81,14 +82,19 @@
         flags = creds + ' ' + flags
         return self.cmd(cmd, action, flags, params, fail_ok)
 
-    def cmd(self, cmd, action, flags='', params='', fail_ok=False):
+    def cmd(self, cmd, action, flags='', params='', fail_ok=False,
+            merge_stderr=False):
         """Executes specified command for the given action."""
         cmd = ' '.join([CONF.cli.cli_dir + cmd,
                         flags, action, params])
         LOG.info("running: '%s'" % cmd)
         cmd = shlex.split(cmd)
         try:
-            result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+            if merge_stderr:
+                result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+            else:
+                devnull = open('/dev/null', 'w')
+                result = subprocess.check_output(cmd, stderr=devnull)
         except subprocess.CalledProcessError, e:
             LOG.error("command output:\n%s" % e.output)
             raise
diff --git a/cli/simple_read_only/test_compute.py b/cli/simple_read_only/test_compute.py
index 43c3c45..d301d38 100644
--- a/cli/simple_read_only/test_compute.py
+++ b/cli/simple_read_only/test_compute.py
@@ -22,7 +22,6 @@
 import testtools
 
 import cli
-from tempest import config
 
 
 CONF = cfg.CONF
@@ -73,7 +72,7 @@
     def test_admin_dns_domains(self):
         self.nova('dns-domains')
 
-    @testtools.skip("Test needs parameters, Bug: 1157349")
+    @testtools.skip("Test needs parameters, Bug #1157349")
     def test_admin_dns_list(self):
         self.nova('dns-list')
 
@@ -111,7 +110,7 @@
     def test_admin_image_list(self):
         self.nova('image-list')
 
-    @testtools.skip("Test needs parameters, Bug: 1157349")
+    @testtools.skip("Test needs parameters, Bug #1157349")
     def test_admin_interface_list(self):
         self.nova('interface-list')
 
@@ -136,7 +135,7 @@
     def test_admin_secgroup_list(self):
         self.nova('secgroup-list')
 
-    @testtools.skip("Test needs parameters, Bug: 1157349")
+    @testtools.skip("Test needs parameters, Bug #1157349")
     def test_admin_secgroup_list_rules(self):
         self.nova('secgroup-list-rules')
 
diff --git a/cli/simple_read_only/test_compute_manage.py b/cli/simple_read_only/test_compute_manage.py
index 17b3bf6..bbcc5b1 100644
--- a/cli/simple_read_only/test_compute_manage.py
+++ b/cli/simple_read_only/test_compute_manage.py
@@ -18,8 +18,6 @@
 import logging
 import subprocess
 
-import testtools
-
 import cli
 
 
@@ -49,9 +47,20 @@
     def test_help_flag(self):
         self.nova_manage('', '-h')
 
-    @testtools.skip("version is empty, bug 1138844")
     def test_version_flag(self):
-        self.assertNotEqual("", self.nova_manage('', '--version'))
+        # Bug 1159957: nova-manage --version writes to stderr
+        self.assertNotEqual("", self.nova_manage('', '--version',
+                                                 merge_stderr=True))
+        self.assertEqual(self.nova_manage('version'),
+                         self.nova_manage('', '--version', merge_stderr=True))
+
+    def test_debug_flag(self):
+        self.assertNotEqual("", self.nova_manage('instance_type list',
+                            '--debug'))
+
+    def test_verbose_flag(self):
+        self.assertNotEqual("", self.nova_manage('instance_type list',
+                            '--verbose'))
 
     # test actions
     def test_version(self):
@@ -59,3 +68,16 @@
 
     def test_flavor_list(self):
         self.assertNotEqual("", self.nova_manage('flavor list'))
+        self.assertEqual(self.nova_manage('instance_type list'),
+                         self.nova_manage('flavor list'))
+
+    def test_db_archive_deleted_rows(self):
+        # make sure command doesn't error out
+        self.nova_manage('db archive_deleted_rows 50')
+
+    def test_db_sync(self):
+        # make sure command doesn't error out
+        self.nova_manage('db sync')
+
+    def test_db_version(self):
+        self.assertNotEqual("", self.nova_manage('db version'))
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index d73b8a9..27733ac 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -47,10 +47,12 @@
             raise exceptions.NotFound(body)
         return resp, body['floating_ip']
 
-    def create_floating_ip(self):
+    def create_floating_ip(self, pool_name=None):
         """Allocate a floating IP to the project."""
         url = 'os-floating-ips'
-        resp, body = self.post(url, None, None)
+        post_body = {'pool': pool_name}
+        post_body = json.dumps(post_body)
+        resp, body = self.post(url, post_body, self.headers)
         body = json.loads(body)
         return resp, body['floating_ip']
 
diff --git a/tempest/services/compute/xml/floating_ips_client.py b/tempest/services/compute/xml/floating_ips_client.py
index 74b4be2..93f5208 100644
--- a/tempest/services/compute/xml/floating_ips_client.py
+++ b/tempest/services/compute/xml/floating_ips_client.py
@@ -22,6 +22,7 @@
 from tempest import exceptions
 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
 
 
@@ -60,10 +61,17 @@
             raise exceptions.NotFound(body)
         return resp, body
 
-    def create_floating_ip(self):
+    def create_floating_ip(self, pool_name=None):
         """Allocate a floating IP to the project."""
         url = 'os-floating-ips'
-        resp, body = self.post(url, None, self.headers)
+        if pool_name:
+            doc = Document()
+            pool = Element("pool")
+            pool.append(Text(pool_name))
+            doc.append(pool)
+            resp, body = self.post(url, str(doc), self.headers)
+        else:
+            resp, body = self.post(url, None, self.headers)
         body = self._parse_floating_ip(etree.fromstring(body))
         return resp, body
 
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index fceeb28..008417b 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -401,6 +401,19 @@
     def remove_security_group(self, server_id, name):
         return self.action(server_id, 'removeSecurityGroup', None, name=name)
 
+    def live_migrate_server(self, server_id, dest_host, use_block_migration):
+        """This should be called with administrator privileges ."""
+
+        req_body = Element("os-migrateLive",
+                           xmlns=XMLNS_11,
+                           disk_over_commit=False,
+                           block_migration=use_block_migration,
+                           host=dest_host)
+
+        resp, body = self.post("servers/%s/action" % str(server_id),
+                               str(Document(req_body)), self.headers)
+        return resp, body
+
     def list_server_metadata(self, server_id):
         resp, body = self.get("servers/%s/metadata" % str(server_id),
                               self.headers)
diff --git a/tempest/tests/boto/test_s3_objects.py b/tempest/tests/boto/test_s3_objects.py
index c735215..dcb7c86 100644
--- a/tempest/tests/boto/test_s3_objects.py
+++ b/tempest/tests/boto/test_s3_objects.py
@@ -18,7 +18,6 @@
 from contextlib import closing
 
 from boto.s3.key import Key
-import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
index 888481a..2b21710 100644
--- a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
@@ -73,6 +73,14 @@
             #Deleting the floating IP which is created in this method
             self.client.delete_floating_ip(floating_ip_id_allocated)
 
+    @attr(type='negative')
+    def test_allocate_floating_ip_from_nonexistent_pool(self):
+        # Positive test:Allocation of a new floating IP from a nonexistent_pool
+        #to a project should fail
+        self.assertRaises(exceptions.NotFound,
+                          self.client.create_floating_ip,
+                          "non_exist_pool")
+
     @attr(type='positive')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
diff --git a/tempest/tests/compute/images/test_images.py b/tempest/tests/compute/images/test_images.py
index fb0364a..d9e4153 100644
--- a/tempest/tests/compute/images/test_images.py
+++ b/tempest/tests/compute/images/test_images.py
@@ -108,7 +108,7 @@
         self.assertRaises(exceptions.Duplicate, self.client.create_image,
                           server['id'], snapshot_name)
 
-    @testtools.skip("Until Bug 1039739 is fixed")
+    @testtools.skip("Until Bug #1039739 is fixed")
     @attr(type='negative')
     def test_create_image_when_server_is_rebooting(self):
         # Return error when creating an image of server that is rebooting
diff --git a/tempest/tests/compute/images/test_images_oneserver.py b/tempest/tests/compute/images/test_images_oneserver.py
index f7008f0..9412d39 100644
--- a/tempest/tests/compute/images/test_images_oneserver.py
+++ b/tempest/tests/compute/images/test_images_oneserver.py
@@ -58,7 +58,7 @@
             cls.alt_client = cls.alt_manager.images_client
 
     @attr(type='negative')
-    @testtools.skip("Until Bug 1006725 is fixed")
+    @testtools.skip("Until Bug #1006725 is fixed")
     def test_create_image_specify_multibyte_character_image_name(self):
         # Return an error if the image name has multi-byte characters
         snapshot_name = rand_name('\xef\xbb\xbf')
@@ -67,7 +67,7 @@
                           snapshot_name)
 
     @attr(type='negative')
-    @testtools.skip("Until Bug 1005423 is fixed")
+    @testtools.skip("Until Bug #1005423 is fixed")
     def test_create_image_specify_invalid_metadata(self):
         # Return an error when creating image with invalid metadata
         snapshot_name = rand_name('test-snap-')
@@ -76,7 +76,7 @@
                           self.server['id'], snapshot_name, meta)
 
     @attr(type='negative')
-    @testtools.skip("Until Bug 1005423 is fixed")
+    @testtools.skip("Until Bug #1005423 is fixed")
     def test_create_image_specify_metadata_over_limits(self):
         # Return an error when creating image with meta data over 256 chars
         snapshot_name = rand_name('test-snap-')
diff --git a/tempest/tests/compute/servers/test_list_server_filters.py b/tempest/tests/compute/servers/test_list_server_filters.py
index ff599fe..4d2b99f 100644
--- a/tempest/tests/compute/servers/test_list_server_filters.py
+++ b/tempest/tests/compute/servers/test_list_server_filters.py
@@ -126,11 +126,12 @@
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
     @attr(type='positive')
-    def test_list_servers_detailed_filter_by_limit(self):
+    def test_list_servers_filter_by_limit(self):
         # Verify only the expected number of servers are returned
         params = {'limit': 1}
-        resp, servers = self.client.list_servers_with_detail(params)
-        self.assertEqual(1, len(servers['servers']))
+        resp, servers = self.client.list_servers(params)
+        #when _interface='xml', one element for servers_links in servers
+        self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
     @attr(type='positive')
diff --git a/tempest/tests/compute/servers/test_server_actions.py b/tempest/tests/compute/servers/test_server_actions.py
index d5b2650..5634784 100644
--- a/tempest/tests/compute/servers/test_server_actions.py
+++ b/tempest/tests/compute/servers/test_server_actions.py
@@ -87,7 +87,7 @@
             self.assertGreater(new_boot_time, boot_time)
 
     @attr(type='smoke')
-    @testtools.skip('Until bug 1014647 is dealt with.')
+    @testtools.skip('Until Bug #1014647 is dealt with.')
     def test_reboot_server_soft(self):
         # The server should be signaled to reboot gracefully
         if self.run_ssh:
@@ -239,7 +239,7 @@
                           '!@#$%^&*()', 10)
 
     @attr(type='positive')
-    @testtools.skip('Until tempest bug 1014683 is fixed.')
+    @testtools.skip('Until tempest Bug #1014683 is fixed.')
     def test_get_console_output_server_id_in_reboot_status(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id in reboot status
diff --git a/tempest/tests/compute/servers/test_server_addresses.py b/tempest/tests/compute/servers/test_server_addresses.py
index cb8e85e..05fa320 100644
--- a/tempest/tests/compute/servers/test_server_addresses.py
+++ b/tempest/tests/compute/servers/test_server_addresses.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.compute import base
diff --git a/tempest/tests/compute/servers/test_server_rescue.py b/tempest/tests/compute/servers/test_server_rescue.py
index 9230305..61ba384 100644
--- a/tempest/tests/compute/servers/test_server_rescue.py
+++ b/tempest/tests/compute/servers/test_server_rescue.py
@@ -15,17 +15,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import base64
-import time
-
 import testtools
 
 from tempest.common.utils.data_utils import rand_name
-from tempest.common.utils.linux.remote_client import RemoteClient
 import tempest.config
 from tempest import exceptions
 from tempest.test import attr
-from tempest.tests import compute
 from tempest.tests.compute import base
 
 
@@ -112,6 +107,11 @@
     def _delete(self, volume_id):
         self.volumes_extensions_client.delete_volume(volume_id)
 
+    def _unrescue(self, server_id):
+        resp, body = self.servers_client.unrescue_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
     @attr(type='smoke')
     def test_rescue_unrescue_instance(self):
         resp, body = self.servers_client.rescue_server(
@@ -123,9 +123,8 @@
         self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
 
     @attr(type='negative')
-    @testtools.skip("Skipped until Bug:1126163 is resolved")
     def test_rescued_vm_reboot(self):
-        self.assertRaises(exceptions.BadRequest, self.servers_client.reboot,
+        self.assertRaises(exceptions.Duplicate, self.servers_client.reboot,
                           self.rescue_id, 'HARD')
 
     @attr(type='negative')
@@ -135,37 +134,23 @@
                           self.rescue_id,
                           self.image_ref_alt)
 
-    @attr(type='positive')
-    @testtools.skip("Skipped due to Bug:1126187")
+    @attr(type='negative')
     def test_rescued_vm_attach_volume(self):
         client = self.volumes_extensions_client
 
         # Rescue the server
         self.servers_client.rescue_server(self.server_id, self.password)
         self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        self.addCleanup(self._unrescue, self.server_id)
 
         # Attach the volume to the server
-        resp, body = \
-        self.servers_client.attach_volume(self.server_id,
-                                          self.volume_to_attach['id'],
-                                          device='/dev/%s' % self.device)
-        self.assertEqual(200, resp.status)
-        client.wait_for_volume_status(self.volume_to_attach['id'], 'in-use')
+        self.assertRaises(exceptions.Duplicate,
+                          self.servers_client.attach_volume,
+                          self.server_id,
+                          self.volume_to_attach['id'],
+                          device='/dev/%s' % self.device)
 
-        # Detach the volume to the server
-        resp, body = \
-        self.servers_client.detach_volume(self.server_id,
-                                          self.volume_to_attach['id'])
-        self.assertEqual(202, resp.status)
-        client.wait_for_volume_status(self.volume_to_attach['id'], 'available')
-
-        # Unrescue the server
-        resp, body = self.servers_client.unrescue_server(self.server_id)
-        self.assertEqual(202, resp.status)
-        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
-
-    @attr(type='positive')
-    @testtools.skip("Skipped until Bug:1126187 is resolved")
+    @attr(type='negative')
     def test_rescued_vm_detach_volume(self):
         # Attach the volume to the server
         self.servers_client.attach_volume(self.server_id,
@@ -177,19 +162,13 @@
         # Rescue the server
         self.servers_client.rescue_server(self.server_id, self.password)
         self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        self.addCleanup(self._unrescue, self.server_id)
 
-        # Detach the volume to the server
-        resp, body = \
-        self.servers_client.detach_volume(self.server_id,
-                                          self.volume_to_detach['id'])
-        self.assertEqual(202, resp.status)
-        client = self.volumes_extensions_client
-        client.wait_for_volume_status(self.volume_to_detach['id'], 'available')
-
-        # Unrescue the server
-        resp, body = self.servers_client.unrescue_server(self.server_id)
-        self.assertEqual(202, resp.status)
-        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+        # Detach the volume from the server expecting failure
+        self.assertRaises(exceptions.Duplicate,
+                          self.servers_client.detach_volume,
+                          self.server_id,
+                          self.volume_to_detach['id'])
 
     @attr(type='positive')
     def test_rescued_vm_associate_dissociate_floating_ip(self):
@@ -217,7 +196,7 @@
         self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
 
     @attr(type='positive')
-    @testtools.skip("Skipped until Bug: 1126257 is resolved")
+    @testtools.skip("Skipped until Bug #1126257 is resolved")
     def test_rescued_vm_add_remove_security_group(self):
         #Add Security group
         resp, body = self.servers_client.add_security_group(self.server_id,
diff --git a/tempest/tests/compute/test_authorization.py b/tempest/tests/compute/test_authorization.py
index 4ca197a..02ea4d4 100644
--- a/tempest/tests/compute/test_authorization.py
+++ b/tempest/tests/compute/test_authorization.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/compute/test_live_block_migration.py b/tempest/tests/compute/test_live_block_migration.py
index abaaf85..e5a7d5b 100644
--- a/tempest/tests/compute/test_live_block_migration.py
+++ b/tempest/tests/compute/test_live_block_migration.py
@@ -27,7 +27,7 @@
 
 
 @attr(category='live-migration')
-class LiveBlockMigrationTest(base.BaseComputeAdminTest):
+class LiveBlockMigrationTestJSON(base.BaseComputeAdminTest):
     _interface = 'json'
 
     live_migration_available = (
@@ -38,7 +38,7 @@
 
     @classmethod
     def setUpClass(cls):
-        super(LiveBlockMigrationTest, cls).setUpClass()
+        super(LiveBlockMigrationTestJSON, cls).setUpClass()
 
         cls.admin_hosts_client = cls.os_adm.hosts_client
         cls.admin_servers_client = cls.os_adm.servers_client
@@ -125,4 +125,8 @@
         for server_id in cls.created_server_ids:
             cls.servers_client.delete_server(server_id)
 
-        super(LiveBlockMigrationTest, cls).tearDownClass()
+        super(LiveBlockMigrationTestJSON, cls).tearDownClass()
+
+
+class LiveBlockMigrationTestXML(LiveBlockMigrationTestJSON):
+    _interface = 'xml'
diff --git a/tempest/tests/compute/volumes/test_attach_volume.py b/tempest/tests/compute/volumes/test_attach_volume.py
index d9abe41..57f1e20 100644
--- a/tempest/tests/compute/volumes/test_attach_volume.py
+++ b/tempest/tests/compute/volumes/test_attach_volume.py
@@ -17,7 +17,6 @@
 
 import testtools
 
-from tempest.common.utils.data_utils import rand_name
 from tempest.common.utils.linux.remote_client import RemoteClient
 import tempest.config
 from tempest.test import attr
diff --git a/tempest/tests/identity/admin/test_users.py b/tempest/tests/identity/admin/test_users.py
index 224272e..80c6fc9 100644
--- a/tempest/tests/identity/admin/test_users.py
+++ b/tempest/tests/identity/admin/test_users.py
@@ -77,7 +77,7 @@
                           self.data.tenant['id'], self.data.test_email)
 
     @attr(type='negative')
-    @testtools.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug #999084 is fixed")
     def test_create_user_with_empty_password(self):
         # User with an empty password should not be created
         self.data.setup_test_tenant()
@@ -86,7 +86,7 @@
                           self.alt_email)
 
     @attr(type='nagative')
-    @testtools.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug #999084 is fixed")
     def test_create_user_with_long_password(self):
         # User having password exceeding max length should not be created
         self.data.setup_test_tenant()
@@ -95,7 +95,7 @@
                           self.alt_email)
 
     @attr(type='negative')
-    @testtools.skip("Until Bug 999084 is fixed")
+    @testtools.skip("Until Bug #999084 is fixed")
     def test_create_user_with_invalid_email_format(self):
         # Email format should be validated while creating a user
         self.data.setup_test_tenant()
diff --git a/tempest/tests/image/base.py b/tempest/tests/image/base.py
index 65d81b6..f12e957 100644
--- a/tempest/tests/image/base.py
+++ b/tempest/tests/image/base.py
@@ -15,7 +15,6 @@
 #    under the License.
 
 import logging
-import time
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/image/v1/test_images.py b/tempest/tests/image/v1/test_images.py
index af09b79..d455d84 100644
--- a/tempest/tests/image/v1/test_images.py
+++ b/tempest/tests/image/v1/test_images.py
@@ -17,7 +17,6 @@
 
 import cStringIO as StringIO
 
-from tempest import clients
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.image import base
diff --git a/tempest/tests/image/v2/test_images.py b/tempest/tests/image/v2/test_images.py
index 19a7a95..eddeb78 100644
--- a/tempest/tests/image/v2/test_images.py
+++ b/tempest/tests/image/v2/test_images.py
@@ -19,7 +19,6 @@
 import cStringIO as StringIO
 import random
 
-from tempest import clients
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.image import base
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
index dad6309..d5fa96c 100644
--- a/tempest/tests/object_storage/test_container_sync.py
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -61,7 +61,7 @@
             #Attempt to delete the container
             resp, _ = client[0].delete_container(cont_name)
 
-    @testtools.skip('Until Bug 1093743 is resolved.')
+    @testtools.skip('Until Bug #1093743 is resolved.')
     @attr(type='positive')
     def test_container_synchronization(self):
         #Container to container synchronization
diff --git a/tempest/tests/object_storage/test_object_expiry.py b/tempest/tests/object_storage/test_object_expiry.py
index 8411ef5..c12ec3d 100644
--- a/tempest/tests/object_storage/test_object_expiry.py
+++ b/tempest/tests/object_storage/test_object_expiry.py
@@ -55,7 +55,7 @@
         #Attempt to delete the container
         resp, _ = cls.container_client.delete_container(cls.container_name)
 
-    @testtools.skip('Until bug 1069849 is resolved.')
+    @testtools.skip('Until Bug #1069849 is resolved.')
     @attr(type='regression')
     def test_get_object_after_expiry_time(self):
         # GET object after expiry time
diff --git a/tempest/tests/object_storage/test_object_services.py b/tempest/tests/object_storage/test_object_services.py
index 76fab0b..1edce92 100644
--- a/tempest/tests/object_storage/test_object_services.py
+++ b/tempest/tests/object_storage/test_object_services.py
@@ -590,7 +590,7 @@
                           self.container_name, object_name,
                           metadata=self.custom_headers)
 
-    @testtools.skip('Until bug 1097137 is resolved.')
+    @testtools.skip('Until Bug #1097137 is resolved.')
     @attr(type='positive')
     def test_get_object_using_temp_url(self):
         #Access object using temp url within expiry time
diff --git a/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py
index f528cec..13fcbbf 100644
--- a/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/tests/volume/admin/test_volume_types_extra_specs_negative.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
 import uuid
 
 from tempest.common.utils.data_utils import rand_name
diff --git a/tempest/tests/volume/admin/test_volume_types_negative.py b/tempest/tests/volume/admin/test_volume_types_negative.py
index 1b11d68..daf804d 100644
--- a/tempest/tests/volume/admin/test_volume_types_negative.py
+++ b/tempest/tests/volume/admin/test_volume_types_negative.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
 import uuid
 
 from tempest import exceptions
diff --git a/tools/hacking.py b/tools/hacking.py
index 617682d..7e46b74 100755
--- a/tools/hacking.py
+++ b/tools/hacking.py
@@ -21,7 +21,6 @@
 built on top of pep8.py
 """
 
-import fnmatch
 import inspect
 import logging
 import os
@@ -323,6 +322,30 @@
                 return (pos, "T404: test functions must "
                         "not have doc strings")
 
+SKIP_DECORATOR = '@testtools.skip('
+
+
+def tempest_skip_bugs(physical_line):
+    """Check skip lines for proper bug entries
+
+    T601: Bug not in skip line
+    T602: Bug in message formatted incorrectly
+    """
+
+    pos = physical_line.find(SKIP_DECORATOR)
+
+    skip_re = re.compile(r'^\s*@testtools.skip.*')
+
+    if pos != -1 and skip_re.match(physical_line):
+        bug = re.compile(r'^.*\bbug\b.*', re.IGNORECASE)
+        if bug.match(physical_line) is None:
+            return (pos, 'T601: skips must have an associated bug')
+
+        bug_re = re.compile(r'.*skip\(.*Bug\s\#\d+', re.IGNORECASE)
+
+        if bug_re.match(physical_line) is None:
+            return (pos, 'T602: Bug number formatted incorrectly')
+
 
 FORMAT_RE = re.compile("%(?:"
                        "%|"           # Ignore plain percents
diff --git a/tools/install_venv.py b/tools/install_venv.py
index 20dcefa..ef7b0a8 100644
--- a/tools/install_venv.py
+++ b/tools/install_venv.py
@@ -21,9 +21,7 @@
 
 """Installation script for Tempest's development virtualenv."""
 
-import optparse
 import os
-import subprocess
 import sys
 
 import install_venv_common as install_venv
diff --git a/tools/tempest_coverage.py b/tools/tempest_coverage.py
index a46d0fb..c385eae 100755
--- a/tools/tempest_coverage.py
+++ b/tools/tempest_coverage.py
@@ -16,7 +16,6 @@
 
 import json
 import os
-import re
 import shutil
 import sys
 
@@ -24,7 +23,6 @@
 
 from tempest.common.rest_client import RestClient
 from tempest import config
-from tempest.tests.compute import base
 
 CONF = config.TempestConfig()