Repository: getmoto/moto

Issue:
Cloudformation: Incorrect/missing outputs when creating a change set
**moto version:**
1.3.15 (spulec/moto: master)

**module:**
mock_cloudformation

**action:**
`create_change_set`
When we create a change set and describe it using the following code, the result is not the same as running using boto3:
```
dummy_template = {
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Stack 1",
    "Resources": {
        "BucketResource": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "BucketName": "moto-test-123456789",
            },
        }
    },
}

dummy_template_json = json.dumps(dummy_template)


@mock_cloudformation
def test_change_set():
    cf_conn = boto3.client("cloudformation", region_name="eu-west-1")
    cf_conn.create_change_set(
        StackName="NewStack",
        TemplateBody=dummy_template_json,
        ChangeSetName="NewChangeSet",
        ChangeSetType="CREATE",
    )

    print(cf_conn.describe_change_set(ChangeSetName="NewChangeSet"))


if __name__ == '__main__':
    test_change_set()
```

**expected behavior:**
```
aws cloudformation describe-change-set --change-set-name NewChangeSet --stack-name NewStack
{
    "Changes": [
        {
            "Type": "Resource",
            "ResourceChange": {
                "Action": "Add",
                "LogicalResourceId": "BucketResource",
                "ResourceType": "AWS::S3::Bucket",
                "Scope": [],
                "Details": []
            }
        }
    ],
    "ChangeSetName": "NewChangeSet",
    "ChangeSetId": "arn:aws:cloudformation:eu-west-1:664685189390:changeSet/NewChangeSet/ae79ab51-a4a8-4f4f-8306-af6117f2a1ef",
    "StackId": "arn:aws:cloudformation:eu-west-1:664685189390:stack/NewStack/0b05cf30-a0e0-11ea-9051-0aa5f1c3ad6c",
    "StackName": "NewStack",
    "Description": "Stack 1",
    "Parameters": null,
    "CreationTime": "2020-05-28T12:37:50.669Z",
    "ExecutionStatus": "AVAILABLE",
    "Status": "CREATE_COMPLETE",
    "StatusReason": null,
    "NotificationARNs": [],
    "RollbackConfiguration": {},
    "Capabilities": [],
    "Tags": null
}
```
- Status should be 'CREATE_COMPLETE' (should be fixed by PR #3033)
- Execution status should be 'AVAILABLE' (should be fixed by PR #3033)
- Creation time should be set to the datetime.utcnow() (should be fixed by PR #3033)
- Stack Id should contain the same region in its name as the change set itself, not us-east-1 (should be fixed by PR #3033)
- Changes are missing

**actual behavior:**
```
{
  'ChangeSetName': 'NewChangeSet',
  'ChangeSetId': 'arn:aws:cloudformation:eu-west-1:123456789:changeSet/NewChangeSet/3b0423d6-7514-4b50-91cd-46856bd251de',
  'StackId': 'arn:aws:cloudformation:us-east-1:123456789:stack/NewStack/f62e9101-95c5-4967-a704-fc62190d87ee',
  'StackName': 'NewStack',
  'Description': 'Stack 1',
  'Parameters': [
    
  ],
  'CreationTime': datetime.datetime(2011, 5, 23, 15, 47, 44, tzinfo=tzutc()),
  'ExecutionStatus': '',
  'Status': 'REVIEW_IN_PROGRESS',
  'StatusReason': '',
  'NotificationARNs': [
    
  ],
  'ResponseMetadata': {
    'HTTPStatusCode': 200,
    'HTTPHeaders': {
      'server': 'amazon.com'
    },
    'RetryAttempts': 0
  }
}
```


Discussion:

Resolving patch:
diff --git a/moto/cloudformation/models.py b/moto/cloudformation/models.py
--- a/moto/cloudformation/models.py
+++ b/moto/cloudformation/models.py
@@ -240,7 +240,8 @@ def __init__(
         self.resource_map = self._create_resource_map()
         self.output_map = self._create_output_map()
         if create_change_set:
-            self.status = "REVIEW_IN_PROGRESS"
+            self.status = "CREATE_COMPLETE"
+            self.execution_status = "AVAILABLE"
         else:
             self.create_resources()
             self._add_stack_event("CREATE_COMPLETE")
@@ -397,6 +398,7 @@ def __init__(
         self.change_set_id = change_set_id
         self.change_set_name = change_set_name
         self.changes = self.diff(template=template, parameters=parameters)
+        self.creation_time = datetime.utcnow()
 
     def diff(self, template, parameters=None):
         self.template = template
@@ -587,7 +589,7 @@ def create_change_set(
             if stack is None:
                 raise ValidationError(stack_name)
         else:
-            stack_id = generate_stack_id(stack_name)
+            stack_id = generate_stack_id(stack_name, region_name)
             stack_template = template
 
         change_set_id = generate_changeset_id(change_set_name, region_name)
diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py
--- a/moto/cloudformation/responses.py
+++ b/moto/cloudformation/responses.py
@@ -609,7 +609,7 @@ def update_stack_instances(self):
         </member>
       {% endfor %}
     </Parameters>
-    <CreationTime>2011-05-23T15:47:44Z</CreationTime>
+    <CreationTime>{{ change_set.creation_time_iso_8601 }}</CreationTime>
     <ExecutionStatus>{{ change_set.execution_status }}</ExecutionStatus>
     <Status>{{ change_set.status }}</Status>
     <StatusReason>{{ change_set.status_reason }}</StatusReason>


Test patch:
diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
--- a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
+++ b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
@@ -819,7 +819,7 @@ def test_create_change_set_from_s3_url():
         in response["Id"]
     )
     assert (
-        "arn:aws:cloudformation:us-east-1:123456789:stack/NewStack"
+        "arn:aws:cloudformation:us-west-1:123456789:stack/NewStack"
         in response["StackId"]
     )
 
@@ -838,7 +838,12 @@ def test_describe_change_set():
 
     stack["ChangeSetName"].should.equal("NewChangeSet")
     stack["StackName"].should.equal("NewStack")
-    stack["Status"].should.equal("REVIEW_IN_PROGRESS")
+    stack["Status"].should.equal("CREATE_COMPLETE")
+    stack["ExecutionStatus"].should.equal("AVAILABLE")
+    two_secs_ago = datetime.now(tz=pytz.UTC) - timedelta(seconds=2)
+    assert (
+        two_secs_ago < stack["CreationTime"] < datetime.now(tz=pytz.UTC)
+    ), "Change set should have been created recently"
 
     cf_conn.create_change_set(
         StackName="NewStack",
@@ -868,7 +873,7 @@ def test_execute_change_set_w_arn():
     )
     ec2.describe_instances()["Reservations"].should.have.length_of(0)
     cf_conn.describe_change_set(ChangeSetName="NewChangeSet")["Status"].should.equal(
-        "REVIEW_IN_PROGRESS"
+        "CREATE_COMPLETE"
     )
     # Execute change set
     cf_conn.execute_change_set(ChangeSetName=change_set["Id"])