123456789_123456789_123456789_123456789_123456789_

Class: Test::Unit::TestSuiteProcessRunner

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: Test::Unit::TestSuiteRunner
Defined in: lib/test/unit/test-suite-process-runner.rb

Constant Summary

Class Attribute Summary

Class Method Summary

Instance Method Summary

Constructor Details

This class inherits a constructor from Test::Unit::TestSuiteRunner

Class Method Details

.add_result(result, data) (private)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 162

def add_result(result, data)
  action = data[:action]
  args = data[:args]
  result.__send__(action, *args)
end

.emit_event(event_listener, data) (private)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 168

def emit_event(event_listener, data)
  event_name = data[:event_name]
  args = data[:args]
  event_listener.call(event_name, *args)
end

.run_all_tests(result, options)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 51

def run_all_tests(result, options)
  n_workers = TestSuiteRunner.n_workers
  test_suite = options[:test_suite]

  start_tcp_server do |tcp_server|
    workers = []
    begin
      n_workers.times do |i|
        load_paths = options[:load_paths]
        base_directory = options[:base_directory]
        test_paths = options[:test_paths]
        command_line = [Gem.ruby, File.join(__dir__, "process-worker.rb")]
        load_paths.each do |load_path|
          command_line << "--load-path" << load_path
        end
        unless base_directory.nil?
          command_line << "--base-directory" << base_directory
        end
        command_line << "--worker-id" << (i + 1).to_s
        if Gem.win_platform?
          local_address = tcp_server.local_address
          command_line << "--ip-address" << local_address.ip_address
          command_line << "--ip-port" << local_address.ip_port.to_s
        end
        command_line.concat(test_paths)
        if Gem.win_platform?
          # On Windows, file descriptors 3 and above cannot be passed to
          # child processes.
          pid = spawn(*command_line)
          data_socket = tcp_server.accept
          workers << Worker.new(pid, data_socket, data_socket)
        else
          main_to_worker_input, main_to_worker_output = IO.pipe
          worker_to_main_input, worker_to_main_output = IO.pipe
          pid = spawn(*command_line, {MAIN_TO_WORKER_INPUT_FILENO => main_to_worker_input,
                                      WORKER_TO_MAIN_OUTPUT_FILENO => worker_to_main_output})
          main_to_worker_input.close
          worker_to_main_output.close
          workers << Worker.new(pid, main_to_worker_output, worker_to_main_input)
        end
      end

      run_context = TestProcessRunContext.new(self)
      yield(run_context)
      run_context.progress_block.call(TestSuite::STARTED, test_suite.name)
      run_context.progress_block.call(TestSuite::STARTED_OBJECT, test_suite)

      worker_inputs = workers.collect(&:worker_to_main_input)
      until run_context.test_names.empty? do
        select_each_worker(worker_inputs, workers) do |_, worker, data|
          case data[:status]
          when :ready
            test_name = run_context.test_names.shift
            break if test_name.nil?
            worker.send(test_name)
          when :result
            add_result(result, data)
          when :event
            emit_event(options[:event_listener], data)
          end
        end
      end
      workers.each do |worker|
        worker.send(nil)
      end
      until worker_inputs.empty? do
        select_each_worker(worker_inputs, workers) do |worker_to_main_input, worker, data|
          case data[:status]
          when :result
            add_result(result, data)
          when :event
            emit_event(options[:event_listener], data)
          when :done
            worker_inputs.delete(worker_to_main_input)
            worker.send(nil)
          end
        end
      end
    ensure
      workers.each do |worker|
        worker.wait
      end
    end

    run_context.progress_block.call(TestSuite::FINISHED, test_suite.name)
    run_context.progress_block.call(TestSuite::FINISHED_OBJECT, test_suite)
  end
end

.select_each_worker(worker_inputs, workers) (private)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 151

def select_each_worker(worker_inputs, workers)
  readables, = IO.select(worker_inputs)
  readables.each do |worker_to_main_input|
    worker = workers.find do |w|
      w.worker_to_main_input == worker_to_main_input
    end
    data = worker.receive
    yield(worker_to_main_input, worker, data)
  end
end

.start_tcp_server (private)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 141

def start_tcp_server
  if Gem.win_platform?
    TCPServer.open("127.0.0.1", 0) do |tcp_server|
      yield(tcp_server)
    end
  else
    yield
  end
end

Instance Method Details

#run(worker_context, &progress_block)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 175

def run(worker_context, &progress_block)
  worker_context.run_context.progress_block = progress_block
  run_tests_recursive(@test_suite, worker_context, &progress_block)
end

#run_tests_recursive(test_suite, worker_context, &progress_block) (private)

[ GitHub ]

  
# File 'lib/test/unit/test-suite-process-runner.rb', line 181

def run_tests_recursive(test_suite, worker_context, &progress_block)
  run_context = worker_context.run_context
  if test_suite.have_fixture?
    run_context.test_names << test_suite.name
  else
    test_suite.tests.each do |test|
      if test.is_a?(TestSuite)
        run_tests_recursive(test, worker_context, &progress_block)
      else
        run_context.test_names << test.name
      end
    end
  end
end