chemtrail 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/examples/lib/templates/config/load_balancer.yml +23 -0
  3. data/examples/lib/templates/config/nat_device.yml +49 -0
  4. data/examples/lib/templates/config/opsworks.yml +5 -0
  5. data/examples/lib/templates/config/private_network.yml +34 -0
  6. data/examples/lib/templates/config/{resources.yml → public_network.yml} +4 -14
  7. data/examples/lib/templates/config/public_network_acl.yml +54 -0
  8. data/examples/lib/templates/config/{mappings.yml → stack.yml} +24 -17
  9. data/examples/lib/templates/opsworks_vpc/load_balancer.rb +36 -0
  10. data/examples/lib/templates/opsworks_vpc/nat_device.rb +58 -0
  11. data/examples/lib/templates/opsworks_vpc/opsworks.rb +27 -0
  12. data/examples/lib/templates/opsworks_vpc/private_network.rb +89 -0
  13. data/examples/lib/templates/opsworks_vpc/public_network.rb +79 -0
  14. data/examples/lib/templates/opsworks_vpc/public_network_acl.rb +72 -0
  15. data/examples/lib/templates/opsworks_vpc_template.rb +71 -67
  16. data/examples/spec/lib/templates/opsworks_vpc/load_balancer_spec.rb +22 -0
  17. data/examples/spec/lib/templates/opsworks_vpc/nat_device_spec.rb +45 -0
  18. data/examples/spec/lib/templates/opsworks_vpc/opsworks_spec.rb +21 -0
  19. data/examples/spec/lib/templates/opsworks_vpc/private_network_spec.rb +62 -0
  20. data/examples/spec/lib/templates/opsworks_vpc/public_network_acl_spec.rb +63 -0
  21. data/examples/spec/lib/templates/opsworks_vpc/public_network_spec.rb +40 -0
  22. data/examples/spec/lib/templates/opsworks_vpc_template_spec.rb +37 -39
  23. data/lib/chemtrail/matchers/be_reference_to.rb +11 -0
  24. data/lib/chemtrail/matchers/have_entry.rb +36 -0
  25. data/lib/chemtrail/matchers/have_field.rb +7 -20
  26. data/lib/chemtrail/matchers/have_mapping.rb +4 -2
  27. data/lib/chemtrail/matchers/have_output.rb +46 -0
  28. data/lib/chemtrail/matchers/have_parameter.rb +9 -8
  29. data/lib/chemtrail/matchers/have_property.rb +35 -20
  30. data/lib/chemtrail/matchers/have_resource.rb +9 -8
  31. data/lib/chemtrail/matchers/have_tag.rb +7 -20
  32. data/lib/chemtrail/reference_presenter.rb +8 -6
  33. data/lib/chemtrail/rspec.rb +3 -1
  34. data/lib/chemtrail/version.rb +1 -1
  35. metadata +24 -6
  36. data/examples/lib/templates/config/parameters.yml +0 -18
  37. data/lib/chemtrail/matchers/have_mapping_key.rb +0 -49
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ describe OpsworksVpc::PublicNetworkAcl do
4
+ let(:vpc) { double(:vpc, id: "VPC") }
5
+ let(:subnet) { double(:subnet, id: "PublicSubnet") }
6
+
7
+ subject(:network) { OpsworksVpc::PublicNetworkAcl.new(vpc, subnet) }
8
+
9
+ describe "#resources" do
10
+ its(:resources) { should have_resource("PublicNetworkAcl").with_type("AWS::EC2::NetworkAcl") }
11
+ its(:resources) { should have_resource("PublicSubnetNetworkAclAssociation").with_type("AWS::EC2::SubnetNetworkAclAssociation") }
12
+ its(:resources) { should have_resource("InboundHTTPPublicNetworkAclEntry").with_type("AWS::EC2::NetworkAclEntry") }
13
+ its(:resources) { should have_resource("InboundHTTPSPublicNetworkAclEntry").with_type("AWS::EC2::NetworkAclEntry") }
14
+ its(:resources) { should have_resource("InboundSSHPublicNetworkAclEntry").with_type("AWS::EC2::NetworkAclEntry") }
15
+ its(:resources) { should have_resource("InboundEmphemeralPublicNetworkAclEntry").with_type("AWS::EC2::NetworkAclEntry") }
16
+ its(:resources) { should have_resource("OutboundPublicNetworkAclEntry").with_type("AWS::EC2::NetworkAclEntry") }
17
+
18
+ describe "PublicNetworkAcl" do
19
+ its(:network_acl) { should have_property("VpcId").with_reference("VPC") }
20
+ its(:network_acl) { should have_tag("Application").with_reference("AWS::StackName") }
21
+ end
22
+
23
+ describe "PublicSubnetNetworkAclAssociation" do
24
+ its(:network_acl_association) { should have_property("SubnetId").with_reference("PublicSubnet") }
25
+ its(:network_acl_association) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
26
+ end
27
+
28
+ describe "InboundHTTPPublicNetworkAclEntry" do
29
+ its(:http_entry) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
30
+ its(:http_entry) { should have_property("PortRange").with_value("From" => "80", "To" => "80") }
31
+ its(:http_entry) { should have_property("RuleNumber").with_value("100") }
32
+ its(:http_entry) { should have_property("Egress").with_value("false") }
33
+ end
34
+
35
+ describe "InboundHTTPSPublicNetworkAclEntry" do
36
+ its(:https_entry) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
37
+ its(:https_entry) { should have_property("PortRange").with_value("From" => "443", "To" => "443") }
38
+ its(:https_entry) { should have_property("RuleNumber").with_value("101") }
39
+ its(:https_entry) { should have_property("Egress").with_value("false") }
40
+ end
41
+
42
+ describe "InboundSSHPublicNetworkAclEntry" do
43
+ its(:ssh_entry) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
44
+ its(:ssh_entry) { should have_property("PortRange").with_value("From" => "22", "To" => "22") }
45
+ its(:ssh_entry) { should have_property("RuleNumber").with_value("102") }
46
+ its(:ssh_entry) { should have_property("Egress").with_value("false") }
47
+ end
48
+
49
+ describe "InboundEmphemeralPublicNetworkAclEntry" do
50
+ its(:ephemeral_entry) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
51
+ its(:ephemeral_entry) { should have_property("PortRange").with_value("From" => "1024", "To" => "65535") }
52
+ its(:ephemeral_entry) { should have_property("RuleNumber").with_value("103") }
53
+ its(:ephemeral_entry) { should have_property("Egress").with_value("false") }
54
+ end
55
+
56
+ describe "OutboundPublicNetworkAclEntry" do
57
+ its(:outbound_entry) { should have_property("NetworkAclId").with_reference("PublicNetworkAcl") }
58
+ its(:outbound_entry) { should have_property("PortRange").with_value("From" => "0", "To" => "65535") }
59
+ its(:outbound_entry) { should have_property("RuleNumber").with_value("100") }
60
+ its(:outbound_entry) { should have_property("Egress").with_value("true") }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe OpsworksVpc::PublicNetwork do
4
+ let(:vpc) { double(:vpc, id: "VPC") }
5
+ let(:subnet) { double(:subnet, find: "found") }
6
+
7
+ subject(:network) { OpsworksVpc::PublicNetwork.new(vpc, subnet) }
8
+
9
+ describe "#resources" do
10
+ its(:resources) { should have_resource("PublicSubnet").with_type("AWS::EC2::Subnet") }
11
+ its(:resources) { should have_resource("InternetGateway").with_type("AWS::EC2::InternetGateway") }
12
+ its(:resources) { should have_resource("GatewayToInternet").with_type("AWS::EC2::VPCGatewayAttachment") }
13
+ its(:resources) { should have_resource("PublicRouteTable").with_type("AWS::EC2::RouteTable") }
14
+ its(:resources) { should have_resource("PublicSubnetRouteTableAssociation").with_type("AWS::EC2::SubnetRouteTableAssociation") }
15
+
16
+ describe "PublicSubnet" do
17
+ its(:subnet) { should have_property("CidrBlock") }
18
+ its(:subnet) { should have_tag("Application").with_reference("AWS::StackName") }
19
+ end
20
+
21
+ describe "InternetGateway" do
22
+ its(:internet_gateway) { should have_tag("Application").with_reference("AWS::StackName") }
23
+ end
24
+
25
+ describe "GatewayToInternet" do
26
+ its(:gateway_to_internet) { should have_property("VpcId").with_reference("VPC") }
27
+ its(:gateway_to_internet) { should have_property("InternetGatewayId").with_reference("InternetGateway") }
28
+ end
29
+
30
+ describe "PublicRouteTable" do
31
+ its(:route_table) { should have_property("VpcId").with_reference("VPC") }
32
+ its(:route_table) { should have_tag("Application").with_reference("AWS::StackName") }
33
+ end
34
+
35
+ describe "PublicSubnetRouteTableAssociation" do
36
+ its(:route_table_association) { should have_property("SubnetId").with_reference("PublicSubnet") }
37
+ its(:route_table_association) { should have_property("RouteTableId").with_reference("PublicRouteTable") }
38
+ end
39
+ end
40
+ end
@@ -1,59 +1,57 @@
1
1
  require "spec_helper"
