Skip to content

Commit 0f22db2

Browse files
committed
feat: locate matching rules correctly for v3 pacts
1 parent 07013de commit 0f22db2

8 files changed

+204
-38
lines changed

lib/pact/consumer_contract/http_consumer_contract_parser.rb

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,24 @@ class HttpConsumerContractParser
44

55
def call(hash)
66
hash = symbolize_keys(hash)
7-
interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash)}
8-
7+
options = { pact_specification_version: pact_specification_version(hash) }
8+
interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash, options) }
99
ConsumerContract.new(
1010
:consumer => ServiceConsumer.from_hash(hash[:consumer]),
1111
:provider => ServiceProvider.from_hash(hash[:provider]),
1212
:interactions => interactions
1313
)
1414
end
1515

16+
def pact_specification_version hash
17+
# TODO handle all 3 ways of defining this...
18+
# metadata.pactSpecificationVersion
19+
maybe_pact_specification_version_1 = hash[:metadata] && hash[:metadata]['pactSpecification'] && hash[:metadata]['pactSpecification']['version']
20+
maybe_pact_specification_version_2 = hash[:metadata] && hash[:metadata]['pactSpecificationVersion']
21+
pact_specification_version = maybe_pact_specification_version_1 || maybe_pact_specification_version_2
22+
Gem::Version.new(pact_specification_version)
23+
end
24+
1625
def can_parse?(hash)
1726
hash.key?('interactions') || hash.key?(:interactions)
1827
end

lib/pact/consumer_contract/interaction.rb

+26-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,33 @@ def initialize attributes = {}
1919
@provider_state = attributes[:provider_state] || attributes[:providerState]
2020
end
2121

22-
def self.from_hash hash
23-
request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'])
22+
def self.from_hash hash, options = {}
23+
pact_specification_version = options[:pact_specification_version] || Gem::Version.new("") # use some global default
24+
case pact_specification_version.segments.first
25+
when 1, 2 then parse_v2_interaction(hash, pact_specification_version: pact_specification_version)
26+
else parse_v3_interaction(hash, pact_specification_version: pact_specification_version)
27+
end
28+
end
29+
30+
def self.parse_v2_interaction hash, options
31+
request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'], options)
2432
request = Pact::Request::Expected.from_hash(request_hash)
25-
response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'])
33+
response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'], options)
34+
response = Pact::Response.from_hash(response_hash)
35+
new(symbolize_keys(hash).merge(request: request, response: response))
36+
end
37+
38+
def self.parse_v3_interaction hash, options
39+
40+
request_hash = hash['request'].keys.each_with_object({}) do | key, new_hash |
41+
new_hash[key] = Pact::MatchingRules.merge(hash['request'][key], hash['request'].fetch('matchingRules', {})[key], options)
42+
end
43+
request = Pact::Request::Expected.from_hash(request_hash)
44+
45+
response_hash = hash['response'].keys.each_with_object({}) do | key, new_hash |
46+
new_hash[key] = Pact::MatchingRules.merge(hash['response'][key], hash['response'].fetch('matchingRules', {})[key], options)
47+
end
48+
2649
response = Pact::Response.from_hash(response_hash)
2750
new(symbolize_keys(hash).merge(request: request, response: response))
2851
end

lib/pact/matching_rules.rb

+16-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
require 'pact/matching_rules/extract'
22
require 'pact/matching_rules/merge'
3+
require 'pact/matching_rules/v3/merge'
34

45
module Pact
56
module MatchingRules
67

78
# @api public Used by pact-mock_service
8-
def self.extract object_graph
9+
def self.extract object_graph, options = {}
910
Extract.(object_graph)
1011
end
1112

12-
def self.merge object_graph, matching_rules
13-
Merge.(object_graph, matching_rules)
13+
def self.merge object_graph, matching_rules, options = {}
14+
case options[:pact_specification_version].segments.first
15+
when nil
16+
Pact.configuration.error_stream.puts "No pact specification version found, using v2 code to parse contract"
17+
Merge.(object_graph, matching_rules)
18+
when 1, 2
19+
Merge.(object_graph, matching_rules)
20+
when 3
21+
V3::Merge.(object_graph, matching_rules)
22+
else
23+
Pact.configuration.error_stream.puts "This code only knows how to parse v3 pacts, attempting to parse v#{options[:pact_specification_version]} pact using v3 code."
24+
V3::Merge.(object_graph, matching_rules)
25+
end
1426
end
15-
1627
end
17-
end
28+
end

