pact 1.0.9 → 1.0.10

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 (86) hide show
  1. data/CHANGELOG.md +20 -0
  2. data/Gemfile.lock +3 -3
  3. data/example/animal-service/Gemfile +14 -0
  4. data/example/animal-service/Gemfile.lock +67 -0
  5. data/example/animal-service/Rakefile +3 -0
  6. data/example/animal-service/spec/service_consumers/pact_helper.rb +24 -0
  7. data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +9 -0
  8. data/example/zoo-app/Gemfile.lock +2 -15
  9. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +21 -6
  10. data/example/zoo-app/spec/service_providers/animal_service_spec.rb +1 -1
  11. data/lib/pact/consumer.rb +10 -11
  12. data/lib/pact/consumer/app_manager.rb +1 -0
  13. data/lib/pact/consumer/configuration.rb +179 -0
  14. data/lib/pact/consumer/interaction_builder.rb +1 -2
  15. data/lib/pact/consumer/mock_service.rb +1 -370
  16. data/lib/pact/consumer/mock_service/app.rb +70 -0
  17. data/lib/pact/consumer/mock_service/interaction_delete.rb +28 -0
  18. data/lib/pact/consumer/mock_service/interaction_list.rb +57 -0
  19. data/lib/pact/consumer/mock_service/interaction_post.rb +25 -0
  20. data/lib/pact/consumer/mock_service/interaction_replay.rb +126 -0
  21. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +26 -0
  22. data/lib/pact/consumer/mock_service/rack_request_helper.rb +51 -0
  23. data/lib/pact/consumer/mock_service/startup_poll.rb +22 -0
  24. data/lib/pact/consumer/mock_service/verification_get.rb +35 -0
  25. data/lib/pact/consumer/mock_service_client.rb +3 -1
  26. data/lib/pact/consumer/mock_service_interaction_expectation.rb +33 -0
  27. data/lib/pact/consumer/request.rb +27 -0
  28. data/lib/pact/consumer/rspec.rb +1 -4
  29. data/lib/pact/consumer_contract/consumer_contract.rb +11 -8
  30. data/lib/pact/consumer_contract/interaction.rb +9 -22
  31. data/lib/pact/consumer_contract/request.rb +68 -0
  32. data/lib/pact/consumer_contract/service_consumer.rb +6 -2
  33. data/lib/pact/consumer_contract/service_provider.rb +6 -2
  34. data/lib/pact/matchers/index_not_found.rb +20 -0
  35. data/lib/pact/matchers/matchers.rb +14 -28
  36. data/lib/pact/matchers/unexpected_index.rb +17 -0
  37. data/lib/pact/matchers/unexpected_key.rb +17 -0
  38. data/lib/pact/provider.rb +1 -1
  39. data/lib/pact/provider/configuration.rb +129 -0
  40. data/lib/pact/provider/request.rb +59 -0
  41. data/lib/pact/provider/rspec.rb +4 -5
  42. data/lib/pact/provider/test_methods.rb +14 -52
  43. data/lib/pact/shared/dsl.rb +20 -0
  44. data/lib/pact/shared/key_not_found.rb +24 -0
  45. data/lib/pact/shared/null_expectation.rb +31 -0
  46. data/lib/pact/shared/request.rb +68 -0
  47. data/lib/pact/something_like.rb +7 -1
  48. data/lib/pact/symbolize_keys.rb +12 -0
  49. data/lib/pact/tasks.rb +1 -1
  50. data/lib/pact/tasks/task_helper.rb +23 -0
  51. data/lib/pact/{verification_task.rb → tasks/verification_task.rb} +4 -4
  52. data/lib/pact/version.rb +1 -1
  53. data/lib/tasks/pact.rake +5 -4
  54. data/pact.gemspec +1 -1
  55. data/spec/features/consumption_spec.rb +1 -73
  56. data/spec/features/production_spec.rb +3 -0
  57. data/spec/integration/consumer_spec.rb +170 -0
  58. data/spec/integration/pact/consumer_configuration_spec.rb +1 -1
  59. data/spec/lib/pact/consumer/{dsl_spec.rb → configuration_spec.rb} +10 -9
  60. data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +2 -2
  61. data/spec/lib/pact/consumer/interaction_builder_spec.rb +1 -1
  62. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +66 -0
  63. data/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +82 -0
  64. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +54 -0
  65. data/spec/lib/pact/consumer/request_spec.rb +24 -0
  66. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +1 -1
  67. data/spec/lib/pact/consumer_contract/interaction_spec.rb +0 -34
  68. data/spec/lib/pact/{request_spec.rb → consumer_contract/request_spec.rb} +45 -121
  69. data/spec/lib/pact/matchers/matchers_spec.rb +29 -13
  70. data/spec/lib/pact/provider/configuration_spec.rb +163 -0
  71. data/spec/lib/pact/provider/request_spec.rb +78 -0
  72. data/spec/lib/pact/provider/test_methods_spec.rb +0 -30
  73. data/spec/lib/pact/verification_task_spec.rb +1 -1
  74. data/spec/spec_helper.rb +3 -0
  75. data/spec/support/factories.rb +5 -1
  76. data/spec/support/pact_helper.rb +6 -0
  77. data/spec/support/shared_examples_for_request.rb +83 -0
  78. data/spec/support/test_app_fail.json +3 -0
  79. data/spec/support/test_app_pass.json +18 -1
  80. metadata +68 -31
  81. data/lib/pact/consumer/dsl.rb +0 -157
  82. data/lib/pact/pact_task_helper.rb +0 -21
  83. data/lib/pact/provider/dsl.rb +0 -115
  84. data/lib/pact/request.rb +0 -167
  85. data/spec/lib/pact/consumer/mock_service_spec.rb +0 -143
  86. data/spec/lib/pact/provider/dsl_spec.rb +0 -179
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'pact/term'
3
- require 'pact/something_like'
4
2
  require 'pact/matchers'
