def test_function_order(): t = { "Parameters": {"Test": {"Value": "test"}}, "Conditions": {"test": True}, } template = Template(t) test_if = { "Fn::Cidr": { "Fn::If": "select", } } with pytest.raises(ValueError) as ex: _ = template.resolve_values(test_if, functions.ALL_FUNCTIONS) assert "Fn::If not allowed here." in str(ex) with pytest.raises(ValueError) as ex: _ = template.resolve_values({"Fn::Base64": ""}, functions.CONDITIONS) assert "Fn::Base64 not allowed here." in str(ex) with pytest.raises(ValueError) as ex: _ = template.resolve_values({"Fn::Not": ""}, functions.INTRINSICS) assert "Fn::Not not allowed here." in str(ex)
def test_render_invalid_ref(): t = { "Parameters": {"testParam": {"Default": "Test Value"}}, "Conditions": {"Bar": {"Fn::Equals": [{"Ref": "testParam"}, "Test Value"]}}, "Resources": { "Foo": {"Condition": "Bar", "Properties": {"Name": {"Ref": "FAKE!"}}} }, } template = Template(t) with pytest.raises(Exception) as ex: _ = template.render() assert "not a valid Resource" in str(ex)
def test_if(fake_t: Template): template = {"Conditions": {"test": False}} fake_t.template = template with pytest.raises(TypeError) as e: result = functions.if_(fake_t, {}) assert "must be a List, not dict." in str(e.value) with pytest.raises(ValueError) as e: result = functions.if_(fake_t, [0]) assert "True value and a False value." in str(e.value) with pytest.raises(TypeError) as e: result = functions.if_(fake_t, [0, 0, 0]) assert "Condition should be a String, not int." in str(e.value) result = functions.if_(fake_t, ["test", "true_value", "false_value"]) assert result == "false_value", "Should return the false value." template["Conditions"]["test"] = True result = functions.if_(fake_t, ["test", "true_value", "false_value"]) assert result == "true_value", "Should return the true value." with pytest.raises(Exception): # First value should the name of the condition to lookup functions.if_(fake_t, [True, "True", "False"])
def test_import_value(): name = "TestImport" value = "TestValue" imports = {} template = Template({}, imports) with pytest.raises(TypeError) as e: result = functions.import_value(template, []) assert "Export should be String, not list." in str(e) with pytest.raises(ValueError) as e: result = functions.import_value(template, name) assert "No imports have been configued" in str(e) imports["FakeTest"] = "Fake" with pytest.raises(KeyError) as e: result = functions.import_value(template, name) assert f"{name} not found" in str(e) imports[name] = value result = functions.import_value(template, name) assert result == value
def test_ref(): template = {"Parameters": {"foo": {"Value": "bar"}}, "Resources": {}} add_metadata(template, Template.Region) template = Template(template) for i in inspect.getmembers(Template): if not i[0].startswith("_"): if isinstance(i[1], str): result = functions.ref(template, f"AWS::{i[0]}") assert ( result == i[1] ), "Should be able to reference all pseudo variables." result = functions.ref(template, "foo") assert result == "bar", "Should reference parameters." with pytest.raises(Exception) as ex: result = functions.ref(template, "SomeResource") assert "not a valid Resource" in str(ex) fake = "AWS::FakeVar" with pytest.raises(ValueError) as e: functions.ref(template, fake) assert f"Unrecognized AWS Pseduo variable: '{fake}'." in str(e.value)
def test_resolve(): t = { "Parameters": {"Test": {"Value": "test"}}, "Conditions": {"test": True}, "Resources": {}, } template = Template(t) result = template.resolve_values({"Ref": "Test"}, functions.ALL_FUNCTIONS) assert result == "test", "Should resolve the value from the template." with pytest.raises(Exception) as ex: result = template.resolve_values({"Ref": "Test2"}, functions.ALL_FUNCTIONS) assert "not a valid Resource" in str(ex) result = template.resolve_values( {"level1": {"Fn::If": ["test", "True", "False"]}}, functions.ALL_FUNCTIONS ) assert result == {"level1": "True"}, "Should resolve nested dicts." result = template.resolve_values( [{"level1": {"Fn::If": ["test", "True", "False"]}}], functions.ALL_FUNCTIONS ) assert result == [{"level1": "True"}], "Should resolve nested lists." result = template.resolve_values("test", functions.ALL_FUNCTIONS) assert result == "test", "Should return regular strings."
def test_from_yaml(mock_open): template_dict = {"Foo": "bar"} template = Template.from_yaml("fake.yml") assert template.raw == "Foo: bar\n", "Should load a string version of our template" assert ( template.template == template_dict ), "Should convert string dict to dict object"
def test_constructor(template: Template): with pytest.raises(TypeError) as e: Template("not a dict") # type: ignore assert "Template should be a dict, not str." in str(e) with pytest.raises(TypeError) as e: Template({}, "") # type: ignore assert "Imports should be a dict, not str." in str(e) assert isinstance(template.raw, str), "Should load a string instance of template" assert isinstance( template.template, dict ), "Should return a dictionary of the template" assert ( template.Region == Template.Region ), "Should set the default region from the class."
def test_sub_s(): template_dict = {"Parameters": {"Foo": {"Value": "bar"}}} template = Template(template_dict) result = functions.sub_s(template, "Foo ${Foo}") assert result == "Foo bar", "Should subsuite a parameter." result = functions.sub_s(template, "not ${!Test}") assert result == "not ${Test}", "Should return a string literal." add_metadata(template_dict, "us-east-1") template = Template(template_dict) result = functions.sub(template, "${AWS::Region} ${Foo} ${!BASH_VAR}") assert result == "us-east-1 bar ${BASH_VAR}", "Should render multiple variables."
def test_render_true(): t = { "Parameters": {"testParam": {"Default": "Test Value"}}, "Conditions": {"Bar": {"Fn::Equals": [{"Ref": "testParam"}, "Test Value"]}}, "Resources": {"Foo": {"Condition": "Bar"}}, } template = Template(t) result = template.render() assert t is not result, "Should not pass back a pointer to the same dict." assert template.Region == Template.Region, "Should set the default region." assert "Foo" in result["Resources"], "Resources should not be empty." assert result["Conditions"]["Bar"], "Condition should be true." assert result["Metadata"], "Metadata should be set."
def test_get_att(): template = {"Resources": {}} add_metadata(template, Template.Region) template = Template(template) with pytest.raises(TypeError) as e: functions.get_att(template, {}) assert "Fn::GetAtt - The values must be a List, not dict." in str(e) with pytest.raises(ValueError) as e: functions.get_att(template, [0]) assert "the logicalNameOfResource and attributeName." in str(e) with pytest.raises(TypeError) as e: functions.get_att(template, [0, 0]) assert "logicalNameOfResource and attributeName must be String." in str(e) resource_name = "TestA" att = "TestAttribute" values = [resource_name, att] with pytest.raises(KeyError) as e: functions.get_att(template, values) assert f"{resource_name} not found in template." in str(e) template.template["Resources"]["TestA"] = {} result = functions.get_att(template, values) assert result == f"{resource_name}.{att}"
def test_render_false(): params = {"testParam": "Not Test Value"} t = { "Parameters": {"testParam": {"Default": "Test Value"}}, "Conditions": {"Bar": {"Fn::Equals": [{"Ref": "testParam"}, "Test Value"]}}, "Resources": { "Foo": {"Condition": "Bar"}, "Foobar": { "Properties": {"Something": {"Fn::Sub": "This is a ${testParam}"}} }, }, } template = Template(t) result = template.render(params, region="us-west-2") assert template.Region != Template.Region, "Should not set the default region." assert "Foo" not in result["Resources"], "Resources should be empty." assert not result["Conditions"]["Bar"], "Condition should be false."
def test_find_in_map(): template = {} add_metadata(template, Template.Region) template = Template(template) with pytest.raises(TypeError) as e: functions.find_in_map(template, {}) assert "must be a List, not dict." in str(e) with pytest.raises(ValueError) as e: functions.find_in_map(template, [0]) assert "a MapName, TopLevelKey and SecondLevelKey." in str(e) map_name = "TestMap" first_key = "FirstKey" second_key = "SecondKey" values = [map_name, first_key, second_key] with pytest.raises(KeyError) as e: functions.find_in_map(template, values) assert "Unable to find Mappings section in template." in str(e) template.template["Mappings"] = {} with pytest.raises(KeyError) as e: functions.find_in_map(template, values) assert f"Unable to find {map_name} in Mappings section of template." in str(e) template.template["Mappings"][map_name] = {} with pytest.raises(KeyError) as e: functions.find_in_map(template, values) assert f"Unable to find key {first_key}" in str(e) template.template["Mappings"][map_name][first_key] = {} with pytest.raises(KeyError) as e: functions.find_in_map(template, values) assert f"Unable to find key {second_key}" in str(e) expected = "ExpectedValue" template.template["Mappings"][map_name][first_key][second_key] = expected result = functions.find_in_map(template, values) assert result == expected
def test_condition(): template = {"Conditions": {"test": False}} template = Template(template) with pytest.raises(TypeError) as e: result = functions.condition(template, []) assert "String, not list." in str(e) with pytest.raises(KeyError) as e: result = functions.condition(template, "Fake") assert "Unable to find condition" in str(e) result = functions.condition(template, "test") assert result is False
def test_sub_l(): template_dict = {"Parameters": {"Foo": {"Value": "bar"}}} add_metadata(template_dict, "us-east-1") template = Template(template_dict) with pytest.raises(ValueError) as e: functions.sub_l(template, [0]) assert "source string and a Map of variables." in str(e) with pytest.raises(TypeError) as e: functions.sub_l(template, [0, 0]) assert "String and the second a Map." in str(e) var_map = {"LocalA": "TestA"} input_string = "${AWS::Region} ${Foo} ${!BASH_VAR} ${LocalA}" result = functions.sub_l(template, [input_string, var_map]) assert "us-east-1" in result, "Should render aws pseudo vars." assert "bar" in result, "Should render parameters." assert "${BASH_VAR}" in result, "Should allow escaping variables." assert "TestA" in result, "Should render local variables." test_string = "SomeString" result = functions.sub_l(template, [test_string, var_map]) assert result == test_string
def test_sub(mocker): template_dict = {"Parameters": {"Foo": {"Value": "bar"}}} template = Template(template_dict) mock_s = mocker.patch.object(functions, "sub_s", autospec=True) mock_l = mocker.patch.object(functions, "sub_l", autospec=True) with pytest.raises(TypeError) as e: functions.sub(template, {}) assert "String or List, not dict." in str(e) functions.sub(template, "") mock_s.assert_called() mock_l.assert_not_called() mocker.resetall() functions.sub(template, []) mock_l.assert_called() mock_s.assert_not_called()
def fake_t() -> Template: return Template({})
def test_set_params(): t = {} params = {"Foo": {"Bar"}} template = Template(t) template.set_parameters() assert template.template == {}, "Should do nothing if no parameters in template." with pytest.raises(ValueError) as e: template.set_parameters(params) assert "You supplied parameters for a template that doesn't have any." in str( e.value ), "Should throw correct exception." template.template = {"Parameters": {"Test": {}}} with pytest.raises(ValueError) as e: template.set_parameters() assert "Must provide values for parameters that don't have a default value." in str( e.value ), "Should throw correct exception." template.set_parameters({"Test": "value"}) assert {"Test": {"Value": "value"}} == template.template[ "Parameters" ], "Should set the value to what we pass in." with pytest.raises(ValueError) as e: template.set_parameters({"Bar": "Foo"}) assert "You passed a Parameter that was not in the Template." in str( e.value ), "Should throw correct exception." template.template = {"Parameters": {"Test": {"Default": "default"}}} template.set_parameters() assert {"Test": {"Default": "default", "Value": "default"}} == template.template[ "Parameters" ], "Should set default values."
def template(): template_path = Path(__file__).parent / "../../templates/log_bucket/log_bucket.yaml" return Template.from_yaml(template_path.resolve(), {})