Class: RSpec::MultiprocessRunner::Worker

Inherits:
Object
  • Object
show all
Defined in:
lib/rspec/multiprocess_runner/worker.rb

Overview

This object has several roles:

  • It forks the worker process

  • In the coordinator process, it is used to send messages to the worker and track the worker’s status, completed specs, and example results.

  • In the worker process, it is used to send messages to the coordinator and actually run specs.

Constant Summary collapse

COMMAND_QUIT =
"quit"
COMMAND_RUN_FILE =
"run_file"
STATUS_EXAMPLE_COMPLETE =
"example_complete"
STATUS_RUN_COMPLETE =
"run_complete"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(environment_number, file_timeout, rspec_arguments = []) ⇒ Worker

Returns a new instance of Worker.



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/rspec/multiprocess_runner/worker.rb', line 32

def initialize(environment_number, file_timeout, rspec_arguments=[])
  @environment_number = environment_number
  @worker_socket, @coordinator_socket = Socket.pair(:UNIX, :STREAM)
  @rspec_arguments = rspec_arguments + ["--format", ReportingFormatter.to_s]
  @file_timeout = file_timeout
  @example_results = []

  # Use a single configuration and world across all individual runs
  # This will not be necessary to do manually in RSpec 3 — it does not
  # reset the globals after each run.
  @rspec_configuration = RSpec.configuration
  @rspec_world = RSpec.world
end

Instance Attribute Details

#current_fileObject (readonly)

Returns the value of attribute current_file.



23
24
25
# File 'lib/rspec/multiprocess_runner/worker.rb', line 23

def current_file
  @current_file
end

#deactivation_reasonObject

Returns the value of attribute deactivation_reason.



24
25
26
# File 'lib/rspec/multiprocess_runner/worker.rb', line 24

def deactivation_reason
  @deactivation_reason
end

#environment_numberObject (readonly)

Returns the value of attribute environment_number.



23
24
25
# File 'lib/rspec/multiprocess_runner/worker.rb', line 23

def environment_number
  @environment_number
end

#example_resultsObject (readonly)

Returns the value of attribute example_results.



23
24
25
# File 'lib/rspec/multiprocess_runner/worker.rb', line 23

def example_results
  @example_results
end

#pidObject (readonly)

Returns the value of attribute pid.



23
24
25
# File 'lib/rspec/multiprocess_runner/worker.rb', line 23

def pid
  @pid
end

Instance Method Details

#==(other) ⇒ Object

Workers can be found in the coordinator process by their coordinator socket.



48
49
50
51
52
53
54
55
# File 'lib/rspec/multiprocess_runner/worker.rb', line 48

def ==(other)
  case other
  when Socket
    other == @coordinator_socket
  else
    super
  end
end

#quitObject



87
88
89
# File 'lib/rspec/multiprocess_runner/worker.rb', line 87

def quit
  send_message_to_worker(command: COMMAND_QUIT)
end

#reapObject



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rspec/multiprocess_runner/worker.rb', line 109

def reap
  begin
    Timeout.timeout(4) do
      $stderr.puts "Reaping troubled process #{environment_number} (#{pid}; #{@current_file}) with QUIT"
      Process.kill(:QUIT, pid)
      Process.wait(pid)
    end
  rescue Timeout::Error
    $stderr.puts "Reaping troubled process #{environment_number} (#{pid}) with KILL"
    Process.kill(:KILL, pid)
    Process.wait(pid)
  end
end

#receive_and_act_on_message_from_workerObject



123
124
125
# File 'lib/rspec/multiprocess_runner/worker.rb', line 123

def receive_and_act_on_message_from_worker
  act_on_message_from_worker(receive_message_from_worker)
end

#report_example_result(example_status, description, details) ⇒ Object



168
169
170
171
172
173
174
175
# File 'lib/rspec/multiprocess_runner/worker.rb', line 168

def report_example_result(example_status, description, details)
  send_message_to_coordinator(
    status: STATUS_EXAMPLE_COMPLETE,
    example_status: example_status,
    description: description,
    details: details
  )
end

#run_file(filename) ⇒ Object



95
96
97
98
99
# File 'lib/rspec/multiprocess_runner/worker.rb', line 95

def run_file(filename)
  send_message_to_worker(command: COMMAND_RUN_FILE, filename: filename)
  @current_file = filename
  @current_file_started_at = Time.now
end

#socketObject



73
74
75
76
77
78
79
# File 'lib/rspec/multiprocess_runner/worker.rb', line 73

def socket
  if self.pid == Process.pid
    @worker_socket
  else
    @coordinator_socket
  end
end

#stalled?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/rspec/multiprocess_runner/worker.rb', line 105

def stalled?
  working? && (Time.now - @current_file_started_at > @file_timeout)
end

#startObject

Forks the worker process. In the parent, returns the PID.



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rspec/multiprocess_runner/worker.rb', line 59

def start
  pid = fork
  if pid
    @worker_socket.close
    @pid = pid
  else
    @coordinator_socket.close
    @pid = Process.pid
    ENV["TEST_ENV_NUMBER"] = environment_number.to_s
    set_process_name
    run_loop
  end
end

#wait_until_quitObject



91
92
93
# File 'lib/rspec/multiprocess_runner/worker.rb', line 91

def wait_until_quit
  Process.wait(self.pid)
end

#working?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/rspec/multiprocess_runner/worker.rb', line 101

def working?
  @current_file
end