pact 1.0.22 → 1.0.23
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -1
- data/lib/pact/consumer/mock_service/interaction_list.rb +25 -6
- data/lib/pact/consumer/mock_service/interaction_mismatch.rb +51 -0
- data/lib/pact/consumer/mock_service/interaction_replay.rb +17 -15
- data/lib/pact/consumer/mock_service/verification_get.rb +13 -3
- data/lib/pact/consumer/mock_service_client.rb +1 -1
- data/lib/pact/consumer/request.rb +2 -2
- data/lib/pact/version.rb +1 -1
- data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +15 -3
- data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +49 -0
- data/spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb +0 -0
- data/spec/support/factories.rb +2 -2
- metadata +9 -4
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@ Do this to generate your change history
|
|
2
2
|
|
3
3
|
git log --date=relative --pretty=format:' * %h - %s (%an, %ad)'
|
4
4
|
|
5
|
+
### 1.0.23 (29 November 2013)
|
6
|
+
|
7
|
+
* a978654 - Improving the display of verification errors in the consumer project. (Beth Skurrie, 2 days ago)
|
8
|
+
|
5
9
|
### 1.0.22 (25 November 2013)
|
6
10
|
|
7
11
|
* f742833 - Updating README (Beth Skurrie, 36 seconds ago)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pact (1.0.
|
4
|
+
pact (1.0.23)
|
5
5
|
awesome_print (~> 1.1.0)
|
6
6
|
find_a_port (~> 1.0.1)
|
7
7
|
json
|
@@ -13,6 +13,7 @@ PATH
|
|
13
13
|
|
14
14
|
GEM
|
15
15
|
remote: https://rubygems.org/
|
16
|
+
remote: http://rea-rubygems/
|
16
17
|
specs:
|
17
18
|
activesupport (4.0.0)
|
18
19
|
i18n (~> 0.6, >= 0.6.4)
|
@@ -4,6 +4,7 @@ module Pact
|
|
4
4
|
|
5
5
|
attr_reader :interactions
|
6
6
|
attr_reader :unexpected_requests
|
7
|
+
attr_reader :interaction_mismatches
|
7
8
|
|
8
9
|
def initialize
|
9
10
|
clear
|
@@ -13,6 +14,7 @@ module Pact
|
|
13
14
|
def clear
|
14
15
|
@interactions = []
|
15
16
|
@matched_interactions = []
|
17
|
+
@interaction_mismatches = []
|
16
18
|
@unexpected_requests = []
|
17
19
|
end
|
18
20
|
|
@@ -28,18 +30,35 @@ module Pact
|
|
28
30
|
@unexpected_requests << request
|
29
31
|
end
|
30
32
|
|
33
|
+
def register_interaction_mismatch interaction_mismatch
|
34
|
+
@interaction_mismatches << interaction_mismatch
|
35
|
+
end
|
36
|
+
|
31
37
|
def all_matched?
|
32
38
|
interaction_diffs.empty?
|
33
39
|
end
|
34
40
|
|
35
41
|
def missing_interactions
|
36
|
-
@interactions - @matched_interactions
|
42
|
+
@interactions - @matched_interactions - @interaction_mismatches.collect(&:candidate_interactions).flatten
|
43
|
+
end
|
44
|
+
|
45
|
+
def missing_interactions_summaries
|
46
|
+
missing_interactions.collect(&:request).collect(&:method_and_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def interaction_mismatches_summaries
|
50
|
+
interaction_mismatches.collect(&:short_summary)
|
51
|
+
end
|
52
|
+
|
53
|
+
def unexpected_requests_summaries
|
54
|
+
unexpected_requests.collect(&:method_and_path)
|
37
55
|
end
|
38
56
|
|
39
57
|
def interaction_diffs
|
40
58
|
{
|
41
|
-
:missing_interactions =>
|
42
|
-
:
|
59
|
+
:missing_interactions => missing_interactions_summaries,
|
60
|
+
:interaction_mismatches => interaction_mismatches_summaries,
|
61
|
+
:unexpected_requests => unexpected_requests_summaries
|
43
62
|
}.inject({}) do | hash, pair |
|
44
63
|
hash[pair.first] = pair.last if pair.last.any?
|
45
64
|
hash
|
@@ -49,9 +68,9 @@ module Pact
|
|
49
68
|
def find_candidate_interactions actual_request
|
50
69
|
interactions.select do | interaction |
|
51
70
|
interaction.request.matches_route? actual_request
|
52
|
-
end
|
53
|
-
end
|
71
|
+
end
|
72
|
+
end
|
54
73
|
|
55
|
-
end
|
74
|
+
end
|
56
75
|
end
|
57
76
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pact
|
2
|
+
module Consumer
|
3
|
+
class InteractionMismatch
|
4
|
+
|
5
|
+
attr_accessor :candidate_interactions, :actual_request
|
6
|
+
|
7
|
+
# Assumes the method and path matches...
|
8
|
+
|
9
|
+
def initialize candidate_interactions, actual_request
|
10
|
+
@candidate_interactions = candidate_interactions
|
11
|
+
@actual_request = actual_request
|
12
|
+
@candiate_diffs = candidate_interactions.collect{ | candidate_interaction| CandidateDiff.new(candidate_interaction, actual_request)}
|
13
|
+
end
|
14
|
+
|
15
|
+
def diffs
|
16
|
+
candiate_diffs.collect(&:diff_summary)
|
17
|
+
end
|
18
|
+
|
19
|
+
def short_summary
|
20
|
+
mismatched_attributes = candiate_diffs.collect(&:mismatched_attributes).flatten.uniq.join(", ").reverse.sub(",", "dna ").reverse #OMG what a hack!
|
21
|
+
actual_request.method_and_path + " (#{mismatched_attributes} did not match)"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_accessor :candiate_diffs
|
27
|
+
|
28
|
+
class CandidateDiff
|
29
|
+
attr_accessor :candidate_interaction, :actual_request
|
30
|
+
def initialize candidate_interaction, actual_request
|
31
|
+
@candidate_interaction = candidate_interaction
|
32
|
+
@actual_request = actual_request
|
33
|
+
end
|
34
|
+
|
35
|
+
def mismatched_attributes
|
36
|
+
diff.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
def diff_summary
|
40
|
+
summary = {:description => candidate_interaction.description}
|
41
|
+
summary[:provider_state] = candidate_interaction.provider_state if candidate_interaction.provider_state
|
42
|
+
summary.merge(diff)
|
43
|
+
end
|
44
|
+
|
45
|
+
def diff
|
46
|
+
@diff ||= candidate_interaction.request.difference(actual_request)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'pact/matchers'
|
2
2
|
require 'pact/consumer/mock_service/rack_request_helper'
|
3
|
+
require 'pact/consumer/mock_service/interaction_mismatch'
|
3
4
|
|
4
5
|
module Pact
|
5
6
|
module Consumer
|
@@ -70,11 +71,8 @@ module Pact
|
|
70
71
|
multiple_interactions_found_response actual_request, matching_interactions
|
71
72
|
end
|
72
73
|
|
73
|
-
def
|
74
|
-
candidate_interactions
|
75
|
-
diff = candidate_interaction.request.difference(actual_request)
|
76
|
-
diff_summary_for candidate_interaction, diff
|
77
|
-
end
|
74
|
+
def interaction_mismatch actual_request, candidate_interactions
|
75
|
+
InteractionMismatch.new(candidate_interactions, actual_request)
|
78
76
|
end
|
79
77
|
|
80
78
|
def diff_summary_for interaction, diff
|
@@ -90,25 +88,29 @@ module Pact
|
|
90
88
|
summary
|
91
89
|
end
|
92
90
|
|
93
|
-
def unrecognised_request_response
|
91
|
+
def unrecognised_request_response interaction_mismatch
|
94
92
|
response = {
|
95
|
-
message: "No interaction found for #{actual_request.method_and_path}",
|
96
|
-
interaction_diffs:
|
93
|
+
message: "No interaction found for #{interaction_mismatch.actual_request.method_and_path}",
|
94
|
+
interaction_diffs: interaction_mismatch.diffs
|
97
95
|
}
|
98
96
|
[500, {'Content-Type' => 'application/json'}, [response.to_json]]
|
99
97
|
end
|
100
98
|
|
101
|
-
def log_unrecognised_request_and_interaction_diff
|
102
|
-
logger.error "No interaction found on #{name} for #{actual_request.method_and_path}"
|
99
|
+
def log_unrecognised_request_and_interaction_diff interaction_mismatch
|
100
|
+
logger.error "No interaction found on #{name} for #{interaction_mismatch.actual_request.method_and_path}"
|
103
101
|
logger.error 'Interaction diffs for that route:'
|
104
|
-
logger.ap(
|
102
|
+
logger.ap(interaction_mismatch.diffs, :error)
|
105
103
|
end
|
106
104
|
|
107
105
|
def handle_unrecognised_request actual_request, candidate_interactions
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
106
|
+
interaction_mismatch = interaction_mismatch(actual_request, candidate_interactions)
|
107
|
+
if candidate_interactions.any?
|
108
|
+
interaction_list.register_interaction_mismatch interaction_mismatch
|
109
|
+
else
|
110
|
+
interaction_list.register_unexpected_request actual_request
|
111
|
+
end
|
112
|
+
log_unrecognised_request_and_interaction_diff interaction_mismatch
|
113
|
+
unrecognised_request_response interaction_mismatch
|
112
114
|
end
|
113
115
|
|
114
116
|
def response_from response
|
@@ -26,9 +26,19 @@ module Pact
|
|
26
26
|
logger.info "Verifying - interactions matched for example \"#{example_description(env)}\""
|
27
27
|
[200, {}, ['Interactions matched']]
|
28
28
|
else
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
|
30
|
+
missing_interactions_summaries = interaction_list.missing_interactions_summaries
|
31
|
+
interaction_mismatches_summaries = interaction_list.interaction_mismatches_summaries
|
32
|
+
unexpected_requests_summaries = interaction_list.unexpected_requests_summaries
|
33
|
+
error_message = "Missing requests:
|
34
|
+
#{missing_interactions_summaries.join("\n ")}
|
35
|
+
Incorrect requests:
|
36
|
+
#{interaction_mismatches_summaries.join("\n ")}
|
37
|
+
Unexpected requests:
|
38
|
+
#{unexpected_requests_summaries.join("\n ")}"
|
39
|
+
logger.warn "Verifying - actual interactions do not match expected interactions for example \"#{example_description(env)}\". \n#{error_message}"
|
40
|
+
logger.warn error_message
|
41
|
+
[500, {}, ["Actual interactions do not match expected interactions for mock #{name}.\n#{error_message}\nSee #{log_description} for details."]]
|
32
42
|
end
|
33
43
|
end
|
34
44
|
|
@@ -12,7 +12,7 @@ module Pact
|
|
12
12
|
|
13
13
|
def verify example_description
|
14
14
|
response = http.request_get("/verify?example_description=#{URI.encode(example_description)}", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
15
|
-
raise response.body unless response.is_a? Net::HTTPSuccess
|
15
|
+
raise "\e[31m#{response.body}\e[m" unless response.is_a? Net::HTTPSuccess
|
16
16
|
end
|
17
17
|
|
18
18
|
def log msg
|
data/lib/pact/version.rb
CHANGED
@@ -6,18 +6,21 @@ module Pact::Consumer
|
|
6
6
|
describe InteractionList do
|
7
7
|
shared_context "unexpected requests and missed interactions" do
|
8
8
|
let(:expected_interaction) { InteractionFactory.create }
|
9
|
-
let(:unexpected_request) { RequestFactory.create_actual }
|
9
|
+
let(:unexpected_request) { RequestFactory.create_actual method: 'put' }
|
10
|
+
let(:candidate_interaction) { double("Pact::Interaction") }
|
11
|
+
let(:candidate_interactions) { [candidate_interaction] }
|
12
|
+
let(:interaction_mismatch) { instance_double("Pact::Consumer::InteractionMismatch", :short_summary => 'blah', :candidate_interactions => candidate_interactions)}
|
10
13
|
subject {
|
11
14
|
interactionList = InteractionList.new
|
12
15
|
interactionList.add expected_interaction
|
13
16
|
interactionList.register_unexpected_request unexpected_request
|
17
|
+
interactionList.register_interaction_mismatch interaction_mismatch
|
14
18
|
interactionList
|
15
19
|
}
|
16
20
|
end
|
17
21
|
|
18
22
|
shared_context "no unexpected requests or missed interactions exist" do
|
19
23
|
let(:expected_interaction) { InteractionFactory.create }
|
20
|
-
let(:unexpected_request) { RequestFactory.create_actual }
|
21
24
|
subject {
|
22
25
|
interactionList = InteractionList.new
|
23
26
|
interactionList.add expected_interaction
|
@@ -30,7 +33,9 @@ module Pact::Consumer
|
|
30
33
|
context "when unexpected requests and missed interactions exist" do
|
31
34
|
include_context "unexpected requests and missed interactions"
|
32
35
|
let(:expected_diff) {
|
33
|
-
{:missing_interactions=>[
|
36
|
+
{:missing_interactions=>["GET /path"],
|
37
|
+
:unexpected_requests=>["PUT /path"],
|
38
|
+
:interaction_mismatches => ['blah']}
|
34
39
|
}
|
35
40
|
it "returns the unexpected requests and missed interactions" do
|
36
41
|
expect(subject.interaction_diffs).to eq expected_diff
|
@@ -62,5 +67,12 @@ module Pact::Consumer
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
end
|
70
|
+
|
71
|
+
describe "missing_interactions_summaries" do
|
72
|
+
include_context "unexpected requests and missed interactions"
|
73
|
+
it "returns a list of the method and paths for each missing interaction" do
|
74
|
+
expect(subject.missing_interactions_summaries).to eq ["GET /path"]
|
75
|
+
end
|
76
|
+
end
|
65
77
|
end
|
66
78
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pact/consumer/mock_service/interaction_mismatch'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module Consumer
|
6
|
+
describe InteractionMismatch do
|
7
|
+
let(:actual_request) { instance_double('Pact::Consumer::Request::Actual', :method_and_path => 'GET /path') }
|
8
|
+
let(:expected_request_1) { instance_double('Pact::Request::Expected') }
|
9
|
+
let(:expected_request_2) { instance_double('Pact::Request::Expected') }
|
10
|
+
let(:candidate_1) { instance_double('Pact::Interaction', request: expected_request_1) }
|
11
|
+
let(:candidate_2) { instance_double('Pact::Interaction', request: expected_request_2) }
|
12
|
+
let(:candidate_interactions) { [candidate_1, candidate_2] }
|
13
|
+
subject { InteractionMismatch.new(candidate_interactions, actual_request) }
|
14
|
+
let(:diff_1) { {body: nil} }
|
15
|
+
let(:diff_2) { {} }
|
16
|
+
|
17
|
+
before do
|
18
|
+
expected_request_1.stub(:difference).with(actual_request).and_return(diff_1)
|
19
|
+
expected_request_2.stub(:difference).with(actual_request).and_return(diff_2)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "short_summary" do
|
23
|
+
it "includes the method and path" do
|
24
|
+
expect(subject.short_summary).to match /GET \/path \(.*\)/
|
25
|
+
end
|
26
|
+
context "when the body does not match" do
|
27
|
+
let(:diff_1) { {body: nil} }
|
28
|
+
|
29
|
+
it "returns a message indicating that the body does not match" do
|
30
|
+
expect(subject.short_summary).to include "(body did not match)"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
context "when the headers do not match" do
|
34
|
+
let(:diff_1) { {headers: nil} }
|
35
|
+
it "returns a message indicating that the body does not match" do
|
36
|
+
expect(subject.short_summary).to include "(headers did not match)"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
context "when the headers and body do not match" do
|
40
|
+
let(:diff_1) { {body: nil, headers: nil} }
|
41
|
+
let(:diff_2) { {body: nil, headers: nil} }
|
42
|
+
it "returns a message indicating that the headers and body do not match" do
|
43
|
+
expect(subject.short_summary).to include "(body and headers did not match)"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
File without changes
|
data/spec/support/factories.rb
CHANGED
@@ -76,7 +76,7 @@ class RequestFactory
|
|
76
76
|
deep_merge(DEFAULTS, overrides)
|
77
77
|
end
|
78
78
|
|
79
|
-
def self.create_actual
|
80
|
-
Pact::Consumer::Request::Actual.from_hash(create_hash)
|
79
|
+
def self.create_actual overrides = {}
|
80
|
+
Pact::Consumer::Request::Actual.from_hash(create_hash(overrides))
|
81
81
|
end
|
82
82
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pact
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.23
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2013-11-
|
16
|
+
date: 2013-11-28 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: randexp
|
@@ -307,6 +307,7 @@ files:
|
|
307
307
|
- lib/pact/consumer/mock_service/app.rb
|
308
308
|
- lib/pact/consumer/mock_service/interaction_delete.rb
|
309
309
|
- lib/pact/consumer/mock_service/interaction_list.rb
|
310
|
+
- lib/pact/consumer/mock_service/interaction_mismatch.rb
|
310
311
|
- lib/pact/consumer/mock_service/interaction_post.rb
|
311
312
|
- lib/pact/consumer/mock_service/interaction_replay.rb
|
312
313
|
- lib/pact/consumer/mock_service/log_get.rb
|
@@ -372,6 +373,8 @@ files:
|
|
372
373
|
- spec/lib/pact/consumer/interaction_builder_spec.rb
|
373
374
|
- spec/lib/pact/consumer/interactions_spec.rb
|
374
375
|
- spec/lib/pact/consumer/mock_service/interaction_list_spec.rb
|
376
|
+
- spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb
|
377
|
+
- spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb
|
375
378
|
- spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb
|
376
379
|
- spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb
|
377
380
|
- spec/lib/pact/consumer/request_spec.rb
|
@@ -421,7 +424,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
421
424
|
version: '0'
|
422
425
|
segments:
|
423
426
|
- 0
|
424
|
-
hash:
|
427
|
+
hash: -1054460629994905299
|
425
428
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
426
429
|
none: false
|
427
430
|
requirements:
|
@@ -430,7 +433,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
430
433
|
version: '0'
|
431
434
|
segments:
|
432
435
|
- 0
|
433
|
-
hash:
|
436
|
+
hash: -1054460629994905299
|
434
437
|
requirements: []
|
435
438
|
rubyforge_project:
|
436
439
|
rubygems_version: 1.8.23
|
@@ -453,6 +456,8 @@ test_files:
|
|
453
456
|
- spec/lib/pact/consumer/interaction_builder_spec.rb
|
454
457
|
- spec/lib/pact/consumer/interactions_spec.rb
|
455
458
|
- spec/lib/pact/consumer/mock_service/interaction_list_spec.rb
|
459
|
+
- spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb
|
460
|
+
- spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb
|
456
461
|
- spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb
|
457
462
|
- spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb
|
458
463
|
- spec/lib/pact/consumer/request_spec.rb
|