pact 1.3.3 → 1.4.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/CHANGELOG.md +16 -1
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +34 -13
  4. data/README.md +3 -2
  5. data/example/animal-service/lib/animal_service/api.rb +1 -0
  6. data/example/zoo-app/lib/zoo_app/animal_service_client.rb +0 -9
  7. data/example/zoo-app/lib/zoo_app/models/alligator.rb +2 -0
  8. data/lib/pact.rb +6 -5
  9. data/lib/pact/cli.rb +0 -26
  10. data/lib/pact/consumer/configuration.rb +0 -1
  11. data/lib/pact/consumer/configuration/configuration_extensions.rb +51 -0
  12. data/lib/pact/consumer/consumer_contract_builder.rb +1 -2
  13. data/lib/pact/consumer/interaction_builder.rb +2 -4
  14. data/lib/pact/doc/interaction_view_model.rb +9 -6
  15. data/lib/pact/doc/sort_interactions.rb +1 -1
  16. data/lib/pact/provider/rspec.rb +11 -9
  17. data/lib/pact/version.rb +1 -1
  18. data/pact.gemspec +5 -0
  19. data/spec/lib/pact/consumer/interaction_builder_spec.rb +4 -8
  20. data/spec/support/case-insensitive-response-header-matching.json +21 -0
  21. data/spec/support/case-insensitive-response-header-matching.rb +15 -0
  22. data/tasks/pact-test.rake +5 -0
  23. metadata +42 -122
  24. data/lib/pact/configuration.rb +0 -195
  25. data/lib/pact/consumer/app_manager.rb +0 -158
  26. data/lib/pact/consumer/interactions_filter.rb +0 -48
  27. data/lib/pact/consumer/mock_service.rb +0 -2
  28. data/lib/pact/consumer/mock_service/app.rb +0 -82
  29. data/lib/pact/consumer/mock_service/interaction_delete.rb +0 -33
  30. data/lib/pact/consumer/mock_service/interaction_list.rb +0 -76
  31. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +0 -73
  32. data/lib/pact/consumer/mock_service/interaction_post.rb +0 -31
  33. data/lib/pact/consumer/mock_service/interaction_replay.rb +0 -139
  34. data/lib/pact/consumer/mock_service/log_get.rb +0 -28
  35. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +0 -30
  36. data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +0 -31
  37. data/lib/pact/consumer/mock_service/pact_post.rb +0 -33
  38. data/lib/pact/consumer/mock_service/rack_request_helper.rb +0 -51
  39. data/lib/pact/consumer/mock_service/verification_get.rb +0 -68
  40. data/lib/pact/consumer/mock_service_client.rb +0 -65
  41. data/lib/pact/consumer/mock_service_interaction_expectation.rb +0 -37
  42. data/lib/pact/consumer/request.rb +0 -27
  43. data/lib/pact/consumer/server.rb +0 -90
  44. data/lib/pact/consumer_contract.rb +0 -1
  45. data/lib/pact/consumer_contract/consumer_contract.rb +0 -115
  46. data/lib/pact/consumer_contract/consumer_contract_writer.rb +0 -84
  47. data/lib/pact/consumer_contract/file_name.rb +0 -19
  48. data/lib/pact/consumer_contract/headers.rb +0 -51
  49. data/lib/pact/consumer_contract/interaction.rb +0 -67
  50. data/lib/pact/consumer_contract/pact_file.rb +0 -24
  51. data/lib/pact/consumer_contract/request.rb +0 -73
  52. data/lib/pact/consumer_contract/service_consumer.rb +0 -28
  53. data/lib/pact/consumer_contract/service_provider.rb +0 -28
  54. data/lib/pact/logging.rb +0 -14
  55. data/lib/pact/matchers.rb +0 -1
  56. data/lib/pact/matchers/actual_type.rb +0 -16
  57. data/lib/pact/matchers/base_difference.rb +0 -37
  58. data/lib/pact/matchers/differ.rb +0 -153
  59. data/lib/pact/matchers/difference.rb +0 -13
  60. data/lib/pact/matchers/difference_indicator.rb +0 -26
  61. data/lib/pact/matchers/embedded_diff_formatter.rb +0 -62
  62. data/lib/pact/matchers/expected_type.rb +0 -35
  63. data/lib/pact/matchers/index_not_found.rb +0 -15
  64. data/lib/pact/matchers/list_diff_formatter.rb +0 -101
  65. data/lib/pact/matchers/matchers.rb +0 -139
  66. data/lib/pact/matchers/no_diff_indicator.rb +0 -18
  67. data/lib/pact/matchers/regexp_difference.rb +0 -13
  68. data/lib/pact/matchers/type_difference.rb +0 -16
  69. data/lib/pact/matchers/unexpected_index.rb +0 -11
  70. data/lib/pact/matchers/unexpected_key.rb +0 -11
  71. data/lib/pact/matchers/unix_diff_formatter.rb +0 -114
  72. data/lib/pact/reification.rb +0 -28
  73. data/lib/pact/rspec.rb +0 -53
  74. data/lib/pact/shared/active_support_support.rb +0 -51
  75. data/lib/pact/shared/dsl.rb +0 -76
  76. data/lib/pact/shared/jruby_support.rb +0 -18
  77. data/lib/pact/shared/json_differ.rb +0 -15
  78. data/lib/pact/shared/key_not_found.rb +0 -15
  79. data/lib/pact/shared/null_expectation.rb +0 -31
  80. data/lib/pact/shared/request.rb +0 -80
  81. data/lib/pact/shared/text_differ.rb +0 -14
  82. data/lib/pact/something_like.rb +0 -49
  83. data/lib/pact/symbolize_keys.rb +0 -12
  84. data/lib/pact/term.rb +0 -85
  85. data/spec/lib/pact/consumer/request_spec.rb +0 -24
  86. data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +0 -58
  87. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +0 -180
  88. data/spec/lib/pact/consumer_contract/headers_spec.rb +0 -107
  89. data/spec/lib/pact/consumer_contract/interaction_spec.rb +0 -107
  90. data/spec/lib/pact/consumer_contract/request_spec.rb +0 -329
  91. data/spec/lib/pact/matchers/differ_spec.rb +0 -214
  92. data/spec/lib/pact/matchers/difference_spec.rb +0 -22
  93. data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +0 -90
  94. data/spec/lib/pact/matchers/index_not_found_spec.rb +0 -21
  95. data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +0 -114
  96. data/spec/lib/pact/matchers/matchers_spec.rb +0 -500
  97. data/spec/lib/pact/matchers/regexp_difference_spec.rb +0 -20
  98. data/spec/lib/pact/matchers/type_difference_spec.rb +0 -34
  99. data/spec/lib/pact/matchers/unexpected_index_spec.rb +0 -20
  100. data/spec/lib/pact/matchers/unexpected_key_spec.rb +0 -20
  101. data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +0 -216
  102. data/spec/lib/pact/reification_spec.rb +0 -67
  103. data/spec/lib/pact/shared/dsl_spec.rb +0 -86
  104. data/spec/lib/pact/shared/json_differ_spec.rb +0 -36
  105. data/spec/lib/pact/shared/key_not_found_spec.rb +0 -20
  106. data/spec/lib/pact/shared/request_spec.rb +0 -111
  107. data/spec/lib/pact/shared/text_differ_spec.rb +0 -54
  108. data/spec/lib/pact/something_like_spec.rb +0 -21
  109. data/spec/lib/pact/term_spec.rb +0 -89
  110. data/spec/support/dsl_spec_support.rb +0 -7