5
3
 
6
4
  describe Pact::Matchers do
@@ -24,7 +22,7 @@ describe Pact::Matchers do
24
22
  context "when an unexpected key is found" do
25
23
  let(:expected) { {:a => 1} }
26
24
  let(:actual) { {:a => 1, :b => 2} }
27
- let(:difference) { {:b => {:expected => '<key not to be present>', :actual => 2 }} }
25
+ let(:difference) { {:b => {:expected => Pact::UnexpectedKey.new, :actual => 2 }} }
28
26
  it "returns it in the diff" do
29
27
  expect(diff(expected, actual, allow_unexpected_keys: false)).to eq difference
30
28
  end
@@ -34,7 +32,7 @@ describe Pact::Matchers do
34
32
  describe "expecting key to be present with nil value and not finding key" do
35
33
  let(:expected) { {a: nil} }
36
34
  let(:actual) { {} }
37
- let(:difference) { {a: {expected: nil, actual: Pact::Matchers::KeyNotFound.new }} }
35
+ let(:difference) { {a: {expected: nil, actual: Pact::KeyNotFound.new }} }
38
36
  it "returns the key in the diff" do
39
37
  expect(diff(expected, actual)).to eq difference
40
38
  end
@@ -56,7 +54,7 @@ describe Pact::Matchers do
56
54
  context "when a key is not found" do
57
55
  let(:actual) { {a: 'blah'} }
58
56
  let(:expected) { {b: 'blah'} }
59
- let(:difference) { {:b=>{:expected=>{:class=>String, :eg=>"blah"}, :actual=>Pact::Matchers::KeyNotFound.new}} }
57
+ let(:difference) { {:b=>{:expected=>{:class=>String, :eg=>"blah"}, :actual=>Pact::KeyNotFound.new}} }
60
58
  it "returns the difference" do
