Allow referencing conditions by name

This change allows reference with other conditions by name in
definition of a condition, something like:
   conditions:
     cd1: {equals: [{get_param: env_type}, 'prod']}
     cd2: {not: cd1}
     cd3: {equals: [{get_param: zone}, 'fujian']}
     cd4: {and: [cd1, cd3]}

Change-Id: I6a0a00c23aa7d559dedd6998adaa7962d607f315
Co-Authored-By: huangtianhua <huangtianhua@huawei.com>
Blueprint: support-conditions-function
Related-Bug: #1621529
diff --git a/functional/test_conditions.py b/functional/test_conditions.py
index 95b43fe..659d372 100644
--- a/functional/test_conditions.py
+++ b/functional/test_conditions.py
@@ -38,6 +38,14 @@
     - Fn::Equals:
       - Ref: zone
       - beijing
+  Xian_Zone:
+    Fn::Equals:
+    - Ref: zone
+    - xian
+  Xianyang_Zone:
+    Fn::Equals:
+    - Ref: zone
+    - xianyang
   Fujian_Zone:
     Fn::Or:
     - Fn::Equals:
@@ -46,6 +54,16 @@
     - Fn::Equals:
       - Ref: zone
       - xiamen
+  Fujian_Prod:
+    Fn::And:
+    - Fujian_Zone
+    - Prod
+  Shannxi_Provice:
+    Fn::Or:
+    - Xian_Zone
+    - Xianyang_Zone
+  Not_Shannxi:
+    Fn::Not: [Shannxi_Provice]
 Resources:
   test_res:
     Type: OS::Heat::TestResource
@@ -71,6 +89,21 @@
     Condition: Fujian_Zone
     Properties:
       value: fujian_res
+  fujian_prod_res:
+    Type: OS::Heat::TestResource
+    Condition: Fujian_Prod
+    Properties:
+      value: fujian_prod_res
+  shannxi_res:
+    Type: OS::Heat::TestResource
+    Condition: Shannxi_Provice
+    Properties:
+      value: shannxi_res
+  not_shannxi_res:
+    Type: OS::Heat::TestResource
+    Condition: Not_Shannxi
+    Properties:
+      value: not_shannxi_res
 Outputs:
   res_value:
     Value: {"Fn::GetAtt": [prod_res, output]}
@@ -112,6 +145,14 @@
     - equals:
       - get_param: env_type
       - prod
+  xian_zone:
+    equals:
+    - get_param: zone
+    - xian
+  xianyang_zone:
+    equals:
+    - get_param: zone
+    - xianyang
   fujian_zone:
     or:
     - equals:
@@ -120,6 +161,16 @@
     - equals:
       - get_param: zone
       - xiamen
+  fujian_prod:
+    and:
+    - fujian_zone
+    - prod
+  shannxi_provice:
+    or:
+    - xian_zone
+    - xianyang_zone
+  not_shannxi:
+    not: shannxi_provice
 resources:
   test_res:
     type: OS::Heat::TestResource
@@ -145,6 +196,21 @@
     condition: fujian_zone
     properties:
       value: fujian_res
+  fujian_prod_res:
+    type: OS::Heat::TestResource
+    condition: fujian_prod
+    properties:
+      value: fujian_prod_res
+  shannxi_res:
+    type: OS::Heat::TestResource
+    condition: shannxi_provice
+    properties:
+      value: shannxi_res
+  not_shannxi_res:
+    type: OS::Heat::TestResource
+    condition: not_shannxi
+    properties:
+      value: not_shannxi_res
 outputs:
   res_value:
     value: {get_attr: [prod_res, output]}
@@ -244,30 +310,43 @@
     def setUp(self):
         super(CreateUpdateResConditionTest, self).setUp()
 
-    def res_assert_for_prod(self, resources, bj_prod=True, fj_zone=False):
+    def res_assert_for_prod(self, resources, bj_prod=True, fj_zone=False,
+                            shannxi_provice=False):
         res_names = [res.resource_name for res in resources]
         if bj_prod:
-            self.assertEqual(3, len(resources))
+            self.assertEqual(4, len(resources))
             self.assertIn('beijing_prod_res', res_names)
+            self.assertIn('not_shannxi_res', res_names)
         elif fj_zone:
-            self.assertEqual(3, len(resources))
+            self.assertEqual(5, len(resources))
             self.assertIn('fujian_res', res_names)
             self.assertNotIn('beijing_prod_res', res_names)
+            self.assertIn('not_shannxi_res', res_names)
+            self.assertIn('fujian_prod_res', res_names)
+        elif shannxi_provice:
+            self.assertEqual(3, len(resources))
+            self.assertIn('shannxi_res', res_names)
         else:
-            self.assertEqual(2, len(resources))
+            self.assertEqual(3, len(resources))
+            self.assertIn('not_shannxi_res', res_names)
         self.assertIn('prod_res', res_names)
         self.assertIn('test_res', res_names)
 
