Skip to content

Commit 4471df3

Browse files
committed
feat(v3): parse array of provider states with params
1 parent 9159e06 commit 4471df3

10 files changed

+180
-14
lines changed

lib/pact/consumer_contract/interaction.rb

+13-7
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,32 @@ module Pact
55
class Interaction
66
include ActiveSupportSupport
77

8-
attr_accessor :description, :request, :response, :provider_state
8+
attr_accessor :description, :request, :response, :provider_state, :provider_states
99

1010
def initialize attributes = {}
1111
@description = attributes[:description]
1212
@request = attributes[:request]
1313
@response = attributes[:response]
1414
@provider_state = attributes[:provider_state] || attributes[:providerState]
15+
@provider_states = attributes[:provider_states]
1516
end
1617

1718
def self.from_hash hash, options = {}
1819
InteractionParser.call(hash, options)
1920
end
2021

2122
def to_hash
22-
{
23-
description: description,
24-
provider_state: provider_state,
25-
request: request.to_hash,
26-
response: response.to_hash
27-
}
23+
h = { description: description }
24+
25+
if provider_states
26+
h[:provider_states] = provider_states.collect(&:to_hash)
27+
else
28+
h[:provider_state] = provider_state
29+
end
30+
31+
h[:request] = request.to_hash
32+
h[:response] = response.to_hash
33+
h
2834
end
2935

3036
def http?

lib/pact/consumer_contract/interaction_v2_parser.rb

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'pact/consumer_contract/request'
22
require 'pact/consumer_contract/response'
3+
require 'pact/consumer_contract/provider_state'
34
require 'pact/symbolize_keys'
45
require 'pact/matching_rules'
56
require 'pact/errors'
@@ -12,7 +13,8 @@ class InteractionV2Parser
1213
def self.call hash, options
1314
request = parse_request(hash['request'], options)
1415
response = parse_response(hash['response'], options)
15-
Interaction.new(symbolize_keys(hash).merge(request: request, response: response))
16+
provider_states = parse_provider_states(hash['providerState'] || hash['provider_state'])
17+
Interaction.new(symbolize_keys(hash).merge(request: request, response: response, provider_states: provider_states))
1618
end
1719

1820
def self.parse_request request_hash, options
@@ -24,5 +26,9 @@ def self.parse_response response_hash, options
2426
response_hash = Pact::MatchingRules.merge(response_hash, response_hash['matchingRules'], options)
2527
Pact::Response.from_hash(response_hash)
2628
end
29+
30+
def self.parse_provider_states provider_state_name
31+
provider_state_name ? [Pact::ProviderState.new(provider_state_name)] : []
32+
end
2733
end
2834
end

lib/pact/consumer_contract/interaction_v3_parser.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'pact/consumer_contract/request'
22
require 'pact/consumer_contract/response'
3+
require 'pact/consumer_contract/provider_state'
34
require 'pact/symbolize_keys'
45
require 'pact/matching_rules'
56
require 'pact/errors'
@@ -13,7 +14,12 @@ class InteractionV3Parser
1314
def self.call hash, options
1415
request = parse_request(hash['request'], options)
1516
response = parse_response(hash['response'], options)
16-
Interaction.new(symbolize_keys(hash).merge(request: request, response: response))
17+
provider_states = parse_provider_states(hash['providerStates'])
18+
provider_state = provider_states.any? ? provider_states.first.name : nil
19+
if provider_states && provider_states.size > 1
20+
Pact.configuration.error_stream.puts("WARN: Currently only 1 provider state is supported. Ignoring ")
21+
end
22+
Interaction.new(symbolize_keys(hash).merge(request: request, response: response, provider_states: provider_states, provider_state: provider_state))
1723
end
1824

1925
def self.parse_request request_hash, options
@@ -57,5 +63,11 @@ def self.parse_response_with_string_body response_hash, response_matching_rules,
5763
string_with_matching_rules = StringWithMatchingRules.new(response_hash['body'], options[:pact_specification_version], response_matching_rules)
5864
Pact::Response.from_hash(response_hash.merge('body' => string_with_matching_rules))
5965
end
66+
67+
def self.parse_provider_states provider_states
68+
(provider_states || []).collect do | provider_state_hash |
69+
Pact::ProviderState.new(provider_state_hash['name'], provider_state_hash['params'])
70+
end
71+
end
6072
end
6173
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module Pact
2+
class ProviderState
3+
4+
attr_reader :name, :params
5+
6+
def initialize name, params = {}
7+
@name = name
8+
@params = params
9+
end
10+
11+
def self.from_hash(hash)
12+
new(hash["name"], hash["params"])
13+
end
14+
15+
def ==(other)
16+
other.is_a?(Pact::ProviderState) && other.name == self.name && other.params == self.params
17+
end
18+
19+
def to_hash
20+
{
21+
"name" => name,
22+
"params" => params
23+
}
24+
end
25+
26+
def to_json(opts = {})
27+
as_json(opts).to_json(opts)
28+
end
29+
30+
def as_json(opts = {})
31+
to_hash
32+
end
33+
end
34+
end

