Class: MiniAutobot::Parallel
- Inherits:
-
Object
- Object
- MiniAutobot::Parallel
- Defined in:
- lib/mini_autobot/parallel.rb
Instance Attribute Summary collapse
-
#all_tests ⇒ Object
readonly
Returns the value of attribute all_tests.
-
#simultaneous_jobs ⇒ Object
readonly
Returns the value of attribute simultaneous_jobs.
Instance Method Summary collapse
-
#aggregate_tap_results ⇒ Object
Aggregate all individual test_*.t files replace them with one file - test_aggregated_result.tap so they will be considered as one test plan by tap result parser.
-
#clean_result! ⇒ Object
remove all results files under @result_dir if there’s any.
- #count_autobot_process ⇒ Object
-
#initialize(simultaneous_jobs, all_tests) ⇒ Parallel
constructor
A new instance of Parallel.
-
#keep_running_full(all_to_run) ⇒ Object
recursively keep running ##simultaneous_jobs number of tests in parallel exit when no test left to run.
- #remove_redundant_tap ⇒ Object
-
#run_in_parallel! ⇒ Object
run multiple commands with logging to start multiple tests in parallel n = number of tests will be running in parallel.
-
#run_on_mac? ⇒ boolean
return true only if specified to run on mac in connector.
-
#run_test_set(test_set) ⇒ Object
runs each test from a test set in a separate child process.
-
#wait_all_done_saucelabs ⇒ Object
deprecated
Deprecated.
Too time consuming and fragile, should use more native wait/check of Process
-
#wait_for_pids(pids) ⇒ Object
deprecated
Deprecated.
Use more native wait/check of Process
Constructor Details
#initialize(simultaneous_jobs, all_tests) ⇒ Parallel
Returns a new instance of Parallel.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/mini_autobot/parallel.rb', line 6 def initialize(simultaneous_jobs, all_tests) @start_time = Time.now @result_dir = 'logs/tap_results' connector = MiniAutobot.settings.connector @on_sauce = true if connector.include? 'saucelabs' @platform = connector.split(':')[2] || '' @simultaneous_jobs = simultaneous_jobs @simultaneous_jobs = 10 if run_on_mac? # saucelabs account limit for parallel is 10 for mac @all_tests = all_tests @pids = [] @static_run_command = "mini_autobot -c #{MiniAutobot.settings.connector} -e #{MiniAutobot.settings.env}" if MiniAutobot.settings.rerun_failure @static_run_command += " -R #{MiniAutobot.settings.rerun_failure}" end if MiniAutobot.settings.google_sheets? @static_run_command += " -g #{MiniAutobot.settings.google_sheet}" end unless MiniAutobot.settings.feature_flips.empty? @static_run_command += " -f #{MiniAutobot.settings.feature_flips}" end tap_reporter_path = MiniAutobot.gem_root.join('lib/tapout/custom_reporters/fancy_tap_reporter.rb') @pipe_tap = "--tapy | tapout --no-color -r #{tap_reporter_path.to_s} fancytap" end |
Instance Attribute Details
#all_tests ⇒ Object (readonly)
Returns the value of attribute all_tests.
4 5 6 |
# File 'lib/mini_autobot/parallel.rb', line 4 def all_tests @all_tests end |
#simultaneous_jobs ⇒ Object (readonly)
Returns the value of attribute simultaneous_jobs.
4 5 6 |
# File 'lib/mini_autobot/parallel.rb', line 4 def simultaneous_jobs @simultaneous_jobs end |
Instance Method Details
#aggregate_tap_results ⇒ Object
Aggregate all individual test_*.t files replace them with one file - test_aggregated_result.tap so they will be considered as one test plan by tap result parser
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/mini_autobot/parallel.rb', line 78 def aggregate_tap_results results_count = Dir.glob("#{@result_dir}/*.t").size File.open("#{@result_dir}/test_aggregated_result.tap", 'a+') do |result_file| result_stats = { 'pass' => 0, 'fail' => 0, 'errs' => 0, 'todo' => 0, 'omit' => 0 } result_stats_line_start = ' # 1 tests:' result_file.puts "1..#{results_count}" file_count = 0 Dir.glob("#{@result_dir}/*.t") do |filename| file_count += 1 File.open(filename, 'r') do |file| breakpoint_line = 0 file.each_with_index do |line, index| next if index == 0 || (breakpoint_line > 0 && index > breakpoint_line) if line.start_with?(result_stats_line_start) pass, fail, errs, todo, omit = line.match(/(\d+) pass, (\d+) fail, (\d+) errs, (\d+) todo, (\d+) omit/).captures one_test_result = { 'pass' => pass.to_i, 'fail' => fail.to_i, 'errs' => errs.to_i, 'todo' => todo.to_i, 'omit' => omit.to_i } result_stats = result_stats.merge(one_test_result) { |k, total, one| total + one } breakpoint_line = index elsif line.strip == '#' next else if line.start_with?('ok 1') || line.start_with?('not ok 1') line_begin, line_end = line.split('1 -') result_file.puts [line_begin, line_end].join("#{file_count} -") else result_file.puts line end end end end File.delete(filename) end result_file.puts ' #' result_file.puts " # #{results_count} tests: #{result_stats['pass']} pass, #{result_stats['fail']} fail, #{result_stats['errs']} errs, #{result_stats['todo']} todo, #{result_stats['omit']} omit" result_file.puts " # [00:00:00.00 0.00t/s 00.0000s/t] Finished at: #{Time.now}" end end |
#clean_result! ⇒ Object
remove all results files under @result_dir if there’s any
41 42 43 44 45 46 47 |
# File 'lib/mini_autobot/parallel.rb', line 41 def clean_result! raise Exception, '@result_dir is not set' if @result_dir.nil? unless Dir.glob("#{@result_dir}/*").empty? FileUtils.rm_rf(Dir.glob("#{@result_dir}/*")) end puts "Cleaning result files.\n" end |
#count_autobot_process ⇒ Object
128 129 130 131 |
# File 'lib/mini_autobot/parallel.rb', line 128 def count_autobot_process counting_process_output = IO.popen "ps -ef | grep 'bin/#{@static_run_command}' -c" counting_process_output.readlines[0].to_i - 1 # minus grep process end |
#keep_running_full(all_to_run) ⇒ Object
recursively keep running ##simultaneous_jobs number of tests in parallel exit when no test left to run
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/mini_autobot/parallel.rb', line 165 def keep_running_full(all_to_run) running_subprocess_count = count_autobot_process - 1 # minus parent process puts "WARNING: running_subprocess_count = #{running_subprocess_count} is more than what it is supposed to run(#{simultaneous_jobs}), notify mini_autobot maintainers" if running_subprocess_count > simultaneous_jobs + 1 while running_subprocess_count >= simultaneous_jobs sleep 5 running_subprocess_count = count_autobot_process - 1 end to_run_count = simultaneous_jobs - running_subprocess_count tests_to_run = all_to_run.slice!(0, to_run_count) run_test_set(tests_to_run) keep_running_full(all_to_run) if all_to_run.size > 0 end |
#remove_redundant_tap ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/mini_autobot/parallel.rb', line 49 def remove_redundant_tap ever_failed_tests_file = "#{@result_dir}/ever_failed_tests.json" if File.file? ever_failed_tests_file data_hash = JSON.parse(File.read(ever_failed_tests_file)) data_hash.keys.each do |test| if test.start_with? 'test_' tap_result_file = "#{@result_dir}/#{test}.t" result_lines = IO.readlines(tap_result_file) last_tap_start_index = 0 last_tap_end_index = result_lines.size - 1 result_lines.each_with_index do |l, index| last_tap_start_index = index if l.delete!("\n") == '1..1' end File.open(tap_result_file, 'w') do |f| f.puts result_lines[last_tap_start_index..last_tap_end_index] end puts "Processed #{tap_result_file}" else next end end else puts "==> File #{ever_failed_tests_file} doesn't exist - all tests passed!" end end |
#run_in_parallel! ⇒ Object
run multiple commands with logging to start multiple tests in parallel n = number of tests will be running in parallel
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/mini_autobot/parallel.rb', line 136 def run_in_parallel! size = all_tests.size if size <= simultaneous_jobs run_test_set(all_tests) puts "CAUTION! All #{size} tests are starting at the same time!" puts "will not really run it since computer will die" if size > 30 sleep 20 else first_test_set = all_tests[0, simultaneous_jobs] all_to_run = all_tests[simultaneous_jobs..(all_tests.size - 1)] run_test_set(first_test_set) keep_running_full(all_to_run) end Process.waitall puts "\nAll Complete! Started at #{@start_time} and finished at #{Time.now}\n" end |
#run_on_mac? ⇒ boolean
return true only if specified to run on mac in connector
36 37 38 |
# File 'lib/mini_autobot/parallel.rb', line 36 def run_on_mac? @platform.include?('osx') end |
#run_test_set(test_set) ⇒ Object
runs each test from a test set in a separate child process
155 156 157 158 159 160 161 |
# File 'lib/mini_autobot/parallel.rb', line 155 def run_test_set(test_set) test_set.each do |test| run_command = "#{@static_run_command} -n #{test} #{@pipe_tap} > #{@result_dir}/#{test}.t" pipe = IO.popen(run_command) puts "Running #{test} #{pipe.pid}" end end |
#wait_all_done_saucelabs ⇒ Object
Too time consuming and fragile, should use more native wait/check of Process
198 199 200 201 202 203 204 205 206 |
# File 'lib/mini_autobot/parallel.rb', line 198 def wait_all_done_saucelabs size = all_tests.size job_statuses = saucelabs_last_n_statuses(size) while job_statuses.include?('in progress') puts "There are tests still running, waiting..." sleep 20 job_statuses = saucelabs_last_n_statuses(size) end end |
#wait_for_pids(pids) ⇒ Object
Use more native wait/check of Process
183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/mini_autobot/parallel.rb', line 183 def wait_for_pids(pids) running_pids = pids # assume all pids are running at this moment while running_pids.size > 1 sleep 5 puts "running_pids = #{running_pids}" running_pids.each do |pid| unless process_running?(pid) puts "#{pid} is not running, removing it from pool" running_pids.delete(pid) end end end end |