Hacking rule to forbid resource unsafe fixtures

Extend the existing T105, which was missing checks for
tearDownClass anyways. Forbid overriding setUpClass
and tearDownClass except for tempest/test.py where the
test base class is defined.

To be able to enforce the rule, fixing setUpClass
which was added with new tests before this patch could
merge.

Partially-implements bp resource-cleanup

Change-Id: Ib4d98c2ff8776ea1379a044b5a30fb02e351ce75
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 58ad39c..e20b58e 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -222,11 +222,11 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.network_feature_enabled.ipv6:
             skip_msg = "IPv6 Tests are disabled."
             raise cls.skipException(skip_msg)
-        super(SecGroupIPv6Test, cls).setUpClass()
+        super(SecGroupIPv6Test, cls).resource_setup()
 
 
 class SecGroupIPv6TestXML(SecGroupIPv6Test):
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 2e3091e..97e4cb7 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -198,11 +198,11 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.network_feature_enabled.ipv6:
             skip_msg = "IPv6 Tests are disabled."
             raise cls.skipException(skip_msg)
-        super(NegativeSecGroupIPv6Test, cls).setUpClass()
+        super(NegativeSecGroupIPv6Test, cls).resource_setup()
 
 
 class NegativeSecGroupIPv6TestXML(NegativeSecGroupIPv6Test):
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 55cc89b..6014cff 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -24,7 +24,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')
+SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class')
 SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
 VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
 mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
@@ -58,15 +58,15 @@
                         "T104: Scenario tests require a service decorator")
 
 
-def no_setupclass_for_unit_tests(physical_line, filename):
+def no_setup_teardown_class_for_tests(physical_line, filename):
 
     if pep8.noqa(physical_line):
         return
 
-    if 'tempest/tests' in filename:
-        if SETUPCLASS_DEFINITION.match(physical_line):
+    if 'tempest/test.py' not in filename:
+        if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
             return (physical_line.find('def'),
-                    "T105: setUpClass can not be used with unit tests")
+                    "T105: (setUp|tearDown)Class can not be used in tests")
 
 
 def no_vi_headers(physical_line, line_number, lines):
@@ -119,7 +119,7 @@
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
-    register(no_setupclass_for_unit_tests)
+    register(no_setup_teardown_class_for_tests)
     register(no_vi_headers)
     register(service_tags_not_in_module_path)
     register(no_mutable_default_args)
diff --git a/tempest/tests/common/utils/test_misc.py b/tempest/tests/common/utils/test_misc.py
index aee9805..554027f 100644
--- a/tempest/tests/common/utils/test_misc.py
+++ b/tempest/tests/common/utils/test_misc.py
@@ -82,7 +82,7 @@
         self.assertEqual(':tearDown', tearDown())
 
     def test_find_test_caller_teardown_class(self):
-        def tearDownClass(cls):
+        def tearDownClass(cls):  # noqa
             return misc.find_test_caller()
         self.assertEqual('TestMisc:tearDownClass',
                          tearDownClass(self.__class__))
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 37ad18e..6857461 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -47,13 +47,27 @@
     just assertTrue if the check is expected to fail and assertFalse if it
     should pass.
     """
-    def test_no_setupclass_for_unit_tests(self):
-        self.assertTrue(checks.no_setupclass_for_unit_tests(
+    def test_no_setup_teardown_class_for_tests(self):
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls):", './tempest/tests/fake_test.py'))
-        self.assertIsNone(checks.no_setupclass_for_unit_tests(
+        self.assertIsNone(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls): # noqa", './tempest/tests/fake_test.py'))
-        self.assertFalse(checks.no_setupclass_for_unit_tests(
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls):", './tempest/api/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def setUpClass(cls):", './tempest/scenario/fake_test.py'))
+        self.assertFalse(checks.no_setup_teardown_class_for_tests(
+            "  def setUpClass(cls):", './tempest/test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/tests/fake_test.py'))
+        self.assertIsNone(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls): # noqa", './tempest/tests/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/api/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/scenario/fake_test.py'))
+        self.assertFalse(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/test.py'))
 
     def test_import_no_clients_in_api(self):
         for client in checks.PYTHON_CLIENTS: