Move aws nested stack tests to functional tests

- use swift to post templates to.
- move limit tests to test_stack_resource

Part of blueprint decouple-nested
Change-Id: Id11e86835addc21301b3534a559d1754a802425e
diff --git a/functional/test_aws_stack.py b/functional/test_aws_stack.py
new file mode 100644
index 0000000..2e2cd9d
--- /dev/null
+++ b/functional/test_aws_stack.py
@@ -0,0 +1,213 @@
+#    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 hashlib
+import json
+import logging
+import random
+import urlparse
+
+from swiftclient import utils as swiftclient_utils
+import yaml
+
+from heat_integrationtests.common import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class AwsStackTest(test.HeatIntegrationTest):
+    test_template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Resources:
+  the_nested:
+    Type: AWS::CloudFormation::Stack
+    Properties:
+      TemplateURL: the.yaml
+      Parameters:
+        KeyName: foo
+Outputs:
+  output_foo:
+    Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]}
+'''
+
+    nested_template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+  KeyName:
+    Type: String
+Outputs:
+  Foo:
+    Value: bar
+'''
+
+    update_template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+  KeyName:
+    Type: String
+Outputs:
+  Foo:
+    Value: foo
+'''
+
+    nested_with_res_template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+  KeyName:
+    Type: String
+Resources:
+  NestedResource:
+    Type: OS::Heat::RandomString
+Outputs:
+  Foo:
+    Value: {"Fn::GetAtt": [NestedResource, value]}
+'''
+
+    def setUp(self):
+        super(AwsStackTest, self).setUp()
+        self.client = self.orchestration_client
+        self.object_container_name = AwsStackTest.__name__
+        self.project_id = self.identity_client.auth_ref.project_id
+        self.object_client.put_container(self.object_container_name)
+        self.nested_name = '%s.yaml' % test.rand_name()
+
+    def publish_template(self, name, contents):
+        oc = self.object_client
+
+        # post the object
+        oc.put_object(self.object_container_name, name, contents)
+        # TODO(asalkeld) see if this is causing problems.
+        # self.addCleanup(self.object_client.delete_object,
+        #                self.object_container_name, name)
+
+        # make the tempurl
+        key_header = 'x-account-meta-temp-url-key'
+        if key_header not in oc.head_account():
+            swift_key = hashlib.sha224(
+                str(random.getrandbits(256))).hexdigest()[:32]
+            LOG.warn('setting swift key to %s' % swift_key)
+            oc.post_account({key_header: swift_key})
+        key = oc.head_account()[key_header]
+        path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
+                                      self.object_container_name, name)
+        timeout = self.conf.build_timeout * 10
+        tempurl = swiftclient_utils.generate_temp_url(path, timeout,
+                                                      key, 'GET')
+        sw_url = urlparse.urlparse(oc.url)
+        return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
+
+    def test_nested_stack_create(self):
+        url = self.publish_template(self.nested_name, self.nested_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        stack_identifier = self.stack_create(template=self.template)
+        stack = self.client.stacks.get(stack_identifier)
+        self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
+        self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
+
+    def test_nested_stack_create_with_timeout(self):
+        url = self.publish_template(self.nested_name, self.nested_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        timeout_template = yaml.load(self.template)
+        props = timeout_template['Resources']['the_nested']['Properties']
+        props['TimeoutInMinutes'] = '50'
+
+        stack_identifier = self.stack_create(
+            template=timeout_template)
+        stack = self.client.stacks.get(stack_identifier)
+        self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
+        self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
+
+    def test_nested_stack_adopt_ok(self):
+        url = self.publish_template(self.nested_name,
+                                    self.nested_with_res_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        adopt_data = {
+            "resources": {
+                "the_nested": {
+                    "resource_id": "test-res-id",
+                    "resources": {
+                        "NestedResource": {
+                            "type": "OS::Heat::RandomString",
+                            "resource_id": "test-nested-res-id",
+                            "resource_data": {"value": "goopie"}
+                        }
+                    }
+                }
+            },
+            "environment": {"parameters": {}},
+            "template": yaml.load(self.template)
+        }
+
+        stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
+
+        self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
+        stack = self.client.stacks.get(stack_identifier)
+        self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
+
+    def test_nested_stack_adopt_fail(self):
+        url = self.publish_template(self.nested_name,
+                                    self.nested_with_res_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        adopt_data = {
+            "resources": {
+                "the_nested": {
+                    "resource_id": "test-res-id",
+                    "resources": {
+                    }
+                }
+            },
+            "environment": {"parameters": {}},
+            "template": yaml.load(self.template)
+        }
+
+        stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
+                                            wait_for_status='ADOPT_FAILED')
+        rsrc = self.client.resources.get(stack_identifier, 'the_nested')
+        self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
+
+    def test_nested_stack_update(self):
+        url = self.publish_template(self.nested_name, self.nested_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        stack_identifier = self.stack_create(template=self.template)
+        original_nested_id = self.assert_resource_is_a_stack(
+            stack_identifier, 'the_nested')
+        stack = self.client.stacks.get(stack_identifier)
+        self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
+
+        new_template = yaml.load(self.template)
+        props = new_template['Resources']['the_nested']['Properties']
+        props['TemplateURL'] = self.publish_template(self.nested_name,
+                                                     self.update_template)
+
+        self.update_stack(stack_identifier, new_template)
+
+        # Expect the physical resource name staying the same after update,
+        # so that the nested was actually updated instead of replaced.
+        new_nested_id = self.assert_resource_is_a_stack(
+            stack_identifier, 'the_nested')
+        self.assertEqual(original_nested_id, new_nested_id)
+        updt_stack = self.client.stacks.get(stack_identifier)
+        self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
+
+    def test_nested_stack_suspend_resume(self):
+        url = self.publish_template(self.nested_name, self.nested_template)
+        self.template = self.test_template.replace('the.yaml', url)
+        stack_identifier = self.stack_create(template=self.template)
+
+        self.client.actions.suspend(stack_id=stack_identifier)
+        self._wait_for_resource_status(
+            stack_identifier, 'the_nested', 'SUSPEND_COMPLETE')
+
+        self.client.actions.resume(stack_id=stack_identifier)
+        self._wait_for_resource_status(
+            stack_identifier, 'the_nested', 'RESUME_COMPLETE')