Skip to content

Commit

Permalink
feat(message contracts): read message pact into Ruby object
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Jan 8, 2018
1 parent 98aca2f commit 6573bd4
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 23 deletions.
15 changes: 12 additions & 3 deletions lib/pact/consumer_contract/consumer_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
require 'pact/consumer_contract/service_consumer'
require 'pact/consumer_contract/service_provider'
require 'pact/consumer_contract/interaction'
require 'pact/consumer_contract/message'
require 'pact/consumer_contract/pact_file'

module Pact
Expand All @@ -31,10 +32,18 @@ def initialize(attributes = {})

def self.from_hash(hash)
hash = symbolize_keys(hash)
interactions = if hash[:interactions]
hash[:interactions].collect { |hash| Interaction.from_hash(hash)}
elsif hash[:messages]
hash[:messages].collect { |hash| Message.from_hash(hash)}
else
[]
end

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

Expand All @@ -54,9 +63,9 @@ def self.maintain_backwards_compatiblity_with_producer_keys string
def find_interaction criteria
interactions = find_interactions criteria
if interactions.size == 0
raise "Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
raise Pact::Error.new("Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
elsif interactions.size > 1
raise "Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
raise Pact::Error.new("Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
end
interactions.first
end
Expand Down
67 changes: 67 additions & 0 deletions lib/pact/consumer_contract/message.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'pact/consumer_contract/message/content'
require 'pact/symbolize_keys'
require 'pact/shared/active_support_support'
require 'pact/matching_rules'
require 'pact/errors'

module Pact
class Message
include ActiveSupportSupport
include SymbolizeKeys

attr_accessor :description, :content, :provider_state

def initialize attributes = {}
@description = attributes[:description]
@request = attributes[:content]
@provider_state = attributes[:provider_state] || attributes[:providerState]
end

def self.from_hash hash
content_hash = Pact::MatchingRules.merge(hash['content'], hash['content']['matchingRules'])
content = Pact::Message::Content.new(content_hash)
new(symbolize_keys(hash).merge(content: content))
end

def to_hash
{
description: description,
provider_state: provider_state,
content: content.to_hash,
}
end

def validate!
raise Pact::InvalidMessageError.new(self) unless description && content
end

def == other
other.is_a?(Message) && to_hash == other.to_hash
end

def matches_criteria? criteria
criteria.each do | key, value |
unless match_criterion self.send(key.to_s), value
return false
end
end
true
end

def match_criterion target, criterion
target == criterion || (criterion.is_a?(Regexp) && criterion.match(target))
end

def eq? other
self == other
end

def description_with_provider_state_quoted
provider_state ? "\"#{description}\" given \"#{provider_state}\"" : "\"#{description}\""
end

def to_s
to_hash.to_s
end
end
end
9 changes: 9 additions & 0 deletions lib/pact/consumer_contract/message/content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Pact
class Message
class Content < Hash
include ActiveSupportSupport
include SymbolizeKeys

end
end
end
3 changes: 3 additions & 0 deletions lib/pact/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ module Pact
class Error < ::StandardError
end

class InvalidMessageError < Error
end

# Raised when the interaction is not defined correctly
class InvalidInteractionError < Error
def initialize(interaction)
Expand Down
65 changes: 45 additions & 20 deletions spec/lib/pact/consumer_contract/consumer_contract_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,66 @@

module Pact
describe ConsumerContract do

describe ".from_json" do

let(:loaded_pact) { ConsumerContract.from_json(string) }
context "when the top level object is a ConsumerContract" do
let(:string) { '{"interactions":[{"request": {"path":"/path", "method" : "get"}, "response": {"status" : 200}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"} }' }

it "should create a Pact" do
expect(loaded_pact).to be_instance_of ConsumerContract
end
context "with an HTTP contract" do
context "when the top level object is a ConsumerContract" do
let(:string) { '{"interactions":[{"request": {"path":"/path", "method" : "get"}, "response": {"status" : 200}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"} }' }

it "should have interactions" do
expect(loaded_pact.interactions).to be_instance_of Array
end
it "should create a Pact" do
expect(loaded_pact).to be_instance_of ConsumerContract
end

it "should have a consumer" do
expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
it "should have interactions" do
expect(loaded_pact.interactions).to be_instance_of Array
end

it "should have a consumer" do
expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
end

it "should have a provider" do
expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
end
end

it "should have a provider" do
expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
context "with old 'producer' key" do
let(:string) { File.read('./spec/support/a_consumer-a_producer.json')}
it "should create a Pact" do
expect(loaded_pact).to be_instance_of ConsumerContract
end

it "should have interactions" do
expect(loaded_pact.interactions).to be_instance_of Array
end

it "should have a consumer" do
expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
end

it "should have a provider" do
expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
expect(loaded_pact.provider.name).to eq "an old producer"
end

it "should have a provider_state" do
expect(loaded_pact.interactions.first.provider_state).to eq 'state one'
end
end
end

context "with old 'producer' key" do
let(:string) { File.read('./spec/support/a_consumer-a_producer.json')}
context "with a Message contract" do
let(:string) { '{"messages":[{"content": {"foo": "bar"}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"}}' }

it "should create a Pact" do
expect(loaded_pact).to be_instance_of ConsumerContract
end

it "should have interactions" do
it "should have messages" do
expect(loaded_pact.interactions).to be_instance_of Array
expect(loaded_pact.interactions.first).to be_instance_of Pact::Message
end

it "should have a consumer" do
Expand All @@ -42,12 +71,8 @@ module Pact

it "should have a provider" do
expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
expect(loaded_pact.provider.name).to eq "an old producer"
end

it "should have a provider_state" do
expect(loaded_pact.interactions.first.provider_state).to eq 'state one'
end
end
end

Expand Down

0 comments on commit 6573bd4

Please sign in to comment.