Permalink
Browse files

Make testjour slaves fork a child per feature file.

  • Loading branch information...
1 parent e516b00 commit 091a8ee93678436c7398b34c2aa28c1fd4fc53a2 Luke Melia and Lee Bankewitz committed Dec 7, 2009
Showing with 48 additions and 8 deletions.
  1. +3 −1 features/step_definitions/testjour_steps.rb
  2. +5 −1 lib/testjour.rb
  3. +40 −6 lib/testjour/commands/run_slave.rb
@@ -77,7 +77,9 @@
pids = log.scan(/\[\d+\]/).uniq
# One master process and the slaves
- pids.size.should == count.to_i + 1
+ if pids.size != count.to_i + 1
+ raise("Expected #{count} slave PIDs, got #{pids.size - 1}:\nLog is:\n#{log}")
+ end
end
end
View
@@ -38,12 +38,16 @@ def self.logger
setup_logger
@logger
end
+
+ def self.override_logger_pid(pid)
+ @overridden_logger_pid = pid
+ end
def self.setup_logger(dir = "./")
@logger = Logger.new(File.expand_path(File.join(dir, "testjour.log")))
@logger.formatter = proc do |severity, time, progname, msg|
- "#{time.strftime("%b %d %H:%M:%S")} [#{$PID}]: #{msg}\n"
+ "#{time.strftime("%b %d %H:%M:%S")} [#{@overridden_logger_pid || $PID}]: #{msg}\n"
end
@logger.level = Logger::DEBUG
@@ -11,17 +11,22 @@ module Commands
class RunSlave < Command
+ # Boolean indicating whether this worker can or can not fork.
+ # Automatically set if a fork(2) fails.
+ attr_accessor :cant_fork
+
def execute
configuration.parse!
configuration.parse_uri!
+ enable_gc_optimizations
Dir.chdir(configuration.path) do
Testjour.setup_logger(configuration.path)
Testjour.logger.info "Starting run:slave"
begin
configuration.setup
configuration.setup_mysql
- require_files
+ require_cucumber_files
work
rescue Object => ex
Testjour.logger.error "run:slave error: #{ex.message}"
@@ -36,11 +41,19 @@ def work
while feature_file
if (feature_file = queue.pop(:feature_files))
- Testjour.logger.info "Running: #{feature_file}"
+ Testjour.logger.info "Loading: #{feature_file}"
features = load_plain_text_features(feature_file)
- Testjour.logger.info "Loaded: #{feature_file}"
- execute_features(features)
- Testjour.logger.info "Finished running: #{feature_file}"
+ parent_pid = $PID
+ if @child = fork
+ Testjour.logger.info "Forked #{@child} at #{Time.now.to_i}"
+ Process.wait
+ Testjour.logger.info "Finished running: #{feature_file}"
+ else
+ Testjour.override_logger_pid(parent_pid)
+ Testjour.logger.info "Executing: #{feature_file}"
+ execute_features(features)
+ exit! unless @cant_fork
+ end
else
Testjour.logger.info "No feature file found. Finished"
end
@@ -55,11 +68,32 @@ def execute_features(features)
tree_walker.visit_features(features)
end
- def require_files
+ def require_cucumber_files
step_mother.load_code_files(configuration.cucumber_configuration.support_to_load)
step_mother.after_configuration(configuration.cucumber_configuration)
step_mother.load_code_files(configuration.cucumber_configuration.step_defs_to_load)
end
+
+ # Not every platform supports fork. Here we do our magic to
+ # determine if yours does.
+ def fork
+ return if @cant_fork
+
+ begin
+ Kernel.fork
+ rescue NotImplementedError
+ @cant_fork = true
+ nil
+ end
+ end
+
+ # Enables GC Optimizations if you're running REE.
+ # http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
+ def enable_gc_optimizations
+ if GC.respond_to?(:copy_on_write_friendly=)
+ GC.copy_on_write_friendly = true
+ end
+ end
end

0 comments on commit 091a8ee

Please sign in to comment.