spork 0.4.4 → 0.5.1
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/features/diagnostic_mode.feature +37 -0
- data/features/rails_integration.feature +81 -0
- data/features/steps/rails_steps.rb +7 -0
- data/features/steps/sandbox_steps.rb +78 -0
- data/features/support/env.rb +98 -0
- data/lib/spork.rb +54 -25
- data/lib/spork/app_framework.rb +46 -0
- data/lib/spork/app_framework/rails.rb +109 -0
- data/lib/spork/app_framework/rails_stub_files/application.rb +2 -0
- data/lib/spork/app_framework/rails_stub_files/application_controller.rb +2 -0
- data/lib/spork/app_framework/rails_stub_files/application_helper.rb +2 -0
- data/lib/spork/app_framework/unknown.rb +6 -0
- data/lib/spork/custom_io_streams.rb +23 -0
- data/lib/spork/diagnoser.rb +72 -0
- data/lib/spork/runner.rb +24 -9
- data/lib/spork/server.rb +37 -23
- data/spec/spec_helper.rb +95 -13
- data/spec/spork/app_framework/rails_spec.rb +24 -0
- data/spec/spork/app_framework_spec.rb +16 -0
- data/spec/spork/diagnoser_spec.rb +91 -0
- data/spec/spork/runner_spec.rb +2 -2
- data/spec/spork/server_spec.rb +8 -13
- data/spec/spork_spec.rb +18 -15
- metadata +21 -2
@@ -0,0 +1,109 @@
|
|
1
|
+
class Spork::AppFramework::Rails < Spork::AppFramework
|
2
|
+
|
3
|
+
# TODO - subclass this out to handle different versions of rails
|
4
|
+
class NinjaPatcher
|
5
|
+
def self.run
|
6
|
+
::Rails::Initializer.class_eval do
|
7
|
+
alias :load_environment_without_spork :load_environment unless method_defined?(:load_environment_without_spork)
|
8
|
+
def load_environment
|
9
|
+
result = load_environment_without_spork
|
10
|
+
Spork::AppFramework[:Rails].ninja_patcher.install_hooks
|
11
|
+
result
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.install_hooks
|
17
|
+
auto_reestablish_db_connection
|
18
|
+
delay_observer_loading
|
19
|
+
delay_app_preload
|
20
|
+
delay_application_controller_loading
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.delay_observer_loading
|
24
|
+
if ::Rails::Initializer.instance_methods.include?('load_observers')
|
25
|
+
Spork.trap_method(::Rails::Initializer, :load_observers)
|
26
|
+
end
|
27
|
+
if Object.const_defined?(:ActionController)
|
28
|
+
require "action_controller/dispatcher.rb"
|
29
|
+
Spork.trap_class_method(::ActionController::Dispatcher, :define_dispatcher_callbacks) if ActionController::Dispatcher.respond_to?(:define_dispatcher_callbacks)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.delay_app_preload
|
34
|
+
if ::Rails::Initializer.instance_methods.include?('load_application_classes')
|
35
|
+
Spork.trap_method(::Rails::Initializer, :load_application_classes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.delay_application_controller_loading
|
40
|
+
if application_controller_source = ["#{Dir.pwd}/app/controllers/application.rb", "#{Dir.pwd}/app/controllers/application_controller.rb"].find { |f| File.exist?(f) }
|
41
|
+
application_helper_source = "#{Dir.pwd}/app/helpers/application_helper.rb"
|
42
|
+
load_paths = (::ActiveSupport.const_defined?(:Dependencies) ? ::ActiveSupport::Dependencies : ::Dependencies).load_paths
|
43
|
+
load_paths.unshift(File.expand_path('rails_stub_files', File.dirname(__FILE__)))
|
44
|
+
Spork.each_run do
|
45
|
+
require application_controller_source
|
46
|
+
require application_helper_source if File.exist?(application_helper_source)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.auto_reestablish_db_connection
|
52
|
+
if Object.const_defined?(:ActiveRecord)
|
53
|
+
Spork.each_run do
|
54
|
+
ActiveRecord::Base.establish_connection
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def bootstrap_required?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
def preload(&block)
|
65
|
+
STDERR.puts "Preloading Rails environment"
|
66
|
+
STDERR.flush
|
67
|
+
ENV["RAILS_ENV"] ||= 'test'
|
68
|
+
preload_rails
|
69
|
+
require environment_file
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
|
73
|
+
def environment_file
|
74
|
+
@environment_file ||= File.expand_path("config/environment.rb", Dir.pwd)
|
75
|
+
end
|
76
|
+
|
77
|
+
def boot_file
|
78
|
+
@boot_file ||= File.join(File.dirname(environment_file), 'boot')
|
79
|
+
end
|
80
|
+
|
81
|
+
def environment_contents
|
82
|
+
@environment_contents ||= File.read(environment_file)
|
83
|
+
end
|
84
|
+
|
85
|
+
def vendor
|
86
|
+
@vendor ||= File.expand_path("vendor/rails", Dir.pwd)
|
87
|
+
end
|
88
|
+
|
89
|
+
def version
|
90
|
+
@version ||= (
|
91
|
+
if /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/.match(environment_contents)
|
92
|
+
$1
|
93
|
+
else
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def ninja_patcher
|
100
|
+
::Spork::AppFramework::Rails::NinjaPatcher
|
101
|
+
end
|
102
|
+
|
103
|
+
def preload_rails
|
104
|
+
Object.const_set(:RAILS_GEM_VERSION, version) if version
|
105
|
+
require boot_file
|
106
|
+
ninja_patcher.run
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Spork::CustomIOStreams
|
2
|
+
def self.included(klass)
|
3
|
+
klass.send(:extend, ::Spork::CustomIOStreams::ClassMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
def stderr
|
7
|
+
self.class.stderr
|
8
|
+
end
|
9
|
+
|
10
|
+
def stdout
|
11
|
+
self.class.stdout
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def stderr
|
16
|
+
$stderr
|
17
|
+
end
|
18
|
+
|
19
|
+
def stdout
|
20
|
+
$stdout
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Spork::Diagnoser
|
2
|
+
class << self
|
3
|
+
def loaded_files
|
4
|
+
@loaded_files ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def install_hook!(dir = Dir.pwd)
|
8
|
+
@dir = File.expand_path(Dir.pwd, dir)
|
9
|
+
|
10
|
+
Kernel.class_eval do
|
11
|
+
alias :require_without_diagnoser :require
|
12
|
+
alias :load_without_diagnoser :load
|
13
|
+
|
14
|
+
def require(string)
|
15
|
+
::Spork::Diagnoser.add_included_file(string, caller)
|
16
|
+
require_without_diagnoser(string)
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(string)
|
20
|
+
::Spork::Diagnoser.add_included_file(string, caller)
|
21
|
+
load_without_diagnoser(string)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_included_file(filename, callstack)
|
27
|
+
filename = expand_filename(filename)
|
28
|
+
return unless File.exist?(filename)
|
29
|
+
loaded_files[filename] = caller.select { |f| ! f.include?('lib/spork/diagnoser.rb')} if subdirectory?(filename)
|
30
|
+
end
|
31
|
+
|
32
|
+
def expand_filename(filename)
|
33
|
+
([Dir.pwd] + $:).each do |attempted_path|
|
34
|
+
attempted_filename = File.expand_path(filename, attempted_path)
|
35
|
+
return attempted_filename if File.file?(attempted_filename)
|
36
|
+
attempted_filename = attempted_filename + ".rb"
|
37
|
+
return attempted_filename if File.file?(attempted_filename)
|
38
|
+
end
|
39
|
+
filename
|
40
|
+
end
|
41
|
+
|
42
|
+
def subdirectory?(directory)
|
43
|
+
File.expand_path(directory, Dir.pwd).include?(@dir)
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove_hook!
|
47
|
+
return unless Kernel.private_instance_methods.include?('require_without_diagnoser')
|
48
|
+
Kernel.class_eval do
|
49
|
+
alias :require :require_without_diagnoser
|
50
|
+
alias :load :load_without_diagnoser
|
51
|
+
|
52
|
+
undef_method(:require_without_diagnoser)
|
53
|
+
undef_method(:load_without_diagnoser)
|
54
|
+
end
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def output_results(stdout)
|
59
|
+
project_prefix = Dir.pwd + "/"
|
60
|
+
minimify = lambda { |f| f.gsub(project_prefix, '')}
|
61
|
+
stdout.puts "- Spork Diagnosis -\n"
|
62
|
+
stdout.puts "-- Summary --"
|
63
|
+
stdout.puts loaded_files.keys.sort.map(&minimify)
|
64
|
+
stdout.puts "\n\n\n"
|
65
|
+
stdout.puts "-- Detail --"
|
66
|
+
loaded_files.keys.sort.each do |file|
|
67
|
+
stdout.puts "\n\n\n--- #{minimify.call(file)} ---\n"
|
68
|
+
stdout.puts loaded_files[file].map(&minimify)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/spork/runner.rb
CHANGED
@@ -19,6 +19,7 @@ module Spork
|
|
19
19
|
|
20
20
|
opt.separator "Options:"
|
21
21
|
opt.on("-b", "--bootstrap") {|ignore| @options[:bootstrap] = true }
|
22
|
+
opt.on("-d", "--diagnose") {|ignore| @options[:diagnose] = true }
|
22
23
|
opt.on("-h", "--help") {|ignore| @options[:help] = true }
|
23
24
|
non_option_args = args.select { |arg| ! args[0].match(/^-/) }
|
24
25
|
@options[:server_matcher] = non_option_args[0]
|
@@ -45,7 +46,7 @@ module Spork
|
|
45
46
|
if options[:server_matcher]
|
46
47
|
@server = Spork::Server.supported_servers(options[:server_matcher]).first
|
47
48
|
unless @server
|
48
|
-
@
|
49
|
+
@error.puts <<-ERROR
|
49
50
|
#{options[:server_matcher].inspect} didn't match a supported test framework.
|
50
51
|
|
51
52
|
#{supported_servers_text}
|
@@ -54,7 +55,7 @@ module Spork
|
|
54
55
|
end
|
55
56
|
|
56
57
|
unless @server.available?
|
57
|
-
@
|
58
|
+
@error.puts <<-USEFUL_ERROR
|
58
59
|
I can't find the helper file #{@server.helper_file} for the #{@server.server_name} testing framework.
|
59
60
|
Are you running me from the project directory?
|
60
61
|
USEFUL_ERROR
|
@@ -63,7 +64,7 @@ Are you running me from the project directory?
|
|
63
64
|
else
|
64
65
|
@server = Spork::Server.available_servers.first
|
65
66
|
if @server.nil?
|
66
|
-
@
|
67
|
+
@error.puts <<-USEFUL_ERROR
|
67
68
|
I can't find any testing frameworks to use.
|
68
69
|
Are you running me from a project directory?
|
69
70
|
USEFUL_ERROR
|
@@ -76,12 +77,26 @@ Are you running me from a project directory?
|
|
76
77
|
def run
|
77
78
|
return false unless find_server
|
78
79
|
ENV["DRB"] = 'true'
|
79
|
-
|
80
|
-
@
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
@error.puts "Using #{server.server_name}"
|
81
|
+
@error.flush
|
82
|
+
case
|
83
|
+
when options[:bootstrap]
|
84
|
+
server.bootstrap
|
85
|
+
when options[:diagnose]
|
86
|
+
require 'spork/diagnoser'
|
87
|
+
|
88
|
+
Spork::Diagnoser.install_hook!
|
89
|
+
server.preload
|
90
|
+
Spork::Diagnoser.output_results(@output)
|
91
|
+
return true
|
92
|
+
else
|
93
|
+
return(false) unless server.preload
|
94
|
+
server.run
|
95
|
+
return true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def diagnose
|
85
100
|
end
|
86
101
|
|
87
102
|
private
|
data/lib/spork/server.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'drb/drb'
|
2
2
|
require 'rbconfig'
|
3
3
|
require 'spork/forker.rb'
|
4
|
+
require 'spork/custom_io_streams.rb'
|
5
|
+
require 'spork/app_framework.rb'
|
4
6
|
|
5
7
|
# This is based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate
|
6
8
|
class Spork::Server
|
@@ -9,6 +11,8 @@ class Spork::Server
|
|
9
11
|
LOAD_PREFERENCE = ['RSpec', 'Cucumber']
|
10
12
|
BOOTSTRAP_FILE = File.dirname(__FILE__) + "/../../assets/bootstrap.rb"
|
11
13
|
|
14
|
+
include Spork::CustomIOStreams
|
15
|
+
|
12
16
|
def self.port
|
13
17
|
raise NotImplemented
|
14
18
|
end
|
@@ -45,20 +49,16 @@ class Spork::Server
|
|
45
49
|
LOAD_PREFERENCE.index(server_name) || LOAD_PREFERENCE.length
|
46
50
|
end
|
47
51
|
|
48
|
-
def self.using_rails?
|
49
|
-
File.exist?("config/environment.rb")
|
50
|
-
end
|
51
|
-
|
52
52
|
def self.bootstrapped?
|
53
53
|
File.read(helper_file).include?("Spork.prefork")
|
54
54
|
end
|
55
55
|
|
56
56
|
def self.bootstrap
|
57
57
|
if bootstrapped?
|
58
|
-
puts "Already bootstrapped!"
|
58
|
+
stderr.puts "Already bootstrapped!"
|
59
59
|
return
|
60
60
|
end
|
61
|
-
puts "Bootstrapping #{helper_file}."
|
61
|
+
stderr.puts "Bootstrapping #{helper_file}."
|
62
62
|
contents = File.read(helper_file)
|
63
63
|
bootstrap_code = File.read(BOOTSTRAP_FILE)
|
64
64
|
File.open(helper_file, "wb") do |f|
|
@@ -66,7 +66,7 @@ class Spork::Server
|
|
66
66
|
f.puts contents
|
67
67
|
end
|
68
68
|
|
69
|
-
puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
|
69
|
+
stderr.puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
|
70
70
|
true
|
71
71
|
end
|
72
72
|
|
@@ -80,7 +80,8 @@ class Spork::Server
|
|
80
80
|
trap("SIGTERM") { abort; exit!(0) }
|
81
81
|
trap("USR2") { abort; restart } if Signal.list.has_key?("USR2")
|
82
82
|
DRb.start_service("druby://127.0.0.1:#{port}", self)
|
83
|
-
puts "Spork is ready and listening on #{port}!"
|
83
|
+
stderr.puts "Spork is ready and listening on #{port}!"
|
84
|
+
stderr.flush
|
84
85
|
DRb.thread.join
|
85
86
|
end
|
86
87
|
|
@@ -94,9 +95,10 @@ class Spork::Server
|
|
94
95
|
|
95
96
|
def run(argv, stderr, stdout)
|
96
97
|
return false if running?
|
98
|
+
|
97
99
|
@child = ::Spork::Forker.new do
|
98
100
|
$stdout, $stderr = stdout, stderr
|
99
|
-
Spork.exec_each_run
|
101
|
+
Spork.exec_each_run { load helper_file }
|
100
102
|
run_tests(argv, stderr, stdout)
|
101
103
|
end
|
102
104
|
@child.result
|
@@ -107,20 +109,30 @@ class Spork::Server
|
|
107
109
|
end
|
108
110
|
|
109
111
|
private
|
112
|
+
def self.framework
|
113
|
+
@framework ||= Spork::AppFramework.detect_framework
|
114
|
+
end
|
115
|
+
|
110
116
|
def self.preload
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
puts "There's nothing I can really do for you. Bailing."
|
122
|
-
return false
|
117
|
+
Spork.exec_prefork do
|
118
|
+
unless bootstrapped?
|
119
|
+
stderr.puts "#{helper_file} has not been bootstrapped. Run spork --bootstrap to do so."
|
120
|
+
stderr.flush
|
121
|
+
|
122
|
+
if framework.bootstrap_required?
|
123
|
+
stderr.puts "I can't do anything for you by default for the framework your using: #{framework.short_name}.\nYou must bootstrap #{helper_file} to continue."
|
124
|
+
stderr.flush
|
125
|
+
return false
|
126
|
+
end
|
123
127
|
end
|
128
|
+
|
129
|
+
framework.preload do
|
130
|
+
if bootstrapped?
|
131
|
+
stderr.puts "Loading Spork.prefork block..."
|
132
|
+
stderr.flush
|
133
|
+
load(helper_file)
|
134
|
+
end
|
135
|
+
end
|
124
136
|
end
|
125
137
|
true
|
126
138
|
end
|
@@ -130,7 +142,8 @@ class Spork::Server
|
|
130
142
|
end
|
131
143
|
|
132
144
|
def restart
|
133
|
-
puts "restarting"
|
145
|
+
stderr.puts "restarting"
|
146
|
+
stderr.flush
|
134
147
|
config = ::Config::CONFIG
|
135
148
|
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
|
136
149
|
command_line = [ruby, $0, ARGV].flatten.join(' ')
|
@@ -144,7 +157,8 @@ class Spork::Server
|
|
144
157
|
def sig_int_received
|
145
158
|
if running?
|
146
159
|
abort
|
147
|
-
puts "Running tests stopped. Press CTRL-C again to stop the server."
|
160
|
+
stderr.puts "Running tests stopped. Press CTRL-C again to stop the server."
|
161
|
+
stderr.flush
|
148
162
|
else
|
149
163
|
exit!(0)
|
150
164
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,20 +1,102 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'spec'
|
3
3
|
|
4
|
-
$
|
5
|
-
$
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
require '
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
unless $spec_helper_loaded
|
5
|
+
$spec_helper_loaded = true
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
|
8
|
+
SPEC_TMP_DIR = File.expand_path('tmp', File.dirname(__FILE__))
|
9
|
+
|
10
|
+
require 'spork'
|
11
|
+
require 'spork/runner.rb'
|
12
|
+
require 'spork/server.rb'
|
13
|
+
require 'spork/diagnoser.rb'
|
14
|
+
require 'stringio'
|
15
|
+
require 'fileutils'
|
16
|
+
|
17
|
+
Spec::Runner.configure do |config|
|
18
|
+
config.before(:each) do
|
19
|
+
$test_stdout = StringIO.new
|
20
|
+
$test_stderr = StringIO.new
|
21
|
+
end
|
22
|
+
|
23
|
+
config.after(:each) do
|
24
|
+
FileUtils.rm_rf(SPEC_TMP_DIR) if File.directory?(SPEC_TMP_DIR)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_file(filename, contents)
|
29
|
+
FileUtils.mkdir_p(SPEC_TMP_DIR) unless File.directory?(SPEC_TMP_DIR)
|
30
|
+
|
31
|
+
in_current_dir do
|
32
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
33
|
+
File.open(filename, 'wb') { |f| f << contents }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def in_current_dir(&block)
|
38
|
+
Dir.chdir(current_dir, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_dir
|
42
|
+
@current_dir ||= SPEC_TMP_DIR
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
module Spec
|
48
|
+
module Matchers
|
49
|
+
class IncludeAStringLike
|
50
|
+
def initialize(substring_or_regex)
|
51
|
+
case substring_or_regex
|
52
|
+
when String
|
53
|
+
@regex = Regexp.new(Regexp.escape(substring_or_regex))
|
54
|
+
when Regexp
|
55
|
+
@regex = substring_or_regex
|
56
|
+
else
|
57
|
+
raise ArgumentError, "don't know what to do with the #{substring_or_regex.class} you provided"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def matches?(list_of_strings)
|
62
|
+
@list_of_strings = list_of_strings
|
63
|
+
@list_of_strings.any? { |s| s =~ @regex }
|
64
|
+
end
|
65
|
+
def failure_message
|
66
|
+
"#{@list_of_strings.inspect} expected to include a string like #{@regex.inspect}"
|
67
|
+
end
|
68
|
+
def negative_failure_message
|
69
|
+
"#{@list_of_strings.inspect} expected to not include a string like #{@regex.inspect}, but did"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def include_a_string_like(substring_or_regex)
|
74
|
+
IncludeAStringLike.new(substring_or_regex)
|
75
|
+
end
|
76
|
+
end
|
15
77
|
end
|
78
|
+
|
79
|
+
module Spork::TestIOStreams
|
80
|
+
def self.included(klass)
|
81
|
+
klass.send(:extend, ::Spork::TestIOStreams::ClassMethods)
|
82
|
+
end
|
83
|
+
|
84
|
+
def stderr
|
85
|
+
self.class.stderr
|
86
|
+
end
|
87
|
+
|
88
|
+
def stdout
|
89
|
+
self.class.stdout
|
90
|
+
end
|
91
|
+
|
92
|
+
module ClassMethods
|
93
|
+
def stderr
|
94
|
+
$test_stderr
|
95
|
+
end
|
16
96
|
|
17
|
-
|
18
|
-
|
97
|
+
def stdout
|
98
|
+
$test_stdout
|
99
|
+
end
|
100
|
+
end
|
19
101
|
end
|
20
102
|
end
|