#!/usr/bin/env ruby require 'tty-spinner' require 'tty-progressbar' require 'open3' require 'shellwords' require 'fileutils' $LOAD_PATH.unshift File.join(__dir__, '..') require 'doing' require 'helpers/threaded_tests_string' class ThreadedTests include Doing::Color include ThreadedTestString def run(pattern: '*', max_threads: 8, max_tests: 0) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) @results = File.expand_path('results.log') max_threads = 1000 if max_threads.to_i == 0 c = Doing::Color c.coloring = true pattern = "test/doing_*#{pattern}*_test.rb" tests = Dir.glob(pattern) if max_tests.to_i > 0 tests = tests.slice(0, max_tests.to_i - 1) end puts "#{tests.count} test files".boldcyan banner = [ 'Running tests '.bold.white, '['.black, ':bar'.boldcyan, '] '.black, 'T'.green, '/'.white, 'A'.cyan, ' ('.white, max_threads.to_s.bold.magenta, ' threads)'.white ].join('') progress = TTY::ProgressBar::Multi.new(banner, width: 12, clear: true, hide_cursor: true) @children = [] tests.each do |t| test_name = File.basename(t, '.rb').sub(/doing_(.*?)_test/, '\1') new_sp = progress.register("[#{':bar'.cyan}] #{test_name.bold.white}:status", total: tests.count + 8, width: 1, head: ' ', unknown: ' ', hide_cursor: true, clear: true) status = ': waiting'.dark.yellow.reset @children.push([test_name, new_sp, status]) # new_sp.advance(status: ': waiting'.dark.yellow.reset) end @elapsed = 0.0 @test_total = 0 @assrt_total = 0 @error_out = [] # progress.start @threads = [] @running_tests = [] begin while @children.count.positive? slices = @children.slice!(0, max_threads) slices.each { |c| c[1].start } slices.each do |s| @threads << Thread.new do run_test(s) end end @threads.each { |t| t.join } end finish_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) progress.finish rescue progress.stop ensure msg = @running_tests.map { |t| t[1].format.uncolor.sub(/^\[:bar\] (.*?):status/, "#{c.bold}#{c.white}\\1#{c.reset}#{t[2]}") }.join("\n") Doing::Prompt.clear_screen(msg) output = [] output << if @error_out.count.positive? c.boldred("#{@error_out.count} Issues") else c.green('Success') end output << c.green("#{@test_total} tests") output << c.cyan("#{@assrt_total} assertions") output << c.yellow("#{(finish_time - start_time).round(3)}s") puts output.join(', ') if @error_out.count.positive? res = Doing::Prompt.yn('Display error report?', default_response: false) Doing::Pager.paginate = true Doing::Pager.page(@error_out.join("\n----\n".boldwhite)) if res end end end def run_test(s) bar = s[1] s[2] = ": #{'running'.green}" bar.advance(status: s[2]) if @running_tests.count.positive? @running_tests.each do |b| prev_bar = b[1] if prev_bar.complete? prev_bar.reset prev_bar.advance(status: b[2]) prev_bar.finish else prev_bar.update(head: ' ', unfinished: ' ') prev_bar.advance(status: b[2]) end end end @running_tests.push(s) out, _err, status = Open3.capture3(ENV, 'rake', "test:#{s[0]}", stdin_data: nil) time = out.match(/^Finished in (?