spork 0.5.6 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -1
- data/features/rails_delayed_loading_workarounds.feature +9 -0
- data/features/steps/sandbox_steps.rb +4 -0
- data/lib/spork.rb +52 -37
- data/lib/spork/app_framework.rb +36 -12
- data/lib/spork/app_framework/rails.rb +19 -0
- data/lib/spork/app_framework/rails_stub_files/application.rb +1 -0
- data/lib/spork/app_framework/rails_stub_files/application_controller.rb +1 -0
- data/lib/spork/app_framework/rails_stub_files/application_helper.rb +1 -0
- data/lib/spork/app_framework/unknown.rb +4 -0
- data/lib/spork/custom_io_streams.rb +2 -0
- data/lib/spork/diagnoser.rb +20 -0
- data/lib/spork/forker.rb +16 -0
- data/lib/spork/runner.rb +2 -3
- data/lib/spork/server.rb +32 -9
- data/spec/spork/app_framework/rails_spec.rb +0 -2
- data/spec/spork/app_framework/unknown_spec.rb +0 -2
- data/spec/spork/forker_spec.rb +32 -24
- data/spec/spork/server_spec.rb +3 -3
- data/spec/spork_spec.rb +82 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
= Spork
|
2
2
|
|
3
|
-
* http://github.com/timcharper/spork
|
3
|
+
* Repository: http://github.com/timcharper/spork
|
4
|
+
* Issues: http://github.com/timcharper/spork/issues
|
5
|
+
* Changes: http://github.com/timcharper/spork/blob/master/History.txt
|
6
|
+
* Mailing list: http://groups.google.com/group/sporkgem
|
7
|
+
* Wiki: http://wiki.github.com/timcharper/spork
|
4
8
|
|
5
9
|
== SYNOPSIS:
|
6
10
|
|
@@ -62,10 +62,19 @@ Feature: Rails Delayed Work arounds
|
|
62
62
|
get :index
|
63
63
|
response.body.should include('listing users')
|
64
64
|
puts "Controller stack is functioning"
|
65
|
+
response.body.should include('Here is a list of users')
|
66
|
+
puts "Views are not being cached"
|
65
67
|
end
|
66
68
|
end
|
67
69
|
"""
|
68
70
|
When I fire up a spork instance with "spork rspec"
|
71
|
+
And the contents of "app/views/users/index.html.erb" are changed to:
|
72
|
+
"""
|
73
|
+
<%= reverse_text('listing users'.reverse) %>
|
74
|
+
<p>Here is a list of users</p>
|
75
|
+
"""
|
76
|
+
|
69
77
|
And I run spec --drb spec/controllers/users_controller_spec.rb
|
70
78
|
Then the output should contain "Controller stack is functioning"
|
79
|
+
Then the output should contain "Views are not being cached"
|
71
80
|
|
@@ -12,6 +12,10 @@ Given /^a file named "([^\"]*)" with:$/ do |file_name, file_content|
|
|
12
12
|
create_file(file_name, file_content)
|
13
13
|
end
|
14
14
|
|
15
|
+
When /^the contents of "([^\"]*)" are changed to:$/ do |file_name, file_content|
|
16
|
+
create_file(file_name, file_content)
|
17
|
+
end
|
18
|
+
|
15
19
|
# the following code appears in "config/environment.rb" after /Rails::Initializer.run/:
|
16
20
|
Given /^the following code appears in "([^\"]*)" after \/([^\\\/]*)\/:$/ do |file_name, regex, content|
|
17
21
|
# require 'ruby-debug'; Debugger.start; Debugger.start_control; debugger
|
data/lib/spork.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
2
2
|
module Spork
|
3
3
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def prefork(&block)
|
13
|
-
return if already_ran?(caller.first)
|
4
|
+
# 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.
|
5
|
+
#
|
6
|
+
# == Parameters
|
7
|
+
#
|
8
|
+
# * +prevent_double_run+ - Pass false to disable double run prevention
|
9
|
+
def prefork(prevent_double_run = true, &block)
|
10
|
+
return if prevent_double_run && already_ran?(caller.first)
|
14
11
|
yield
|
15
12
|
end
|
16
13
|
|
17
|
-
|
18
|
-
|
14
|
+
# 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.
|
15
|
+
#
|
16
|
+
# == Parameters
|
17
|
+
#
|
18
|
+
# * +prevent_double_run+ - Pass false to disable double run prevention
|
19
|
+
def each_run(prevent_double_run = true, &block)
|
20
|
+
return if prevent_double_run && already_ran?(caller.first)
|
19
21
|
if @state == :using_spork
|
20
22
|
each_run_procs << block
|
21
23
|
else
|
@@ -23,59 +25,72 @@ module Spork
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
|
-
|
27
|
-
return true if already_ran.include?(expanded_caller(caller_script_and_line))
|
28
|
-
already_ran << expanded_caller(caller_script_and_line)
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
28
|
+
# Used by the server. Sets the state to activate spork. Otherwise, prefork and each_run are run in passive mode, allowing specs without a Spork server.
|
32
29
|
def using_spork!
|
33
30
|
@state = :using_spork
|
34
31
|
end
|
35
32
|
|
33
|
+
# Used by the server. Returns the current state of Spork.
|
36
34
|
def state
|
37
35
|
@state ||= :not_using_spork
|
38
36
|
end
|
39
37
|
|
38
|
+
# Used by the server. Called when loading the prefork blocks of the code.
|
40
39
|
def exec_prefork(&block)
|
41
40
|
using_spork!
|
42
41
|
yield
|
43
42
|
end
|
44
43
|
|
44
|
+
# Used by the server. Called to run all of the prefork blocks.
|
45
45
|
def exec_each_run(&block)
|
46
46
|
each_run_procs.each { |p| p.call }
|
47
47
|
each_run_procs.clear
|
48
48
|
yield if block_given?
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
file, line = caller_line.split(":")
|
53
|
-
line.gsub(/:.+/, '')
|
54
|
-
File.expand_path(file, Dir.pwd) + ":" + line
|
55
|
-
end
|
56
|
-
|
51
|
+
# Traps an instance method of a class (or module) so any calls to it don't actually run until Spork.exec_each_run
|
57
52
|
def trap_method(klass, method_name)
|
53
|
+
method_name_without_spork, method_name_with_spork = alias_method_names(method_name, :spork)
|
54
|
+
|
58
55
|
klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
|
59
|
-
alias :#{
|
56
|
+
alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
|
60
57
|
def #{method_name}(*args)
|
61
|
-
Spork.
|
62
|
-
#{
|
58
|
+
Spork.each_run(false) do
|
59
|
+
#{method_name_without_spork}(*args)
|
63
60
|
end
|
64
61
|
end
|
65
62
|
EOF
|
66
63
|
end
|
67
64
|
|
65
|
+
# Same as trap_method, but for class methods instead
|
68
66
|
def trap_class_method(klass, method_name)
|
69
|
-
klass
|
70
|
-
class << self
|
71
|
-
alias :#{method_name}_without_spork :#{method_name} unless method_defined?(:#{method_name}_without_spork)
|
72
|
-
def #{method_name}(*args)
|
73
|
-
Spork.each_run_procs << lambda do
|
74
|
-
#{method_name}_without_spork(*args)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
EOF
|
67
|
+
trap_method((class << klass; self; end), method_name)
|
79
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def alias_method_names(method_name, feature)
|
72
|
+
/^(.+?)([\?\!]{0,1})$/.match(method_name.to_s)
|
73
|
+
["#{$1}_without_spork#{$2}", "#{$1}_with_spork#{$2}"]
|
74
|
+
end
|
75
|
+
|
76
|
+
def already_ran
|
77
|
+
@already_ran ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def expanded_caller(caller_line)
|
81
|
+
file, line = caller_line.split(":")
|
82
|
+
line.gsub(/:.+/, '')
|
83
|
+
File.expand_path(file, Dir.pwd) + ":" + line
|
84
|
+
end
|
85
|
+
|
86
|
+
def already_ran?(caller_script_and_line)
|
87
|
+
return true if already_ran.include?(expanded_caller(caller_script_and_line))
|
88
|
+
already_ran << expanded_caller(caller_script_and_line)
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
def each_run_procs
|
93
|
+
@each_run_procs ||= []
|
94
|
+
end
|
80
95
|
end
|
81
96
|
end
|
data/lib/spork/app_framework.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
1
|
class Spork::AppFramework
|
2
|
+
# A hash of procs where the key is the class name, and the proc takes no arguments and returns true if it detects that said application framework is being used in the project.
|
3
|
+
#
|
4
|
+
# The key :Rails maps to Spork::AppFramework::Rails
|
5
|
+
#
|
6
|
+
# This is used to reduce the amount of code needed to be loaded - only the detected application framework's support code is loaded.
|
2
7
|
SUPPORTED_FRAMEWORKS = {
|
3
|
-
:Rails => lambda
|
8
|
+
:Rails => lambda {
|
4
9
|
File.exist?("config/environment.rb") && File.read("config/environment.rb").include?('RAILS_GEM_VERSION')
|
5
|
-
|
10
|
+
}
|
6
11
|
}
|
7
12
|
|
13
|
+
def self.setup_autoload
|
14
|
+
([:Unknown] + SUPPORTED_FRAMEWORKS.keys).each do |name|
|
15
|
+
autoload name, File.join(File.dirname(__FILE__), "app_framework", name.to_s.downcase)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Iterates through all SUPPORTED_FRAMEWORKS and returns the symbolic name of the project application framework detected. Otherwise, returns :Unknown
|
8
20
|
def self.detect_framework_name
|
9
21
|
SUPPORTED_FRAMEWORKS.each do |key, value|
|
10
22
|
return key if value.call
|
@@ -12,32 +24,37 @@ class Spork::AppFramework
|
|
12
24
|
:Unknown
|
13
25
|
end
|
14
26
|
|
27
|
+
# Same as detect_framework_name, but returns an instance of the specific AppFramework class.
|
15
28
|
def self.detect_framework
|
16
29
|
name = detect_framework_name
|
17
30
|
self[name]
|
18
31
|
end
|
19
32
|
|
33
|
+
# Initializes, stores, and returns a singleton instance of the named AppFramework.
|
34
|
+
#
|
35
|
+
# == Parameters
|
36
|
+
#
|
37
|
+
# # +name+ - A symbolic name of a AppFramework subclass
|
38
|
+
#
|
39
|
+
# == Example
|
40
|
+
#
|
41
|
+
# Spork::AppFramework[:Rails]
|
20
42
|
def self.[](name)
|
21
|
-
instances[name] ||= (
|
22
|
-
require File.join(File.dirname(__FILE__), "app_framework", name.to_s.downcase)
|
23
|
-
const_get(name).new
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.instances
|
28
|
-
@instances ||= {}
|
43
|
+
instances[name] ||= const_get(name).new
|
29
44
|
end
|
30
45
|
|
31
46
|
def self.short_name
|
32
47
|
name.gsub('Spork::AppFramework::', '')
|
33
48
|
end
|
34
49
|
|
50
|
+
# If there is some stuff out of the box that the Spork can do to speed up tests without the test helper file being bootstrapped, this should return false.
|
35
51
|
def bootstrap_required?
|
36
52
|
entry_point.nil?
|
37
53
|
end
|
38
54
|
|
55
|
+
# Abstract: The path to the file that loads the project environment, ie config/environment.rb. Returns nil if there is none.
|
39
56
|
def entry_point
|
40
|
-
|
57
|
+
raise NotImplemented
|
41
58
|
end
|
42
59
|
|
43
60
|
def preload(&block)
|
@@ -47,4 +64,11 @@ class Spork::AppFramework
|
|
47
64
|
def short_name
|
48
65
|
self.class.short_name
|
49
66
|
end
|
50
|
-
|
67
|
+
|
68
|
+
protected
|
69
|
+
def self.instances
|
70
|
+
@instances ||= {}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Spork::AppFramework.setup_autoload
|
@@ -39,6 +39,7 @@ class Spork::AppFramework::Rails < Spork::AppFramework
|
|
39
39
|
delay_app_preload
|
40
40
|
delay_application_controller_loading
|
41
41
|
delay_route_loading
|
42
|
+
delay_eager_view_loading
|
42
43
|
end
|
43
44
|
|
44
45
|
def reset_rails_env
|
@@ -92,6 +93,24 @@ class Spork::AppFramework::Rails < Spork::AppFramework
|
|
92
93
|
Spork.trap_method(::Rails::Initializer, :initialize_routing)
|
93
94
|
end
|
94
95
|
end
|
96
|
+
|
97
|
+
def delay_eager_view_loading
|
98
|
+
# So, in testing mode it seems it would be optimal to not eager load
|
99
|
+
# views (as your may only run a test that uses one or two views).
|
100
|
+
# However, I decided to delay eager loading rather than force it to
|
101
|
+
# disable because you may wish to eager load your views (I.E. you're
|
102
|
+
# testing concurrency)
|
103
|
+
|
104
|
+
# Rails 2.3.x +
|
105
|
+
if defined?(::ActionView::Template::EagerPath)
|
106
|
+
Spork.trap_method(::ActionView::Template::EagerPath, :load!)
|
107
|
+
end
|
108
|
+
# Rails 2.2.x
|
109
|
+
if defined?(::ActionView::PathSet::Path)
|
110
|
+
Spork.trap_method(::ActionView::PathSet::Path, :load)
|
111
|
+
end
|
112
|
+
# Rails 2.0.5 - 2.1.x don't appear to eager cache views.
|
113
|
+
end
|
95
114
|
end
|
96
115
|
|
97
116
|
def preload(&block)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# This class is mainly used for testing.
|
2
|
+
# When included (and used), it gives us an opportunity to stub out the output streams used for a given class
|
1
3
|
module Spork::CustomIOStreams
|
2
4
|
def self.included(klass)
|
3
5
|
klass.send(:extend, ::Spork::CustomIOStreams::ClassMethods)
|
data/lib/spork/diagnoser.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
|
+
# The Diagnoser hooks into load and require and keeps track of when files are required / loaded, and who loaded them.
|
2
|
+
# It's used when you run spork --diagnose
|
3
|
+
#
|
4
|
+
# = Example
|
5
|
+
#
|
6
|
+
# Spork::Diagnoser.install_hook!('/path/env.rb', '/path')
|
7
|
+
# require '/path/to/env.rb'
|
8
|
+
# Spork::Diagnoser.output_results(STDOUT)
|
1
9
|
class Spork::Diagnoser
|
2
10
|
class << self
|
3
11
|
def loaded_files
|
4
12
|
@loaded_files ||= {}
|
5
13
|
end
|
6
14
|
|
15
|
+
# Installs the diagnoser hook into Kernel#require and Kernel#load
|
16
|
+
#
|
17
|
+
# == Parameters
|
18
|
+
#
|
19
|
+
# * +entry_file+ - The file that is used to load the project. Used to filter the backtrace so anything that happens after it is hidden.
|
20
|
+
# * +dir+ - The project directory. Any file loaded outside of this directory will not be logged.
|
7
21
|
def install_hook!(entry_file = nil, dir = Dir.pwd)
|
8
22
|
@dir = File.expand_path(Dir.pwd, dir)
|
9
23
|
@entry_file = entry_file
|
@@ -30,6 +44,7 @@ class Spork::Diagnoser
|
|
30
44
|
loaded_files[filename] = filter_callstack(caller) if subdirectory?(filename)
|
31
45
|
end
|
32
46
|
|
47
|
+
# Uninstall the hook. Generally useful only for testing the Diagnoser.
|
33
48
|
def remove_hook!
|
34
49
|
return unless Kernel.private_instance_methods.include?('require_without_diagnoser')
|
35
50
|
Kernel.class_eval do
|
@@ -42,6 +57,11 @@ class Spork::Diagnoser
|
|
42
57
|
true
|
43
58
|
end
|
44
59
|
|
60
|
+
# output the results of a diagnostic run.
|
61
|
+
#
|
62
|
+
# == Parameters
|
63
|
+
#
|
64
|
+
# * +stdout+ - An IO stream to output the results to.
|
45
65
|
def output_results(stdout)
|
46
66
|
project_prefix = Dir.pwd + "/"
|
47
67
|
minimify = lambda { |f| f.gsub(project_prefix, '')}
|
data/lib/spork/forker.rb
CHANGED
@@ -1,4 +1,16 @@
|
|
1
|
+
# A helper class that allows you to run a block inside of a fork, and then get the result from that block.
|
2
|
+
#
|
3
|
+
# == Example:
|
4
|
+
#
|
5
|
+
# forker = Spork::Forker.new do
|
6
|
+
# sleep 3
|
7
|
+
# "success"
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# forker.result # => "success"
|
1
11
|
class Spork::Forker
|
12
|
+
|
13
|
+
# Raised if the fork died (was killed) before it sent it's response back.
|
2
14
|
class ForkDiedException < Exception; end
|
3
15
|
def initialize(&block)
|
4
16
|
return unless block_given?
|
@@ -20,6 +32,9 @@ class Spork::Forker
|
|
20
32
|
@child_io.close
|
21
33
|
end
|
22
34
|
|
35
|
+
# Wait for the fork to finish running, and then return its return value.
|
36
|
+
#
|
37
|
+
# If the fork was aborted, then result returns nil.
|
23
38
|
def result
|
24
39
|
return unless running?
|
25
40
|
result_thread = Thread.new do
|
@@ -36,6 +51,7 @@ class Spork::Forker
|
|
36
51
|
@result
|
37
52
|
end
|
38
53
|
|
54
|
+
# abort the current running fork
|
39
55
|
def abort
|
40
56
|
if running?
|
41
57
|
Process.kill(Signal.list['TERM'], @child_pid)
|
data/lib/spork/runner.rb
CHANGED
@@ -2,6 +2,7 @@ require 'optparse'
|
|
2
2
|
require 'spork/server'
|
3
3
|
|
4
4
|
module Spork
|
5
|
+
# This is used by bin/spork. It's wrapped in a class because it's easier to test that way.
|
5
6
|
class Runner
|
6
7
|
attr_reader :server
|
7
8
|
|
@@ -42,6 +43,7 @@ module Spork
|
|
42
43
|
text.string
|
43
44
|
end
|
44
45
|
|
46
|
+
# Returns a server for the specified (or the detected default) testing framework. Returns nil if none detected, or if the specified is not supported or available.
|
45
47
|
def find_server
|
46
48
|
if options[:server_matcher]
|
47
49
|
@server = Spork::Server.supported_servers(options[:server_matcher]).first
|
@@ -96,9 +98,6 @@ Are you running me from a project directory?
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
|
-
def diagnose
|
100
|
-
end
|
101
|
-
|
102
101
|
private
|
103
102
|
attr_reader :options
|
104
103
|
|
data/lib/spork/server.rb
CHANGED
@@ -4,7 +4,9 @@ require 'spork/forker.rb'
|
|
4
4
|
require 'spork/custom_io_streams.rb'
|
5
5
|
require 'spork/app_framework.rb'
|
6
6
|
|
7
|
-
#
|
7
|
+
# An abstract class that is implemented to create a server
|
8
|
+
#
|
9
|
+
# (This was originally based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate)
|
8
10
|
class Spork::Server
|
9
11
|
@@supported_servers = []
|
10
12
|
|
@@ -13,26 +15,27 @@ class Spork::Server
|
|
13
15
|
|
14
16
|
include Spork::CustomIOStreams
|
15
17
|
|
18
|
+
# Abstract method: returns the servers port. Override this to return the port that should be used by the test framework.
|
16
19
|
def self.port
|
17
20
|
raise NotImplemented
|
18
21
|
end
|
19
22
|
|
23
|
+
# Abstract method: returns the entry file that loads the testing environment, such as spec/spec_helper.rb.
|
20
24
|
def self.helper_file
|
21
25
|
raise NotImplemented
|
22
26
|
end
|
23
27
|
|
28
|
+
# Convenience method that turns the class name without the namespace
|
24
29
|
def self.server_name
|
25
30
|
self.name.gsub('Spork::Server::', '')
|
26
31
|
end
|
27
32
|
|
28
|
-
|
29
|
-
@@supported_servers << subclass
|
30
|
-
end
|
31
|
-
|
33
|
+
# Returns a list of all testing servers that have detected their testing framework being used in the project.
|
32
34
|
def self.available_servers
|
33
35
|
supported_servers.select { |s| s.available? }
|
34
36
|
end
|
35
37
|
|
38
|
+
# Returns a list of all servers that have been implemented (it keeps track of them automatically via Class.inherited)
|
36
39
|
def self.supported_servers(starting_with = nil)
|
37
40
|
@@supported_servers.sort! { |a,b| a.load_preference_index <=> b.load_preference_index }
|
38
41
|
return @@supported_servers if starting_with.nil?
|
@@ -41,18 +44,22 @@ class Spork::Server
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
47
|
+
# Returns true if the testing frameworks helper file exists. Override if this is not sufficient to detect your testing framework.
|
44
48
|
def self.available?
|
45
49
|
File.exist?(helper_file)
|
46
50
|
end
|
47
51
|
|
52
|
+
# Used to specify
|
48
53
|
def self.load_preference_index
|
49
54
|
LOAD_PREFERENCE.index(server_name) || LOAD_PREFERENCE.length
|
50
55
|
end
|
51
56
|
|
57
|
+
# Detects if the test helper has been bootstrapped.
|
52
58
|
def self.bootstrapped?
|
53
59
|
File.read(helper_file).include?("Spork.prefork")
|
54
60
|
end
|
55
61
|
|
62
|
+
# Bootstraps the current test helper file by prepending a Spork.prefork and Spork.each_run block at the beginning.
|
56
63
|
def self.bootstrap
|
57
64
|
if bootstrapped?
|
58
65
|
stderr.puts "Already bootstrapped!"
|
@@ -75,6 +82,7 @@ class Spork::Server
|
|
75
82
|
new.listen
|
76
83
|
end
|
77
84
|
|
85
|
+
# Sets up signals and starts the DRb service. If it's successful, it doesn't return. Not ever. You don't need to override this.
|
78
86
|
def listen
|
79
87
|
trap("SIGINT") { sig_int_received }
|
80
88
|
trap("SIGTERM") { abort; exit!(0) }
|
@@ -93,6 +101,14 @@ class Spork::Server
|
|
93
101
|
self.class.helper_file
|
94
102
|
end
|
95
103
|
|
104
|
+
# This is the public facing method that is served up by DRb. To use it from the client side (in a testing framework):
|
105
|
+
#
|
106
|
+
# DRb.start_service("druby://localhost:0") # this allows Ruby to do some magical stuff so you can pass an output stream over DRb.
|
107
|
+
# # see http://redmine.ruby-lang.org/issues/show/496 to see why localhost:0 is used.
|
108
|
+
# spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
|
109
|
+
# spec_server.run(options.argv, $stderr, $stdout)
|
110
|
+
#
|
111
|
+
# When implementing a test server, don't override this method: override run_tests instead.
|
96
112
|
def run(argv, stderr, stdout)
|
97
113
|
abort if running?
|
98
114
|
|
@@ -104,11 +120,22 @@ class Spork::Server
|
|
104
120
|
@child.result
|
105
121
|
end
|
106
122
|
|
123
|
+
# returns whether or not the child (a test run) is running right now.
|
107
124
|
def running?
|
108
125
|
@child && @child.running?
|
109
126
|
end
|
110
127
|
|
128
|
+
protected
|
129
|
+
# Abstract method: here is where the server runs the tests.
|
130
|
+
def run_tests(argv, input, output)
|
131
|
+
raise NotImplemented
|
132
|
+
end
|
133
|
+
|
111
134
|
private
|
135
|
+
def self.inherited(subclass)
|
136
|
+
@@supported_servers << subclass
|
137
|
+
end
|
138
|
+
|
112
139
|
def self.framework
|
113
140
|
@framework ||= Spork::AppFramework.detect_framework
|
114
141
|
end
|
@@ -143,10 +170,6 @@ class Spork::Server
|
|
143
170
|
true
|
144
171
|
end
|
145
172
|
|
146
|
-
def run_tests(argv, input, output)
|
147
|
-
raise NotImplemented
|
148
|
-
end
|
149
|
-
|
150
173
|
def restart
|
151
174
|
stderr.puts "restarting"
|
152
175
|
stderr.flush
|
data/spec/spork/forker_spec.rb
CHANGED
@@ -1,36 +1,44 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
3
|
describe Spork::Forker do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
describe ".new" do
|
5
|
+
it "runs a block in a fork" do
|
6
|
+
$var = "hello world"
|
7
|
+
Spork::Forker.new { $var = "booyah" }.result
|
8
|
+
$var.should == "hello world"
|
9
|
+
end
|
8
10
|
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
describe "#result" do
|
13
|
+
it "returns the result" do
|
14
|
+
Spork::Forker.new { "results" }.result.should == "results"
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
describe "#running?" do
|
19
|
+
it "reports when the fork is running" do
|
20
|
+
forker = Spork::Forker.new { sleep 0.1 }
|
21
|
+
forker.running?.should == true
|
22
|
+
forker.result
|
23
|
+
sleep 0.1
|
24
|
+
forker.running?.should == false
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
describe "#abort" do
|
29
|
+
it "aborts a fork and returns nil for the result" do
|
30
|
+
started_at = Time.now
|
31
|
+
ended_at = nil
|
32
|
+
forker = Spork::Forker.new { sleep 5 }
|
33
|
+
Thread.new do
|
34
|
+
forker.result.should == nil
|
35
|
+
ended_at = Time.now
|
36
|
+
end
|
37
|
+
sleep 0.5
|
38
|
+
forker.abort
|
39
|
+
sleep 0.1
|
40
|
+
(ended_at - started_at).should be_close(0.5, 0.1)
|
41
|
+
forker.running?.should == false
|
29
42
|
end
|
30
|
-
sleep 0.5
|
31
|
-
forker.abort
|
32
|
-
sleep 0.1
|
33
|
-
(ended_at - started_at).should be_close(0.5, 0.1)
|
34
|
-
forker.running?.should == false
|
35
43
|
end
|
36
44
|
end
|
data/spec/spork/server_spec.rb
CHANGED
@@ -96,12 +96,12 @@ describe Spork::Server do
|
|
96
96
|
File.read(FakeServer.helper_file).should include(File.read(FakeServer::BOOTSTRAP_FILE))
|
97
97
|
end
|
98
98
|
|
99
|
-
it "
|
99
|
+
it "aborts the current running thread when another run is started" do
|
100
100
|
create_helper_file
|
101
101
|
@fake.wait_time = 0.25
|
102
|
-
first_run = Thread.new { @fake.run("test", STDOUT, STDIN).should ==
|
102
|
+
first_run = Thread.new { @fake.run("test", STDOUT, STDIN).should == nil }
|
103
103
|
sleep(0.05)
|
104
|
-
@fake.run("test", STDOUT, STDIN).should ==
|
104
|
+
@fake.run("test", STDOUT, STDIN).should == true
|
105
105
|
|
106
106
|
# wait for the first to finish
|
107
107
|
first_run.join
|
data/spec/spork_spec.rb
CHANGED
@@ -57,6 +57,87 @@ describe Spork do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
it "expands a caller line, preserving the line number" do
|
60
|
-
Spork.expanded_caller
|
60
|
+
Spork.send(:expanded_caller, "/boo/../yah.rb:31").should == "/yah.rb:31"
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#trap_method" do
|
64
|
+
before(:each) do
|
65
|
+
Spork.using_spork!
|
66
|
+
|
67
|
+
Object.class_eval do
|
68
|
+
class TrapTest
|
69
|
+
def self.output
|
70
|
+
@output ||= []
|
71
|
+
end
|
72
|
+
|
73
|
+
def hello
|
74
|
+
TrapTest.output << 'hello'
|
75
|
+
end
|
76
|
+
|
77
|
+
def goodbye
|
78
|
+
TrapTest.output << 'goodbye'
|
79
|
+
end
|
80
|
+
|
81
|
+
def say_something!
|
82
|
+
TrapTest.output << 'something'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@trap_test = TrapTest.new
|
87
|
+
end
|
88
|
+
|
89
|
+
after(:each) do
|
90
|
+
Object.send(:remove_const, :TrapTest)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "delays execution of a method until after Spork.exec_each_run is called" do
|
94
|
+
Spork.using_spork!
|
95
|
+
Spork.trap_method(TrapTest, :hello)
|
96
|
+
@trap_test.hello
|
97
|
+
@trap_test.goodbye
|
98
|
+
Spork.exec_each_run
|
99
|
+
TrapTest.output.should == ['goodbye', 'hello']
|
100
|
+
end
|
101
|
+
|
102
|
+
it "works with methods that have punctuation" do
|
103
|
+
Spork.trap_method(TrapTest, :say_something!)
|
104
|
+
@trap_test.say_something!
|
105
|
+
TrapTest.output.should == []
|
106
|
+
Spork.exec_each_run
|
107
|
+
TrapTest.output.should == ['something']
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#trap_class_method" do
|
112
|
+
before(:each) do
|
113
|
+
Object.class_eval do
|
114
|
+
class TrapTest
|
115
|
+
def self.output
|
116
|
+
@output ||= []
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.hello
|
120
|
+
output << 'hello'
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.goodbye
|
124
|
+
output << 'goodbye'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
after(:each) do
|
131
|
+
Object.send(:remove_const, :TrapTest)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "delays execution of a method until after Spork.exec_each_run is called" do
|
135
|
+
Spork.using_spork!
|
136
|
+
Spork.trap_class_method(TrapTest, :hello)
|
137
|
+
TrapTest.hello
|
138
|
+
TrapTest.goodbye
|
139
|
+
Spork.exec_each_run
|
140
|
+
TrapTest.output.should == ['goodbye', 'hello']
|
141
|
+
end
|
61
142
|
end
|
62
143
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spork
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Harper
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-17 00:00:00 -06:00
|
13
13
|
default_executable: spork
|
14
14
|
dependencies: []
|
15
15
|
|