2
2
 
3
- describe OpsworksVpc do
4
- subject(:template) { OpsworksVpc.new }
3
+ describe OpsworksVpc::Stack do
4
+ subject(:template) { OpsworksVpc::Stack.new }
5
5
 
6
6
  its(:description) { should include("VPC environment for AWS OpsWorks") }
7
7
 
8
8
  describe "#parameters" do
9
- it { should have_parameter("NATInstanceType").with_type("String") }
9
+ its(:parameters) { should have_parameter("NATInstanceType").with_type("String") }
10
10
 
11
- it { should have_field("Default").with_value("m1.small").on("NATInstanceType") }
12
- it { should have_field("AllowedValues").including("t1.micro").on("NATInstanceType") }
13
- it { should have_field("ConstraintDescription").including("valid EC2 instance").on("NATInstanceType") }
11
+ describe "NATInstanceType" do
12
+ its(:nat_instance_type) { should have_field("Default").with_value("m1.small") }
13
+ its(:nat_instance_type) { should have_field("AllowedValues").including("t1.micro") }
14
+ its(:nat_instance_type) { should have_field("ConstraintDescription").including("valid EC2 instance") }
15
+ end
14
16
  end
15
17
 
16
18
  describe "#mappings" do
17
- it { should have_mapping("AWSNATAMI") }
18
- it { should have_mapping("AWSInstanceType2Arch") }
19
- it { should have_mapping("SubnetConfig") }
20
-
21
- it { should have_mapping_key("us-east-1").including("AMI" => "ami-c6699baf").on("AWSNATAMI") }
22
- it { should have_mapping_key("m1.medium").including("Arch" => "64").on("AWSInstanceType2Arch") }
23
- it { should have_mapping_key("VPC").including("CIDR" => "10.0.0.0/16").on("SubnetConfig") }
24
- it { should have_mapping_key("Public").including("CIDR" => "10.0.0.0/24").on("SubnetConfig") }
25
- it { should have_mapping_key("Private").including("CIDR" => "10.0.1.0/24").on("SubnetConfig") }
26
- end
19
+ its(:mappings) { should have_mapping "AWSNATAMI" }
20
+ its(:mappings) { should have_mapping "AWSInstanceType2Arch" }
21
+ its(:mappings) { should have_mapping "SubnetConfig" }
27
22
 
