diff --git a/Readme.md b/Readme.md index b825d263..16b9520f 100644 --- a/Readme.md +++ b/Readme.md @@ -224,8 +224,10 @@ Options are: --runtime-log [PATH] Location of previously recorded test runtimes --allowed-missing Allowed percentage of missing runtimes (default = 50) --unknown-runtime [FLOAT] Use given number as unknown runtime (otherwise use average time) - --verbose Print more output - --quiet Do not print anything, apart from test output + --verbose Print debug output + --verbose-process-command Print the command that will be executed by each process before it begins + --verbose-rerun-command After a process fails, print the command executed by that process + --quiet Print only test output -v, --version Show Version -h, --help Show this. diff --git a/lib/parallel_tests/cli.rb b/lib/parallel_tests/cli.rb index a7bda591..ae8584be 100644 --- a/lib/parallel_tests/cli.rb +++ b/lib/parallel_tests/cli.rb @@ -124,7 +124,7 @@ def report_failure_rerun_commmand(test_results, options) failing_sets = test_results.reject { |r| r[:exit_status] == 0 } return if failing_sets.none? - if options[:verbose] + if options[:verbose] || options[:verbose_rerun_command] puts "\n\nTests have failed for a parallel_test group. Use the following command to run the group again:\n\n" failing_sets.each do |failing_set| command = failing_set[:command] @@ -219,8 +219,10 @@ def parse_options!(argv) opts.on("--allowed-missing [INT]", Integer, "Allowed percentage of missing runtimes (default = 50)") { |percent| options[:allowed_missing_percent] = percent } opts.on("--unknown-runtime [FLOAT]", Float, "Use given number as unknown runtime (otherwise use average time)") { |time| options[:unknown_runtime] = time } opts.on("--first-is-1", "Use \"1\" as TEST_ENV_NUMBER to not reuse the default test environment") { options[:first_is_1] = true } - opts.on("--verbose", "Print more output (mutually exclusive with quiet)") { options[:verbose] = true } - opts.on("--quiet", "Print tests output only (mutually exclusive with verbose)") { options[:quiet] = true } + opts.on("--verbose", "Print debug output") { options[:verbose] = true } + opts.on("--verbose-process-command", "Displays only the command that will be executed by each process") { options[:verbose_process_command] = true } + opts.on("--verbose-rerun-command", "When there are failures, displays the command executed by each process that failed") { options[:verbose_rerun_command] = true } + opts.on("--quiet", "Print only tests output") { options[:quiet] = true } opts.on("-v", "--version", "Show Version") { puts ParallelTests::VERSION; exit } opts.on("-h", "--help", "Show this.") { puts opts; exit } end.parse!(argv) diff --git a/lib/parallel_tests/test/runner.rb b/lib/parallel_tests/test/runner.rb index 525e3745..dcba5128 100644 --- a/lib/parallel_tests/test/runner.rb +++ b/lib/parallel_tests/test/runner.rb @@ -78,7 +78,7 @@ def execute_command(cmd, process_number, num_processes, options) cmd = "nice #{cmd}" if options[:nice] cmd = "#{cmd} 2>&1" if options[:combine_stderr] - puts cmd if options[:verbose] && !options[:serialize_stdout] + puts cmd if report_process_command?(options) && !options[:serialize_stdout] execute_command_and_capture_output(env, cmd, options) end @@ -94,7 +94,9 @@ def execute_command_and_capture_output(env, cmd, options) exitstatus = $?.exitstatus seed = output[/seed (\d+)/,1] - output = [cmd, output].join("\n") if options[:verbose] && options[:serialize_stdout] + if report_process_command?(options) && options[:serialize_stdout] + output = [cmd, output].join("\n") + end {:stdout => output, :exit_status => exitstatus, :command => cmd, :seed => seed} end @@ -235,6 +237,12 @@ def files_in_folder(folder, options={}) end Dir[File.join(folder, pattern)].uniq end + + private + + def report_process_command?(options) + options[:verbose] || options[:verbose_process_command] + end end end end diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb index 2c636663..3fc3aecd 100644 --- a/spec/integration_spec.rb +++ b/spec/integration_spec.rb @@ -60,6 +60,9 @@ def self.it_fails_without_any_files(type) end end + let(:printed_commands) { "specs per process\nbundle exec rspec" } + let(:printed_rerun) { "run the group again:\n\nbundle exec rspec" } + it "runs tests in parallel" do write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}' write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){puts "TEST2"}}' @@ -111,14 +114,30 @@ def test_unicode expect(result).to include('Took') end - it "shows command with --verbose" do + it "shows command and rerun with --verbose" do write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}' - write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){expect(1).to eq(1)}}' - result = run_tests "spec --verbose", :type => 'rspec' + write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){expect(1).to eq(2)}}' + result = run_tests "spec --verbose", :type => 'rspec', :fail => true + expect(result).to include printed_commands + expect(result).to include printed_rerun expect(result).to include "bundle exec rspec spec/xxx_spec.rb" expect(result).to include "bundle exec rspec spec/xxx2_spec.rb" end + it "shows only rerun with --verbose-rerun-command" do + write 'spec/xxx_spec.rb', 'describe("it"){it("should"){expect(1).to eq(2)}}' + result = run_tests "spec --verbose-rerun-command", :type => 'rspec', :fail => true + expect(result).to include printed_rerun + expect(result).to_not include printed_commands + end + + it "shows only process with --verbose-process-command" do + write 'spec/xxx_spec.rb', 'describe("it"){it("should"){expect(1).to eq(2)}}' + result = run_tests "spec --verbose-process-command", :type => 'rspec', :fail => true + expect(result).to_not include printed_rerun + expect(result).to include printed_commands + end + it "fails when tests fail" do write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}' write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){expect(1).to eq(2)}}' diff --git a/spec/parallel_tests/cli_spec.rb b/spec/parallel_tests/cli_spec.rb index 1d658327..1a373aa0 100644 --- a/spec/parallel_tests/cli_spec.rb +++ b/spec/parallel_tests/cli_spec.rb @@ -50,6 +50,18 @@ def call(*args) expect(call(["test", "--verbose"])).to eq(defaults.merge(:verbose => true)) end + it "parses --verbose-process-command" do + expect(call(['test', '--verbose-process-command'])).to eq( + defaults.merge(verbose_process_command: true) + ) + end + + it "parses --verbose-rerun-command" do + expect(call(['test', '--verbose-rerun-command'])).to eq( + defaults.merge(verbose_rerun_command: true) + ) + end + it "parses --quiet" do expect(call(["test", "--quiet"])).to eq(defaults.merge(:quiet => true)) end @@ -155,6 +167,8 @@ def call(*args) end describe ".report_failure_rerun_commmand" do + let(:single_failed_command) { [{exit_status: 1, command: 'foo', seed: nil, output: 'blah'}] } + it "prints nothing if there are no failures" do expect($stdout).not_to receive(:puts) @@ -166,37 +180,35 @@ def call(*args) ) end - shared_examples :not_verbose_rerun do |options| + def self.it_prints_nothing_about_rerun_commands(options) it 'prints nothing about rerun commands' do - expect { - subject.send(:report_failure_rerun_commmand, - [ - {exit_status: 1, command: 'foo', seed: nil, output: 'blah'} - ], - options - ) - }.to_not output(/Use the following command to run the group again/).to_stdout + expect { + subject.send(:report_failure_rerun_commmand, single_failed_command, options) + }.to_not output(/Use the following command to run the group again/).to_stdout end end describe "failure" do - context 'with empty options hash' do - include_examples :not_verbose_rerun, {} + context 'without options' do + it_prints_nothing_about_rerun_commands({}) + end + + context 'with verbose disabled' do + it_prints_nothing_about_rerun_commands(verbose: false) end - context 'with option !verbose' do - include_examples :not_verbose_rerun, {verbose: false} + context "with verbose rerun" do + it "prints command if there is a failure" do + expect { + subject.send(:report_failure_rerun_commmand, single_failed_command, verbose_rerun_command: true) + }.to output("\n\nTests have failed for a parallel_test group. Use the following command to run the group again:\n\nfoo\n").to_stdout + end end - context 'with option verbose' do + context 'with verbose' do it "prints a message and the command if there is a failure" do expect { - subject.send(:report_failure_rerun_commmand, - [ - {exit_status: 1, command: 'foo', seed: nil, output: 'blah'} - ], - {verbose: true} - ) + subject.send(:report_failure_rerun_commmand, single_failed_command, verbose: true) }.to output("\n\nTests have failed for a parallel_test group. Use the following command to run the group again:\n\nfoo\n").to_stdout end @@ -233,13 +245,10 @@ def call(*args) subject.instance_variable_set(:@runner, ParallelTests::Test::Runner) expect(ParallelTests::Test::Runner).to receive(:command_with_seed).with(command, seed). and_return("my seeded command result --seed #{seed}") + single_failed_command[0].merge!(seed: seed, command: command) + expect { - subject.send(:report_failure_rerun_commmand, - [ - {exit_status: 1, command: command, seed: 555, output: 'blah'}, - ], - {verbose: true} - ) + subject.send(:report_failure_rerun_commmand, single_failed_command, verbose: true) }.to output(/my seeded command result --seed 555/).to_stdout end end