Merge "Up the default timeout for stack builds"
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 1832259..7656ff3 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -120,3 +120,20 @@
         """Return a stack output value for a given key."""
         return next((o['output_value'] for o in stack['outputs']
                     if o['output_key'] == output_key), None)
+
+    def assert_fields_in_dict(self, obj, *fields):
+        for field in fields:
+            self.assertIn(field, obj)
+
+    def list_resources(self, stack_identifier):
+        """Get a dict mapping of resource names to types."""
+        resp, resources = self.client.list_resources(stack_identifier)
+        self.assertEqual('200', resp['status'])
+        self.assertIsInstance(resources, list)
+        for res in resources:
+            self.assert_fields_in_dict(res, 'logical_resource_id',
+                                       'resource_type', 'resource_status',
+                                       'updated_time')
+
+        return dict((r['resource_name'], r['resource_type'])
+                    for r in resources)
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 4b1b5ef..9ef95a1 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -40,16 +40,18 @@
         cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
         cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
 
-    def assert_fields_in_dict(self, obj, *fields):
-        for field in fields:
-            self.assertIn(field, obj)
+    def _list_stacks(self, expected_num=None, **filter_kwargs):
+        resp, stacks = self.client.list_stacks(params=filter_kwargs)
+        self.assertEqual('200', resp['status'])
+        self.assertIsInstance(stacks, list)
+        if expected_num is not None:
+            self.assertEqual(expected_num, len(stacks))
+        return stacks
 
     @attr(type='gate')
     def test_stack_list(self):
         """Created stack should be in the list of existing stacks."""
-        resp, stacks = self.client.list_stacks()
-        self.assertEqual('200', resp['status'])
-        self.assertIsInstance(stacks, list)
+        stacks = self._list_stacks()
         stacks_names = map(lambda stack: stack['stack_name'], stacks)
         self.assertIn(self.stack_name, stacks_names)
 
@@ -89,20 +91,8 @@
     def test_list_resources(self):
         """Getting list of created resources for the stack should be possible.
         """
-        resp, resources = self.client.list_resources(self.stack_identifier)
-        self.assertEqual('200', resp['status'])
-        self.assertIsInstance(resources, list)
-        for res in resources:
-            self.assert_fields_in_dict(res, 'logical_resource_id',
-                                       'resource_type', 'resource_status',
-                                       'updated_time')
-
-        resources_names = map(lambda resource: resource['logical_resource_id'],
-                              resources)
-        self.assertIn(self.resource_name, resources_names)
-        resources_types = map(lambda resource: resource['resource_type'],
-                              resources)
-        self.assertIn(self.resource_type, resources_types)
+        resources = self.list_resources(self.stack_identifier)
+        self.assertEqual({self.resource_name: self.resource_type}, resources)
 
     @attr(type='gate')
     def test_show_resource(self):
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 234faad..270851d 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -47,7 +47,7 @@
     T104: Scenario tests require a services decorator
     """
 
-    if 'tempest/scenario' in filename:
+    if 'tempest/scenario/test_' in filename:
         if TEST_DEFINITION.match(physical_line):
             if not SCENARIO_DECORATOR.match(previous_logical):
                 return (physical_line.find('def'),
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 89070a3..13e00a5 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -14,19 +14,17 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest.common.utils import test_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
+from tempest.scenario import utils as test_utils
 from tempest import test
 
-import testscenarios
-
 CONF = config.CONF
 
 LOG = logging.getLogger(__name__)
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test_utils.load_tests_input_scenario_utils
 
 
 class TestServerBasicOps(manager.OfficialClientTest):
@@ -43,13 +41,6 @@
      * Terminate the instance
     """
 
-    scenario_utils = test_utils.InputScenarioUtils()
-    scenario_flavor = scenario_utils.scenario_flavors
-    scenario_image = scenario_utils.scenario_images
-
-    scenarios = testscenarios.multiply_scenarios(scenario_image,
-                                                 scenario_flavor)
-
     def setUp(self):
         super(TestServerBasicOps, self).setUp()
         # Setup image and flavor the test instance
diff --git a/tempest/common/utils/test_utils.py b/tempest/scenario/utils.py
similarity index 85%
rename from tempest/common/utils/test_utils.py
rename to tempest/scenario/utils.py
index cc0d831..4c7b6d7 100644
--- a/tempest/common/utils/test_utils.py
+++ b/tempest/scenario/utils.py
@@ -12,15 +12,19 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import clients
-from tempest.common.utils import misc
-from tempest import config
 
 import json
 import re
 import string
 import unicodedata
 
+import testscenarios
+import testtools
+
+from tempest import clients
+from tempest.common.utils import misc
+from tempest import config
+
 CONF = config.CONF
 
 
@@ -79,7 +83,7 @@
 
     class TestInputScenario(manager.OfficialClientTest):
 
-        scenario_utils = test_utils.InputScenarioUtils()
+        scenario_utils = utils.InputScenarioUtils()
         scenario_flavor = scenario_utils.scenario_flavors
         scenario_image = scenario_utils.scenario_images
         scenarios = testscenarios.multiply_scenarios(scenario_image,
@@ -134,3 +138,22 @@
                 for f in flavors if re.search(self.flavor_pattern, str(f.name))
             ]
         return self._scenario_flavors
+
+
+def load_tests_input_scenario_utils(*args):
+    """
+    Wrapper for testscenarios to set the scenarios to avoid running a getattr
+    on the CONF object at import.
+    """
+    if getattr(args[0], 'suiteClass', None) is not None:
+        loader, standard_tests, pattern = args
+    else:
+        standard_tests, module, loader = args
+    scenario_utils = InputScenarioUtils()
+    scenario_flavor = scenario_utils.scenario_flavors
+    scenario_image = scenario_utils.scenario_images
+    for test in testtools.iterate_tests(standard_tests):
+        setattr(test, 'scenarios', testscenarios.multiply_scenarios(
+            scenario_image,
+            scenario_flavor))
+    return testscenarios.load_tests_apply_scenarios(*args)