28
- describe "#resources" do
29
- describe "VPC" do
30
- it { should have_resource("VPC").with_type("AWS::EC2::VPC") }
31
-
32
- it { should have_property("CidrBlock").on("VPC") }
33
- it { should have_tag("Application").with_reference("AWS::StackName").on("VPC") }
34
- it { should have_tag("Network").with_value("Public").on("VPC") }
23
+ describe "AWSInstanceType2Arch" do
24
+ its(:instance_type_arch) { should have_entry("m1.medium").including("Arch" => "64") }
35
25
  end
36
26
 
37
- describe "PublicSubnet" do
38
- it { should have_resource("PublicSubnet").with_type("AWS::EC2::Subnet") }
39
-
40
- it { should have_property("CidrBlock").on("PublicSubnet") }
41
- it { should have_tag("Application").with_reference("AWS::StackName").on("PublicSubnet") }
42
- it { should have_tag("Network").with_value("Public").on("PublicSubnet") }
27
+ describe "SubnetConfig" do
28
+ its(:subnet_config) { should have_entry("VPC").including("CIDR" => "10.0.0.0/16") }
29
+ its(:subnet_config) { should have_entry("Public").including("CIDR" => "10.0.0.0/24") }
30
+ its(:subnet_config) { should have_entry("Private").including("CIDR" => "10.0.1.0/24") }
43
31
  end
