Class: Browsery::Parallel
- Inherits:
-
Object
- Object
- Browsery::Parallel
- Defined in:
- lib/browsery/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_browsery_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 |
# File 'lib/browsery/parallel.rb', line 6 def initialize(simultaneous_jobs, all_tests) @start_time = Time.now @result_dir = 'logs/tap_results' connector = Browsery.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 = "browsery -c #{Browsery.settings.connector} -e #{Browsery.settings.env}" if Browsery.settings.rerun_failure @static_run_command += " -R #{Browsery.settings.rerun_failure}" end tap_reporter_path = Browsery.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/browsery/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/browsery/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
72 73 74 75 76 77 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 |
# File 'lib/browsery/parallel.rb', line 72 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
35 36 37 38 39 40 41 |
# File 'lib/browsery/parallel.rb', line 35 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_browsery_process ⇒ Object
122 123 124 125 |
# File 'lib/browsery/parallel.rb', line 122 def count_browsery_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
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/browsery/parallel.rb', line 159 def keep_running_full(all_to_run) running_subprocess_count = count_browsery_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 browsery maintainers" if running_subprocess_count > simultaneous_jobs + 1 while running_subprocess_count >= simultaneous_jobs sleep 5 running_subprocess_count = count_browsery_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
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/browsery/parallel.rb', line 43 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
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/browsery/parallel.rb', line 130 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
30 31 32 |
# File 'lib/browsery/parallel.rb', line 30 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
149 150 151 152 153 154 155 |
# File 'lib/browsery/parallel.rb', line 149 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
192 193 194 195 196 197 198 199 200 |
# File 'lib/browsery/parallel.rb', line 192 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
177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/browsery/parallel.rb', line 177 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 |