61
59
  expect(structure_diff(expected, actual)).to eq difference
62
60
  end
@@ -140,6 +138,24 @@ describe Pact::Matchers do
140
138
 
141
139
  describe 'diffing' do
142
140
 
141
+ context "when expected is longer than the actual" do
142
+ subject { [1,2,3] }
143
+ let(:actual) { [1,2]}
144
+ let(:difference) { [Pact::Matchers::NO_DIFF_INDICATOR, Pact::Matchers::NO_DIFF_INDICATOR, {expected: 3, actual: Pact::IndexNotFound.new}] }
145
+ it 'returns the diff' do
146
+ expect(diff(subject, actual)).to eq(difference)
147
+ end
148
+ end
149
+
150
+ context "when actual array is longer than the expected" do
151
+ subject { [1] }
152
+ let(:actual) { [1,2]}
153
+ let(:difference) { [Pact::Matchers::NO_DIFF_INDICATOR, {expected: Pact::UnexpectedIndex.new , actual: 2}] }
154
+ it 'returns the diff' do
155
+ expect(diff(subject, actual)).to eq(difference)
156
+ end
157
+ end
158
+
143
159
  context 'where an expected value is a non-empty string' do
144
160
 
145
161
  subject { {:a => 'a', :b => 'b'} }
@@ -167,7 +183,7 @@ describe Pact::Matchers do
167
183
  end
168
184
  context "when the actual value is an hash" do
169
185
  let(:actual) { {b: 'c'} }
170
- let(:difference) { { a: {expected:"b", actual: Pact::Matchers::KeyNotFound.new}} }
186
+ let(:difference) { { a: {expected:"b", actual: Pact::KeyNotFound.new}} }
171
187
  it "should return the diff" do
172
188
  expect(diff(subject, actual)).to eql(difference)
173
189
  end
@@ -331,10 +347,10 @@ describe Pact::Matchers do
331
347
  context "a deep mismatch" do
332
348
  subject { {a: {b: { c: [1,2]}, d: { e: Pact::Term.new(matcher: /a/, generate: 'apple')}}, f: 1, g: {h: 99}} }
333
349
  let(:actual) { {a: {b: { c: [1,2]}, d: { e: 'food'}}, f: "thing"} }
334
- let(:difference) { {:a=>{:d=>{:e=>{:expected=>/a/, :actual=>"food"}}}, :f=>{:expected=>1, :actual=>"thing"}, :g=>{:expected=>{:h=>99}, :actual=> Pact::Matchers::KeyNotFound.new}} }
350
+ let(:difference) { {:a=>{:d=>{:e=>{:expected=>/a/, :actual=>"food"}}}, :f=>{:expected=>1, :actual=>"thing"}, :g=>{:expected=>{:h=>99}, :actual=> Pact::KeyNotFound.new}} }
335
351
 
336
352
  it 'should return the diff' do
337
- expect(diff(subject, actual)).to eql(difference)
353
+ expect(diff(subject, actual)).to eq(difference)
338
354
  end
339
355
  end
340
356
 
@@ -344,7 +360,7 @@ describe Pact::Matchers do
344
360
  let(:actual) { {:a => "apple" } }
345
361
 
346
362
  it 'does not include this in the diff' do
347
- expect(diff(subject, actual)).to eql({})
363
+ expect(diff(subject, actual)).to eq({})
348
364
  end
349
365
  end
350
366
 
@@ -362,7 +378,7 @@ describe Pact::Matchers do
362
378
  let(:actual) { [4,5,6] }
363
379
 
364
380
  it 'includes this in the diff' do
365
- expect(diff(subject, actual)).to eql({:expected => {:a => :b}, :actual => [4,5,6] })
381
+ expect(diff(subject, actual)).to eq({:expected => {:a => :b}, :actual => [4,5,6] })
366
382
  end
367
383
  end
368
384
 
