Skip to content

Commit

Permalink
feat: use new 'pacts for verification' endpoint to retrieve pacts (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque authored Sep 26, 2019
1 parent 39e6221 commit 55bb935
Show file tree
Hide file tree
Showing 20 changed files with 344 additions and 206 deletions.
16 changes: 11 additions & 5 deletions lib/pact/cli/run_pact_verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ def load_pact_helper
end

def run_specs
exit_code = if options[:pact_uri]
run_with_pact_uri
exit_code = if options[:pact_uri].is_a?(String)
run_with_pact_url_string
elsif options[:pact_uri]
run_with_pact_uri_object # from pact-provider-verifier
else
run_with_configured_pacts
run_with_configured_pacts_from_pact_helper
end
exit exit_code
end

def run_with_pact_uri
def run_with_pact_url_string
pact_repository_uri_options = {}
pact_repository_uri_options[:username] = options[:pact_broker_username] if options[:pact_broker_username]
pact_repository_uri_options[:password] = options[:pact_broker_password] if options[:pact_broker_password]
Expand All @@ -61,7 +63,11 @@ def run_with_pact_uri
Pact::Provider::PactSpecRunner.new([pact_uri], pact_spec_options).run
end

def run_with_configured_pacts
def run_with_pact_uri_object
Pact::Provider::PactSpecRunner.new([options[:pact_uri]], pact_spec_options).run
end

def run_with_configured_pacts_from_pact_helper
pact_urls = Pact.provider_world.pact_urls
raise "Please configure a pact to verify" if pact_urls.empty?
Pact::Provider::PactSpecRunner.new(pact_urls, pact_spec_options).run
Expand Down
7 changes: 5 additions & 2 deletions lib/pact/hal/http_client.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'pact/retry'
require 'pact/hal/authorization_header_redactor'
require 'net/http'
require 'rack'

module Pact
module Hal
Expand All @@ -15,9 +16,11 @@ def initialize options
end

def get href, params = {}, headers = {}
query = params.collect{ |(key, value)| "#{CGI::escape(key)}=#{CGI::escape(value)}" }.join("&")
uri = URI(href)
uri.query = query
if params && params.any?
existing_params = Rack::Utils.parse_nested_query(uri.query)
uri.query = Rack::Utils.build_nested_query(existing_params.merge(params))
end
perform_request(create_request(uri, 'Get', nil, headers), uri)
end

Expand Down
20 changes: 19 additions & 1 deletion lib/pact/hal/link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ def get(payload = {}, headers = {})
wrap_response(href, @http_client.get(href, payload, headers))
end

def get!(*args)
get(*args).assert_success!
end

def put(payload = nil, headers = {})
wrap_response(href, @http_client.put(href, payload ? payload.to_json : nil, headers))
end
Expand All @@ -51,11 +55,25 @@ def post(payload = nil, headers = {})
def expand(params)
expanded_url = expand_url(params, href)
new_attrs = @attrs.merge('href' => expanded_url)
Link.new(new_attrs, @http_client)
Link.new(new_attrs, http_client)
end

def with_query(query)
if query && query.any?
uri = URI(href)
existing_query_params = Rack::Utils.parse_nested_query(uri.query)
uri.query = Rack::Utils.build_nested_query(existing_query_params.merge(query))
new_attrs = attrs.merge('href' => uri.to_s)
Link.new(new_attrs, http_client)
else
self
end
end

private

attr_reader :attrs, :http_client

def wrap_response(href, http_response)
require 'pact/hal/entity' # avoid circular reference
if http_response.success?
Expand Down
14 changes: 10 additions & 4 deletions lib/pact/pact_broker.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
require 'pact/pact_broker/fetch_pacts'
require 'pact/pact_broker/fetch_pending_pacts'
require 'pact/pact_broker/fetch_pact_uris_for_verification'
require 'pact/provider/pact_uri'

#
# @public Use by Pact Provider Verifier
# @public Used by Pact Provider Verifier
#
module Pact
module PactBroker
extend self

# Keep for backwards compatibility with pact-provider-verifier < 1.23.1
def fetch_pact_uris *args
Pact::PactBroker::FetchPacts.call(*args).collect(&:uri)
end

def fetch_pending_pact_uris *args
Pact::PactBroker::FetchPendingPacts.call(*args).collect(&:uri)
def fetch_pact_uris_for_verification *args
Pact::PactBroker::FetchPactURIsForVerification.call(*args)
end

def build_pact_uri(*args)
Pact::Provider::PactURI.new(*args)
end
end
end
96 changes: 96 additions & 0 deletions lib/pact/pact_broker/fetch_pact_uris_for_verification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require 'pact/hal/entity'
require 'pact/hal/http_client'
require 'pact/provider/pact_uri'
require 'pact/errors'
require 'pact/pact_broker/fetch_pacts'

module Pact
module PactBroker
class FetchPactURIsForVerification
attr_reader :provider, :consumer_version_selectors, :provider_version_tags, :broker_base_url, :http_client_options, :http_client

PACTS_FOR_VERIFICATION_RELATION = 'beta:provider-pacts-for-verification'.freeze
PACTS = 'pacts'.freeze
HREF = 'href'.freeze
LINKS = '_links'.freeze
SELF = 'self'.freeze
EMBEDDED = '_embedded'.freeze

def initialize(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options)
@provider = provider
@consumer_version_selectors = consumer_version_selectors
@provider_version_tags = provider_version_tags
@http_client_options = http_client_options
@broker_base_url = broker_base_url
@http_client = Pact::Hal::HttpClient.new(http_client_options)
end

def self.call(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options)
new(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options).call
end

def call
if index.can?(PACTS_FOR_VERIFICATION_RELATION)
log_message
pacts_for_verification
else
# Fall back to old method of fetching pacts
consumer_version_tags = consumer_version_selectors.collect{ | selector | selector[:tag] }
FetchPacts.call(provider, consumer_version_tags, broker_base_url, http_client_options)
end
end

private

def index
@index_entity ||= Pact::Hal::Link.new({ "href" => broker_base_url }, http_client).get.assert_success!
end

def pacts_for_verification
pacts_for_verification_entity.response.body[EMBEDDED][PACTS].collect do | pact |
metadata = {
pending: pact["verificationProperties"]["pending"],
pending_reason: pact["verificationProperties"]["pendingReason"],
inclusion_reason: pact["verificationProperties"]["inclusionReason"],
}
Pact::Provider::PactURI.new(pact[LINKS][SELF][HREF], http_client_options, metadata)
end
end

def pacts_for_verification_entity
index
._link(PACTS_FOR_VERIFICATION_RELATION)
.expand(provider: provider)
.with_query(query)
.get!
end

def query
q = {}
if consumer_version_selectors&.any?
q["consumer_version_selectors"] = consumer_version_selectors
end

if provider_version_tags&.any?
q["provider_version_tags"] = provider_version_tags
end
q
end

def log_message
latest = consumer_version_selectors&.any? ? "" : "latest "
message = "INFO: Fetching #{latest}pacts for #{provider} from #{broker_base_url}"
if consumer_version_selectors&.any?
desc = consumer_version_selectors.collect do |selector|
all_or_latest = selector[:all] ? "all" : "latest"
# TODO support fallback
name = selector[:fallback] ? "#{selector[:tag]} (or #{selector[:fallback]} if not found)" : selector[:tag]
"#{all_or_latest} #{name}"
end.join(", ")
message << " for tags: #{desc}"
end
Pact.configuration.output_stream.puts message
end
end
end
end
58 changes: 0 additions & 58 deletions lib/pact/pact_broker/fetch_pending_pacts.rb

This file was deleted.

26 changes: 22 additions & 4 deletions lib/pact/provider/configuration/pact_verification_from_broker.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'pact/shared/dsl'
require 'pact/provider/world'
require 'pact/pact_broker/fetch_pacts'
require 'pact/pact_broker/fetch_pact_uris_for_verification'
require 'pact/errors'

module Pact
Expand All @@ -14,10 +14,11 @@ class PactVerificationFromBroker
# in parent scope, it will clash with these ones,
# so put an underscore in front of the name to be safer.

attr_accessor :_provider_name, :_pact_broker_base_url, :_consumer_version_tags, :_basic_auth_options, :_verbose
attr_accessor :_provider_name, :_pact_broker_base_url, :_consumer_version_tags, :_provider_version_tags, :_basic_auth_options, :_verbose

def initialize(provider_name)
def initialize(provider_name, provider_version_tags)
@_provider_name = provider_name
@_provider_version_tags = provider_version_tags
@_consumer_version_tags = []
@_verbose = false
end
Expand Down Expand Up @@ -45,10 +46,27 @@ def finalize
private

def create_pact_verification
fetch_pacts = Pact::PactBroker::FetchPacts.new(_provider_name, _consumer_version_tags, _pact_broker_base_url, _basic_auth_options.merge(verbose: _verbose))
fetch_pacts = Pact::PactBroker::FetchPactURIsForVerification.new(
_provider_name,
consumer_version_selectors,
_provider_version_tags,
_pact_broker_base_url,
_basic_auth_options.merge(verbose: _verbose)
)

Pact.provider_world.add_pact_uri_source fetch_pacts
end

def consumer_version_selectors
# TODO support "all"
_consumer_version_tags.collect do | tag |
{
tag: tag,
latest: true
}
end
end

def validate
raise Pact::Error.new("Please provide a pact_broker_base_url from which to retrieve the pacts") unless _pact_broker_base_url
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact/provider/configuration/service_provider_dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def create_pact_verification consumer_name, options, &block
end

def create_pact_verification_from_broker(&block)
PactVerificationFromBroker.build(name, &block)
PactVerificationFromBroker.build(name, tags, &block)
end

def finalize
Expand Down
10 changes: 6 additions & 4 deletions lib/pact/provider/pact_uri.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
module Pact
module Provider
class PactURI
attr_reader :uri, :options
attr_reader :uri, :options, :metadata

def initialize (uri, options={})
def initialize (uri, options = nil, metadata = nil)
@uri = uri
@options = options
@options = options || {}
@metadata = metadata || {} # make sure it's not nil if nil is passed in
end

def == other
other.is_a?(PactURI) &&
uri == other.uri &&
options == other.options
options == other.options &&
metadata == other.metadata
end

def basic_auth?
Expand Down
12 changes: 7 additions & 5 deletions lib/pact/provider/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ module ClassMethods
include ::RSpec::Core::DSL

def honour_pactfile pact_uri, pact_json, options
pact_description = options[:ignore_failures] ? "Pending pact" : "pact"
Pact.configuration.output_stream.puts "INFO: Reading #{pact_description} at #{pact_uri}"
Pact.configuration.output_stream.puts "INFO: Filtering interactions by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
Pact.configuration.output_stream.puts "INFO: Reading pact at #{pact_uri}"
Pact.configuration.output_stream.puts("DEBUG: #{pact_uri.metadata[:inclusion_reason]}") if pact_uri.metadata[:inclusion_reason]
Pact.configuration.output_stream.puts("DEBUG: #{pact_uri.metadata[:pending_reason]}") if pact_uri.metadata[:pending_reason]
Pact.configuration.output_stream.puts "DEBUG: Filtering interactions by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
consumer_contract = Pact::ConsumerContract.from_json(pact_json)
::RSpec.describe "Verifying a #{pact_description} between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}", pactfile_uri: pact_uri do
suffix = pact_uri.metadata[:pending] ? " [PENDING]": ""
::RSpec.describe "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}#{suffix}", pactfile_uri: pact_uri do
honour_consumer_contract consumer_contract, options.merge(pact_json: pact_json, pact_uri: pact_uri)
end
end
Expand Down Expand Up @@ -74,7 +76,7 @@ def describe_interaction interaction, options
pact_interaction: interaction,
pact_interaction_example_description: interaction_description_for_rerun_command(interaction),
pact_uri: options[:pact_uri],
pact_ignore_failures: options[:ignore_failures]
pact_ignore_failures: options[:pact_uri].metadata[:pending]
}

describe description_for(interaction), metadata do
Expand Down
Loading

0 comments on commit 55bb935

Please sign in to comment.