From 094ac33d2f463c02db3aafaa03f452a21e3fb0fb Mon Sep 17 00:00:00 2001 From: Austin Blatt Date: Wed, 2 Aug 2017 12:32:52 -0700 Subject: [PATCH] (MAINT) Fix fatal error in test unit --parallel When there are no tests `pdk test unit` outputs `No examples found`, but the parallel_tests gem aborts with an error and does not output JSON. This catches that error situation and standardizes the output --- lib/pdk/tests/unit.rb | 11 +++++ spec/acceptance/test_unit_spec.rb | 7 +++ spec/unit/pdk/test/unit_spec.rb | 74 ++++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/lib/pdk/tests/unit.rb b/lib/pdk/tests/unit.rb index c073b02b9..3d572e0f4 100644 --- a/lib/pdk/tests/unit.rb +++ b/lib/pdk/tests/unit.rb @@ -12,6 +12,12 @@ def self.cmd(_tests, opts = {}) [File.join(PDK::Util.module_root, 'bin', 'rake'), rake_task] end + def self.parallel_with_no_tests?(ran_in_parallel, json_result, result) + ran_in_parallel && json_result.empty? && + !result[:exit_code].zero? && + result[:stderr].strip =~ %r{Pass files or folders to run$} + end + def self.invoke(report, options = {}) PDK::Util::Bundler.ensure_bundle! PDK::Util::Bundler.ensure_binstubs!('rake') @@ -50,6 +56,11 @@ def self.invoke(report, options = {}) end end + if parallel_with_no_tests?(options.key?(:parallel), json_result, result) + json_result = [{ 'messages' => ['No examples found.'] }] + result[:exit_code] = 0 + end + raise PDK::CLI::FatalError, _('Unit test output did not contain a valid JSON result: %{output}') % { output: result[:stdout] } if json_result.nil? || json_result.empty? json_result = merge_json_results(json_result, result[:duration]) if options.key?(:parallel) diff --git a/spec/acceptance/test_unit_spec.rb b/spec/acceptance/test_unit_spec.rb index 8d33547f3..936bfdade 100644 --- a/spec/acceptance/test_unit_spec.rb +++ b/spec/acceptance/test_unit_spec.rb @@ -16,6 +16,13 @@ its(:stderr) { is_expected.to match(%r{no examples found}i) } its(:stderr) { is_expected.to match(%r{evaluated 0 tests}i) } end + + describe command('pdk test unit --parallel') do + its(:exit_status) { is_expected.to eq(0) } + its(:stderr) { is_expected.to match(%r{running unit tests in parallel}i) } + its(:stderr) { is_expected.to match(%r{no examples found}i) } + its(:stderr) { is_expected.to match(%r{evaluated 0 tests}i) } + end end context 'with passing tests' do diff --git a/spec/unit/pdk/test/unit_spec.rb b/spec/unit/pdk/test/unit_spec.rb index fb758944c..97cd20f01 100644 --- a/spec/unit/pdk/test/unit_spec.rb +++ b/spec/unit/pdk/test/unit_spec.rb @@ -6,6 +6,19 @@ expect(described_class.methods(false)).to include(:invoke) end + describe '.parallel_with_no_tests?' do + context 'when not parallel' do + it 'is false' do + result = { + stderr: 'Pass files or folders to run', + exit_code: 1, + } + + expect(described_class.parallel_with_no_tests?(false, ['json_result'], result)).to be(false) + end + end + end + describe '.merge_json_results' do let(:duration) { 55 } let(:results) do @@ -153,24 +166,6 @@ describe '.invoke' do let(:report) { PDK::Report.new } - let(:rspec_json_output) do - '{ - "examples": - [ - { - "id": "./spec/fixtures/modules/testmod/spec/classes/testmod_spec.rb[1:3:1]", - "status": "passed", - "pending_message": null - } - ], - "summary": { - "duration": 0.295112, - "example_count": 1, - "failure_count": 0, - "pending_count": 0 - } - }' - end before(:each) do allow(PDK::Util::Bundler).to receive(:ensure_bundle!) @@ -180,10 +175,45 @@ allow(described_class).to receive(:parse_output) end - it 'executes and parses output' do - expect(described_class).to receive(:parse_output).once - exit_code = described_class.invoke(report, tests: 'a_test_spec.rb') - expect(exit_code).to eq(-1) + context 'in parallel without examples' do + let(:rspec_json_output) do + 'Pass files or folders to run' + end + + it "returns 0 and doesn't error" do + expect(described_class).to receive(:parallel_with_no_tests?).and_return(true) + + exit_code = -1 + expect { exit_code = described_class.invoke(report, tests: 'a_test_spec.rb') }.not_to raise_exception + expect(exit_code).to eq(0) + end + end + + context 'with examples' do + let(:rspec_json_output) do + '{ + "examples": + [ + { + "id": "./spec/fixtures/modules/testmod/spec/classes/testmod_spec.rb[1:3:1]", + "status": "passed", + "pending_message": null + } + ], + "summary": { + "duration": 0.295112, + "example_count": 1, + "failure_count": 0, + "pending_count": 0 + } + }' + end + + it 'executes and parses output' do + expect(described_class).to receive(:parse_output).once + exit_code = described_class.invoke(report, tests: 'a_test_spec.rb') + expect(exit_code).to eq(-1) + end end end # rubocop:enable RSpec/AnyInstance