Module: Minitest

Defined in:
lib/minitest/parallel_fork.rb

Defined Under Namespace

Modules: Unparallelize

Class Method Summary collapse

Class Method Details

.__run(reporter, options) ⇒ Object

Override __run to use a child forks to run the speeds, which allows for parallel spec execution on MRI.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/minitest/parallel_fork.rb', line 25

def self.__run(reporter, options)
  suites = Runnable.runnables.shuffle
  stat_reporter = parallel_fork_stat_reporter(reporter)

  n = (ENV['NCPU'] || 4).to_i
  reads = []
  if defined?(@before_parallel_fork)
    @before_parallel_fork.call
  end
  n.times do |i|
    read, write = IO.pipe.each{|io| io.binmode}
    reads << read
    fork do
      read.close
      if defined?(@after_parallel_fork)
        @after_parallel_fork.call(i)
      end

      p_suites = []
      suites.each_with_index{|s, j| p_suites << s if j % n == i}
      p_suites.each do |s|
        if s.is_a?(Minitest::Parallel::Test::ClassMethods)
         s.extend(Unparallelize)
        end

        s.run(reporter, options)
      end

      data = %w'count assertions results'.map{|meth| stat_reporter.send(meth)}
      if data[-1].any?{|result| !result.is_a?(Minitest::Result)}
        data[-1] = data[-1].map do |result|
          Minitest::Result.from(result)
        end
      end

      data[-1].each do |result|
        result.failures.each do |failure|
          if failure.is_a?(Minitest::UnexpectedError)
            e = failure.exception
            begin
              Marshal.dump(e)
            rescue TypeError
              failure.exception = RuntimeError.new("Wrapped undumpable exception for: #{e.class}: #{e.message}")
              failure.exception.set_backtrace(e.backtrace)
            end
          end
        end
      end

      write.write(Marshal.dump(data))
      write.close
    end
    write.close
  end

  reads.map{|read| Thread.new(read, &:read)}.map(&:value).each do |data|
    count, assertions, results = Marshal.load(data)
    stat_reporter.count += count
    stat_reporter.assertions += assertions
    stat_reporter.results.concat(results)
  end

  nil
end

.after_parallel_fork(i = nil, &block) ⇒ Object

Set the after_parallel_fork block to the given block



11
12
13
# File 'lib/minitest/parallel_fork.rb', line 11

def self.after_parallel_fork(i=nil, &block)
  @after_parallel_fork = block
end

.before_parallel_fork(&block) ⇒ Object

Set the before_parallel_fork block to the given block



6
7
8
# File 'lib/minitest/parallel_fork.rb', line 6

def self.before_parallel_fork(&block)
  @before_parallel_fork = block
end

.parallel_fork_stat_reporter(reporter) ⇒ Object



19
20
21
# File 'lib/minitest/parallel_fork.rb', line 19

def self.parallel_fork_stat_reporter(reporter)
  reporter.reporters.detect{|rep| rep.is_a?(StatisticsReporter)}
end