""" Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ import string from unittest import TestCase from cfnlint.conditions._utils import get_hash from cfnlint.decode import decode_str from cfnlint.template import Template class TestConditions(TestCase): """Test Conditions""" def test_bad_condition_definition(self): """Badly formatted condition statements will return no results""" template = decode_str( """ Conditions: IsProd: !Equals [!Ref Environment, "prod", "production"] IsUsEast1: !Equals [!Ref "AWS::Region", "us-east-1"] """ )[0] cfn = Template("", template) self.assertEqual( len(cfn.conditions._conditions), 1 ) # would be 2 but IsProd fails # test coverage for KeyErrors in the following functions self.assertTrue(cfn.conditions.check_implies({"Test": True}, "IsUsEast1")) self.assertEqual( list(cfn.conditions.build_scenarios(["IsProd", "IsUsEast1"])), [] ) def test_run_away_scenarios(self): """We cap runaway scenarios""" template = { "Parameters": {}, "Conditions": {}, } condition_names = [] for p in string.ascii_letters[0:10]: template["Parameters"][f"{p}Parameter"] = { "Type": "String", } template["Conditions"][f"{p}Condition"] = { "Fn::Equals": [{"Ref": f"{p}Parameter"}, "{p}"] } condition_names.append(f"{p}Condition") cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 10) self.assertEqual( len(list(cfn.conditions.build_scenarios(condition_names))), cfn.conditions._max_scenarios, ) def test_check_implies(self): """We properly validate implies scenarios""" template = { "Parameters": {}, "Conditions": {}, } condition_names = [] for p in string.ascii_letters[0:4]: template["Parameters"][f"{p}Parameter"] = { "Type": "String", } template["Conditions"][f"{p}Condition"] = { "Fn::Equals": [{"Ref": f"{p}Parameter"}, "{p}"] } condition_names.append(f"{p}Condition") cfn = Template("", template) self.assertFalse( cfn.conditions.check_implies({"aCondition": False}, "aCondition") ) self.assertTrue( cfn.conditions.check_implies({"aCondition": True}, "aCondition") ) self.assertTrue( cfn.conditions.check_implies( {"aCondition": True, "bCondition": False}, "aCondition" ) ) def test_check_always_true_or_false(self): """We properly validate static equals""" template = decode_str( """ Parameters: FalseParameter: Default: "false" Type: String Conditions: IsTrue: !Equals ["true", "true"] IsFalse: !Equals [!Ref FalseParameter, !Ref FalseParameter] """ )[0] cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 2) # test coverage for KeyErrors in the following functions self.assertFalse(cfn.conditions.check_implies({"IsTrue": True}, "IsFalse")) def test_check_never_false(self): """With allowed values two conditions can not both be false""" template = decode_str( """ Parameters: Environment: Type: String AllowedValues: ["prod", "dev"] Conditions: IsProd: !Equals [!Ref Environment, "prod"] IsDev: !Equals [!Ref Environment, "dev"] """ )[0] cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 2) self.assertListEqual( list(cfn.conditions.build_scenarios(["IsProd", "IsDev"])), [ {"IsProd": True, "IsDev": False}, {"IsProd": False, "IsDev": True}, ], ) def test_check_can_be_false(self): """With allowed values two conditions can both be false""" template = decode_str( """ Parameters: Environment: Type: String AllowedValues: ["prod", "dev", "stage"] Conditions: IsProd: !Equals [!Ref Environment, "prod"] IsDev: !Equals [!Ref Environment, "dev"] """ )[0] cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 2) self.assertListEqual( list(cfn.conditions.build_scenarios(["IsProd", "IsDev"])), [ {"IsProd": True, "IsDev": False}, {"IsProd": False, "IsDev": True}, {"IsProd": False, "IsDev": False}, ], ) def test_check_can_be_good_when_condition_value(self): """Some times a condition Equals doesn't match to allowed values""" template = decode_str( """ Parameters: Environment: Type: String AllowedValues: ["prod", "dev", "stage"] Conditions: IsGamma: !Equals [!Ref Environment, "gamma"] IsBeta: !Equals ["beta", !Ref Environment] """ )[0] cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 2) self.assertListEqual( list(cfn.conditions.build_scenarios(["IsGamma", "IsBeta"])), [ {"IsBeta": False, "IsGamma": False}, ], ) self.assertListEqual( list(cfn.conditions.build_scenarios(["IsGamma"])), [ {"IsGamma": False}, ], ) def test_check_condition_region(self): """Regional based condition testing""" template = decode_str( """ Parameters: Environment: Type: String AllowedValues: ["prod", "dev", "stage"] Conditions: IsUsEast1: !Equals [!Ref AWS::Region, "us-east-1"] IsUsWest2: !Equals ["us-west-2", !Ref AWS::Region] IsProd: !Equals [!Ref Environment, "prod"] """ )[0] cfn = Template("", template) self.assertEqual(len(cfn.conditions._conditions), 3) self.assertListEqual( list(cfn.conditions.build_scenerios_on_region("IsUsEast1", "us-east-1")), [ True, ], ) self.assertListEqual( list(cfn.conditions.build_scenerios_on_region("IsUsEast1", "us-west-2")), [ False, ], ) self.assertListEqual( list(cfn.conditions.build_scenerios_on_region("IsUsWest2", "us-west-2")), [ True, ], ) self.assertListEqual( list(cfn.conditions.build_scenerios_on_region("IsUsWest2", "us-east-1")), [ False, ], ) self.assertListEqual( list(cfn.conditions.build_scenerios_on_region("IsProd", "us-east-1")), [ True, False, ], ) def test_test_condition(self): """Get condition and test""" template = decode_str( """ Parameters: Environment: Type: String AllowedValues: ["prod", "dev", "stage"] Conditions: IsUsEast1: !Equals [!Ref AWS::Region, "us-east-1"] IsUsWest2: !Equals ["us-west-2", !Ref AWS::Region] IsProd: !Equals [!Ref Environment, "prod"] IsUsEast1AndProd: !And [!Condition IsUsEast1, !Condition IsProd] """ )[0] h_region = get_hash({"Ref": "AWS::Region"}) h_environment = get_hash({"Ref": "Environment"}) cfn = Template("", template) self.assertTrue(cfn.conditions.get("IsUsEast1").test({h_region: "us-east-1"})) self.assertFalse(cfn.conditions.get("IsProd").test({h_environment: "dev"})) self.assertTrue( cfn.conditions.get("IsUsEast1AndProd").test( {h_region: "us-east-1", h_environment: "prod"} ) ) self.assertFalse( cfn.conditions.get("IsUsEast1AndProd").test( {h_region: "us-east-1", h_environment: "dev"} ) )