-    def res_assert_for_test(self, resources, fj_zone=False):
+    def res_assert_for_test(self, resources, fj_zone=False,
+                            shannxi_provice=False):
         res_names = [res.resource_name for res in resources]
 
         if fj_zone:
-            self.assertEqual(3, len(resources))
+            self.assertEqual(4, len(resources))
             self.assertIn('fujian_res', res_names)
-        else:
-            self.assertEqual(2, len(resources))
+            self.assertIn('not_shannxi_res', res_names)
+        elif shannxi_provice:
+            self.assertEqual(3, len(resources))
             self.assertNotIn('fujian_res', res_names)
-
+            self.assertIn('shannxi_res', res_names)
+        else:
+            self.assertEqual(3, len(resources))
+            self.assertIn('not_shannxi_res', res_names)
         self.assertIn('test_res', res_names)
         self.assertIn('test_res1', res_names)
         self.assertNotIn('prod_res', res_names)
@@ -334,6 +413,15 @@
         self.res_assert_for_test(resources, fj_zone=True)
         self.output_assert_for_test(stack_identifier)
 
+        parms = {'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=cfn_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_test(resources, shannxi_provice=True)
+        self.output_assert_for_test(stack_identifier)
+
         parms = {'env_type': 'prod'}
         self.update_stack(stack_identifier,
                           template=cfn_template,
@@ -363,6 +451,17 @@
         self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True)
         self.output_assert_for_prod(stack_identifier, False)
 
+        parms = {'env_type': 'prod',
+                 'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=cfn_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
+                                 shannxi_provice=True)
+        self.output_assert_for_prod(stack_identifier, False)
+
     def test_stack_create_update_cfn_template_prod_to_test(self):
         parms = {'env_type': 'prod'}
         stack_identifier = self.stack_create(template=cfn_template,
@@ -381,6 +480,28 @@
         self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True)
         self.output_assert_for_prod(stack_identifier, bj_prod=False)
 
+        parms = {'zone': 'xianyang',
+                 'env_type': 'prod'}
+        self.update_stack(stack_identifier,
+                          template=cfn_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
+                                 shannxi_provice=True)
+        self.output_assert_for_prod(stack_identifier, bj_prod=False)
+
+        parms = {'zone': 'shanghai',
+                 'env_type': 'prod'}
+        self.update_stack(stack_identifier,
+                          template=cfn_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
+                                 shannxi_provice=False)
+        self.output_assert_for_prod(stack_identifier, bj_prod=False)
+
         parms = {'env_type': 'test'}
         self.update_stack(stack_identifier,
                           template=cfn_template,
@@ -400,12 +521,32 @@
         self.res_assert_for_test(resources, fj_zone=True)
         self.output_assert_for_test(stack_identifier)
 
+        parms = {'env_type': 'test',
+                 'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=cfn_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_test(resources, fj_zone=False,
+                                 shannxi_provice=True)
+        self.output_assert_for_test(stack_identifier)
+
     def test_stack_create_update_hot_template_test_to_prod(self):
         stack_identifier = self.stack_create(template=hot_template)
         resources = self.client.resources.list(stack_identifier)
         self.res_assert_for_test(resources)
         self.output_assert_for_test(stack_identifier)
 
+        parms = {'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=hot_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_test(resources, shannxi_provice=True)
+        self.output_assert_for_test(stack_identifier)
+
         parms = {'env_type': 'prod'}
         self.update_stack(stack_identifier,
                           template=hot_template,
@@ -425,6 +566,16 @@
         self.res_assert_for_prod(resources, False)
         self.output_assert_for_prod(stack_identifier, False)
 
+        parms = {'env_type': 'prod',
+                 'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=hot_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_prod(resources, False, shannxi_provice=True)
+        self.output_assert_for_prod(stack_identifier, False)
+
     def test_stack_create_update_hot_template_prod_to_test(self):
         parms = {'env_type': 'prod'}
         stack_identifier = self.stack_create(template=hot_template,
@@ -433,6 +584,16 @@
         self.res_assert_for_prod(resources)
         self.output_assert_for_prod(stack_identifier)
 
+        parms = {'env_type': 'prod',
+                 'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=hot_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_prod(resources, False, shannxi_provice=True)
+        self.output_assert_for_prod(stack_identifier, False)
+
         parms = {'env_type': 'test'}
         self.update_stack(stack_identifier,
                           template=hot_template,
@@ -442,6 +603,17 @@
         self.res_assert_for_test(resources)
         self.output_assert_for_test(stack_identifier)
 
+        parms = {'env_type': 'test',
+                 'zone': 'xianyang'}
+        self.update_stack(stack_identifier,
+                          template=hot_template,
+                          parameters=parms)
+
+        resources = self.client.resources.list(stack_identifier)
+        self.res_assert_for_test(resources, fj_zone=False,
+                                 shannxi_provice=True)
+        self.output_assert_for_test(stack_identifier)
+
     def test_condition_rename(self):
         stack_identifier = self.stack_create(template=before_rename_tmpl)
         self.update_stack(stack_identifier, template=after_rename_tmpl)