spec/fixtures/pact-http-v3.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"consumer": {
3+
"name": "consumer"
4+
},
5+
"interactions": [
6+
{
7+
"description": "a test request",
8+
"providerState": "the weather is sunny",
9+
"request": {
10+
"method": "get",
11+
"path": "/foo"
12+
},
13+
"response": {
14+
"body": {
15+
"foo": "bar"
16+
},
17+
"matchingRules": {
18+
"body": {
19+
"$.foo": {
20+
"matchers": [{ "match": "type" }]
21+
}
22+
}
23+
},
24+
"status": 200
25+
}
26+
}
27+
],
28+
"provider": {
29+
"name": "provider"
30+
},
31+
"metadata": {
32+
"pactSpecification": {
33+
"version": "3.0"
34+
}
35+
}
36+
}

spec/fixtures/pact-v3.json

-27
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'pact/consumer_contract/http_consumer_contract_parser'
2+
3+
module Pact
4+
describe HttpConsumerContractParser do
5+
describe "#call integration test" do
6+
subject { HttpConsumerContractParser.new.call(pact_hash) }
7+
8+
context "with a v3 pact" do
9+
let(:pact_hash) { load_json_fixture('pact-http-v3.json') }
10+
11+
it "correctly parses the pact" do
12+
expect(subject.interactions.first.response.body['foo']).to be_a(Pact::SomethingLike)
13+
end
14+
end
15+
end
16+
end
17+
end

spec/lib/pact/consumer_contract/interaction_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module Consumer
6565
context "when there are matching rules" do
6666
let(:hash) { load_json_fixture 'interaction-with-matching-rules.json' }
6767

68-
subject { Interaction.from_hash hash }
68+
subject { Interaction.from_hash hash, pact_specification_version: Gem::Version.new("2") }
6969

7070
it "merges the rules with the example for the request" do
7171
expect(subject.request.body['name']).to be_instance_of(Pact::Term)

spec/lib/pact/matching_rules_spec.rb

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
require 'pact/matching_rules'
2+
3+
module Pact
4+
module MatchingRules
5+
describe ".merge" do
6+
before do
7+
allow(V3::Merge).to receive(:call)
8+
allow(Merge).to receive(:call)
9+
allow(Pact.configuration.error_stream).to receive(:puts)
10+
end
11+
12+
let(:object) { double('object') }
13+
let(:rules) { double('rules') }
14+
let(:options) { { pact_specification_version: Gem::Version.new(pact_specification_version) } }
15+
16+
subject { MatchingRules.merge(object, rules, options)}
17+
18+
context "when the pact_specification_version is nil" do
19+
let(:pact_specification_version) { nil }
20+
21+
it "prints a warning" do
22+
expect(Pact.configuration.error_stream).to receive(:puts).with(/No pact specification version found/)
23+
subject
24+
end
25+
26+
it "calls Merge" do
27+
expect(Merge).to receive(:call)
28+
subject
29+
end
30+
end
31+
32+
context "when the pact_specification_version starts with '1.'" do
33+
let(:pact_specification_version) { "1.0" }
34+
35+
it "calls Merge" do
36+
expect(Merge).to receive(:call)
37+
subject
38+
end
39+
end
40+
41+
context "when the pact_specification_version is with '1'" do
42+
let(:pact_specification_version) { "1" }
43+
44+
it "calls Merge" do
45+
expect(Merge).to receive(:call)
46+
subject
47+
end
48+
end
49+
50+
context "when the pact_specification_version starts with '2.'" do
51+
let(:pact_specification_version) { "2.0" }
52+
53+
it "calls Merge" do
54+
expect(Merge).to receive(:call)
55+
subject
56+
end
57+
end
58+
59+
context "when the pact_specification_version starts with '3.'" do
60+
let(:pact_specification_version) { "3.0" }
61+
62+
it "calls V3::Merge" do
63+
expect(V3::Merge).to receive(:call)
64+
subject
65+
end
66+
end
67+
68+
context "when the pact_specification_version starts with '4.'" do
69+
let(:pact_specification_version) { "4.0" }
70+
71+
it "prints a warning" do
72+
expect(Pact.configuration.error_stream).to receive(:puts).with(/only knows how to parse v3 pacts/)
73+
subject
74+
end
75+
76+
it "calls V3::Merge" do
77+
expect(V3::Merge).to receive(:call)
78+
subject
79+
end
80+
end
81+
82+
context "when the pact_specification_version is with '11'" do
83+
let(:pact_specification_version) { "11" }
84+
85+
it "prints a warning" do
86+
expect(Pact.configuration.error_stream).to receive(:puts).with(/only knows how to parse v3 pacts/)
87+
subject
88+
end
89+
90+
it "calls V3::Merge" do
91+
expect(V3::Merge).to receive(:call)
92+
subject
93+
end
94+
end
95+
end
96+
end
97+
end

0 commit comments

Comments
 (0)