lib/pact/consumer_contract/query.rb

-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33

44
module Pact
55
class Query
6-
76
def self.create query
87
if query.is_a? Hash
98
Pact::QueryHash.new(query)
109
else
1110
Pact::QueryString.new(query)
1211
end
1312
end
14-
1513
end
1614
end

lib/pact/consumer_contract/query_hash.rb

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ def empty?
4747
@hash && @hash.empty?
4848
end
4949

50+
def to_hash
51+
@hash
52+
end
53+
5054
private
5155

5256
def convert_to_hash_of_arrays(query)

spec/lib/pact/consumer_contract/interaction_spec.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ module Consumer
3838

3939
describe "matches_criteria?" do
4040
subject { InteractionFactory.create(:description => 'a request for food') }
41+
4142
context "by description" do
4243
context "when the interaction matches" do
4344
it "returns true" do
4445
expect(subject.matches_criteria?(:description => /request.*food/)).to be true
4546
end
4647
end
48+
4749
context "when the interaction does not match" do
4850
it "returns false" do
4951
expect(subject.matches_criteria?(:description => /blah/)).to be false
@@ -52,10 +54,7 @@ module Consumer
5254
end
5355
end
5456

55-
56-
5757
describe "request_modifies_resource_without_checking_response_body?" do
58-
5958
let(:interaction) { Interaction.new(request: request, response: response)}
6059

6160
subject { interaction.request_modifies_resource_without_checking_response_body?}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require 'pact/consumer_contract/interaction_v2_parser'
2+
3+
module Pact
4+
describe InteractionV2Parser do
5+
describe ".call" do
6+
let(:interaction_hash) do
7+
{
8+
"description" => "description",
9+
"request" => { "method" => "GET", "path" => "/" },
10+
"response" => { "status" => 200 },
11+
"providerState" => "foo"
12+
}
13+
end
14+
15+
let(:options) do
16+
{
17+
pact_specification_version: Pact::SpecificationVersion.new("3.0")
18+
}
19+
end
20+
21+
subject { InteractionV2Parser.call(interaction_hash, options) }
22+
23+
describe "provider_states" do
24+
it "returns an array of provider states with size 1" do
25+
expect(subject.provider_states.size).to eq 1
26+
end
27+
28+
it "sets the name of the provider state to the string provided" do
29+
expect(subject.provider_states.first.name)
30+
end
31+
32+
it "sets the params to an empty hash" do
33+
expect(subject.provider_states.first.params).to eq({})
34+
end
35+
36+
context "when the providerState is nil" do
37+
before do
38+
interaction_hash["providerState"] = nil
39+
end
40+
41+
it "returns an empty list" do
42+
expect(subject.provider_states).to be_empty
43+
end
44+
end
45+
end
46+
47+
describe "provider_state" do
48+
it "sets the name from the hash" do
49+
expect(subject.provider_state).to eq "foo"
50+
end
51+
end
52+
end
53+
end
54+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
require 'pact/consumer_contract/interaction_v3_parser'
2+
3+
module Pact
4+
describe InteractionV3Parser do
5+
describe ".call" do
6+
7+
let(:interaction_hash) do
8+
{
9+
"description" => "description",
10+
"request" => { "method" => "GET", "path" => "/" },
11+
"response" => { "status" => 200 },
12+
"providerStates" => [{
13+
"name" => "foo",
14+
"params" => {"a" => "b"}
15+
}]
16+
}
17+
end
18+
19+
let(:options) do
20+
{
21+
pact_specification_version: Pact::SpecificationVersion.new("3.0")
22+
}
23+
end
24+
25+
subject { InteractionV3Parser.call(interaction_hash, options) }
26+
27+
describe "provider_states" do
28+
it "parses the array of provider states" do
29+
expect(subject.provider_states.size).to eq 1
30+
end
31+
32+
it "parses the name of each" do
33+
expect(subject.provider_states.first.name)
34+
end
35+
36+
it "parses the params of each" do
37+
expect(subject.provider_states.first.params).to eq "a" => "b"
38+
end
39+
end
40+
41+
describe "provider_state" do
42+
it "sets the provider_state string to the name of the first providerState for backwards compatibility while we implement v3" do
43+
expect(subject.provider_state).to eq "foo"
44+
end
45+
end
46+
end
47+
end
48+
end

spec/support/factories.rb

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ def self.create hash = {}
4040
'body' => {a: 'response body'}
4141
}
4242
}
43+
44+
if hash.key?(:provider_states) || hash.key?('provider_states')
45+
defaults.delete('provider_state')
46+
end
47+
4348
Pact::Interaction.from_hash(stringify_keys(deep_merge(defaults, stringify_keys(hash))))
4449
end
4550
end

0 commit comments

Comments
 (0)