Class: ParallelTests::Test::Runner
- Inherits:
-
Object
- Object
- ParallelTests::Test::Runner
- Defined in:
- lib/parallel_tests/test/runner.rb
Direct Known Subclasses
Constant Summary collapse
- RuntimeLogTooSmallError =
Class.new(StandardError)
Class Method Summary collapse
-
.command_with_seed(cmd, seed) ⇒ Object
remove old seed and add new seed.
- .default_test_folder ⇒ Object
- .execute_command(cmd, process_number, num_processes, options) ⇒ Object
- .execute_command_and_capture_output(env, cmd, options) ⇒ Object
- .find_results(test_output) ⇒ Object
-
.line_is_result?(line) ⇒ Boolean
ignores other commands runner noise.
- .print_command(command, env) ⇒ Object
- .run_tests(test_files, process_number, num_processes, options) ⇒ Object
-
.runtime_log ⇒ Object
— usually overwritten by other runners.
- .summarize_results(results) ⇒ Object
- .test_env_number(process_number, options = {}) ⇒ Object
- .test_file_name ⇒ Object
- .test_suffix ⇒ Object
-
.tests_in_groups(tests, num_groups, options = {}) ⇒ Object
finds all tests and partitions them into groups.
- .tests_with_size(tests, options) ⇒ Object
Class Method Details
.command_with_seed(cmd, seed) ⇒ Object
remove old seed and add new seed
152 153 154 155 |
# File 'lib/parallel_tests/test/runner.rb', line 152 def command_with_seed(cmd, seed) clean = remove_command_arguments(cmd, '--seed') [*clean, '--seed', seed] end |
.default_test_folder ⇒ Object
21 22 23 |
# File 'lib/parallel_tests/test/runner.rb', line 21 def default_test_folder "test" end |
.execute_command(cmd, process_number, num_processes, options) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/parallel_tests/test/runner.rb', line 88 def execute_command(cmd, process_number, num_processes, ) number = test_env_number(process_number, ).to_s env = ([:env] || {}).merge( "TEST_ENV_NUMBER" => number, "PARALLEL_TEST_GROUPS" => num_processes.to_s, "PARALLEL_PID_FILE" => ParallelTests.pid_file_path ) cmd = ["nice", *cmd] if [:nice] # being able to run with for example `-output foo-$TEST_ENV_NUMBER` worked originally and is convenient cmd = cmd.map { |c| c.gsub("$TEST_ENV_NUMBER", number).gsub("${TEST_ENV_NUMBER}", number) } print_command(cmd, env) if report_process_command?() && ![:serialize_stdout] execute_command_and_capture_output(env, cmd, ) end |
.execute_command_and_capture_output(env, cmd, options) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/parallel_tests/test/runner.rb', line 110 def execute_command_and_capture_output(env, cmd, ) = {} # do not add `pgroup: true`, it will break `binding.irb` inside the test [:err] = [:child, :out] if [:combine_stderr] pid = nil output = IO.popen(env, cmd, ) do |io| pid = io.pid ParallelTests.pids.add(pid) capture_output(io, env, ) end ParallelTests.pids.delete(pid) if pid exitstatus = $?.exitstatus seed = output[/seed (\d+)/, 1] output = "#{Shellwords.shelljoin(cmd)}\n#{output}" if report_process_command?() && [:serialize_stdout] { env: env, stdout: output, exit_status: exitstatus, command: cmd, seed: seed } end |
.find_results(test_output) ⇒ Object
129 130 131 132 133 134 135 136 |
# File 'lib/parallel_tests/test/runner.rb', line 129 def find_results(test_output) test_output.lines.map do |line| line.chomp! line.gsub!(/\e\[\d+m/, '') # remove color coding next unless line_is_result?(line) line end.compact end |
.line_is_result?(line) ⇒ Boolean
ignores other commands runner noise
43 44 45 |
# File 'lib/parallel_tests/test/runner.rb', line 43 def line_is_result?(line) line =~ /\d+ failure(?!:)/ end |
.print_command(command, env) ⇒ Object
105 106 107 108 |
# File 'lib/parallel_tests/test/runner.rb', line 105 def print_command(command, env) env_str = ['TEST_ENV_NUMBER', 'PARALLEL_TEST_GROUPS'].map { |e| "#{e}=#{env[e]}" }.join(' ') puts [env_str, Shellwords.shelljoin(command)].compact.join(' ') end |
.run_tests(test_files, process_number, num_processes, options) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/parallel_tests/test/runner.rb', line 29 def run_tests(test_files, process_number, num_processes, ) require_list = test_files.map { |file| file.gsub(" ", "\\ ") }.join(" ") cmd = [ *executable, '-Itest', '-e', "%w[#{require_list}].each { |f| require %{./\#{f}} }", '--', *[:test_options] ] execute_command(cmd, process_number, num_processes, ) end |
.runtime_log ⇒ Object
— usually overwritten by other runners
13 14 15 |
# File 'lib/parallel_tests/test/runner.rb', line 13 def runtime_log 'tmp/parallel_runtime_test.log' end |
.summarize_results(results) ⇒ Object
146 147 148 149 |
# File 'lib/parallel_tests/test/runner.rb', line 146 def summarize_results(results) sums = sum_up_results(results) sums.sort.map { |word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ') end |
.test_env_number(process_number, options = {}) ⇒ Object
138 139 140 141 142 143 144 |
# File 'lib/parallel_tests/test/runner.rb', line 138 def test_env_number(process_number, = {}) if process_number == 0 && ![:first_is_1] '' else process_number + 1 end end |
.test_file_name ⇒ Object
25 26 27 |
# File 'lib/parallel_tests/test/runner.rb', line 25 def test_file_name "test" end |
.test_suffix ⇒ Object
17 18 19 |
# File 'lib/parallel_tests/test/runner.rb', line 17 def test_suffix /_(test|spec).rb$/ end |
.tests_in_groups(tests, num_groups, options = {}) ⇒ Object
finds all tests and partitions them into groups
50 51 52 53 |
# File 'lib/parallel_tests/test/runner.rb', line 50 def tests_in_groups(tests, num_groups, = {}) tests = tests_with_size(tests, ) Grouper.in_even_groups_by_size(tests, num_groups, ) end |
.tests_with_size(tests, options) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/parallel_tests/test/runner.rb', line 55 def tests_with_size(tests, ) tests = find_tests(tests, ) case [:group_by] when :found tests.map! { |t| [t, 1] } when :filesize sort_by_filesize(tests) when :runtime sort_by_runtime( tests, runtimes(tests, ), .merge(allowed_missing: ([:allowed_missing_percent] || 50) / 100.0) ) when nil # use recorded test runtime if we got enough data runtimes = begin runtimes(tests, ) rescue StandardError [] end if runtimes.size * 1.5 > tests.size puts "Using recorded test runtime" unless [:quiet] sort_by_runtime(tests, runtimes) else sort_by_filesize(tests) end else raise ArgumentError, "Unsupported option #{[:group_by]}" end tests end |