From ef978983be355815057dc31595a5d4665ada35d7 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Sun, 24 Jun 2018 20:05:48 +1000 Subject: [PATCH] feat: allow pacts to be dynamically fetched from a pact broker by provider name and tags --- .../pact_verification_from_broker.rb | 39 ++++---- .../configuration/service_provider_dsl.rb | 8 +- lib/pact/provider/world.rb | 18 +++- .../pact_verification_from_broker_spec.rb | 92 +++++++++++++------ spec/lib/pact/provider/world_spec.rb | 37 +++++++- spec/support/bar_pact_helper.rb | 43 +++++---- tasks/foo-bar.rake | 3 +- 7 files changed, 167 insertions(+), 73 deletions(-) diff --git a/lib/pact/provider/configuration/pact_verification_from_broker.rb b/lib/pact/provider/configuration/pact_verification_from_broker.rb index 6f307520..cf74c769 100644 --- a/lib/pact/provider/configuration/pact_verification_from_broker.rb +++ b/lib/pact/provider/configuration/pact_verification_from_broker.rb @@ -1,30 +1,33 @@ -require 'pact/provider/pact_verification' -require 'pact/provider/pact_uri' require 'pact/shared/dsl' require 'pact/provider/world' +require 'pact/pact_broker/fetch_pacts' module Pact module Provider - module Configuration - class PactVerificationFromBroker extend Pact::DSL - attr_accessor :name, :pact_broker_base_url, :tags + # If user declares a variable with the same name as one of these attributes + # in parent scope, it will clash with these ones, + # so put an underscore in front of the name to be safer. - def initialize(name, options = {}) - @tags = options.fetch(:consumer_version_tags) || [] - @pact_broker_base_url = options.fetch(:pact_broker_base_url) || '' - @provider_name = name - @options = options + attr_accessor :_provider_name, :_pact_broker_base_url, :_consumer_version_tags, :_basic_auth_options + + def initialize(provider_name) + @_provider_name = provider_name + @_consumer_version_tags = [] end dsl do - def pact_broker_base_url pact_broker_base_url, options - @pact_broker_base_url = URI(pact_broker_base_url) - @pact_broker_base_url.set_user(options[:username]) if options[:username] # not sure about this exactly, I'll work it out when I get there. + def pact_broker_base_url pact_broker_base_url, basic_auth_options = {} + self._pact_broker_base_url = pact_broker_base_url + self._basic_auth_options = basic_auth_options + end + + def consumer_version_tags consumer_version_tags + self._consumer_version_tags = *consumer_version_tags end end @@ -36,17 +39,13 @@ def finalize private def create_pact_verification - pacts = Pact::PactBroker::FetchPacts.call(@provider_name, tags, pact_broker_base_url, @options) - pacts.each do |pact_uri| - verification = Pact::Provider::PactVerification.new(nil, pact_uri, nil) - Pact.provider_world.add_pact_verification verification - end + fetch_pacts = Pact::PactBroker::FetchPacts.new(_provider_name, _consumer_version_tags, _pact_broker_base_url, _basic_auth_options) + Pact.provider_world.add_pact_uri_source fetch_pacts end def validate - raise "Please provide a pact_broker_base_url for the verification" unless pact_broker_base_url + raise Pact::Error.new("Please provide a pact_broker_base_url from which to retrieve the pacts") unless _pact_broker_base_url end - end end end diff --git a/lib/pact/provider/configuration/service_provider_dsl.rb b/lib/pact/provider/configuration/service_provider_dsl.rb index 245a45fa..bdd29ce4 100644 --- a/lib/pact/provider/configuration/service_provider_dsl.rb +++ b/lib/pact/provider/configuration/service_provider_dsl.rb @@ -55,8 +55,8 @@ def honours_pact_with consumer_name, options = {}, &block create_pact_verification consumer_name, options, &block end - def honours_pacts_from_pact_broker options = {}, &block - create_pact_verification_from_broker options, &block + def honours_pacts_from_pact_broker &block + create_pact_verification_from_broker &block end end @@ -64,8 +64,8 @@ def create_pact_verification consumer_name, options, &block PactVerification.build(consumer_name, options, &block) end - def create_pact_verification_from_broker(options, &block) - PactVerificationFromBroker.build(name, options, &block) + def create_pact_verification_from_broker(&block) + PactVerificationFromBroker.build(name, &block) end def finalize diff --git a/lib/pact/provider/world.rb b/lib/pact/provider/world.rb index 4f812d00..73b0effd 100644 --- a/lib/pact/provider/world.rb +++ b/lib/pact/provider/world.rb @@ -29,8 +29,22 @@ def pact_verifications end def pact_urls - pact_verifications.collect(&:uri) + (pact_verifications.collect(&:uri) + pact_uris_from_pact_uri_sources).compact + end + + def add_pact_uri_source pact_uri_source + pact_uri_sources << pact_uri_source + end + + private + + def pact_uri_sources + @pact_uri_sources ||= [] + end + + def pact_uris_from_pact_uri_sources + pact_uri_sources.collect{| pact_uri_source| pact_uri_source.call }.flatten end end end -end \ No newline at end of file +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 bd4e96e2..f93c5fd6 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 @@ -1,47 +1,87 @@ -require 'spec_helper' require 'pact/provider/configuration/pact_verification' -require 'pact/pact_broker/fetch_pacts' module Pact module Provider module Configuration - describe PactVerification do - - describe 'create_verification' do - let(:url) { 'http://some/uri' } + describe PactVerificationFromBroker do + describe 'build' do let(:provider_name) {'provider-name'} - let(:pact_repository_uri_options) do + let(:base_url) { "http://broker.org" } + let(:basic_auth_options) do { username: 'pact_broker_username', password: 'pact_broker_password' } end - let(:tag) do - { - name: 'tag-name', - all: false, - fallback: 'master' - } - end + let(:tags) { ['master'] } - let(:options) do - { - pact_broker_base_url: url, - consumer_version_tags: [tag] - } + before do + allow(Pact::PactBroker::FetchPacts).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, options) do + PactVerificationFromBroker.build(provider_name) do + pact_broker_base_url base_url, basic_auth_options + consumer_version_tags tags + end + end + + let(:fetch_pacts) { double('FetchPacts') } + + it "creates a instance of Pact::PactBroker::FetchPacts" do + expect(Pact::PactBroker::FetchPacts).to receive(:new).with(provider_name, tags, base_url, basic_auth_options) + subject + end + + it "adds a pact_uri_source to the provider world" do + expect(Pact.provider_world).to receive(:add_pact_uri_source).with(fetch_pacts) + subject + end + end + + context "with a missing base url" do + subject do + PactVerificationFromBroker.build(provider_name) do + + end + end + + let(:fetch_pacts) { double('FetchPacts') } + + it "raises an error" do + expect { subject }.to raise_error Pact::Error, /Please provide a pact_broker_base_url/ + end + end + + context "with a non array object for consumer_version_tags" do + subject do + PactVerificationFromBroker.build(provider_name) do + pact_broker_base_url base_url + consumer_version_tags "master" + end + end + + 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) + subject + end + end + + context "when no consumer_version_tags are provided" do + subject do + PactVerificationFromBroker.build(provider_name) do + pact_broker_base_url base_url end end - it "creates a Verification" do - allow(Pact::PactBroker::FetchPacts).to receive(:call).and_return(['pact-urls']) + let(:fetch_pacts) { double('FetchPacts') } - tags = [tag] - expect(Pact::PactBroker::FetchPacts).to receive(:call).with(provider_name, tags, url, options) - expect(Pact::Provider::PactVerification).to receive(:new).with(nil, 'pact-urls', nil) + 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) subject end end @@ -49,4 +89,4 @@ module Configuration end end end -end \ No newline at end of file +end diff --git a/spec/lib/pact/provider/world_spec.rb b/spec/lib/pact/provider/world_spec.rb index 7866ae9b..f71a8cad 100644 --- a/spec/lib/pact/provider/world_spec.rb +++ b/spec/lib/pact/provider/world_spec.rb @@ -26,6 +26,7 @@ module Provider describe World do subject { World.new } + describe "provider_states" do it "returns a provider state proxy" do expect(subject.provider_states).to be_instance_of State::ProviderStateProxy @@ -33,9 +34,43 @@ module Provider it "returns the same object each time" do expect(subject.provider_states).to be subject.provider_states end - end + describe "pact_urls" do + context "with pact_uri_sources" do + before do + subject.add_pact_uri_source(pact_uri_source_1) + subject.add_pact_uri_source(pact_uri_source_2) + end + + let(:pact_uri_source_1) { double('pact_uri_source_1', call: ["uri-1"]) } + let(:pact_uri_source_2) { double('pact_uri_source_2', call: ["uri-2"]) } + + let(:pact_urls) { subject.pact_urls } + + it "invokes call on the pact_uri_sources" do + expect(pact_uri_source_1).to receive(:call) + expect(pact_uri_source_2).to receive(:call) + pact_urls + end + + it "concatenates the results" do + expect(pact_urls).to eq ["uri-1", "uri-2"] + end + + context "with a pact_verification" do + before do + subject.add_pact_verification(pact_verification) + end + + let(:pact_verification) { double('PactVerification', uri: "uri-3") } + + it "concatenates the results with those of the pact_uri_sources" do + expect(pact_urls).to eq ["uri-3", "uri-1", "uri-2"] + end + end + end + end end end end diff --git a/spec/support/bar_pact_helper.rb b/spec/support/bar_pact_helper.rb index e518fb3f..3b001de2 100644 --- a/spec/support/bar_pact_helper.rb +++ b/spec/support/bar_pact_helper.rb @@ -2,26 +2,31 @@ require 'pact/provider/rspec' module Pact - module Test - class BarApp - def call env - [200, {'Content-Type' => 'application/json'}, [{"status" => "5"},{"status" => "6"}].to_json] - end - end + module Test + class BarApp + def call env + [200, {'Content-Type' => 'application/json'}, [{"status" => "5"},{"status" => "6"}].to_json] + end + end - Pact.configure do | config | - config.logger.level = Logger::DEBUG - end + Pact.configure do | config | + config.logger.level = Logger::DEBUG + end - Pact.service_provider "Bar" do - app { BarApp.new } - app_version '1.2.3' - app_version_tags ['master'] - publish_verification_results true + Pact.service_provider "Bar" do + app { BarApp.new } + app_version '1.2.3' + app_version_tags ['master'] + publish_verification_results true - honours_pact_with 'Foo' do - pact_uri './spec/support/foo-bar.json' - end - end - end + honours_pacts_from_pact_broker do + pact_broker_base_url "http://localhost:9292" + consumer_version_tags ["prod"] + end + + honours_pact_with 'Foo' do + pact_uri './spec/support/foo-bar.json' + end + end + end end diff --git a/tasks/foo-bar.rake b/tasks/foo-bar.rake index 53633f37..a7037737 100644 --- a/tasks/foo-bar.rake +++ b/tasks/foo-bar.rake @@ -24,8 +24,9 @@ task 'pact:foobar:publish' do puts response.code unless response.code == '200' end +#'./spec/pacts/foo-bar.json' Pact::VerificationTask.new('foobar') do | pact | - pact.uri './spec/pacts/foo-bar.json', pact_helper: './spec/support/bar_pact_helper.rb' + pact.uri nil, pact_helper: './spec/support/bar_pact_helper.rb' end