@@ -371,7 +387,7 @@ describe Pact::Matchers do
371
387
  let(:actual) { {:a => :b} }
372
388
 
373
389
  it 'includes this in the diff' do
374
- expect(diff(subject, actual)).to eql({:expected => [4,5,6], :actual => {:a => :b} })
390
+ expect(diff(subject, actual)).to eq({:expected => [4,5,6], :actual => {:a => :b} })
375
391
  end
376
392
  end
377
393
 
@@ -381,7 +397,7 @@ describe Pact::Matchers do
381
397
  let(:difference) { [Pact::Matchers::NO_DIFF_INDICATOR, {:expected=>5, :actual=>6}, {:expected=>6, :actual=>7}] }
382
398
 
383
399
  it 'includes this in the diff' do
384
- expect(diff(subject, actual)).to eql(difference)
400
+ expect(diff(subject, actual)).to eq(difference)
385
401
  end
386
402
  end
387
403
 
@@ -390,7 +406,7 @@ describe Pact::Matchers do
390
406
  let(:actual) { ["4","5","6"] }
391
407
 
392
408
  it 'includes this in the diff' do
393
- expect(diff(subject, actual)).to eql({})
409
+ expect(diff(subject, actual)).to eq({})
394
410
  end
395
411
  end
396
412
 
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+ require 'pact/provider/configuration'
3
+
4
+ module Pact::Provider::Configuration
5
+
6
+ describe "service_provider" do
7
+
8
+ before do
9
+ Pact.clear_configuration
10
+ end
11
+
12
+ let(:mock_config) { MockConfig.new }
13
+ context "when a provider is configured" do
14
+ before do
15
+ Pact.service_provider "Fred" do
16
+ app { "An app" }
17
+ end
18
+ end
19
+ it "should allow configuration of the test app" do
20
+ expect(Pact.configuration.provider.app).to eql "An app"
21
+ end
22
+ end
23
+
24
+ context "when a provider is not configured" do
25
+ it "raises an error" do
26
+ expect{ Pact.configuration.provider }.to raise_error(/Please configure your provider/)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe PactVerification do
32
+
33
+ describe 'create_verification' do
34
+ let(:url) {'http://some/uri'}
35
+ let(:consumer_name) {'some consumer'}
36
+ let(:ref) {:prod}
37
+ let(:options) { {:ref => :prod} }
38
+ context "with valid values" do
39
+ subject do
40
+ uri = url
41
+ PactVerification.build(consumer_name, options) do
42
+ pact_uri uri
43
+ end
44
+ end
45
+
46
+ it "creates a Verification" do
47
+ Pact::Provider::PactVerification.should_receive(:new).with(consumer_name, url, ref)
48
+ subject
49
+ end
50
+ end
51
+
52
+ context "with a nil uri" do
53
+ subject do
54
+ PactVerification.build(consumer_name, options) do
55
+ pact_uri nil
56
+ end
57
+ end
58
+
59
+ it "raises a validation error" do
60
+ expect{ subject }.to raise_error /Please provide a pact_uri/
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe ServiceProviderDSL do
67
+
68
+ describe "initialize" do
69
+
70
+ context "with an object instead of a block" do
71
+ subject do
72
+ ServiceProviderDSL.build 'name' do
73
+ app 'blah'
74
+ end
75
+ end
76
+ it "raises an error" do
77
+ expect{ subject }.to raise_error /wrong number of arguments/
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ describe "validate" do
84
+ context "when no name is provided" do
85
+ subject do
86
+ ServiceProviderDSL.new ' ' do
87
+ app { Object.new }
88
+ end
89
+ end
90
+ it "raises an error" do
91
+ expect{ subject.send(:validate)}.to raise_error("Please provide a name for the Provider")
92
+ end
93
+ end
94
+ context "when nil name is provided" do
95
+ subject do
96
+ ServiceProviderDSL.new nil do
97
+ app { Object.new }
98
+ end
99
+ end
100
+ it "raises an error" do
101
+ expect{ subject.send(:validate)}.to raise_error("Please provide a name for the Provider")
102
+ end
103
+ end
104
+ context "when no app is provided" do
105
+ subject do
106
+ ServiceProviderDSL.new 'Blah' do
107
+ end
108
+ end
109
+ it "raises an error" do
110
+ expect{ subject.send(:validate) }.to raise_error("Please configure an app for the Provider")
111
+ end
112
+ end
113
+ end
114
+
115
+ describe 'honours_pact_with' do
116
+ before do
117
+ Pact.clear_configuration
118
+ end
119
+
120
+ context "with no optional params" do
121
+ subject do
122
+ ServiceProviderDSL.build 'some-provider' do
123
+ app {}
124
+ honours_pact_with 'some-consumer' do
125
+ pact_uri 'blah'
126
+ end
127
+ end
128
+ end
129
+ it 'adds a verification to the Pact.configuration' do
130
+ subject
131
+ expect(Pact.configuration.pact_verifications.first).to eq(Pact::Provider::PactVerification.new('some-consumer', 'blah', :head))
132
+ end
133
+ end
134
+
135
+ context "with all params specified" do
136
+ subject do
137
+ ServiceProviderDSL.build 'some-provider' do
138
+ app {}
139
+ honours_pact_with 'some-consumer', :ref => :prod do
140
+ pact_uri 'blah'
141
+ end
142
+ end
143
+ end
144
+ it 'adds a verification to the Pact.configuration' do
145
+ subject
146
+ expect(Pact.configuration.pact_verifications.first).to eq(Pact::Provider::PactVerification.new('some-consumer', 'blah', :prod))
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+ end
153
+
154
+ describe ServiceProviderConfig do
155
+ describe "app" do
156
+ subject { ServiceProviderConfig.new { Object.new } }
157
+ it "should execute the app_block each time" do
158
+ expect(subject.app.object_id).to_not equal(subject.app.object_id)
159
+ end
160
+ end
161
+ end
162
+
163
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+ require 'pact/provider/request'
3
+
4
+ describe Pact::Provider::Request::Replayable do
5
+
6
+ let(:path) { '/path?something' }
7
+ let(:body) { {a: 'body'} }
8
+ let(:headers) { {} }
9
+ let(:expected_request) do
10
+ instance_double('Pact::Request::Expected',
11
+ :method => 'post',
12
+ :full_path => path,
13
+ :body => body,
14
+ :headers => headers)
15
+ end
16
+
17
+ subject { described_class.new(expected_request)}
18
+
19
+ describe "method" do
20
+ it 'returns the method' do
21
+ expect(subject.method).to eq 'post'
22
+ end
23
+ end
24
+ describe "path" do
25
+ it "returns the full path" do
26
+ expect(subject.path).to eq(path)
27
+ end
28
+ end
29
+
30
+ describe "body" do
31
+ context "when body is a NullExpectation" do
32
+ let(:body) { Pact::NullExpectation.new }
33
+ it "returns an empty string, not sure if it should do this or return nil???" do
34
+ expect(subject.body).to eq ""
35
+ end
36
+ end
37
+ context "when body is an empty string" do
38
+ let(:body) { '' }
39
+ it "returns an empty string" do
40
+ expect(subject.body).to eq ""
41
+ end
42
+ end
43
+ context "when body is a string" do
44
+ let(:body) { 'a string'}
45
+ it "returns the string" do
46
+ expect(subject.body).to eq body
47
+ end
48
+ end
49
+ context "when body is a Term" do
50
+ let(:body) { Pact::Term.new(generate: 'a', matcher: /a/) }
51
+ it "returns the generated value" do
52
+ expect(subject.body).to eq "a"
53
+ end
54
+ end
55
+ context "when body is not a string" do
56
+ let(:body) { {a: 'body'} }
57
+ it "returns the object as a json string" do
58
+ expect(subject.body).to eq body.to_json
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "headers" do
64
+ context "when headers are expected" do
65
+ let(:headers) { {"Content-Type" => "text/plain", "Accept" => "application/json"} }
66
+ let(:expected_headers) { {"CONTENT_TYPE" => "text/plain", "HTTP_ACCEPT" => "application/json"} }
67
+ it "transforms the headers into Rack format" do
68
+ expect(subject.headers).to eq( expected_headers )
69
+ end
70
+ end
71
+ context "when headers are not specified" do
72
+ let(:headers) { Pact::NullExpectation.new }
73
+ it "returns an empty hash" do
74
+ expect(subject.headers).to eq({})
75
+ end
76
+ end
77
+ end
78
+ end
@@ -16,35 +16,5 @@ module Pact::Provider
16
16
  expect{ subject.send(:get_provider_state, 'some state', 'consumer') }.to raise_error /Could not find.*some state.*consumer.*/
