def test_cannot_merge_if_sam_transform_version_is_different(self): source = Stack(Transform="123") target = Stack(Transform="456") # Exercise & Verify with pytest.raises(StackMergeError) as excinfo: target.merge_stack(source) assert "transform version" in str(excinfo.value).lower()
def test_cannot_merge_if_template_version_is_different(self): source = Stack(AWSTemplateFormatVersion="123") target = Stack(AWSTemplateFormatVersion="456") # Exercise & Verify with pytest.raises(StackMergeError) as excinfo: target.merge_stack(source) assert "template version" in str(excinfo.value).lower()
def test_merge_returns_target_stack(self): # Setup source = Stack(Resources={"SomeResource": SimpleResource()}) target = Stack() # Exercise result = target.merge_stack(source) # Verify assert target is result
def test_does_not_copy_description(self): # Setup source = Stack(Description="Source Description") original_description = "Target Description" target = Stack(Description=original_description) # Exercise target.merge_stack(source) # Verify assert target.Description == original_description
def test_stack_cannot_be_set_when_it_is_already_set(self): # Setup dumper = AmazonCFNDumper(None) stack1 = Stack() stack2 = Stack() dumper.cfn_stack = stack1 # Exercise & Verify with pytest.raises(RuntimeError) as excinfo: dumper.cfn_stack = stack2 assert "already set" in str(excinfo.value)
def test_does_not_copy_flying_circus_metadata(self): # Setup source = Stack() source.Metadata["FlyingCircus"]["version"] = "gamma-gamma" target = Stack() original_fc_data = target.Metadata["FlyingCircus"] # Exercise target.merge_stack(source) # Verify assert target.Metadata["FlyingCircus"] == original_fc_data
def test_fail_if_object_doesnt_exist_except_in_another_stack(self): # Setup name = "Foo" stack = Stack() stack2 = Stack() data = ZeroAttributeObject() stack2.Resources[name] = data # Exercise & Verify with pytest.raises(ValueError) as excinfo: stack.get_logical_name(data) assert "not part of this stack" in str(excinfo.value)
def test_item_is_added_to_the_target_stack(self, stack_attribute, item): # Setup item_name = "SomeChildProperty" source = Stack() source[stack_attribute] = {item_name: item} target = Stack() # Exercise target.merge_stack(source) # Verify assert len(target[stack_attribute]) == 1 assert target[stack_attribute][item_name] is item
def test_stack_can_be_set_after_it_has_been_reset(self): # Setup dumper = AmazonCFNDumper(None) stack1 = Stack() stack2 = Stack() dumper.cfn_stack = stack1 dumper.cfn_stack = None # Exercise dumper.cfn_stack = stack2 # Verify assert dumper.cfn_stack is stack2
def test_item_is_not_removed_from_source_stack(self, stack_attribute, item): # Setup item_name = "SomeChildProperty" source = Stack() source[stack_attribute] = {item_name: item} target = Stack() # Exercise target.merge_stack(source) # Verify assert len(source[stack_attribute]) == 1 assert source[stack_attribute][item_name] is item
def test_should_throw_error_when_called_a_second_time_with_wrong_stack( self): # Setup: Create stack with gateway stack = Stack() stack.Resources["MyVPC"] = vpc = VPC() vpc.ensure_internet_gateway_exists(stack) # Setup: Create second stack unrelated_stack = Stack() # Exercise & Verify with pytest.raises(RuntimeError) as excinfo: vpc.ensure_internet_gateway_exists(unrelated_stack) assert "not in this stack" in str(excinfo.value)
def test_should_use_existing_igw_attached_to_vpc_in_stack(self): # Setup stack = Stack() stack.Resources["MyVPC"] = vpc = VPC() stack.Resources["MyGateway"] = igw = InternetGateway() stack.Resources[ "MyGatewayAttachment"] = attachment = VPCGatewayAttachment( Properties=dict( InternetGatewayId=Ref(igw), VpcId=Ref(vpc), )) # Exercise vpc.ensure_internet_gateway_exists(stack) # Verify self._verify_vpc_has_valid_internet_gateway(vpc) self._verify_resource_is_in_stack(vpc.internet_gateway, stack, unique=True) self._verify_resource_is_in_stack(vpc.internet_gateway_attachment, stack, unique=True) # Verify existing Internet Gateway is used assert vpc.internet_gateway is igw assert vpc.internet_gateway_attachment is attachment
def simple_scaling_policy(alarm, asg_name, downscale=False): """Create a simple scaling policy using the supplied alarm.""" stack = Stack(Description="Resources for a single scaling policy.") scaling_policy = ScalingPolicy( Properties=dict( AdjustmentType="ChangeInCapacity", # TODO consider making this a lookup value AutoScalingGroupName=asg_name, Cooldown=1, ScalingAdjustment=-1 if downscale else 1, ), ) stack.Resources["ScalingPolicy"] = scaling_policy # TODO need properties to be a real object (not a dict), and to auto-create empty lists. alarm.Properties.setdefault("AlarmActions", []).append(fn.Ref(scaling_policy)) alarm.Properties.setdefault("Dimensions", []).append( # TODO logical class that wraps this up instead, and allows you to express in a mroe convenient way dict( Name="AutoScalingGroupName", Value=asg_name, ) ) stack.Resources["ScalingAlarm"] = alarm return stack
def test_standard_metadata_is_present(self): # Exercise stack = Stack() # Verify assert stack.Metadata["FlyingCircus"][ "version"] == flyingcircus.__version__
def test_cannot_merge_if_two_outputs_have_the_same_export_name(self): # Setup export_name = "SpecialExportedValue" source_output = Output(Value=123, Export={"Name": export_name}) source = Stack(Outputs={"SourceOutput": source_output}) target_output = Output(Value=987, Export={"Name": export_name}) target = Stack(Outputs={"TargetOutput": target_output}) # Exercise & Verify with pytest.raises(StackMergeError) as excinfo: target.merge_stack(source) assert "the target stack already has exports" in str( excinfo.value).lower()
def test_should_not_use_existing_igw_attached_to_different_vpc_in_stack( self): # Setup stack = Stack() stack.Resources["MyVPC"] = vpc = VPC() stack.Resources["OtherVPC"] = other_vpc = VPC() stack.Resources["MyGateway"] = igw = InternetGateway() stack.Resources[ "MyGatewayAttachment"] = attachment = VPCGatewayAttachment( Properties=dict( InternetGatewayId=Ref(igw), VpcId=Ref(other_vpc), )) # Exercise vpc.ensure_internet_gateway_exists(stack) # Verify self._verify_vpc_has_valid_internet_gateway(vpc) self._verify_resource_is_in_stack(vpc.internet_gateway, stack) self._verify_resource_is_in_stack(vpc.internet_gateway_attachment, stack) # Verify existing Internet Gateway attachment is not used assert igw is not vpc.internet_gateway self._verify_resource_is_in_stack(igw, stack) assert attachment is not vpc.internet_gateway_attachment self._verify_resource_is_in_stack(attachment, stack)
def test_find_a_pseudo_parameter(self): # Setup data = AWS_Region stack = Stack() # Exercise & Verify assert stack.get_logical_name(data) == "AWS::Region"
def test_should_do_nothing_when_called_a_second_time(self): # Setup: Create stack stack = Stack() stack.Resources["MyVPC"] = vpc = VPC() # Setup: Call once vpc.ensure_internet_gateway_exists(stack) original_igw = vpc.internet_gateway original_attachment = vpc.internet_gateway_attachment # Exercise vpc.ensure_internet_gateway_exists(stack) # Verify self._verify_vpc_has_valid_internet_gateway(vpc) self._verify_resource_is_in_stack(vpc.internet_gateway, stack, unique=True) self._verify_resource_is_in_stack(vpc.internet_gateway_attachment, stack, unique=True) # Verify Internet Gateway hasn't changed assert vpc.internet_gateway is original_igw assert vpc.internet_gateway_attachment is original_attachment
def test_resource_like_object_has_tags_applied(self, apply_tags): # Setup Resource-like object. # # For simplicity of testing we use the same data structure as a # normal resource to store the tagging information class ResourceLikeThing(AWSObject): AWS_ATTRIBUTES = {"Properties"} def tag(self, tags=None, tag_derived_resources=True): # noinspection PyAttributeOutsideInit self.Properties = ResourceProperties( property_names={"Tags"}, Tags=[{ "Key": key, "Value": value } for key, value in tags.items()], ) resource = ResourceLikeThing() # Setup stack = Stack(Resources={"Foo": resource}) key = "foo" value = "bar" # Exercise apply_tags(stack, key, value) # Verify self.verify_tag_exists(resource, key, value)
def test_cannot_merge_if_logical_name_is_already_used_for_that_item_type( self, stack_attribute, item): # Setup item_name = "SomeChildProperty" source = Stack() source[stack_attribute] = {item_name: item} existing_item = copy(item) target = Stack() target[stack_attribute] = {item_name: existing_item} # Exercise & Verify with pytest.raises(StackMergeError) as excinfo: target.merge_stack(source) assert "in this stack already has an item with the logical name" in str( excinfo.value)
def test_find_a_resource_when_only_searching_resources(self): # Setup name = "Foo" stack = Stack() data = ZeroAttributeObject() stack.Resources[name] = data # Exercise & Verify assert stack.get_logical_name(data, resources_only=True) == name
def test_find_a_resource_which_is_a_plain_dict(self): # Setup name = "Foo" stack = Stack() data = dict() stack.Resources[name] = data # Exercise & Verify assert stack.get_logical_name(data) == name
def test_find_a_resource(self): # Setup name = "Foo" stack = Stack() data = ZeroAttributeObject() stack.Resources[name] = data # Exercise & Verify assert stack.get_logical_name(data) == name
def test_find_a_parameter(self): # Setup name = "Foo" stack = Stack() data = Parameter(Type="String") stack.Parameters[name] = data # Exercise & Verify assert stack.get_logical_name(data) == name
def test_prefix_must_be_string(self, prefix): # Setup stack = Stack(Resources={"SomeName": SimpleResource()}) # Exercise & Verify with pytest.raises(TypeError) as excinfo: _ = stack.with_prefixed_names(prefix) assert "string" in str(excinfo.value).lower()
def test_prefix_cannot_contain_special_characters(self, prefix): # Setup stack = Stack(Resources={"SomeName": SimpleResource()}) # Exercise & Verify with pytest.raises(ValueError) as excinfo: _ = stack.with_prefixed_names(prefix) assert "alphanumeric" in str(excinfo.value).lower()
def test_prefix_cannot_be_empty(self): # Setup stack = Stack(Resources={"SomeName": SimpleResource()}) # Exercise & Verify with pytest.raises(ValueError) as excinfo: _ = stack.with_prefixed_names("") assert "empty" in str(excinfo.value).lower()
def test_stack_returns_the_supplied_value(self): # Setup dumper = AmazonCFNDumper(None) stack = Stack() dumper.cfn_stack = stack # Exercise & Verify assert dumper.cfn_stack is stack
def test_prefix_must_have_leading_capital(self): # Setup stack = Stack(Resources={"SomeName": SimpleResource()}) # Exercise & Verify with pytest.raises(ValueError) as excinfo: _ = stack.with_prefixed_names( "lowercasedCamelsAreBactrianButInvalid") assert "uppercase" in str(excinfo.value).lower()
def test_return_value_is_a_new_stack(self): # Setup stack = Stack(Resources={"SomeName": SimpleResource()}) # Exercise new_stack = stack.with_prefixed_names(self.STACK_PREFIX) # Verify assert isinstance(new_stack, Stack) assert new_stack is not stack