Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

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

5 participants

@phuongnd08

Address #164

  • Do not abort a run if another run is wanted.
  • Do kill all forks if spork is terminating
  • Provide Spork.run_count so each process know some thing about it. This allow the rotation of database connections for running test in parallel (I'm working on this: https://github.com/phuongnd08/multi_spork)
@sergio-fry

+1

I think, that it is very useful

@phuongnd08

It's one month already. Any feed back on that?

@msaspence

+1 this would really useful

@robmathews

This would be useful

@sahilm
Owner

Closing old pull requests. Please send new ones if this is still an issue.

@sahilm sahilm closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
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,9 +95,9 @@ 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)
@@ -91,12 +105,12 @@ def #{method_name}(*args, &block)
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,10 +3,14 @@ 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
@@ -14,22 +18,23 @@ def run(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.