17
17
  end
18
18
  end
19
-
20
- describe 'request path' do
21
-
22
- let(:request) { OpenStruct.new(:path => 'path', :query => query)}
23
-
24
- before do
25
- @path = subject.send(:request_path, request)
26
- end
27
-
28
- describe 'query' do
29
-
30
- context 'string query' do
31
-
32
- let(:query) { 'query' }
33
-
34
- it 'gets appended to the path' do
35
- expect(@path).to eq('path?query')
36
- end
37
- end
38
-
39
- context 'Term query' do
40
-
41
- let(:query) { Pact::Term.new(generate: 'query', matcher: /q/) }
42
-
43
- it 'appends the Term\'s generate to the path' do
44
- expect(@path).to eq('path?query')
45
- end
46
- end
47
- end
48
- end
49
19
  end
50
20
  end
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'pact/verification_task'
2
+ require 'pact/tasks/verification_task'
3
3
 
4
4
  module Pact
5
5
  describe VerificationTask do
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'rspec'
2
+ require 'rspec/fire'
1
3
  require 'fakefs/spec_helpers'
2
4
  require 'rspec'
3
5
  require 'pact'
@@ -8,4 +10,5 @@ WebMock.disable_net_connect!(allow_localhost: true)
8
10
 
9
11
  RSpec.configure do | config |
