Skip to content

Commit

Permalink
feat: support merging message pacts when publishing
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed May 2, 2022
1 parent 527f374 commit 732b22d
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 53 deletions.
31 changes: 21 additions & 10 deletions lib/pact_broker/client/merge_pacts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,40 @@ def call pact_hashes
def merge original, additional
new_pact = JSON.parse(original.to_json, symbolize_names: true)

additional[:interactions].each do |new_interaction|
merge_interactions_or_messages(new_pact, original, additional, :interactions)
merge_interactions_or_messages(new_pact, original, additional, :messages)

new_pact
end

private

def merge_interactions_or_messages(new_pact, original, additional, key)
return unless additional[key] || original[key]

additional_messages_or_interactions = additional[key] || []
original_messages_or_interactions = original[key] || []
new_pact[key] ||= []

additional_messages_or_interactions.each do |new_interaction|
# check to see if this interaction matches an existing interaction
overwrite_index = original[:interactions].find_index do |original_interaction|
overwrite_index = original_messages_or_interactions.find_index do |original_interaction|
same_description_and_state?(original_interaction, new_interaction)
end

# overwrite existing interaction if a match is found, otherwise appends the new interaction
if overwrite_index
if new_interaction == original[:interactions][overwrite_index]
new_pact[:interactions][overwrite_index] = new_interaction
if new_interaction == original_messages_or_interactions[overwrite_index]
new_pact[key][overwrite_index] = new_interaction
else
raise PactMergeError, almost_duplicate_message(original[:interactions][overwrite_index], new_interaction)
raise PactMergeError, almost_duplicate_message(original_messages_or_interactions[overwrite_index], new_interaction)
end
else
new_pact[:interactions] << new_interaction
new_pact[key] << new_interaction
end
end

new_pact
end

private

def almost_duplicate_message(original, new_interaction)
"Two interactions have been found with same description (#{new_interaction[:description].inspect}) and provider state (#{new_interaction[:providerState].inspect}) but a different request or response. " +
"Please use a different description or provider state, or hard-code any random data.\n\n" +
Expand Down
189 changes: 146 additions & 43 deletions spec/lib/pact_broker/client/merge_pacts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,166 @@ module PactBroker
module Client
describe MergePacts do
describe ".call" do
let(:pact_hash_1) do
{
other: 'info',
interactions: [
{providerState: 1, description: 1, foo: 'bar' }
]
}
end
describe "with a pact with interactions" do
let(:pact_hash_1) do
{
other: 'info',
interactions: [
{ providerState: 1, description: 1, foo: 'bar' }
]
}
end

let(:pact_hash_2) do
{
interactions: [
{providerState: 2, description: 2, foo: 'wiffle' }
]
}
end
let(:pact_hash_2) do
{
interactions: [
{ providerState: 2, description: 2, foo: 'wiffle' }
]
}
end

let(:pact_hash_3) do
{
interactions: [
{providerState: 3, description: 3, foo: 'meep' },
{providerState: 1, description: 1, foo: 'bar' }
]
}
end
let(:pact_hash_3) do
{
interactions: [
{ providerState: 3, description: 3, foo: 'meep' },
{ providerState: 1, description: 1, foo: 'bar' }
]
}
end

let(:pact_hashes) { [pact_hash_1, pact_hash_2, pact_hash_3] }

let(:expected_merge) do
{
other: 'info',
interactions: [
{providerState: 1, description: 1, foo: 'bar' },
{providerState: 2, description: 2, foo: 'wiffle' },
{providerState: 3, description: 3, foo: 'meep' }
]
}
end
let(:pact_hashes) { [pact_hash_1, pact_hash_2, pact_hash_3] }

let(:expected_merge) do
{
other: 'info',
interactions: [
{ providerState: 1, description: 1, foo: 'bar' },
{ providerState: 2, description: 2, foo: 'wiffle' },
{ providerState: 3, description: 3, foo: 'meep' }
]
}
end

subject { MergePacts.call(pact_hashes) }

subject { MergePacts.call(pact_hashes) }
it "merges the interactions by consumer/provider" do
expect(subject).to eq expected_merge
end

context "when an interaction is found with the same state and description but has a difference elsewhere" do
let(:pact_hash_3) do
{
interactions: [
{ providerState: 3, description: 3, foo: 'meep' },
{ providerState: 1, description: 1, foo: 'different' }
]
}
end

it "merges the interactions by consumer/provider" do
expect(subject).to eq expected_merge
it "raises an error" do
expect { subject }.to raise_error PactMergeError, /foo.*different/
end
end
end

context "when an interaction is found with the same state and description but has a difference elsewhere" do
describe "with a pact with messages" do
let(:pact_hash_1) do
{
other: 'info',
messages: [
{ providerState: 1, description: 1, foo: 'bar' }
]
}
end

let(:pact_hash_2) do
{
messages: [
{ providerState: 2, description: 2, foo: 'wiffle' }
]
}
end

let(:pact_hash_3) do
{
messages: [
{ providerState: 3, description: 3, foo: 'meep' },
{ providerState: 1, description: 1, foo: 'bar' }
]
}
end

let(:pact_hashes) { [pact_hash_1, pact_hash_2, pact_hash_3] }

let(:expected_merge) do
{
other: 'info',
messages: [
{ providerState: 1, description: 1, foo: 'bar' },
{ providerState: 2, description: 2, foo: 'wiffle' },
{ providerState: 3, description: 3, foo: 'meep' }
]
}
end

subject { MergePacts.call(pact_hashes) }

it "merges the messages by consumer/provider" do
expect(subject).to eq expected_merge
end

context "when an interaction is found with the same state and description but has a difference elsewhere" do
let(:pact_hash_3) do
{
messages: [
{ providerState: 3, description: 3, foo: 'meep' },
{ providerState: 1, description: 1, foo: 'different' }
]
}
end

it "raises an error" do
expect { subject }.to raise_error PactMergeError, /foo.*different/
end
end
end

describe "with a pact with messages and a pact with interactions" do
let(:pact_hash_1) do
{
other: 'info',
messages: [
{ providerState: 1, description: 1, foo: 'bar' }
]
}
end

let(:pact_hash_2) do
{
interactions: [
{providerState: 3, description: 3, foo: 'meep' },
{providerState: 1, description: 1, foo: 'different' }
{ providerState: 2, description: 2, foo: 'wiffle' }
]
}
end

it "raises an error" do
expect { subject }.to raise_error PactMergeError, /foo.*different/
let(:pact_hashes) { [pact_hash_1, pact_hash_2] }

let(:expected_merge) do
{
other: 'info',
messages: [
{ providerState: 1, description: 1, foo: 'bar' }
],
interactions: [
{ providerState: 2, description: 2, foo: 'wiffle' }
]
}
end

subject { MergePacts.call(pact_hashes) }

it "merges the messages by consumer/provider" do
expect(subject).to eq expected_merge
end
end
end
Expand Down

0 comments on commit 732b22d

Please sign in to comment.