Merge "Introduce load_tests mechanism for negative tests"
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index b882ff4..162e419 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testscenarios
 import uuid
 
 from tempest.api.compute import base
@@ -21,7 +20,7 @@
 from tempest import exceptions
 from tempest import test
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test.NegativeAutoTest.load_tests
 
 
 class FlavorsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -108,8 +107,6 @@
     _service = 'compute'
     _schema_file = 'compute/admin/flavor_create.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @test.attr(type=['negative', 'gate'])
     def test_create_flavor(self):
         # flavor details are not returned for non-existent flavors
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index 4ba5023..a81b7d9 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -13,13 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testscenarios
 
 from tempest.api.compute import base
 from tempest import test
 
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test.NegativeAutoTest.load_tests
 
 
 class FlavorsListNegativeTestJSON(base.BaseV2ComputeTest,
@@ -27,8 +26,6 @@
     _service = 'compute'
     _schema_file = 'compute/flavors/flavors_list.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @test.attr(type=['negative', 'gate'])
     def test_list_flavors_with_detail(self):
         self.execute(self._schema_file)
@@ -39,8 +36,6 @@
     _service = 'compute'
     _schema_file = 'compute/flavors/flavor_details.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @classmethod
     def setUpClass(cls):
         super(FlavorDetailsNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/servers/test_servers_negative_new.py b/tempest/api/compute/servers/test_servers_negative_new.py
index 42ace76..f860ff9 100644
--- a/tempest/api/compute/servers/test_servers_negative_new.py
+++ b/tempest/api/compute/servers/test_servers_negative_new.py
@@ -13,13 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testscenarios
 
 from tempest.api.compute import base
 from tempest import test
 
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test.NegativeAutoTest.load_tests
 
 
 class GetConsoleOutputNegativeTestJSON(base.BaseV2ComputeTest,
@@ -27,8 +26,6 @@
     _service = 'compute'
     _schema_file = 'compute/servers/get_console_output.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @classmethod
     def setUpClass(cls):
         super(GetConsoleOutputNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/v3/flavors/test_flavors_negative.py b/tempest/api/compute/v3/flavors/test_flavors_negative.py
index 346f6d6..1c0e4fb 100644
--- a/tempest/api/compute/v3/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/v3/flavors/test_flavors_negative.py
@@ -13,13 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testscenarios
-
 from tempest.api.compute import base
 from tempest import test
 
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test.NegativeAutoTest.load_tests
 
 
 class FlavorsListNegativeV3Test(base.BaseV3ComputeTest,
@@ -27,8 +25,6 @@
     _service = 'computev3'
     _schema_file = 'compute/flavors/flavors_list_v3.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @test.attr(type=['negative', 'gate'])
     def test_list_flavors_with_detail(self):
         self.execute(self._schema_file)
@@ -39,8 +35,6 @@
     _service = 'computev3'
     _schema_file = 'compute/flavors/flavor_details_v3.json'
 
-    scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
-
     @classmethod
     def setUpClass(cls):
         super(FlavorDetailsNegativeV3Test, cls).setUpClass()
diff --git a/tempest/test.py b/tempest/test.py
index d2568a6..abf42c0 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -24,10 +24,9 @@
 
 import fixtures
 import testresources
+import testscenarios
 import testtools
 
-from oslo.config import cfg
-
 from tempest import clients
 import tempest.common.generator.valid_generator as valid
 from tempest.common import isolated_creds
@@ -407,6 +406,24 @@
         return json.load(open(fn))
 
     @staticmethod
+    def load_tests(*args):
+        """
+        Wrapper for testscenarios to set the mandatory scenarios variable
+        only in case a real test loader is in place. Will be automatically
+        called in case the variable "load_tests" is set.
+        """
+        if getattr(args[0], 'suiteClass', None) is not None:
+            loader, standard_tests, pattern = args
+        else:
+            standard_tests, module, loader = args
+        for test in testtools.iterate_tests(standard_tests):
+            schema_file = getattr(test, '_schema_file', None)
+            if schema_file is not None:
+                setattr(test, 'scenarios',
+                        NegativeAutoTest.generate_scenario(schema_file))
+        return testscenarios.load_tests_apply_scenarios(*args)
+
+    @staticmethod
     def generate_scenario(description_file):
         """
         Generates the test scenario list for a given description.
@@ -429,17 +446,8 @@
         """
         description = NegativeAutoTest.load_schema(description_file)
         LOG.debug(description)
-
-        # NOTE(mkoderer): since this will be executed on import level the
-        # config doesn't have to be in place (e.g. for the pep8 job).
-        # In this case simply return.
-        try:
-            generator = importutils.import_class(
-                CONF.negative.test_generator)()
-        except cfg.ConfigFilesNotFoundError:
-            LOG.critical(
-                "Tempest config not found. Test scenarios aren't created")
-            return
+        generator = importutils.import_class(
+            CONF.negative.test_generator)()
         generator.validate_schema(description)
         schema = description.get("json-schema", None)
         resources = description.get("resources", [])