10
12
  config.include(FakeFS::SpecHelpers, :fakefs => true)
13
+ config.include(RSpec::Fire)
11
14
  end
@@ -71,8 +71,12 @@ end
71
71
 
72
72
  class RequestFactory
73
73
  extend Pact::HashUtils
74
- DEFAULTS = {:path => '/path', :method => 'get'}.freeze
74
+ DEFAULTS = {:path => '/path', :method => 'get', :query => 'query', :headers => {}}.freeze
75
75
  def self.create_hash overrides = {}
76
76
  deep_merge(DEFAULTS, overrides)
77
77
  end
78
+
79
+ def self.create_actual
80
+ Pact::Consumer::Request::Actual.from_hash(create_hash)
81
+ end
78
82
  end
@@ -8,12 +8,18 @@ module Pact
8
8
  def call env
9
9
  if env['PATH_INFO'] == '/weather'
10
10
  [200, {'Content-Type' => 'application/json'}, [{message: WEATHER[:current_state]}.to_json]]
11
+ elsif env['PATH_INFO'] == '/sometext'
12
+ [200, {'Content-Type' => 'text/plain'}, ['some text']]
11
13
  else
12
14
  raise "unexpected path #{env['PATH_INFO']}!!!"
13
15
  end
14
16
  end
15
17
  end
16
18
 
19
+ Pact.configure do | config |
20
+ config.logger.level = Logger::DEBUG
21
+ end
22
+
17
23
  Pact.service_provider "Some Provider" do
18
24
  app { TestApp.new }
19
25