@@ -1,12 +0,0 @@
1
- module Pact
2
- module SymbolizeKeys
3
-
4
- def self.included(base)
5
- base.extend(self)
6
- end
7
-
8
- def symbolize_keys hash
9
- hash.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
10
- end
11
- end
12
- end
data/lib/pact/term.rb DELETED
@@ -1,85 +0,0 @@
1
- require 'pact/shared/active_support_support'
2
- require 'json/add/regexp'
3
-
4
- module Pact
5
- class Term
6
-
7
- include Pact::ActiveSupportSupport
8
-
9
- attr_reader :generate, :matcher
10
-
11
- def self.json_create(obj)
12
- new(generate: obj['data']['generate'], matcher: obj['data']['matcher'])
13
- end
14
-
15
- def self.unpack_regexps source
16
- case source
17
- when Pact::Term then source.matcher
18
- when Array then unpack_regexps_from_array source
19
- when Hash then unpack_regexps_from_hash source
20
- else
21
- source
22
- end
23
- end
24
-
25
- def initialize(attributes = {})
26
- @generate = attributes[:generate]
27
- @matcher = attributes[:matcher]
28
- raise "Please specify a matcher for the Term" unless @matcher != nil
29
- raise "Please specify a value to generate for the Term" unless @generate != nil
30
- raise "Value to generate \"#{@generate}\" does not match regular expression #{@matcher}" unless @generate =~ @matcher
31
- end
32
-
33
- def to_hash
34
- { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher)} }
35
- end
36
-
37
- def as_json(options = {})
38
- to_hash
39
- end
40
-
41
-
42
- def to_json(options = {})
43
- as_json.to_json(options)
44
- end
45
-
46
- def match(literal)
47
- literal.respond_to?(:to_s) ? matcher.match(literal.to_s) : nil
48
- end
49
-
50
- def ==(other)
51
- return false unless other.respond_to?(:generate) && other.respond_to?(:matcher)
52
- generate == other.generate && matcher == other.matcher
53
- end
54
-
55
- def to_s
56
- "Pact::Term matcher: #{matcher.inspect}" + (generate.nil? ? "" : " generate: \"#{generate}\"")
57
- end
58
-
59
- def diff_with_actual(actual)
60
- match(actual) ? nil : {
61
- expected: self,
62
- actual: actual
63
- }
64
- end
65
-
66
- def empty?
67
- false
68
- end
69
-
70
- private
71
-
72
- def self.unpack_regexps_from_array source
73
- source.each_with_object([]) do | item, destination |
74
- destination << unpack_regexps(item)
75
- end
76
- end
77
-
78
- def self.unpack_regexps_from_hash source
79
- source.keys.each_with_object({}) do | key, destination |
80
- destination[key] = unpack_regexps source[key]
81
- end
82
- end
83
-
84
- end
85
- end
@@ -1,24 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/shared_examples_for_request'
3
-
4
- module Pact
5
- describe Consumer::Request::Actual do
6
- it_behaves_like "a request"
7
-
8
- let(:raw_request) do
9
- {
10
- 'method' => 'get',
11
- 'path' => '/mallory'
12
- }
13
- end
14
-
15
- describe "from_hash" do
16
- context "when field are not defined" do
17
- subject { described_class.from_hash(raw_request) }
18
- it "raises an error" do
19
- expect{subject}.to raise_error KeyError
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,58 +0,0 @@
1
- require 'spec_helper'
2
- require 'pact/shared/active_support_support'
3
-
4
- module Pact
5
- describe ActiveSupportSupport do
6
-
7
- include ActiveSupportSupport
8
-
9
-
10
- describe "fix_regexp" do
11
- let(:regexp) { /moose/ }
12
-
13
- subject { fix_regexp regexp }
14
-
15
- it "returns the original regexp" do
16
- expect(subject).to be(regexp)
17
- end
18
-
19
- it "fixes the as_json method for Regexp that ActiveSupport tramples beneath its destructive hooves of destruction" do
20
- expect(subject.to_json).to eq("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"moose\"}")
21
- end
22
- end
23
-
24
- describe "fix_all_the_things" do
25
- let(:hash) do
26
- { 'body' => Pact::Term.new(matcher: /a*b/, generate: 'abba'), array: [/blah/], thing: /alligator/ }
27
- end
28
-
29
- subject { fix_all_the_things(hash) }
30
-
31
- it "returns the original object" do
32
- expect(subject).to be(hash)
33
- end
34
-
35
- it "finds all the Regexp objects in hashes or Pact class attributes and fixes the as_json method" do
36
- json = subject.to_json
37
- expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"a*b\"}")
38
- expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"blah\"}")
39
- expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"alligator\"}")
40
- end
41
- end
42
-
43
- describe "fix_json_formatting" do
44
- let(:active_support_affected_pretty_generated_json) { "{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"a*b\"}" }
45
- let(:pretty_generated_json) do
46
- '{
47
- "json_class": "Regexp",
48
- "o": 0,
49
- "s": "a*b"
50
- }'
51
- end
52
-
53
- it "pretty formats the json that has been not pretty formatted because of ActiveSupport" do
54
- expect(fix_json_formatting(active_support_affected_pretty_generated_json)).to eq (pretty_generated_json.strip)
55
- end
56
- end
57
- end
58
- end
@@ -1,180 +0,0 @@
1
- require 'spec_helper'
2
- require 'pact/consumer_contract'
3
-
4
- module Pact
5
- describe ConsumerContract do
6
- describe "as_json" do
7
-
8
- class MockInteraction
9
- def as_json(options ={})
10
- {:mock => "interaction"}
11
- end
12
- end
13
-
14
- before do
15
- allow(DateTime).to receive(:now).and_return(DateTime.strptime("2013-08-15T13:27:13+10:00"))
16
- end
17
-
18
- let(:service_consumer) { double('ServiceConsumer', :as_json => {:a => 'consumer'}) }
19
- let(:service_provider) { double('ServiceProvider', :as_json => {:a => 'provider'}) }
20
- let(:pact) { ConsumerContract.new({:interactions => [MockInteraction.new], :consumer => service_consumer, :provider => service_provider }) }
21
- let(:expected_as_json) { {:provider=>{:a=>"provider"}, :consumer=>{:a=>"consumer"}, :interactions=>[{:mock=>"interaction"}], :metadata=>{:pactSpecificationVersion=> "1.0.0" }} }
22
-
23
- it "should return a hash representation of the Pact" do
24
- expect(pact.as_json).to eq expected_as_json
25
- end
26
-
27
- end
28
-
29
- describe ".from_json" do
30
- let(:loaded_pact) { ConsumerContract.from_json(string) }
31
- context "when the top level object is a ConsumerContract" do
32
- let(:string) { '{"interactions":[{"request": {"path":"/path", "method" : "get"}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"} }' }
33
-
34
- it "should create a Pact" do
35
- expect(loaded_pact).to be_instance_of ConsumerContract
36
- end
37
-
38
- it "should have interactions" do
39
- expect(loaded_pact.interactions).to be_instance_of Array
40
- end
41
-
42
- it "should have a consumer" do
43
- expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
44
- end
45
-
46
- it "should have a provider" do
47
- expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
48
- end
49
- end
50
-
51
- context "with old 'producer' key" do
52
- let(:string) { File.read('./spec/support/a_consumer-a_producer.json')}
53
- it "should create a Pact" do
54
- expect(loaded_pact).to be_instance_of ConsumerContract
55
- end
56
-
57
- it "should have interactions" do
58
- expect(loaded_pact.interactions).to be_instance_of Array
59
- end
60
-
61
- it "should have a consumer" do
62
- expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
63
- end
64
-
65
- it "should have a provider" do
66
- expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
67
- expect(loaded_pact.provider.name).to eq "an old producer"
68
- end
69
-
70
- it "should have a provider_state" do
71
- expect(loaded_pact.interactions.first.provider_state).to eq 'state one'
72
- end
73
- end
74
- end
75
-
76
- describe "find_interactions" do
77
- let(:consumer) { double('Pact::ServiceConsumer', :name => 'Consumer')}
78
- let(:provider) { double('Pact::ServiceProvider', :name => 'Provider')}
79
- let(:interaction) { double('Pact::Interaction') }
80
- subject { ConsumerContract.new(:interactions => [interaction], :consumer => consumer, :provider => provider) }
81
- let(:criteria) { {:description => /blah/} }
82
- before do
83
- expect(interaction).to receive(:matches_criteria?).with(criteria).and_return(matches)
84
- end
85
- context "by description" do
86
- context "when no interactions are found" do
87
- let(:matches) { false }
88
- it "returns an empty array" do
89
- expect(subject.find_interactions(criteria)).to eql []
90
- end
91
- end
92
- context "when interactions are found" do
93
- let(:matches) { true }
94
- it "returns an array of the matching interactions" do
95
- expect(subject.find_interactions(criteria)).to eql [interaction]
96
- end
97
- end
98
- end
99
- end
100
-
101
- describe "find_interaction" do
102
- let(:consumer) { double('Pact::ServiceConsumer', :name => 'Consumer')}
103
- let(:provider) { double('Pact::ServiceProvider', :name => 'Provider')}
104
- let(:interaction1) { double('Pact::Interaction') }
105
- let(:interaction2) { double('Pact::Interaction') }
106
- let(:criteria) { {:description => /blah/} }
107
-
108
- before do
109
- expect(interaction1).to receive(:matches_criteria?).with(criteria).and_return(matches1)
110
- expect(interaction2).to receive(:matches_criteria?).with(criteria).and_return(matches2)
111
- end
112
-
113
- subject { ConsumerContract.new(:interactions => [interaction1, interaction2], :consumer => consumer, :provider => provider) }
114
- context "by description" do
115
- context "when a match is found" do
116
- let(:matches1) { true }
117
- let(:matches2) { false }
118
-
119
- it "returns the interaction" do
120
- expect(subject.find_interaction criteria).to eql interaction1
121
- end
122
- end
123
- context "when more than one match is found" do
124
- let(:matches1) { true }
125
- let(:matches2) { true }
126
- it "raises an error" do
127
- expect{ subject.find_interaction(criteria) }.to raise_error "Found more than 1 interaction matching {:description=>/blah/} in pact file between Consumer and Provider."
128
- end
129
- end
130
- context "when a match is not found" do
131
- let(:matches1) { false }
132
- let(:matches2) { false }
133
- it "raises an error" do
134
- expect{ subject.find_interaction(criteria) }.to raise_error "Could not find interaction matching {:description=>/blah/} in pact file between Consumer and Provider."
135
- end
136
- end
137
- end
138
- end
139
-
140
- describe "update_pactfile" do
141
- let(:pacts_dir) { Pathname.new("./tmp/pactfiles") }
142
- let(:expected_pact_path) { pacts_dir + "test_consumer-test_service.json" }
143
- let(:expected_pact_string) do <<-eos
144
- {
145
- "provider": {
146
- "name": "test_service"
147
- },
148
- "consumer": {
149
- "name": "test_consumer"
150
- },
151
- "interactions": [
152
- "something"
153
- ],
154
- "metadata": {
155
- "pactSpecificationVersion": "1.0.0"
156
- }
157
- }
158
- eos
159
- end
160
- let(:consumer) { Pact::ServiceConsumer.new(:name => 'test_consumer')}
161
- let(:provider) { Pact::ServiceProvider.new(:name => 'test_service')}
162
- let(:interactions) { [double("interaction", as_json: "something")]}
163
- subject { ConsumerContract.new(:consumer => consumer, :provider => provider, :interactions => interactions) }
164
- before do
165
- allow(Pact.configuration).to receive(:pact_dir).and_return(Pathname.new("./tmp/pactfiles"))
166
- FileUtils.rm_rf pacts_dir
167
- FileUtils.mkdir_p pacts_dir
168
- subject.update_pactfile
169
- end
170
-
171
- it "should write to a file specified by the consumer and provider name" do
172
- expect(File.exist?(expected_pact_path)).to eq true
173
- end
174
-
175
- it "should write the interactions to the file" do
176
- expect(File.read(expected_pact_path)).to eql expected_pact_string.strip
177
- end
178
- end
179
- end
180
- end
@@ -1,107 +0,0 @@
1
- require 'spec_helper'
2
- require 'pact/consumer_contract/headers'
3
-
4
- module Pact
5
- describe Headers do
6
-
7
- describe "initialize" do
8
-
9
- context "with duplicate headers" do
10
-
11
- subject { Headers.new('Content-Type' => 'application/hippo', 'CONTENT-TYPE' => 'application/giraffe') }
12
-
13
- it "raises an error" do
14
- expect { subject }.to raise_error DuplicateHeaderError, /Content\-Type.*CONTENT\-TYPE/
15
- end
16
-
17
- end
18
-
19
- context "with a symbol as a header name" do
20
-
21
- subject { Headers.new(:'content-type' => 'application/hippo') }
22
-
23
- it "converts the header name to a String" do
24
- expect( subject.to_hash ).to eq 'content-type' => 'application/hippo'
25
- end
26
-
27
- end
28
-
29
- context "with a nil header name" do
30
-
31
- subject { Headers.new(nil => 'application/hippo') }
32
-
33
- it "raises an error" do
34
- expect{ subject }.to raise_error InvalidHeaderNameTypeError
35
- end
36
-
37
- end
38
-
39
- context "with a boolean header name" do
40
-
41
- subject { Headers.new(false => 'application/hippo') }
42
-
43
- it "raises an error" do
44
- expect{ subject }.to raise_error InvalidHeaderNameTypeError
45
- end
46
-
47
- end
48
-
49
- end
50
-
51
- describe "[]" do
52
-
53
- subject { Headers.new 'Content-Type' => 'application/hippo' }
54
-
55
- it "is case insensitive as HTTP headers are case insensitive" do
56
- expect(subject['Content-Type']).to eq('application/hippo')
57
- expect(subject['CONTENT-TYPE']).to eq('application/hippo')
58
- expect(subject['content-type']).to eq('application/hippo')
59
- end
60
-
61
- end
62
-
63
- describe "fetch" do
64
-
65
- subject { Headers.new 'Content-Type' => 'application/hippo' }
66
-
67
- it "is case insensitive as HTTP headers are case insensitive" do
68
- expect(subject.fetch('Content-Type')).to eq('application/hippo')
69
- expect(subject.fetch('CONTENT-TYPE')).to eq('application/hippo')
70
- expect(subject.fetch('content-type')).to eq('application/hippo')
71
- expect(subject.fetch('Content-Length','1')).to eq('1')
72
- expect { subject.fetch('Content-Length')}.to raise_error KeyError
73
- end
74
-
75
- end
76
-
77
- describe "key?" do
78
-
79
- subject { Headers.new 'Content-Type' => 'application/hippo' }
80
-
81
- it "is case insensitive as HTTP headers are case insensitive" do
82
- expect(subject.key?('CONTENT-TYPE')).to be true
83
- expect(subject.key?('CONTENT-LENGTH')).to be false
84
- end
85
- end
86
-
87
- describe "has_key?" do
88
-
89
- subject { Headers.new 'Content-Type' => 'application/hippo' }
90
-
91
- it "is case insensitive as HTTP headers are case insensitive" do
92
- expect(subject.has_key?('CONTENT-TYPE')).to be true
93
- expect(subject.has_key?('CONTENT-LENGTH')).to be false
94
- end
95
- end
96
-
97
- describe "[]=" do
98
-
99
- subject { Headers.new }
100
-
101
- it "does not allow modification" do
102
- expect{ subject['Content-Type'] = 'application/hippo' }.to raise_error /frozen/
103
- end
104
-
105
- end
106
- end
107
- end