From 533faa1d22ae53af97e196a81110e175184efbf6 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Sat, 26 Sep 2020 14:18:22 +1000 Subject: [PATCH] fix: correctly calculate exit code when a mix of pending and non pending pacts are verified Closes: https://github.com/pact-foundation/pact-ruby/issues/223 --- lib/pact/provider/pact_source.rb | 4 ++ lib/pact/provider/pact_spec_runner.rb | 15 ++--- .../provider/rspec/calculate_exit_code.rb | 18 ++++++ lib/pact/provider/rspec/formatter_rspec_3.rb | 10 ++-- lib/pact/provider/world.rb | 2 +- .../rspec/calculate_exit_code_spec.rb | 56 +++++++++++++++++++ 6 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 lib/pact/provider/rspec/calculate_exit_code.rb create mode 100644 spec/lib/pact/provider/rspec/calculate_exit_code_spec.rb diff --git a/lib/pact/provider/pact_source.rb b/lib/pact/provider/pact_source.rb index 5b29c92c..866ee790 100644 --- a/lib/pact/provider/pact_source.rb +++ b/lib/pact/provider/pact_source.rb @@ -20,6 +20,10 @@ def pact_hash @pact_hash ||= JSON.load(pact_json, nil, { max_nesting: 50 }) end + def pending? + uri.metadata[:pending] + end + def hal_entity http_client_keys = [:username, :password, :token] http_client_options = uri.options.reject{ |k, _| !http_client_keys.include?(k) } diff --git a/lib/pact/provider/pact_spec_runner.rb b/lib/pact/provider/pact_spec_runner.rb index e85a443a..d3261d77 100644 --- a/lib/pact/provider/pact_spec_runner.rb +++ b/lib/pact/provider/pact_spec_runner.rb @@ -11,6 +11,7 @@ require 'pact/provider/rspec/pact_broker_formatter' require 'pact/provider/rspec/json_formatter' require 'pact/provider/rspec' +require 'pact/provider/rspec/calculate_exit_code' module Pact module Provider @@ -79,6 +80,7 @@ def configure_rspec executing_with_ruby = executing_with_ruby? config.after(:suite) do | suite | + Pact.provider_world.failed_examples = suite.reporter.failed_examples Pact::Provider::Help::Write.call(Pact.provider_world.pact_sources) if executing_with_ruby end end @@ -90,7 +92,8 @@ def run_specs ::RSpec::Core::CommandLine.new(NoConfigurationOptions.new) .run(::RSpec.configuration.output_stream, ::RSpec.configuration.error_stream) end - pending_mode? ? 0 : exit_code + + Pact::Provider::RSpec::CalculateExitCode.call(pact_sources, Pact.provider_world.failed_examples) end def rspec_runner_options @@ -147,8 +150,6 @@ def configure_output end ::RSpec.configuration.full_backtrace = @options[:full_backtrace] - - ::RSpec.configuration.failure_color = :yellow if pending_mode? end def ordered_pact_json(pact_json) @@ -159,20 +160,12 @@ def ordered_pact_json(pact_json) consumer_contract.to_json end - def all_pacts_pending? - pact_urls.all?{ | pact_url| pact_url.metadata[:pending] } - end - def class_exists? name Kernel.const_get name rescue NameError false end - def pending_mode? - (all_pacts_pending? || options[:ignore_failures]) - end - def executing_with_ruby? ENV['PACT_EXECUTING_LANGUAGE'] == 'ruby' end diff --git a/lib/pact/provider/rspec/calculate_exit_code.rb b/lib/pact/provider/rspec/calculate_exit_code.rb new file mode 100644 index 00000000..472d2599 --- /dev/null +++ b/lib/pact/provider/rspec/calculate_exit_code.rb @@ -0,0 +1,18 @@ +module Pact + module Provider + module RSpec + module CalculateExitCode + def self.call(pact_sources, failed_examples) + any_non_pending_failures = pact_sources.any? do |pact_source| + if pact_source.pending? + nil + else + failed_examples.select { |e| e.metadata[:pact_source] == pact_source }.any? + end + end + any_non_pending_failures ? 1 : 0 + end + end + end + end +end diff --git a/lib/pact/provider/rspec/formatter_rspec_3.rb b/lib/pact/provider/rspec/formatter_rspec_3.rb index 68c46984..566e928c 100644 --- a/lib/pact/provider/rspec/formatter_rspec_3.rb +++ b/lib/pact/provider/rspec/formatter_rspec_3.rb @@ -96,12 +96,14 @@ def print_rerun_commands summary interaction_rerun_commands(pending_interaction_examples(summary)).each do | message | output.puts(message) end + set_rspec_failure_color(:red) end - set_rspec_failure_color(:red) - output.puts("\nFailed interactions:\n\n") - interaction_rerun_commands(failed_interaction_examples(summary)).each do | message | - output.puts(message) + if failed_interactions_count(summary) > 0 + output.puts("\nFailed interactions:\n\n") + interaction_rerun_commands(failed_interaction_examples(summary)).each do | message | + output.puts(message) + end end end diff --git a/lib/pact/provider/world.rb b/lib/pact/provider/world.rb index 7e8ab1ce..d9ee3254 100644 --- a/lib/pact/provider/world.rb +++ b/lib/pact/provider/world.rb @@ -14,7 +14,7 @@ def self.clear_provider_world module Provider class World - attr_accessor :pact_sources + attr_accessor :pact_sources, :failed_examples def provider_states @provider_states_proxy ||= Pact::Provider::State::ProviderStateProxy.new diff --git a/spec/lib/pact/provider/rspec/calculate_exit_code_spec.rb b/spec/lib/pact/provider/rspec/calculate_exit_code_spec.rb new file mode 100644 index 00000000..4e062442 --- /dev/null +++ b/spec/lib/pact/provider/rspec/calculate_exit_code_spec.rb @@ -0,0 +1,56 @@ +require 'pact/provider/rspec/calculate_exit_code' + +module Pact + module Provider + module RSpec + module CalculateExitCode + describe ".call" do + let(:pact_source_1) { double('pact_source_1', pending?: pending_1) } + let(:pending_1) { nil } + let(:pact_source_2) { double('pact_source_2', pending?: pending_2) } + let(:pending_2) { nil } + let(:pact_source_3) { double('pact_source_3', pending?: pending_3) } + let(:pending_3) { nil } + let(:pact_sources) { [pact_source_1, pact_source_2, pact_source_3]} + + let(:failed_examples) { [ example_1, example_2, example_3 ] } + let(:example_1) { double('example_1', metadata: { pact_source: pact_source_1 }) } + let(:example_2) { double('example_2', metadata: { pact_source: pact_source_1 }) } + let(:example_3) { double('example_3', metadata: { pact_source: pact_source_2 }) } + + subject { CalculateExitCode.call(pact_sources, failed_examples ) } + + context "when all pacts are pending" do + let(:pending_1) { true } + let(:pending_2) { true } + let(:pending_3) { true } + + it "returns 0" do + expect(subject).to eq 0 + end + end + + context "when a non pending pact has no failures" do + let(:pending_1) { true } + let(:pending_2) { true } + let(:pending_3) { false } + + it "returns 0" do + expect(subject).to eq 0 + end + end + + context "when a non pending pact no failures" do + let(:pending_1) { true } + let(:pending_2) { false } + let(:pending_3) { false } + + it "returns 1" do + expect(subject).to eq 1 + end + end + end + end + end + end +end