Merge "Adding basic test to exercise the heat event APIs."
diff --git a/functional/test_stack_events.py b/functional/test_stack_events.py
new file mode 100644
index 0000000..b1b2339
--- /dev/null
+++ b/functional/test_stack_events.py
@@ -0,0 +1,112 @@
+#    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.
+
+from heat_integrationtests.functional import functional_base
+
+
+class StackEventsTest(functional_base.FunctionalTestsBase):
+
+    template = '''
+heat_template_version: 2014-10-16
+parameters:
+resources:
+  test_resource:
+    type: OS::Heat::TestResource
+    properties:
+      value: 'test1'
+      fail: False
+      update_replace: False
+      wait_secs: 0
+outputs:
+  resource_id:
+    description: 'ID of resource'
+    value: { get_resource: test_resource }
+'''
+
+    def setUp(self):
+        super(StackEventsTest, self).setUp()
+
+    def _verify_event_fields(self, event, event_characteristics):
+        self.assertIsNotNone(event_characteristics)
+        self.assertIsNotNone(event.event_time)
+        self.assertIsNotNone(event.links)
+        self.assertIsNotNone(event.logical_resource_id)
+        self.assertIsNotNone(event.resource_status)
+        self.assertIn(event.resource_status, event_characteristics[1])
+        self.assertIsNotNone(event.resource_status_reason)
+        self.assertIsNotNone(event.id)
+
+    def test_event(self):
+        parameters = {}
+
+        test_stack_name = self._stack_rand_name()
+        stack_identifier = self.stack_create(
+            stack_name=test_stack_name,
+            template=self.template,
+            parameters=parameters
+        )
+
+        expected_status = ['CREATE_IN_PROGRESS', 'CREATE_COMPLETE']
+        event_characteristics = {
+            test_stack_name: ('OS::Heat::Stack', expected_status),
+            'test_resource': ('OS::Heat::TestResource', expected_status)}
+
+        # List stack events
+        # API: GET /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/events
+        stack_events = self.client.events.list(stack_identifier)
+
+        for stack_event in stack_events:
+            # Key on an expected/valid resource name
+            self._verify_event_fields(
+                stack_event,
+                event_characteristics[stack_event.resource_name])
+
+            # Test the event filtering API based on this resource_name
+            # /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name}/events
+            resource_events = self.client.events.list(
+                stack_identifier,
+                stack_event.resource_name)
+
+            # Resource events are a subset of the original stack event list
+            self.assertTrue(len(resource_events) < len(stack_events))
+
+            # Get the event details for each resource event
+            for resource_event in resource_events:
+                # A resource_event should be in the original stack event list
+                self.assertIn(resource_event, stack_events)
+                # Given a filtered list, the resource names should be identical
+                self.assertEqual(
+                    resource_event.resource_name,
+                    stack_event.resource_name)
+                # Verify all fields, keying off the resource_name
+                self._verify_event_fields(
+                    resource_event,
+                    event_characteristics[resource_event.resource_name])
+
+                # Exercise the event details API
+                # /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name}/events/{event_id}
+                event_details = self.client.events.get(
+                    stack_identifier,
+                    resource_event.resource_name,
+                    resource_event.id)
+                self._verify_event_fields(
+                    event_details,
+                    event_characteristics[event_details.resource_name])
+                # The names should be identical to the non-detailed event
+                self.assertEqual(
+                    resource_event.resource_name,
+                    event_details.resource_name)
+                # Verify the extra field in the detail results
+                self.assertIsNotNone(event_details.resource_type)
+                self.assertEqual(
+                    event_characteristics[event_details.resource_name][0],
+                    event_details.resource_type)