Merge "Create and update func tests for resource group"
diff --git a/common/config.py b/common/config.py
index 71fabe1..562b80b 100644
--- a/common/config.py
+++ b/common/config.py
@@ -11,7 +11,6 @@
 #    under the License.
 
 import os
-import sys
 
 from oslo.config import cfg
 
@@ -108,7 +107,5 @@
     return conf
 
 
-if __name__ == '__main__':
-    cfg.CONF = init_conf(False)
-    import heat.openstack.common.config.generator as generate
-    generate.generate(sys.argv[1:])
+def list_opts():
+    yield None, IntegrationTestGroup
diff --git a/common/test.py b/common/test.py
index 7478f64..450ed82 100644
--- a/common/test.py
+++ b/common/test.py
@@ -22,8 +22,8 @@
 import time
 
 from heatclient import exc as heat_exceptions
+from oslo.utils import timeutils
 
-from heat.openstack.common import timeutils
 from heat_integrationtests.common import clients
 from heat_integrationtests.common import config
 from heat_integrationtests.common import exceptions
@@ -331,7 +331,8 @@
         return dict((r.resource_name, r.resource_type) for r in resources)
 
     def stack_create(self, stack_name=None, template=None, files=None,
-                     parameters=None, environment=None):
+                     parameters=None, environment=None,
+                     expected_status='CREATE_COMPLETE'):
         name = stack_name or self._stack_rand_name()
         templ = template or self.template
         templ_files = files or {}
@@ -349,5 +350,5 @@
 
         stack = self.client.stacks.get(name)
         stack_identifier = '%s/%s' % (name, stack.id)
-        self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+        self._wait_for_stack_status(stack_identifier, expected_status)
         return stack_identifier
diff --git a/functional/test_instance_group.py b/functional/test_instance_group.py
index 9a79801..8478932 100644
--- a/functional/test_instance_group.py
+++ b/functional/test_instance_group.py
@@ -10,11 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 import logging
-import yaml
-
-from heatclient import exc
 
 from heat_integrationtests.common import test
 
@@ -168,31 +164,6 @@
         stack = self.client.stacks.get(stack_identifier)
         self.assert_instance_count(stack, 4)
 
-    def test_create_config_prop_validation(self):
-        """Make sure that during a group create the instance
-        properties are validated. And an error causes the group to fail.
-        """
-        stack_name = self._stack_rand_name()
-
-        # add a property without a default and don't provide a value.
-        # we use this to make the instance fail on a property validation
-        # error.
-        broken = yaml.load(copy.copy(self.instance_template))
-        broken['parameters']['no_default'] = {'type': 'string'}
-        files = {'provider.yaml': yaml.dump(broken)}
-        env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
-               'parameters': {'size': 4,
-                              'image': self.conf.image_ref,
-                              'keyname': self.conf.keypair_name,
-                              'flavor': self.conf.instance_type}}
-
-        # now with static nested stack validation, this gets raised quickly.
-        excp = self.assertRaises(exc.HTTPBadRequest, self.client.stacks.create,
-                                 stack_name=stack_name, template=self.template,
-                                 files=files, disable_rollback=True,
-                                 parameters={}, environment=env)
-        self.assertIn('Property no_default not assigned', str(excp))
-
     def test_size_updates_work(self):
         files = {'provider.yaml': self.instance_template}
         env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
diff --git a/functional/test_remote_stack.py b/functional/test_remote_stack.py
index ee4bdc0..d9eec79 100644
--- a/functional/test_remote_stack.py
+++ b/functional/test_remote_stack.py
@@ -81,7 +81,7 @@
         self.assertEqual(remote_resources, self.list_resources(remote_id))
 
     def test_stack_create_bad_region(self):
-        stack_name = 'stack_to_fail'
+        stack_name = self._stack_rand_name()
         tmpl_bad_region = self.template.replace('RegionOne', 'DARKHOLE')
         files = {'remote_stack.yaml': self.remote_template}
         kwargs = {
@@ -97,7 +97,7 @@
         self.assertEqual(error_msg, six.text_type(ex))
 
     def test_stack_resource_validation_fail(self):
-        stack_name = 'stack_to_fail'
+        stack_name = self._stack_rand_name()
         tmpl_bad_format = self.remote_template.replace('resources', 'resource')
         files = {'remote_stack.yaml': tmpl_bad_format}
         kwargs = {'stack_name': stack_name, 'files': files}
diff --git a/functional/test_validation.py b/functional/test_validation.py
new file mode 100644
index 0000000..52309cd
--- /dev/null
+++ b/functional/test_validation.py
@@ -0,0 +1,95 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import logging
+
+from heat_integrationtests.common import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class StackValidationTest(test.HeatIntegrationTest):
+
+    def setUp(self):
+        super(StackValidationTest, self).setUp()
+        self.client = self.orchestration_client
+        if not self.conf.minimal_image_ref:
+            raise self.skipException("No image configured to test")
+
+        if not self.conf.instance_type:
+            raise self.skipException("No instance_type configured to test")
+
+        if self.conf.keypair_name:
+            self.keypair_name = self.conf.keypair_name
+        else:
+            self.keypair = self.create_keypair()
+            self.keypair_name = self.keypair.id
+
+    def test_stack_validate_provider_references_parent_resource(self):
+        template = '''
+heat_template_version: 2014-10-16
+parameters:
+  keyname:
+    type: string
+  flavor:
+    type: string
+  image:
+    type: string
+resources:
+  config:
+    type: My::Config
+    properties:
+        server: {get_resource: server}
+
+  server:
+    type: OS::Nova::Server
+    properties:
+      image: {get_param: image}
+      flavor: {get_param: flavor}
+      key_name: {get_param: keyname}
+      user_data_format: SOFTWARE_CONFIG
+'''
+        config_template = '''
+heat_template_version: 2014-10-16
+parameters:
+  server:
+    type: string
+resources:
+  config:
+    type: OS::Heat::SoftwareConfig
+
+  deployment:
+    type: OS::Heat::SoftwareDeployment
+    properties:
+      config:
+        get_resource: config
+      server:
+        get_param: server
+'''
+        files = {'provider.yaml': config_template}
+        env = {'resource_registry':
+               {'My::Config': 'provider.yaml'}}
+        parameters = {'keyname': self.keypair_name,
+                      'flavor': self.conf.instance_type,
+                      'image': self.conf.minimal_image_ref}
+        # Note we don't wait for CREATE_COMPLETE, because we're using a
+        # minimal image without the tools to apply the config.
+        # The point of the test is just to prove that validation won't
+        # falsely prevent stack creation starting, ref bug #1407100
+        # Note that we can be sure My::Config will stay IN_PROGRESS as
+        # there's no signal sent to the deployment
+        self.stack_create(template=template,
+                          files=files,
+                          environment=env,
+                          parameters=parameters,
+                          expected_status='CREATE_IN_PROGRESS')