32
+ end
44
33
 
45
- describe "InternetGateway" do
46
- it { should have_resource("InternetGateway").with_type("AWS::EC2::InternetGateway") }
47
-
48
- it { should have_tag("Application").with_reference("AWS::StackName").on("InternetGateway") }
49
- it { should have_tag("Network").with_value("Public").on("InternetGateway") }
50
- end
34
+ describe "#resources" do
35
+ its(:resources) { should have_resource "OpsWorksSecurityGroup" }
36
+ its(:resources) { should have_resource "NATDevice" }
37
+ its(:resources) { should have_resource "ElasticLoadBalancer" }
38
+ its(:resources) { should have_resource "PrivateSubnet" }
39
+ its(:resources) { should have_resource "PublicSubnet" }
40
+ its(:resources) { should have_resource "InboundHTTPPublicNetworkAclEntry" }
51
41
 
52
- describe "GatewayToInternet" do
53
- it { should have_resource("GatewayToInternet").with_type("AWS::EC2::VPCGatewayAttachment") }
42
+ its(:resources) { should have_resource("VPC").with_type("AWS::EC2::VPC") }
54
43
 
55
- it { should have_property("VpcId").with_reference("VPC").on("GatewayToInternet") }
56
- it { should have_property("InternetGatewayId").with_reference("InternetGateway").on("GatewayToInternet") }
44
+ describe "VPC" do
45
+ its(:vpc) { should have_property("CidrBlock") }
46
+ its(:vpc) { should have_tag("Application").with_reference("AWS::StackName") }
47
+ its(:vpc) { should have_tag("Network").with_value("Public") }
57
48
  end
58
49
  end
50
+
51
+ describe "#outputs" do
52
+ its(:outputs) { should have_output("VPC").with_reference("VPC") }
53
+ its(:outputs) { should have_output("PublicSubnets").with_reference("PublicSubnet") }
54
+ its(:outputs) { should have_output("PrivateSubnets").with_reference("PrivateSubnet") }
55
+ its(:outputs) { should have_output("LoadBalancer").with_reference("ElasticLoadBalancer") }
56
+ end
59
57
  end
