Fix race condition for WaitCondition with several signals

This fix is based on changes introduced in patch
Ibf9dd58a66a77d9ae9d4b519b0f11567977f416c.

Follow changes were done in this patch:
 - According previous item code for calculating metadata of
   wait_condition_handle was moved to separate method -
   normalise_signal_data().
 - Same method was implemented for BaseWaitConditionHandle class, which
   returns original signal data without changes.
 - handle_signal method for BaseWaitConditionHandle class was updated:
   * all code related with updating and verification metadata was moved
     to merge_signal_metadata internal method, which will be called from
     metadata_set method.
   * if/else block was changed to raise error in case, when metadata has
     wrong format, so else section was deleted.
 - corresponding tests for waitcondition resource, which expect several
   signals was added.

Change-Id: Ia25146a742ce79dbb0480d9053131216037e5305
Co-Authored-By: Zane Bitter <zbitter@redhat.com>
Closes-Bug: #1497274
diff --git a/functional/test_os_wait_condition.py b/functional/test_os_wait_condition.py
new file mode 100644
index 0000000..5eb3294
--- /dev/null
+++ b/functional/test_os_wait_condition.py
@@ -0,0 +1,106 @@
+#    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 OSWaitCondition(functional_base.FunctionalTestsBase):
+
+    template = '''
+heat_template_version: 2013-05-23
+parameters:
+  flavor:
+    type: string
+  image:
+    type: string
+  network:
+    type: string
+  timeout:
+    type: number
+    default: 60
+resources:
+  instance1:
+    type: OS::Nova::Server
+    properties:
+      flavor: {get_param: flavor}
+      image: {get_param: image}
+      networks:
+      - network: {get_param: network}
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: '#!/bin/sh
+
+            wc_notify --data-binary ''{"status": "SUCCESS"}''
+
+            # signals with reason
+
+            wc_notify --data-binary ''{"status": "SUCCESS", "reason":
+            "signal2"}''
+
+            # signals with data
+
+            wc_notify --data-binary ''{"status": "SUCCESS", "reason":
+            "signal3", "data": "data3"}''
+
+            wc_notify --data-binary ''{"status": "SUCCESS", "reason":
+            "signal4", "data": "data4"}''
+
+            # check signals with the same number
+
+            wc_notify --data-binary ''{"status": "SUCCESS", "id": "5"}''
+
+            wc_notify --data-binary ''{"status": "SUCCESS", "id": "5"}''
+
+            # loop for 25 signals without reasons and data
+
+            for i in `seq 1 25`; do wc_notify --data-binary ''{"status":
+            "SUCCESS"}'' & done
+
+            wait
+            '
+          params:
+            wc_notify:
+              get_attr: [wait_handle, curl_cli]
+
+  wait_condition:
+    type: OS::Heat::WaitCondition
+    depends_on: instance1
+    properties:
+      count: 30
+      handle: {get_resource: wait_handle}
+      timeout: {get_param: timeout}
+
+  wait_handle:
+    type: OS::Heat::WaitConditionHandle
+
+outputs:
+  curl_cli:
+    value:
+      get_attr: [wait_handle, curl_cli]
+  wc_data:
+    value:
+      get_attr: [wait_condition, data]
+'''
+
+    def setUp(self):
+        super(OSWaitCondition, self).setUp()
+        if not self.conf.minimal_image_ref:
+            raise self.skipException("No minimal image configured to test")
+        if not self.conf.minimal_instance_type:
+            raise self.skipException("No minimal flavor configured to test")
+
+    def test_create_stack_with_multi_signal_waitcondition(self):
+        params = {'flavor': self.conf.minimal_instance_type,
+                  'image': self.conf.minimal_image_ref,
+                  'network': self.conf.fixed_network_name}
+        self.stack_create(template=self.template, parameters=params)