Skip to content

Commit

Permalink
feat: locate matching rules correctly for v3 pacts
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Mar 23, 2018
1 parent 07013de commit 0f22db2
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 38 deletions.
13 changes: 11 additions & 2 deletions lib/pact/consumer_contract/http_consumer_contract_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@ class HttpConsumerContractParser

def call(hash)
hash = symbolize_keys(hash)
interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash)}

options = { pact_specification_version: pact_specification_version(hash) }
interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash, options) }
ConsumerContract.new(
:consumer => ServiceConsumer.from_hash(hash[:consumer]),
:provider => ServiceProvider.from_hash(hash[:provider]),
:interactions => interactions
)
end

def pact_specification_version hash
# TODO handle all 3 ways of defining this...
# metadata.pactSpecificationVersion
maybe_pact_specification_version_1 = hash[:metadata] && hash[:metadata]['pactSpecification'] && hash[:metadata]['pactSpecification']['version']
maybe_pact_specification_version_2 = hash[:metadata] && hash[:metadata]['pactSpecificationVersion']
pact_specification_version = maybe_pact_specification_version_1 || maybe_pact_specification_version_2
Gem::Version.new(pact_specification_version)
end

def can_parse?(hash)
hash.key?('interactions') || hash.key?(:interactions)
end
Expand Down
29 changes: 26 additions & 3 deletions lib/pact/consumer_contract/interaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,33 @@ def initialize attributes = {}
@provider_state = attributes[:provider_state] || attributes[:providerState]
end

def self.from_hash hash
request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'])
def self.from_hash hash, options = {}
pact_specification_version = options[:pact_specification_version] || Gem::Version.new("") # use some global default
case pact_specification_version.segments.first
when 1, 2 then parse_v2_interaction(hash, pact_specification_version: pact_specification_version)
else parse_v3_interaction(hash, pact_specification_version: pact_specification_version)
end
end

def self.parse_v2_interaction hash, options
request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'], options)
request = Pact::Request::Expected.from_hash(request_hash)
response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'])
response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'], options)
response = Pact::Response.from_hash(response_hash)
new(symbolize_keys(hash).merge(request: request, response: response))
end

def self.parse_v3_interaction hash, options

request_hash = hash['request'].keys.each_with_object({}) do | key, new_hash |
new_hash[key] = Pact::MatchingRules.merge(hash['request'][key], hash['request'].fetch('matchingRules', {})[key], options)
end
request = Pact::Request::Expected.from_hash(request_hash)

response_hash = hash['response'].keys.each_with_object({}) do | key, new_hash |
new_hash[key] = Pact::MatchingRules.merge(hash['response'][key], hash['response'].fetch('matchingRules', {})[key], options)
end

response = Pact::Response.from_hash(response_hash)
new(symbolize_keys(hash).merge(request: request, response: response))
end
Expand Down
21 changes: 16 additions & 5 deletions lib/pact/matching_rules.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
require 'pact/matching_rules/extract'
require 'pact/matching_rules/merge'
require 'pact/matching_rules/v3/merge'

module Pact
module MatchingRules

# @api public Used by pact-mock_service
def self.extract object_graph
def self.extract object_graph, options = {}
Extract.(object_graph)
end

def self.merge object_graph, matching_rules
Merge.(object_graph, matching_rules)
def self.merge object_graph, matching_rules, options = {}
case options[:pact_specification_version].segments.first
when nil
Pact.configuration.error_stream.puts "No pact specification version found, using v2 code to parse contract"
Merge.(object_graph, matching_rules)
when 1, 2
Merge.(object_graph, matching_rules)
when 3
V3::Merge.(object_graph, matching_rules)
else
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."
V3::Merge.(object_graph, matching_rules)
end
end

end
end
end
36 changes: 36 additions & 0 deletions spec/fixtures/pact-http-v3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"consumer": {
"name": "consumer"
},
"interactions": [
{
"description": "a test request",
"providerState": "the weather is sunny",
"request": {
"method": "get",
"path": "/foo"
},
"response": {
"body": {
"foo": "bar"
},
"matchingRules": {
"body": {
"$.foo": {
"matchers": [{ "match": "type" }]
}
}
},
"status": 200
}
}
],
"provider": {
"name": "provider"
},
"metadata": {
"pactSpecification": {
"version": "3.0"
}
}
}
27 changes: 0 additions & 27 deletions spec/fixtures/pact-v3.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'pact/consumer_contract/http_consumer_contract_parser'

module Pact
describe HttpConsumerContractParser do
describe "#call integration test" do
subject { HttpConsumerContractParser.new.call(pact_hash) }

context "with a v3 pact" do
let(:pact_hash) { load_json_fixture('pact-http-v3.json') }

it "correctly parses the pact" do
expect(subject.interactions.first.response.body['foo']).to be_a(Pact::SomethingLike)
end
end
end
end
end
2 changes: 1 addition & 1 deletion spec/lib/pact/consumer_contract/interaction_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module Consumer
context "when there are matching rules" do
let(:hash) { load_json_fixture 'interaction-with-matching-rules.json' }

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

it "merges the rules with the example for the request" do
expect(subject.request.body['name']).to be_instance_of(Pact::Term)
Expand Down
97 changes: 97 additions & 0 deletions spec/lib/pact/matching_rules_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
require 'pact/matching_rules'

module Pact
module MatchingRules
describe ".merge" do
before do
allow(V3::Merge).to receive(:call)
allow(Merge).to receive(:call)
allow(Pact.configuration.error_stream).to receive(:puts)
end

let(:object) { double('object') }
let(:rules) { double('rules') }
let(:options) { { pact_specification_version: Gem::Version.new(pact_specification_version) } }

subject { MatchingRules.merge(object, rules, options)}

context "when the pact_specification_version is nil" do
let(:pact_specification_version) { nil }

it "prints a warning" do
expect(Pact.configuration.error_stream).to receive(:puts).with(/No pact specification version found/)
subject
end

it "calls Merge" do
expect(Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version starts with '1.'" do
let(:pact_specification_version) { "1.0" }

it "calls Merge" do
expect(Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version is with '1'" do
let(:pact_specification_version) { "1" }

it "calls Merge" do
expect(Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version starts with '2.'" do
let(:pact_specification_version) { "2.0" }

it "calls Merge" do
expect(Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version starts with '3.'" do
let(:pact_specification_version) { "3.0" }

it "calls V3::Merge" do
expect(V3::Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version starts with '4.'" do
let(:pact_specification_version) { "4.0" }

it "prints a warning" do
expect(Pact.configuration.error_stream).to receive(:puts).with(/only knows how to parse v3 pacts/)
subject
end

it "calls V3::Merge" do
expect(V3::Merge).to receive(:call)
subject
end
end

context "when the pact_specification_version is with '11'" do
let(:pact_specification_version) { "11" }

it "prints a warning" do
expect(Pact.configuration.error_stream).to receive(:puts).with(/only knows how to parse v3 pacts/)
subject
end

it "calls V3::Merge" do
expect(V3::Merge).to receive(:call)
subject
end
end
end
end
end

0 comments on commit 0f22db2

Please sign in to comment.