@@ -0,0 +1,11 @@
1
+ require "rspec/expectations"
2
+
3
+ module Chemtrail::RSpec
4
+ extend RSpec::Matchers::DSL
5
+
6
+ matcher :be_reference_to do |expected|
7
+ match do |actual|
8
+ actual.id == expected
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ require "rspec/expectations"
2
+
3
+ module Chemtrail::RSpec
4
+ extend RSpec::Matchers::DSL
5
+
6
+ matcher :have_entry do |entry_name|
7
+ define_method :entry_for do |mapping|
8
+ mapping.entries[entry_name]
9
+ end
10
+
11
+ define_method :matches_value? do |entry|
12
+ if @included_value
13
+ entry.values_at(*@included_value.keys) == @included_value.values
14
+ else
15
+ true
16
+ end
17
+ end
18
+
19
+ match do |mapping|
20
+ entry = entry_for(mapping)
21
+ !mapping.nil? && !entry.nil? && matches_value?(entry)
22
+ end
23
+
24
+ chain :including do |value|
25
+ @included_value = value
26
+ end
27
+
28
+ failure_message_for_should do |mapping|
29
+ if entry = entry_for(mapping)
30
+ %(expected mapping #{mapping.id} field #{entry_name.inspect} to have value #{@included_value.inspect}, but got #{entry.inspect})
31
+ else
32
+ %(expected mapping #{mapping.id} to have type #{entry_name.inspect})
33
+ end
34
+ end
35
+ end
36
+ end
@@ -4,10 +4,6 @@ module Chemtrail::RSpec
4
4
  extend RSpec::Matchers::DSL
5
5
 
6
6
  matcher :have_field do |field_name|
7
- define_method :parameter_for do |actual|
8
- actual.parameters.detect { |p| p.id == @parameter_id }
9
- end
10
-
11
7
  define_method :field_for do |parameter|
12
8
  parameter.fields[field_name]
13
9
  end
@@ -22,14 +18,9 @@ module Chemtrail::RSpec
22
18
  end
23
19
  end
24
20
 
25
- match do |actual|
26
- parameter = parameter_for(actual)
21
+ match do |parameter|
27
22
  field = field_for(parameter)
28
- !parameter.nil? && !field.nil? && matches_value?(field)
29
- end
30
-
31
- chain :on do |parameter_id|
32
- @parameter_id = parameter_id
23
+ !field.nil? && matches_value?(field)
33
24
  end
34
25
 
35
26
  chain :with_value do |value|
@@ -40,16 +31,12 @@ module Chemtrail::RSpec
40
31
  @included_value = value
41
32
  end
42
33
 
43
- failure_message_for_should do |actual|
44
- if parameter = parameter_for(actual)
45
- if field = field_for(parameter)
46
- expected_field = @value || @included_value
47
- %(expected parameter #{@parameter_id.inspect} field #{field_name.inspect} to have value #{expected_field.inspect}, but got #{field.inspect})
48
- else
49
- %(expected parameter #{@parameter_id.inspect} to have type #{field_name.inspect})
50
- end
34
+ failure_message_for_should do |parameter|
35
+ if field = field_for(parameter)
36
+ expected_field = @value || @included_value
37
+ %(expected parameter #{parameter.id} field #{field_name.inspect} to have value #{expected_field.inspect}, but got #{field.inspect})
51
38
  else
52
- %(expected to find parameter #{@parameter_id.inspect}, but got nothing)
39
+ %(expected parameter #{parameter.id} to have type #{field_name.inspect})
53
40
  end
54
41
  end
55
42
  end
@@ -3,7 +3,9 @@ require "rspec/expectations"
3
3
  module Chemtrail::RSpec
4
4
  extend RSpec::Matchers::DSL
5
5
 
6
- matcher :have_mapping do |expected|
7
- match { |actual| actual.mappings.any? { |m| m.id == expected } }
6
+ matcher :have_mapping do |mapping_id|
7
+ match do |mapping_list|
8
+ mapping_list.any? { |m| m.id == mapping_id }
9
+ end
8
10
  end
9
11
  end
@@ -0,0 +1,46 @@
1
+ require "rspec/expectations"
2
+
3
+ module Chemtrail::RSpec
4
+ extend RSpec::Matchers::DSL
5
+
6
+ matcher :have_output do |output_id|
7
+ define_method :output_for do |output_list|
8
+ output_list.detect { |output| output.id == output_id }
9
+ end
10
+
11
+ define_method :matches_value? do |output|
12
+ if @value
13
+ output.value == @value
14
+ elsif @reference
15
+ output.value.id == @reference
16
+ else
17
+ true
18
+ end
19
+ end
20
+
21
+ match do |output_list|
22
+ output = output_for(output_list)
23
+ !output.nil? && matches_value?(output)
24
+ end
25
+
26
+ chain :with_value do |value|
27
+ @value = value
28
+ end
29
+
30
+ chain :with_reference do |reference|
31
+ @reference = reference
32
+ end
33
+
34
+ failure_message_for_should do |output_list|
35
+ if output = output_for(output_list)
36
+ if @value
37
+ %(expected output #{output.id} property #{property_name.inspect} to have value #{@value.inspect}, but got #{output.value.inspect})
38
+ else
39
+ %(expected output #{output.id} property #{property_name.inspect} to refer to #{@reference.inspect}, but got #{output.id.inspect})
40
+ end
41
+ else
42
+ %(expected to find output #{output_id.inspect}, but got nothing)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -4,24 +4,25 @@ module Chemtrail::RSpec
4
4
  extend RSpec::Matchers::DSL
5
5
 
6
6
  matcher :have_parameter do |parameter_id|
7
- define_method :parameter_for do |actual|
8
- actual.parameters.detect { |param| param.id == parameter_id }
7
+ define_method :parameter_for do |parameter_list|
8
+ parameter_list.detect { |param| param.id == parameter_id }
9
9
  end
10
10
 
11
- define_method :matches_type? do |actual|
12
- @type.nil? || parameter_for(actual).type == @type
11
+ define_method :matches_type? do |parameter|
12
+ @type.nil? || parameter.type == @type
13
13
  end
14
14
 
15
- match do |actual|
16
- !parameter_for(actual).nil? && matches_type?(actual)
15
+ match do |parameter_list|
16
+ parameter = parameter_for(parameter_list)
17
+ !parameter.nil? && matches_type?(parameter)
17
18
  end
18
19
 
19
20
  chain :with_type do |type|
20
21
  @type = type
21
22
  end
22
23
 
23
- failure_message_for_should do |actual|
24
- if parameter = parameter_for(actual)
24
+ failure_message_for_should do |parameter_list|
25
+ if parameter = parameter_for(parameter_list)
25
26
  %(expected parameter #{parameter_id.inspect} to have type #{@type.inspect}, but got #{parameter.type.inspect})
26
27
  else
27
28
  %(expected to find parameter #{parameter_id.inspect}, but got nothing)
@@ -4,10 +4,6 @@ module Chemtrail::RSpec
4
4
  extend RSpec::Matchers::DSL
5
5
 
6
6
  matcher :have_property do |property_name|
7
- define_method :resource_for do |actual|
8
- actual.resources.detect { |resource| resource.id == @resource_id }
9
- end
10
-
11
7
  define_method :property_for do |resource|
12
8
  resource.properties[property_name]
13
9
  end
@@ -22,14 +18,27 @@ module Chemtrail::RSpec
22
18
  end
23
19
  end
24
20
 
25
- match do |actual|
26
- resource = resource_for(actual)
27
- property = property_for(resource)
28
- !resource.nil? && !property.nil? && matches_value?(property)
21
+ define_method :includes_value? do |property|
22
+ if @value
23
+ property.includes?(@value)
24
+ elsif @reference
25
+ property.any? { |p| p.id == @reference }
26
+ else
27
+ true
28
+ end
29
29
  end
30
30
 
31
- chain :on do |resource_id|
32
- @resource_id = resource_id
31
+ define_method :matches_strategy? do |property|
32
+ if @including
33
+ includes_value?(property)
34
+ else
35
+ matches_value?(property)
36
+ end
37
+ end
38
+
39
+ match do |resource|
40
+ property = property_for(resource)
41
+ !resource.nil? && !property.nil? && matches_strategy?(property)
33
42
  end
34
43
 
35
44
  chain :with_value do |value|
@@ -40,19 +49,25 @@ module Chemtrail::RSpec
40
49
  @reference = reference
41
50
  end
42
51
 
43
- failure_message_for_should do |actual|
44
- if resource = resource_for(actual)
45
- if property = property_for(resource)
46
- if @value
47
- %(expected resource #{@resource_id.inspect} property #{property_name.inspect} to have value #{@value.inspect}, but got #{property.inspect})
48
- else
49
- %(expected resource #{@resource_id.inspect} property #{property_name.inspect} to refer to #{@reference.inspect}, but got #{property.id.inspect})
50
- end
52
+ chain :including_value do |value|
53
+ @including = true
54
+ @value = value
55
+ end
56
+
57
+ chain :including_reference do |reference|
58
+ @including = true
59
+ @reference = reference
60
+ end
61
+
62
+ failure_message_for_should do |resource|
63
+ if property = property_for(resource)
64
+ if @value
65
+ %(expected resource #{resource.id} property #{property_name.inspect} to have value #{@value.inspect}, but got #{property.inspect})
51
66
  else
52
- %(expected resource #{@resource_id.inspect} to have property #{property_name.inspect})
67
+ %(expected resource #{resource.id} property #{property_name.inspect} to refer to #{@reference.inspect}, but got #{property.id.inspect})
53
68
  end
54
69
  else
55
- %(expected to find resource #{@resource_id.inspect}, but got nothing)
70
+ %(expected resource #{resource.id} to have property #{property_name.inspect})
56
71
  end
57
72
  end
58
73
  end