diff --git a/lib/pact/cli/run_pact_verification.rb b/lib/pact/cli/run_pact_verification.rb index 5dfcffa3..0914b2c4 100644 --- a/lib/pact/cli/run_pact_verification.rb +++ b/lib/pact/cli/run_pact_verification.rb @@ -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] @@ -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 diff --git a/lib/pact/hal/http_client.rb b/lib/pact/hal/http_client.rb index 5a99886c..d32891d0 100644 --- a/lib/pact/hal/http_client.rb +++ b/lib/pact/hal/http_client.rb @@ -1,6 +1,7 @@ require 'pact/retry' require 'pact/hal/authorization_header_redactor' require 'net/http' +require 'rack' module Pact module Hal @@ -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 diff --git a/lib/pact/hal/link.rb b/lib/pact/hal/link.rb index 0494b9b4..7e828586 100644 --- a/lib/pact/hal/link.rb +++ b/lib/pact/hal/link.rb @@ -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 @@ -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? diff --git a/lib/pact/pact_broker.rb b/lib/pact/pact_broker.rb index 45293c07..c91f7ed2 100644 --- a/lib/pact/pact_broker.rb +++ b/lib/pact/pact_broker.rb @@ -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 diff --git a/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb b/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb new file mode 100644 index 00000000..fd3d4d68 --- /dev/null +++ b/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb @@ -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 diff --git a/lib/pact/pact_broker/fetch_pending_pacts.rb b/lib/pact/pact_broker/fetch_pending_pacts.rb deleted file mode 100644 index 10faee5d..00000000 --- a/lib/pact/pact_broker/fetch_pending_pacts.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'pact/hal/entity' -require 'pact/hal/http_client' -require 'pact/provider/pact_uri' -require 'pact/errors' - -module Pact - module PactBroker - class FetchPendingPacts - attr_reader :provider, :tags, :broker_base_url, :http_client_options, :http_client, :index_entity - - PENDING_PROVIDER_RELATION = 'beta:pending-provider-pacts'.freeze - WIP_PROVIDER_RELATION = 'beta:wip-provider-pacts'.freeze # deprecated - PACTS = 'pacts'.freeze - PB_PACTS = 'pb:pacts'.freeze - HREF = 'href'.freeze - - def initialize(provider, broker_base_url, http_client_options) - @provider = provider - @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, broker_base_url, http_client_options) - new(provider, broker_base_url, http_client_options).call - end - - def call - if index.success? - pending_pacts_for_provider - else - raise Pact::Error.new("Error retrieving #{broker_base_url} status=#{index_entity.response.code} #{index_entity.response.raw_body}") - end - end - - private - - def index - @index_entity ||= Pact::Hal::Link.new({ "href" => broker_base_url }, http_client).get.assert_success! - end - - def pending_pacts_for_provider - link = index_entity._link(WIP_PROVIDER_RELATION, PENDING_PROVIDER_RELATION) - if link - get_pact_urls(link.expand(provider: provider).get) - else - [] - end - end - - def get_pact_urls(link_by_provider) - link_by_provider.fetch(PB_PACTS, PACTS).collect do |pact| - Pact::Provider::PactURI.new(pact[HREF], http_client_options) - end - end - end - end -end diff --git a/lib/pact/provider/configuration/pact_verification_from_broker.rb b/lib/pact/provider/configuration/pact_verification_from_broker.rb index c2778723..ea688944 100644 --- a/lib/pact/provider/configuration/pact_verification_from_broker.rb +++ b/lib/pact/provider/configuration/pact_verification_from_broker.rb @@ -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 @@ -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 @@ -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 diff --git a/lib/pact/provider/configuration/service_provider_dsl.rb b/lib/pact/provider/configuration/service_provider_dsl.rb index bdd29ce4..73ce4dde 100644 --- a/lib/pact/provider/configuration/service_provider_dsl.rb +++ b/lib/pact/provider/configuration/service_provider_dsl.rb @@ -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 diff --git a/lib/pact/provider/pact_uri.rb b/lib/pact/provider/pact_uri.rb index c5f36474..1a43ed03 100644 --- a/lib/pact/provider/pact_uri.rb +++ b/lib/pact/provider/pact_uri.rb @@ -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? diff --git a/lib/pact/provider/rspec.rb b/lib/pact/provider/rspec.rb index 9ac48d50..61dfed0d 100644 --- a/lib/pact/provider/rspec.rb +++ b/lib/pact/provider/rspec.rb @@ -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 @@ -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 diff --git a/spec/features/production_spec.rb b/spec/features/production_spec.rb index ca4ccef8..b11a89ed 100644 --- a/spec/features/production_spec.rb +++ b/spec/features/production_spec.rb @@ -81,7 +81,7 @@ def call(env) end end - honour_consumer_contract pact + honour_consumer_contract pact, pact_uri: Pact::Provider::PactURI.new("http://dummy-uri") end @@ -116,7 +116,7 @@ def call(env) end - honour_consumer_contract consumer_contract + honour_consumer_contract consumer_contract, pact_uri: Pact::Provider::PactURI.new("http://dummy-uri") end context "that is a string" do @@ -148,7 +148,7 @@ def call(env) end - honour_consumer_contract consumer_contract + honour_consumer_contract consumer_contract, pact_uri: Pact::Provider::PactURI.new("http://dummy-uri") end end diff --git a/spec/lib/pact/hal/http_client_spec.rb b/spec/lib/pact/hal/http_client_spec.rb index cc076e6f..e8811501 100644 --- a/spec/lib/pact/hal/http_client_spec.rb +++ b/spec/lib/pact/hal/http_client_spec.rb @@ -39,6 +39,20 @@ module Hal do_get expect(request).to have_been_made end + + context "when there are existing params on the URL" do + let!(:request) do + stub_request(:get, "http://example.org/?foo=hello+world&bar=wiffle&a=b"). + to_return(status: 200) + end + + let(:do_get) { subject.get('http://example.org?foo=bar&a=b', { 'foo' => 'hello world', 'bar' => 'wiffle' }) } + + it "merges them in" do + do_get + expect(request).to have_been_made + end + end end context "with broker token set" do diff --git a/spec/lib/pact/hal/link_spec.rb b/spec/lib/pact/hal/link_spec.rb index 3b560904..7e982719 100644 --- a/spec/lib/pact/hal/link_spec.rb +++ b/spec/lib/pact/hal/link_spec.rb @@ -19,9 +19,10 @@ module Hal instance_double('Pact::Hal::Entity') end + let(:href) { 'http://foo/{bar}' } let(:attrs) do { - 'href' => 'http://foo/{bar}', + 'href' => href, 'title' => 'title', method: :post } @@ -94,6 +95,14 @@ module Hal end end + describe "#with_query" do + let(:href) { "http://example.org?a=1&b=2" } + + it "returns a link with the new query merged into the existing query" do + expect(subject.with_query("a" => "5", "c" => "3").href).to eq "http://example.org?a=5&b=2&c=3" + end + end + describe "#expand" do it "returns a duplicate Link with the expanded href" do expect(subject.expand(bar: 'wiffle').href).to eq "http://foo/wiffle" diff --git a/spec/lib/pact/pact_broker/fetch_pending_pacts_spec.rb b/spec/lib/pact/pact_broker/fetch_pact_uris_for_verification_spec.rb similarity index 65% rename from spec/lib/pact/pact_broker/fetch_pending_pacts_spec.rb rename to spec/lib/pact/pact_broker/fetch_pact_uris_for_verification_spec.rb index ea16ae4b..9e8a0688 100644 --- a/spec/lib/pact/pact_broker/fetch_pending_pacts_spec.rb +++ b/spec/lib/pact/pact_broker/fetch_pact_uris_for_verification_spec.rb @@ -1,8 +1,8 @@ -require 'pact/pact_broker/fetch_pending_pacts' +require 'pact/pact_broker/fetch_pact_uris_for_verification' module Pact module PactBroker - describe FetchPendingPacts do + describe FetchPactURIsForVerification do describe "call" do before do allow(Pact.configuration).to receive(:output_stream).and_return(double('output stream').as_null_object) @@ -11,7 +11,10 @@ module PactBroker let(:provider) { "Foo"} let(:broker_base_url) { "http://broker.org" } let(:http_client_options) { {} } - subject { FetchPendingPacts.call(provider, broker_base_url, http_client_options)} + let(:consumer_version_selectors) { [{ tag: "cmaster", latest: true}] } + let(:provider_version_tags) { ["pmaster"] } + + subject { FetchPactURIsForVerification.call(provider, consumer_version_selectors, provider_version_tags, broker_base_url, http_client_options)} context "when there is an error retrieving the index resource" do before do @@ -32,8 +35,9 @@ module PactBroker end end - context "when the pb:pending-provider-pacts relation does not exist" do + context "when the beta:provider-pacts-for-verification relation does not exist" do before do + allow(FetchPacts).to receive(:call) stub_request(:get, "http://broker.org/").to_return(status: 200, body: response_body, headers: response_headers) end @@ -44,8 +48,9 @@ module PactBroker }.to_json end - it "returns an empty list" do - expect(subject).to eq [] + it "calls the old fetch pacts code" do + expect(FetchPacts).to receive(:call).with(provider, ["cmaster"], broker_base_url, http_client_options) + subject end end end diff --git a/spec/lib/pact/pact_broker_spec.rb b/spec/lib/pact/pact_broker_spec.rb index f47a5c23..f19f99db 100644 --- a/spec/lib/pact/pact_broker_spec.rb +++ b/spec/lib/pact/pact_broker_spec.rb @@ -3,41 +3,22 @@ module Pact module PactBroker - describe ".fetch_pact_uris" do + describe ".fetch_pact_uris_for_verification" do before do - allow(Pact::PactBroker::FetchPacts).to receive(:call).and_return([pact_uri]) + allow(Pact::PactBroker::FetchPactURIsForVerification).to receive(:call).and_return([pact_uri]) end let(:pact_uri) { Pact::Provider::PactURI.new("http://pact") } - subject { Pact::PactBroker.fetch_pact_uris("foo") } - - it "calls Pact::PactBroker::FetchPacts" do - expect(Pact::PactBroker::FetchPacts).to receive(:call).with("foo") - subject - end - - it "returns a list of string URLs" do - expect(subject).to eq ["http://pact"] - end - end - - describe ".fetch_pending_pact_uris" do - before do - allow(Pact::PactBroker::FetchPendingPacts).to receive(:call).and_return([pact_uri]) - end - - let(:pact_uri) { Pact::Provider::PactURI.new("http://pact") } - - subject { Pact::PactBroker.fetch_pending_pact_uris("foo") } + subject { Pact::PactBroker.fetch_pact_uris_for_verification("foo") } it "calls Pact::PactBroker::FetchPendingPacts" do - expect(Pact::PactBroker::FetchPendingPacts).to receive(:call).with("foo") + expect(Pact::PactBroker::FetchPactURIsForVerification).to receive(:call).with("foo") subject end - it "returns a list of string URLs" do - expect(subject).to eq ["http://pact"] + it "returns a list of pact uris" do + expect(subject).to eq [pact_uri] end end end diff --git a/spec/lib/pact/provider/configuration/pact_verification_from_broker_spec.rb b/spec/lib/pact/provider/configuration/pact_verification_from_broker_spec.rb index 095beed2..f684fe27 100644 --- a/spec/lib/pact/provider/configuration/pact_verification_from_broker_spec.rb +++ b/spec/lib/pact/provider/configuration/pact_verification_from_broker_spec.rb @@ -6,6 +6,7 @@ module Configuration describe PactVerificationFromBroker do describe 'build' do let(:provider_name) {'provider-name'} + let(:provider_version_tags) { ['master'] } let(:base_url) { "http://broker.org" } let(:basic_auth_options) do { @@ -16,13 +17,13 @@ module Configuration let(:tags) { ['master'] } before do - allow(Pact::PactBroker::FetchPacts).to receive(:new).and_return(fetch_pacts) + allow(Pact::PactBroker::FetchPactURIsForVerification).to receive(:new).and_return(fetch_pacts) allow(Pact.provider_world).to receive(:add_pact_uri_source) end context "with valid values" do subject do - PactVerificationFromBroker.build(provider_name) do + PactVerificationFromBroker.build(provider_name, provider_version_tags) do pact_broker_base_url base_url, basic_auth_options consumer_version_tags tags verbose true @@ -31,9 +32,10 @@ module Configuration let(:fetch_pacts) { double('FetchPacts') } let(:options) { basic_auth_options.merge(verbose: true) } + let(:consumer_version_selectors) { [ { tag: 'master', latest: true }] } - it "creates a instance of Pact::PactBroker::FetchPacts" do - expect(Pact::PactBroker::FetchPacts).to receive(:new).with(provider_name, tags, base_url, options) + it "creates a instance of Pact::PactBroker::FetchPactURIsForVerification" do + expect(Pact::PactBroker::FetchPactURIsForVerification).to receive(:new).with(provider_name, consumer_version_selectors, provider_version_tags, base_url, options) subject end @@ -45,7 +47,7 @@ module Configuration context "with a missing base url" do subject do - PactVerificationFromBroker.build(provider_name) do + PactVerificationFromBroker.build(provider_name, provider_version_tags) do end end @@ -59,7 +61,7 @@ module Configuration context "with a non array object for consumer_version_tags" do subject do - PactVerificationFromBroker.build(provider_name) do + PactVerificationFromBroker.build(provider_name, provider_version_tags) do pact_broker_base_url base_url consumer_version_tags "master" end @@ -68,14 +70,14 @@ module Configuration let(:fetch_pacts) { double('FetchPacts') } it "coerces the value into an array" do - expect(Pact::PactBroker::FetchPacts).to receive(:new).with(anything, ["master"], anything, anything) + expect(Pact::PactBroker::FetchPactURIsForVerification).to receive(:new).with(anything, [{ tag: "master", latest: true}], anything, anything, anything) subject end end context "when no consumer_version_tags are provided" do subject do - PactVerificationFromBroker.build(provider_name) do + PactVerificationFromBroker.build(provider_name, provider_version_tags) do pact_broker_base_url base_url end end @@ -83,22 +85,22 @@ module Configuration let(:fetch_pacts) { double('FetchPacts') } it "creates an instance of FetchPacts with an emtpy array for the consumer_version_tags" do - expect(Pact::PactBroker::FetchPacts).to receive(:new).with(anything, [], anything, anything) + expect(Pact::PactBroker::FetchPactURIsForVerification).to receive(:new).with(anything, [], anything, anything, anything) subject end end context "when no verbose flag is provided" do subject do - PactVerificationFromBroker.build(provider_name) do + PactVerificationFromBroker.build(provider_name, provider_version_tags) do pact_broker_base_url base_url end end let(:fetch_pacts) { double('FetchPacts') } - it "creates an instance of FetchPacts with verbose: false" do - expect(Pact::PactBroker::FetchPacts).to receive(:new).with(anything, anything, anything, hash_including(verbose: false)) + it "creates an instance of FetchPactURIsForVerification with verbose: false" do + expect(Pact::PactBroker::FetchPactURIsForVerification).to receive(:new).with(anything, anything, anything, anything, hash_including(verbose: false)) subject end end diff --git a/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb b/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb index d78b890f..c8e72de8 100644 --- a/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +++ b/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb @@ -156,13 +156,14 @@ module Configuration subject do ServiceProviderDSL.build 'some-provider' do app {} + app_version_tags ['dev'] honours_pacts_from_pact_broker do end end end it 'builds a PactVerificationFromBroker' do - expect(PactVerificationFromBroker).to receive(:build).with('some-provider') + expect(PactVerificationFromBroker).to receive(:build).with('some-provider', ['dev']) subject end end diff --git a/spec/service_providers/pact_ruby_fetch_pacts_for_verification_test.rb b/spec/service_providers/pact_ruby_fetch_pacts_for_verification_test.rb new file mode 100644 index 00000000..75c2e93a --- /dev/null +++ b/spec/service_providers/pact_ruby_fetch_pacts_for_verification_test.rb @@ -0,0 +1,101 @@ +require_relative 'helper' +require 'pact/pact_broker/fetch_pact_uris_for_verification' + +describe Pact::PactBroker::FetchPactURIsForVerification, pact: true do + before do + allow($stdout).to receive(:puts) + end + + let(:get_headers) { { Accept: 'application/hal+json' } } + let(:pacts_for_verification_relation) { Pact::PactBroker::FetchPactURIsForVerification::PACTS_FOR_VERIFICATION_RELATION } + let(:query) do + { + "provider_version_tags[]" => "pdev", + "consumer_version_selectors[][tag]" => "cdev", + "consumer_version_selectors[][latest]" => "true", + } + end + let(:provider_version_tags) { %w[pdev] } + let(:consumer_version_selectors) { [ { tag: "cdev", latest: true }] } + + subject { Pact::PactBroker::FetchPactURIsForVerification.call(provider, consumer_version_selectors, provider_version_tags, broker_base_url, basic_auth_options) } + + describe 'fetch pacts' do + let(:provider) { 'Bar' } + let(:broker_base_url) { pact_broker.mock_service_base_url} + let(:basic_auth_options) { { username: 'username', password: 'password' } } + + before do + pact_broker + .given('the relation for retrieving pacts for verifications exists in the index resource') + .upon_receiving('a request for the index resource') + .with( + method: :get, + path: '/', + headers: get_headers + ) + .will_respond_with( + status: 200, + body: { + _links: { + pacts_for_verification_relation => { + href: Pact.term( + generate: broker_base_url + '/pacts/provider/{provider}/for-verification', + matcher: %r{/pacts/provider/{provider}/for-verification$} + ) + } + } + } + ) + end + + context 'retrieving pacts for verification by provider' do + before do + pact_broker + .given('Foo has a pact with provider Bar') + .upon_receiving('a request to retrieve the pacts for verification for a provider') + .with( + method: :get, + path: '/pacts/provider/Bar/for-verification', + query: query, + headers: get_headers + ) + .will_respond_with( + status: 200, + body: { + "_embedded" => { + "pacts" => [{ + "verificationProperties" => { + "pending" => Pact.like(true), + "pendingReason" => Pact.like("pending reason"), + "inclusionReason" => Pact.like("inclusion reason") + }, + '_links' => { + "self" => { + "href" => Pact.term('http://pact-broker-url-for-foo', %r{http://.*}) + } + } + }] + } + } + ) + end + + let(:expected_metadata) do + { + pending: true, + inclusion_reason: "inclusion reason", + pending_reason: "pending reason" + } + end + + it 'returns the array of pact urls' do + expect(subject).to eq( + [ + Pact::Provider::PactURI.new('http://pact-broker-url-for-foo', basic_auth_options, expected_metadata) + ] + ) + end + end + end +end diff --git a/spec/service_providers/pact_ruby_fetch_wip_pacts_test.rb b/spec/service_providers/pact_ruby_fetch_wip_pacts_test.rb deleted file mode 100644 index baa5a47f..00000000 --- a/spec/service_providers/pact_ruby_fetch_wip_pacts_test.rb +++ /dev/null @@ -1,74 +0,0 @@ -require_relative 'helper' -require 'pact/pact_broker/fetch_pending_pacts' - -describe Pact::PactBroker::FetchPendingPacts, pact: true do - before do - allow($stdout).to receive(:puts) - end - - let(:get_headers) { { Accept: 'application/hal+json' } } - - describe 'fetch pacts' do - let(:provider) { 'provider-1' } - let(:broker_base_url) { pact_broker.mock_service_base_url + '/' } - let(:basic_auth_options) { { username: 'foo', password: 'bar' } } - - before do - pact_broker - .given('the relation for retrieving pending pacts exists in the index resource') - .upon_receiving('a request for the index resource') - .with( - method: :get, - path: '/', - headers: get_headers - ) - .will_respond_with( - status: 200, - body: { - _links: { - 'beta:pending-provider-pacts' => { - href: Pact.term( - generate: broker_base_url + 'pacts/provider/{provider}/pending', - matcher: %r{/pacts/provider/{provider}/pending$} - ) - } - } - } - ) - end - - context 'retrieving pending pacts by provider' do - before do - pact_broker - .given('consumer-1 has a pending pact with provider provider-1') - .upon_receiving('a request to retrieve the pending pacts for provider') - .with( - method: :get, - path: '/pacts/provider/provider-1/pending', - headers: get_headers - ) - .will_respond_with( - status: 200, - body: { - _links: { - 'pb:pacts' => [ - { - href: Pact.term('http://pact-broker-url-for-consumer-1', %r{http://.*}) - } - ] - } - } - ) - end - - it 'returns the array of pact urls' do - pacts = Pact::PactBroker::FetchPendingPacts.call(provider, broker_base_url, basic_auth_options) - expect(pacts).to eq( - [ - Pact::Provider::PactURI.new('http://pact-broker-url-for-consumer-1', basic_auth_options) - ] - ) - end - end - end -end diff --git a/tasks/foo-bar.rake b/tasks/foo-bar.rake index 87d4e5db..ea5abf81 100644 --- a/tasks/foo-bar.rake +++ b/tasks/foo-bar.rake @@ -1,4 +1,5 @@ require 'pact/tasks/verification_task' +require 'faraday' # Use for end to end manual debugging of issues. BROKER_BASE_URL = 'http://localhost:9292' @@ -22,6 +23,11 @@ task 'pact:foobar:publish' do http.request put_request end puts response.code unless response.code == '200' + + tag_response = Faraday.put("#{BROKER_BASE_URL}/pacticipants/Foo/versions/1.0.0/tags/dev", nil, { 'Content-Type' => 'application/json' }) + puts tag_response.status unless tag_response.status == 200 + tag_response = Faraday.put("#{BROKER_BASE_URL}/pacticipants/Foo/versions/1.0.0/tags/prod", nil, { 'Content-Type' => 'application/json' }) + puts tag_response.status unless tag_response.status == 200 end #'./spec/pacts/foo-bar.json'