spork 0.9.0.rc8-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +10 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +134 -0
- data/assets/bootstrap.rb +47 -0
- data/bin/spork +20 -0
- data/features/at_exit_during_each_run.feature +36 -0
- data/features/cucumber_rails_integration.feature +107 -0
- data/features/diagnostic_mode.feature +41 -0
- data/features/gemfiles/rails3.0/Gemfile +14 -0
- data/features/gemfiles/rails3.0/Gemfile.lock +120 -0
- data/features/rails_delayed_loading_workarounds.feature +177 -0
- data/features/rspec_rails_integration.feature +92 -0
- data/features/spork_debugger.feature +108 -0
- data/features/steps/general_steps.rb +3 -0
- data/features/steps/rails_steps.rb +67 -0
- data/features/steps/sandbox_steps.rb +115 -0
- data/features/support/background_job.rb +63 -0
- data/features/support/bundler_helpers.rb +41 -0
- data/features/support/env.rb +105 -0
- data/features/unknown_app_framework.feature +42 -0
- data/lib/spork.rb +155 -0
- data/lib/spork/app_framework.rb +80 -0
- data/lib/spork/app_framework/padrino.rb +22 -0
- data/lib/spork/app_framework/rails.rb +82 -0
- data/lib/spork/app_framework/unknown.rb +6 -0
- data/lib/spork/custom_io_streams.rb +25 -0
- data/lib/spork/diagnoser.rb +105 -0
- data/lib/spork/ext/rails-reloader.rb +14 -0
- data/lib/spork/ext/ruby-debug.rb +150 -0
- data/lib/spork/forker.rb +71 -0
- data/lib/spork/gem_helpers.rb +38 -0
- data/lib/spork/run_strategy.rb +48 -0
- data/lib/spork/run_strategy/forking.rb +35 -0
- data/lib/spork/run_strategy/magazine.rb +151 -0
- data/lib/spork/run_strategy/magazine/magazine_slave.rb +30 -0
- data/lib/spork/run_strategy/magazine/magazine_slave_provider.rb +30 -0
- data/lib/spork/run_strategy/magazine/ring_server.rb +10 -0
- data/lib/spork/runner.rb +90 -0
- data/lib/spork/server.rb +77 -0
- data/lib/spork/test_framework.rb +167 -0
- data/lib/spork/test_framework/cucumber.rb +38 -0
- data/lib/spork/test_framework/rspec.rb +14 -0
- data/spec/spec_helper.rb +113 -0
- data/spec/spork/app_framework/rails_spec.rb +22 -0
- data/spec/spork/app_framework/unknown_spec.rb +12 -0
- data/spec/spork/app_framework_spec.rb +16 -0
- data/spec/spork/diagnoser_spec.rb +105 -0
- data/spec/spork/forker_spec.rb +44 -0
- data/spec/spork/run_strategy/forking_spec.rb +38 -0
- data/spec/spork/runner_spec.rb +50 -0
- data/spec/spork/server_spec.rb +15 -0
- data/spec/spork/test_framework/cucumber_spec.rb +11 -0
- data/spec/spork/test_framework/rspec_spec.rb +10 -0
- data/spec/spork/test_framework_shared_examples.rb +23 -0
- data/spec/spork/test_framework_spec.rb +90 -0
- data/spec/spork_spec.rb +153 -0
- data/spec/support/fake_framework.rb +15 -0
- data/spec/support/fake_run_strategy.rb +21 -0
- metadata +173 -0
data/lib/spork/server.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'spork/forker.rb'
|
4
|
+
require 'spork/custom_io_streams.rb'
|
5
|
+
require 'spork/app_framework.rb'
|
6
|
+
|
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)
|
10
|
+
class Spork::Server
|
11
|
+
attr_reader :run_strategy
|
12
|
+
include Spork::CustomIOStreams
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@run_strategy = options[:run_strategy]
|
16
|
+
@port = options[:port]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.run(options = {})
|
20
|
+
new(options).listen
|
21
|
+
end
|
22
|
+
|
23
|
+
# 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.
|
24
|
+
def listen
|
25
|
+
@run_strategy.assert_ready!
|
26
|
+
trap("SIGINT") { sig_int_received }
|
27
|
+
trap("SIGTERM") { abort; exit!(0) }
|
28
|
+
trap("USR2") { abort; restart } if Signal.list.has_key?("USR2")
|
29
|
+
@drb_service = DRb.start_service("druby://127.0.0.1:#{port}", self)
|
30
|
+
Spork.each_run { @drb_service.stop_service } if @run_strategy.class == Spork::RunStrategy::Forking
|
31
|
+
stderr.puts "Spork is ready and listening on #{port}!"
|
32
|
+
stderr.flush
|
33
|
+
DRb.thread.join
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_accessor :port
|
37
|
+
|
38
|
+
# This is the public facing method that is served up by DRb. To use it from the client side (in a testing framework):
|
39
|
+
#
|
40
|
+
# DRb.start_service("druby://localhost:0") # this allows Ruby to do some magical stuff so you can pass an output stream over DRb.
|
41
|
+
# # see http://redmine.ruby-lang.org/issues/show/496 to see why localhost:0 is used.
|
42
|
+
# spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
|
43
|
+
# spec_server.run(options.argv, $stderr, $stdout)
|
44
|
+
#
|
45
|
+
# When implementing a test server, don't override this method: override run_tests instead.
|
46
|
+
def run(argv, stderr, stdout)
|
47
|
+
puts "Running tests with args #{argv.inspect}..."
|
48
|
+
result = run_strategy.run(argv, stderr, stdout)
|
49
|
+
puts "Done.\n\n"
|
50
|
+
result
|
51
|
+
end
|
52
|
+
|
53
|
+
def abort
|
54
|
+
run_strategy.abort
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def restart
|
59
|
+
stderr.puts "restarting"
|
60
|
+
stderr.flush
|
61
|
+
config = ::Config::CONFIG
|
62
|
+
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
|
63
|
+
command_line = [ruby, $0, ARGV].flatten.join(' ')
|
64
|
+
exec(command_line)
|
65
|
+
end
|
66
|
+
|
67
|
+
def sig_int_received
|
68
|
+
stdout.puts "\n"
|
69
|
+
if run_strategy.running?
|
70
|
+
abort
|
71
|
+
stderr.puts "Running tests stopped. Press CTRL-C again to stop the server."
|
72
|
+
stderr.flush
|
73
|
+
else
|
74
|
+
exit!(0)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
class Spork::TestFramework
|
2
|
+
LOAD_PREFERENCE = ['RSpec', 'Cucumber']
|
3
|
+
BOOTSTRAP_FILE = File.dirname(__FILE__) + "/../../assets/bootstrap.rb"
|
4
|
+
|
5
|
+
@@supported_test_frameworks = []
|
6
|
+
attr_reader :stdout, :stderr
|
7
|
+
|
8
|
+
class FactoryException < Exception; end
|
9
|
+
|
10
|
+
class NoFrameworksAvailable < FactoryException
|
11
|
+
def message
|
12
|
+
"I can\'t find any testing frameworks to use. Are you running me from a project directory?"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class FrameworkNotAvailable < FactoryException
|
17
|
+
def initialize(framework)
|
18
|
+
@framework = framework
|
19
|
+
end
|
20
|
+
|
21
|
+
def message
|
22
|
+
"I can\'t find the file #{@framework.helper_file} for the #{@framework.short_name} testing framework.\nAre you running me from the project directory?"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class NoFrameworkMatched < FactoryException
|
27
|
+
def initialize(beginning_with)
|
28
|
+
@beginning_with = beginning_with
|
29
|
+
end
|
30
|
+
|
31
|
+
def message
|
32
|
+
"Couldn\'t find a supported test framework that begins with '#{@beginning_with}'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(stdout = STDOUT, stderr = STDERR)
|
37
|
+
@stdout, @stderr = stdout, stderr
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.factory(output = STDOUT, error = STDERR, beginning_with = nil)
|
41
|
+
if beginning_with
|
42
|
+
@klass = supported_test_frameworks(beginning_with).first
|
43
|
+
raise(NoFrameworkMatched.new(beginning_with)) if @klass.nil?
|
44
|
+
raise(FrameworkNotAvailable.new(@klass)) unless @klass.available?
|
45
|
+
else
|
46
|
+
@klass = available_test_frameworks.first
|
47
|
+
raise(NoFrameworksAvailable.new) unless @klass
|
48
|
+
end
|
49
|
+
@klass.new(output, error)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.helper_file
|
53
|
+
self::HELPER_FILE
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.default_port
|
57
|
+
(ENV["#{short_name.upcase}_DRB"] || self::DEFAULT_PORT).to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.short_name
|
61
|
+
self.name.gsub('Spork::TestFramework::', '')
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns a list of all testing servers that have detected their testing framework being used in the project.
|
65
|
+
def self.available_test_frameworks
|
66
|
+
supported_test_frameworks.select { |s| s.available? }
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns a list of all servers that have been implemented (it keeps track of them automatically via Class.inherited)
|
70
|
+
def self.supported_test_frameworks(starting_with = nil)
|
71
|
+
@@supported_test_frameworks.sort! { |a,b| a.load_preference_index <=> b.load_preference_index }
|
72
|
+
return @@supported_test_frameworks if starting_with.nil?
|
73
|
+
@@supported_test_frameworks.select do |s|
|
74
|
+
s.short_name.match(/^#{Regexp.escape(starting_with)}/i)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def short_name
|
79
|
+
self.class.short_name
|
80
|
+
end
|
81
|
+
|
82
|
+
def helper_file
|
83
|
+
self.class.helper_file
|
84
|
+
end
|
85
|
+
|
86
|
+
# Detects if the test helper has been bootstrapped.
|
87
|
+
def bootstrapped?
|
88
|
+
File.read(helper_file).include?("Spork.prefork")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Bootstraps the current test helper file by prepending a Spork.prefork and Spork.each_run block at the beginning.
|
92
|
+
def bootstrap
|
93
|
+
if bootstrapped?
|
94
|
+
stderr.puts "Already bootstrapped!"
|
95
|
+
return
|
96
|
+
end
|
97
|
+
stderr.puts "Bootstrapping #{helper_file}."
|
98
|
+
contents = File.read(helper_file)
|
99
|
+
bootstrap_code = File.read(BOOTSTRAP_FILE)
|
100
|
+
File.open(helper_file, "wb") do |f|
|
101
|
+
f.puts bootstrap_code
|
102
|
+
f.puts contents
|
103
|
+
end
|
104
|
+
|
105
|
+
stderr.puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns true if the testing frameworks helper file exists. Override if this is not sufficient to detect your testing framework.
|
110
|
+
def self.available?
|
111
|
+
File.exist?(helper_file)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Used to specify
|
115
|
+
def self.load_preference_index
|
116
|
+
LOAD_PREFERENCE.index(short_name) || LOAD_PREFERENCE.length
|
117
|
+
end
|
118
|
+
|
119
|
+
def preload
|
120
|
+
Spork.exec_prefork do
|
121
|
+
if not bootstrapped?
|
122
|
+
stderr.puts "#{helper_file} has not been bootstrapped. Run spork --bootstrap to do so."
|
123
|
+
stderr.flush
|
124
|
+
|
125
|
+
if framework.bootstrap_required?
|
126
|
+
stderr.puts "I can't do anything for you by default for the framework you're using: #{framework.short_name}.\nYou must bootstrap #{helper_file} to continue."
|
127
|
+
stderr.flush
|
128
|
+
return false
|
129
|
+
else
|
130
|
+
load(framework.entry_point)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
framework.preload do
|
135
|
+
if bootstrapped?
|
136
|
+
stderr.puts "Loading Spork.prefork block..."
|
137
|
+
stderr.flush
|
138
|
+
load(helper_file)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
def run_tests(argv, stderr, stdout)
|
146
|
+
raise NotImplementedError
|
147
|
+
end
|
148
|
+
|
149
|
+
def entry_point
|
150
|
+
bootstrapped? ? helper_file : framework.entry_point
|
151
|
+
end
|
152
|
+
|
153
|
+
def default_port
|
154
|
+
self.class.default_port
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
def self.inherited(subclass)
|
159
|
+
@@supported_test_frameworks << subclass
|
160
|
+
end
|
161
|
+
|
162
|
+
def framework
|
163
|
+
@framework ||= Spork::AppFramework.detect_framework
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
Spork.detect_and_require('spork/test_framework/*.rb')
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Spork::TestFramework::Cucumber < Spork::TestFramework
|
2
|
+
DEFAULT_PORT = 8990
|
3
|
+
HELPER_FILE = File.join(Dir.pwd, "features/support/env.rb")
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# REMOVE WHEN SUPPORT FOR 0.3.95 AND EARLIER IS DROPPED
|
7
|
+
attr_accessor :mother_object
|
8
|
+
end
|
9
|
+
|
10
|
+
def preload
|
11
|
+
require 'cucumber'
|
12
|
+
if ::Cucumber::VERSION >= '0.9.0'
|
13
|
+
# nothing to do nowadays
|
14
|
+
else
|
15
|
+
preload_legacy_cucumbers
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_tests(argv, stderr, stdout)
|
21
|
+
if ::Cucumber::VERSION >= '0.9.0'
|
22
|
+
::Cucumber::Cli::Main.new(argv, stdout, stderr).execute!
|
23
|
+
else
|
24
|
+
::Cucumber::Cli::Main.new(argv, stdout, stderr).execute!(@step_mother)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def preload_legacy_cucumbers
|
31
|
+
begin
|
32
|
+
@step_mother = ::Cucumber::Runtime.new
|
33
|
+
@step_mother.load_programming_language('rb')
|
34
|
+
rescue NoMethodError => pre_cucumber_0_4 # REMOVE WHEN SUPPORT FOR PRE-0.4 IS DROPPED
|
35
|
+
@step_mother = Spork::Server::Cucumber.mother_object
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Spork::TestFramework::RSpec < Spork::TestFramework
|
2
|
+
DEFAULT_PORT = 8989
|
3
|
+
HELPER_FILE = File.join(Dir.pwd, "spec/spec_helper.rb")
|
4
|
+
|
5
|
+
def run_tests(argv, stderr, stdout)
|
6
|
+
::Spec::Runner::CommandLine.run(
|
7
|
+
::Spec::Runner::OptionParser.parse(
|
8
|
+
argv,
|
9
|
+
stderr,
|
10
|
+
stdout
|
11
|
+
)
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
unless $spec_helper_loaded
|
4
|
+
$spec_helper_loaded = true
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
|
7
|
+
SPEC_TMP_DIR = File.expand_path('tmp', File.dirname(__FILE__))
|
8
|
+
require 'spork'
|
9
|
+
require 'stringio'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'rspec'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.before(:each) do
|
15
|
+
$test_stdout = StringIO.new
|
16
|
+
$test_stderr = StringIO.new
|
17
|
+
@current_dir = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
config.after(:each) do
|
21
|
+
FileUtils.rm_rf(SPEC_TMP_DIR) if File.directory?(SPEC_TMP_DIR)
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_file(filename, contents)
|
26
|
+
FileUtils.mkdir_p(SPEC_TMP_DIR) unless File.directory?(SPEC_TMP_DIR)
|
27
|
+
|
28
|
+
in_current_dir do
|
29
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
30
|
+
File.open(filename, 'wb') { |f| f << contents }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_helper_file(test_framework = FakeFramework)
|
35
|
+
create_file(test_framework.helper_file, "# stub spec helper file")
|
36
|
+
end
|
37
|
+
|
38
|
+
def in_current_dir(&block)
|
39
|
+
Dir.chdir(current_dir, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def current_dir
|
43
|
+
@current_dir ||= SPEC_TMP_DIR
|
44
|
+
end
|
45
|
+
|
46
|
+
def change_current_dir(sub_path)
|
47
|
+
@current_dir = File.expand_path(sub_path, SPEC_TMP_DIR)
|
48
|
+
end
|
49
|
+
|
50
|
+
def windows?
|
51
|
+
ENV['OS'] == 'Windows_NT'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
module RSpec
|
57
|
+
module Matchers
|
58
|
+
class IncludeAStringLike
|
59
|
+
def initialize(substring_or_regex)
|
60
|
+
case substring_or_regex
|
61
|
+
when String
|
62
|
+
@regex = Regexp.new(Regexp.escape(substring_or_regex))
|
63
|
+
when Regexp
|
64
|
+
@regex = substring_or_regex
|
65
|
+
else
|
66
|
+
raise ArgumentError, "don't know what to do with the #{substring_or_regex.class} you provided"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def matches?(list_of_strings)
|
71
|
+
@list_of_strings = list_of_strings
|
72
|
+
@list_of_strings.any? { |s| s =~ @regex }
|
73
|
+
end
|
74
|
+
def failure_message
|
75
|
+
"#{@list_of_strings.inspect} expected to include a string like #{@regex.inspect}"
|
76
|
+
end
|
77
|
+
def negative_failure_message
|
78
|
+
"#{@list_of_strings.inspect} expected to not include a string like #{@regex.inspect}, but did"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def include_a_string_like(substring_or_regex)
|
83
|
+
IncludeAStringLike.new(substring_or_regex)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module Spork::TestIOStreams
|
89
|
+
def self.included(klass)
|
90
|
+
klass.send(:extend, ::Spork::TestIOStreams::ClassMethods)
|
91
|
+
end
|
92
|
+
|
93
|
+
def stderr
|
94
|
+
self.class.stderr
|
95
|
+
end
|
96
|
+
|
97
|
+
def stdout
|
98
|
+
self.class.stdout
|
99
|
+
end
|
100
|
+
|
101
|
+
module ClassMethods
|
102
|
+
def stderr
|
103
|
+
$test_stderr
|
104
|
+
end
|
105
|
+
|
106
|
+
def stdout
|
107
|
+
$test_stdout
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
Dir.glob(File.dirname(__FILE__) + "/support/*.rb").each { |f| require(f) }
|
113
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Spork::AppFramework::Rails do
|
4
|
+
describe ".deprecated_version" do
|
5
|
+
it "detects the current version of rails" do
|
6
|
+
create_file("config/environment.rb", "RAILS_GEM_VERSION = '2.1.0'")
|
7
|
+
in_current_dir do
|
8
|
+
Spork::AppFramework::Rails.new.deprecated_version.should == "2.1.0"
|
9
|
+
end
|
10
|
+
|
11
|
+
create_file("config/environment.rb", 'RAILS_GEM_VERSION = "2.1.0"')
|
12
|
+
in_current_dir do
|
13
|
+
Spork::AppFramework::Rails.new.deprecated_version.should == "2.1.0"
|
14
|
+
end
|
15
|
+
|
16
|
+
create_file("config/environment.rb", 'RAILS_GEM_VERSION = "> 2.1.0"')
|
17
|
+
in_current_dir do
|
18
|
+
Spork::AppFramework::Rails.new.deprecated_version.should == "> 2.1.0"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Spork::AppFramework::Unknown do
|
4
|
+
it "requires bootstrapping" do
|
5
|
+
Spork::AppFramework::Unknown.new.bootstrap_required?.should == true
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has no known entry point" do
|
9
|
+
Spork::AppFramework::Unknown.new.entry_point.should be_nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|