Skip to content

V0.9.x - Allow multiple forks to run in parallel and provide a counter to each fork #178

Closed
wants to merge 4 commits into from
View
40 lib/spork.rb
@@ -13,7 +13,21 @@ module Spork
autoload :Diagnoser, (LIBDIR + 'spork/diagnoser').to_s
autoload :GemHelpers, (LIBDIR + 'spork/gem_helpers').to_s
+ @run_count_semaphore = Mutex.new
+
class << self
+
+ def run_count
+ @run_count || 0
+ end
+
+ def increase_run_count
+ @run_count_semaphore.synchronize do
+ @run_count = 0 unless @run_count
+ @run_count += 1
+ end
+ end
+
# Run a block, during prefork mode. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
#
# == Parameters
@@ -23,7 +37,7 @@ def prefork(prevent_double_run = true, &block)
return if prevent_double_run && already_ran?(caller.first)
yield
end
-
+
# Run a block AFTER the fork occurs. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
#
# == Parameters
@@ -37,7 +51,7 @@ def each_run(prevent_double_run = true, &block)
yield
end
end
-
+
# Run a block after specs are run.
#
# == Parameters
@@ -55,13 +69,13 @@ def using_spork?
def state
@state ||= :not_using_spork
end
-
+
# Used by the server. Called when loading the prefork blocks of the code.
def exec_prefork(&block)
@state = :prefork
yield
end
-
+
# Used by the server. Called to run all of the prefork blocks.
def exec_each_run(&block)
@state = :run
@@ -70,7 +84,7 @@ def exec_each_run(&block)
each_run_procs.clear
yield if block_given?
end
-
+
# Used by the server. Called to run all of the after_each_run blocks.
def exec_after_each_run
# processes in reverse order similar to at_exit
@@ -81,22 +95,22 @@ def exec_after_each_run
# Traps an instance method of a class (or module) so any calls to it don't actually run until Spork.exec_each_run
def trap_method(klass, method_name)
method_name_without_spork, method_name_with_spork = alias_method_names(method_name, :spork)
-
+
klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
- alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
+ alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
def #{method_name}(*args, &block)
Spork.each_run(false) do
#{method_name_without_spork}(*args, &block)
end
end
EOF
end
-
+
# Same as trap_method, but for class methods instead
def trap_class_method(klass, method_name)
trap_method((class << klass; self; end), method_name)
end
-
+
def detect_and_require(subfolder)
([LIBDIR.to_s] + other_spork_gem_load_paths).uniq.each do |gem_path|
Dir.glob(File.join(gem_path, subfolder)).each { |file| require file }
@@ -123,11 +137,11 @@ def alias_method_names(method_name, feature)
/^(.+?)([\?\!]{0,1})$/.match(method_name.to_s)
["#{$1}_without_spork#{$2}", "#{$1}_with_spork#{$2}"]
end
-
+
def already_ran
@already_ran ||= []
end
-
+
def expanded_caller(caller_line)
file, line = caller_line.split(/:(\d+)/)
line.gsub(/:.+/, '')
@@ -137,13 +151,13 @@ def expanded_caller(caller_line)
end
expanded
end
-
+
def already_ran?(caller_script_and_line)
return true if already_ran.include?(expanded_caller(caller_script_and_line))
already_ran << expanded_caller(caller_script_and_line)
false
end
-
+
def each_run_procs
@each_run_procs ||= []
end
View
23 lib/spork/run_strategy/forking.rb
@@ -3,33 +3,38 @@ def self.available?
Kernel.respond_to?(:fork)
end
+ def children
+ @children ||= []
+ end
+
def run(argv, stderr, stdout)
- abort if running?
+ Spork.increase_run_count
- @child = ::Spork::Forker.new do
+ children << child = ::Spork::Forker.new do
$stdout, $stderr = stdout, stderr
load test_framework.helper_file
Spork.exec_each_run
result = test_framework.run_tests(argv, stderr, stdout)
Spork.exec_after_each_run
result
end
- @child.result
+ child.result
end
def abort
- @child && @child.abort
+ children.each { |child| child.abort if child.running? }
+ nil
end
- def preload
- test_framework.preload
+ def running?
+ children.any? { |child| child.running? }
end
- def running?
- @child && @child.running?
+ def preload
+ test_framework.preload
end
def assert_ready!
raise RuntimeError, "This process hasn't loaded the environment yet by loading the prefork block" unless Spork.using_spork?
end
-end
+end
View
11 spec/spork/run_strategy/forking_spec.rb
@@ -13,17 +13,6 @@
@run_strategy.run("test", STDOUT, STDIN).should == "tests were ran"
end
- it "aborts the current running thread when another run is started" do
- create_helper_file
- @fake_framework.wait_time = 0.25
- first_run = Thread.new { @run_strategy.run("test", STDOUT, STDIN).should == nil }
- sleep(0.05)
- @run_strategy.run("test", STDOUT, STDIN).should == true
-
- # wait for the first to finish
- first_run.join
- end
-
it "can abort the current run" do
create_helper_file
@fake_framework.wait_time = 5
Something went wrong with that request. Please try again.