spring 0.0.6 → 0.0.7

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.
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/class/attribute'
2
-
3
1
  module Spring
4
2
  @commands = {}
5
3
 
@@ -25,8 +23,19 @@ module Spring
25
23
 
26
24
  module Commands
27
25
  class Command
28
- class_attribute :preloads
29
- self.preloads = []
26
+ @preloads = []
27
+
28
+ def self.preloads
29
+ @preloads ||= superclass.preloads.dup
30
+ end
31
+
32
+ def self.preloads=(val)
33
+ @preloads = val
34
+ end
35
+
36
+ def preloads
37
+ self.class.preloads
38
+ end
30
39
 
31
40
  def setup
32
41
  preload_files
@@ -50,7 +59,7 @@ MESSAGE
50
59
  end
51
60
 
52
61
  class Test < Command
53
- self.preloads += %w(test_helper)
62
+ preloads << "test_helper"
54
63
 
55
64
  def env
56
65
  "test"
@@ -75,11 +84,15 @@ MESSAGE
75
84
  $stderr.puts "you need to specify what test to run: spring test TEST_NAME"
76
85
  end
77
86
  end
87
+
88
+ def description
89
+ "Execute a Test::Unit test."
90
+ end
78
91
  end
79
92
  Spring.register_command "test", Test.new
80
93
 
81
94
  class RSpec < Command
82
- self.preloads += %w(spec_helper)
95
+ preloads << "spec_helper"
83
96
 
84
97
  def env
85
98
  "test"
@@ -95,6 +108,10 @@ MESSAGE
95
108
  $0 = "rspec"
96
109
  ::RSpec::Core::Runner.run(args)
97
110
  end
111
+
112
+ def description
113
+ "Execute an RSpec spec."
114
+ end
98
115
  end
99
116
  Spring.register_command "rspec", RSpec.new
100
117
 
@@ -111,6 +128,10 @@ MESSAGE
111
128
  def call(args)
112
129
  ::Cucumber::Cli::Main.execute(args)
113
130
  end
131
+
132
+ def description
133
+ "Execute a Cucumber feature."
134
+ end
114
135
  end
115
136
  Spring.register_command "cucumber", Cucumber.new
116
137
 
@@ -124,19 +145,27 @@ MESSAGE
124
145
  ARGV.replace args
125
146
  ::Rake.application.run
126
147
  end
148
+
149
+ def description
150
+ "Run a rake task."
151
+ end
127
152
  end
128
153
  Spring.register_command "rake", Rake.new
129
154
 
130
155
 
131
156
  class Console < Command
132
- def call(args)
133
- # This cannot be preloaded as it messes up the IRB prompt on OS X
134
- # for unknown reasons. See discussion in issue #34.
157
+ def setup
135
158
  require "rails/commands/console"
159
+ end
136
160
 
161
+ def call(args)
137
162
  ARGV.replace args
138
163
  ::Rails::Console.start(::Rails.application)
139
164
  end
165
+
166
+ def description
167
+ "Start the Rails console."
168
+ end
140
169
  end
141
170
  Spring.register_command "console", Console.new, alias: "c"
142
171
 
@@ -150,6 +179,10 @@ MESSAGE
150
179
  ARGV.replace args
151
180
  require "rails/commands/generate"
152
181
  end
182
+
183
+ def description
184
+ "Trigger a Rails generator."
185
+ end
153
186
  end
154
187
  Spring.register_command "generate", Generate.new, alias: "g"
155
188
 
@@ -159,6 +192,10 @@ MESSAGE
159
192
  ARGV.replace args
160
193
  require "rails/commands/runner"
161
194
  end
195
+
196
+ def description
197
+ "Execute a command with the Rails runner."
198
+ end
162
199
  end
163
200
  Spring.register_command "runner", Runner.new, alias: "r"
164
201
  end
@@ -167,5 +204,4 @@ MESSAGE
167
204
  # needs to be at the end to allow modification of existing commands.
168
205
  config = File.expand_path("./config/spring.rb")
169
206
  require config if File.exist?(config)
170
-
171
207
  end
@@ -4,6 +4,14 @@ module Spring
4
4
  class << self
5
5
  attr_accessor :application_root
6
6
 
7
+ def after_fork_callbacks
8
+ @after_fork_callbacks ||= []
9
+ end
10
+
11
+ def after_fork(&block)
12
+ after_fork_callbacks << block
13
+ end
14
+
7
15
  def verify_environment!
8
16
  application_root_path
9
17
  end
data/lib/spring/env.rb CHANGED
@@ -25,7 +25,7 @@ module Spring
25
25
  end
26
26
 
27
27
  def socket_path
28
- tmp_path.join(SID.sid.to_s)
28
+ tmp_path.join("spring")
29
29
  end
30
30
 
31
31
  def socket_name
@@ -33,11 +33,14 @@ module Spring
33
33
  end
34
34
 
35
35
  def pidfile_path
36
- tmp_path.join("#{SID.sid}.pid")
36
+ tmp_path.join("spring.pid")
37
37
  end
38
38
 
39
39
  def pid
40
40
  pidfile_path.exist? ? pidfile_path.read.to_i : nil
41
+ rescue Errno::ENOENT
42
+ # This can happen if the pidfile is removed after we check it
43
+ # exists
41
44
  end
42
45
 
43
46
  def app_name
@@ -0,0 +1,65 @@
1
+ module Spring
2
+ # Yes, I know this reimplements a bunch of stuff in Active Support, but
3
+ # I don't want the spring client to depend on AS, in order to keep its
4
+ # load time down.
5
+ class ProcessTitleUpdater
6
+ SECOND = 1
7
+ MINUTE = 60
8
+ HOUR = 60*60
9
+
10
+ def self.run(&block)
11
+ updater = new(&block)
12
+
13
+ Thread.new {
14
+ $0 = updater.value
15
+ loop { $0 = updater.next }
16
+ }
17
+ end
18
+
19
+ attr_reader :block
20
+
21
+ def initialize(start = Time.now, &block)
22
+ @start = start
23
+ @block = block
24
+ end
25
+
26
+ def interval
27
+ distance = Time.now - @start
28
+
29
+ if distance < MINUTE
30
+ SECOND
31
+ elsif distance < HOUR
32
+ MINUTE
33
+ else
34
+ HOUR
35
+ end
36
+ end
37
+
38
+ def next
39
+ sleep interval
40
+ value
41
+ end
42
+
43
+ def value
44
+ block.call(distance_in_words)
45
+ end
46
+
47
+ def distance_in_words(now = Time.now)
48
+ distance = now - @start
49
+
50
+ if distance < MINUTE
51
+ pluralize(distance, "sec")
52
+ elsif distance < HOUR
53
+ pluralize(distance / MINUTE, "min")
54
+ else
55
+ pluralize(distance / HOUR, "hour")
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def pluralize(amount, unit)
62
+ "#{amount.to_i} #{amount.to_i == 1 ? unit : "#{unit}s"}"
63
+ end
64
+ end
65
+ end
data/lib/spring/server.rb CHANGED
@@ -2,6 +2,11 @@ require "socket"
2
2
 
3
3
  require "spring/env"
4
4
  require "spring/application_manager"
5
+ require "spring/process_title_updater"
6
+
7
+ # readline must be required before we setpgid, otherwise the require may hang,
8
+ # if readline has been built against libedit. See issue #70.
9
+ require "readline"
5
10
 
6
11
  module Spring
7
12
  class Server
@@ -18,14 +23,19 @@ module Spring
18
23
  end
19
24
 
20
25
  def boot
26
+ # Boot the server into the process group of the current session.
27
+ # This will cause it to be automatically killed once the session
28
+ # ends (i.e. when the user closes their terminal).
29
+ Process.setpgid(0, SID.pgid)
30
+
21
31
  # Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
22
32
  # will kill the server/application.
23
33
  IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
24
34
 
25
35
  set_exit_hook
26
36
  write_pidfile
27
-
28
- $0 = "spring server | #{env.app_name} | started #{Time.now}"
37
+ redirect_output
38
+ set_process_title
29
39
 
30
40
  server = UNIXServer.open(env.socket_name)
31
41
  loop { serve server.accept }
@@ -62,9 +72,30 @@ module Spring
62
72
  @pidfile.write("#{Process.pid}\n")
63
73
  @pidfile.fsync
64
74
  else
65
- STDERR.puts "#{file.path} is locked; it looks like a server is already running"
75
+ $stderr.puts "#{@pidfile.path} is locked; it looks like a server is already running"
66
76
  exit 1
67
77
  end
68
78
  end
79
+
80
+ # We can't leave STDOUT, STDERR as they as because then they will
81
+ # never get closed for the lifetime of the server. This means that
82
+ # piping, e.g. "spring rake -T | grep db" won't work correctly
83
+ # because grep will hang while waiting for its stdin to reach EOF.
84
+ #
85
+ # However we do want server output to go to the terminal in case
86
+ # there are exceptions etc, so we just open the current terminal
87
+ # device directly.
88
+ def redirect_output
89
+ # ruby doesn't expose ttyname()
90
+ file = open(STDIN.tty? ? `tty`.chomp : "/dev/null", "a")
91
+ STDOUT.reopen(file)
92
+ STDERR.reopen(file)
93
+ end
94
+
95
+ def set_process_title
96
+ ProcessTitleUpdater.run { |distance|
97
+ "spring server | #{env.app_name} | started #{distance} ago"
98
+ }
99
+ end
69
100
  end
70
101
  end
data/lib/spring/sid.rb CHANGED
@@ -1,15 +1,38 @@
1
- require 'fiddle'
1
+ begin
2
+ # If rubygems is present, keep it out of the way when loading fiddle,
3
+ # otherwise if fiddle is not installed then rubygems will load all
4
+ # gemspecs in its (futile) search for fiddle, which is slow.
5
+ if respond_to?(:gem_original_require, true)
6
+ gem_original_require 'fiddle'
7
+ else
8
+ require 'fiddle'
9
+ end
10
+ rescue LoadError
11
+ end
2
12
 
3
13
  module Spring
4
14
  module SID
5
- FUNC = Fiddle::Function.new(
6
- DL::Handle::DEFAULT['getsid'],
7
- [Fiddle::TYPE_INT],
8
- Fiddle::TYPE_INT
9
- )
15
+ def self.fiddle_func
16
+ @fiddle_func ||= Fiddle::Function.new(
17
+ DL::Handle::DEFAULT['getsid'],
18
+ [Fiddle::TYPE_INT],
19
+ Fiddle::TYPE_INT
20
+ )
21
+ end
10
22
 
11
- def self.sid(pid = 0)
12
- FUNC.call(pid)
23
+ def self.sid
24
+ @sid ||= begin
25
+ if Process.respond_to?(:getsid)
26
+ # Ruby 2
27
+ Process.getsid
28
+ elsif defined?(Fiddle)
29
+ # Ruby 1.9.3 compiled with libffi support
30
+ fiddle_func.call(0)
31
+ else
32
+ # last resort: shell out
33
+ `ps -p #{Process.pid} -o sess=`.to_i
34
+ end
35
+ end
13
36
  end
14
37
 
15
38
  def self.pgid
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -3,26 +3,23 @@ require 'io/wait'
3
3
  require "timeout"
4
4
  require "spring/sid"
5
5
  require "spring/env"
6
+ require "pty"
6
7
 
7
8
  class AppTest < ActiveSupport::TestCase
8
9
  def app_root
9
10
  Pathname.new("#{TEST_ROOT}/apps/rails-3-2")
10
11
  end
11
12
 
12
- def server_pidfile
13
- "#{app_root}/tmp/spring/#{Spring::SID.sid}.pid"
13
+ def gem_home
14
+ app_root.join "vendor/gems/#{RUBY_VERSION}"
14
15
  end
15
16
 
16
- def spring_env
17
- @spring_env ||= Spring::Env.new(app_root)
18
- end
19
-
20
- def server_pid
21
- spring_env.pid
17
+ def spring
18
+ gem_home.join "bin/spring"
22
19
  end
23
20
 
24
- def server_running?
25
- spring_env.server_running?
21
+ def spring_env
22
+ @spring_env ||= Spring::Env.new(app_root)
26
23
  end
27
24
 
28
25
  def stdout
@@ -38,90 +35,83 @@ class AppTest < ActiveSupport::TestCase
38
35
 
39
36
  Bundler.with_clean_env do
40
37
  Process.spawn(
41
- {
42
- "GEM_HOME" => "#{app_root}/vendor/gems",
43
- "GEM_PATH" => "",
44
- "PATH" => "#{app_root}/vendor/gems/bin:#{ENV["PATH"]}"
45
- },
46
- command,
38
+ { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => "" },
39
+ command.to_s,
47
40
  out: stdout.last,
48
41
  err: stderr.last,
42
+ in: :close,
49
43
  chdir: app_root.to_s,
50
44
  )
51
45
  end
52
46
 
53
47
  _, status = Timeout.timeout(opts.fetch(:timeout, 5)) { Process.wait2 }
54
48
 
55
- out, err = read_streams
49
+ stdout, stderr = read_streams
50
+ puts dump_streams(stdout, stderr) if ENV["SPRING_DEBUG"]
56
51
 
57
52
  @times << (Time.now - start_time) if @times
58
53
 
59
- print_streams(out, err) if ENV["SPRING_DEBUG"]
60
-
61
- [status, out, err]
62
- rescue Timeout::Error
63
- print_streams *read_streams
64
- raise
54
+ {
55
+ status: status,
56
+ stdout: stdout,
57
+ stderr: stderr,
58
+ }
59
+ rescue Timeout::Error => e
60
+ raise e, "Output:\n\n#{dump_streams(*read_streams)}"
65
61
  end
66
62
 
67
- def print_streams(out, err)
68
- puts "---"
69
- puts out
70
- puts "***"
71
- puts err
72
- puts "---"
63
+ def read_streams
64
+ [stdout, stderr].map(&:first).map do |stream|
65
+ output = ""
66
+ output << stream.readpartial(10240) while IO.select([stream], [], [], 0.1)
67
+ output
68
+ end
73
69
  end
74
70
 
75
- def read_streams
76
- [stdout, stderr].map(&:first).map { |s| s.ready? ? s.readpartial(10240) : "" }
71
+ def dump_streams(stdout, stderr)
72
+ output = "--- stdout ---\n"
73
+ output << "#{stdout.chomp}\n"
74
+ output << "--- stderr ---\n"
75
+ output << "#{stderr.chomp}\n"
76
+ output << "\n"
77
+ output
77
78
  end
78
79
 
79
80
  def await_reload
80
81
  sleep 0.4
81
82
  end
82
83
 
83
- def assert_successful_run(*args)
84
- status, _, _ = app_run(*args)
85
- assert status.success?, "The run should be successful but it wasn't"
86
- end
87
-
88
- def assert_unsuccessful_run(*args)
89
- status, _, _ = app_run(*args)
90
- assert !status.success?, "The run should not be successful but it was"
91
- end
92
-
93
- def assert_stdout(command, expected)
94
- _, stdout, _ = app_run(command)
95
- assert stdout.include?(expected), "expected '#{expected}' to be printed to stdout. But it wasn't, the stdout is:\n#{stdout}"
84
+ def assert_output(artifacts, expected)
85
+ expected.each do |stream, output|
86
+ assert artifacts[stream].include?(output),
87
+ "expected #{stream} to include '#{output}', but it was:\n\n#{artifacts[stream]}"
88
+ end
96
89
  end
97
90
 
98
- def assert_stderr(command, expected)
99
- _, _, stderr = app_run(command)
100
- assert stderr.include?(expected), "expected '#{expected}' to be printed to stderr. But it wasn't, the stderr is:\n#{stderr}"
91
+ def assert_success(command, expected_output = nil)
92
+ artifacts = app_run(command)
93
+ assert artifacts[:status].success?, "expected successful exit status"
94
+ assert_output artifacts, expected_output if expected_output
101
95
  end
102
96
 
103
- def assert_speedup(opts = {})
104
- ratio = opts.fetch(:ratio, 0.5)
105
- from = opts.fetch(:from, 0)
106
- first = @times[from]
107
- second = @times[from + 1]
108
-
109
- assert (second / first) < ratio, "#{second} was not less than #{ratio} of #{first}"
97
+ def assert_failure(command, expected_output = nil)
98
+ artifacts = app_run(command)
99
+ assert !artifacts[:status].success?, "expected unsuccessful exit status"
100
+ assert_output artifacts, expected_output if expected_output
110
101
  end
111
102
 
112
- def assert_server_running(*args)
113
- assert server_running?, "The server should be running but it isn't"
114
- end
115
-
116
- def assert_server_not_running(*args)
117
- assert !server_running?, "The server should not be running but it is"
103
+ def assert_speedup(ratio = 0.6)
104
+ @times = []
105
+ yield
106
+ assert (@times.last / @times.first) < ratio, "#{@times.last} was not less than #{ratio} of #{@times.first}"
107
+ @times = nil
118
108
  end
119
109
 
120
- def test_command
121
- "spring test #{@test}"
110
+ def spring_test_command
111
+ "#{spring} test #{@test}"
122
112
  end
123
113
 
124
- @@installed_spring = false
114
+ @@installed = false
125
115
 
126
116
  setup do
127
117
  @test = "#{app_root}/test/functional/posts_controller_test.rb"
@@ -129,59 +119,51 @@ class AppTest < ActiveSupport::TestCase
129
119
  @controller = "#{app_root}/app/controllers/posts_controller.rb"
130
120
  @controller_contents = File.read(@controller)
131
121
 
132
- @spring_env = Spring::Env.new(app_root)
133
-
134
- unless @@installed_spring
122
+ unless @@installed
123
+ FileUtils.mkdir_p(gem_home)
135
124
  system "gem build spring.gemspec 2>/dev/null 1>/dev/null"
136
- app_run "gem install ../../../spring-*.gem"
137
- @@installed_spring = true
125
+ app_run "gem install ../../../spring-#{Spring::VERSION}.gem"
126
+ app_run "(gem list bundler | grep bundler) || gem install bundler #{'--pre' if RUBY_VERSION >= "2.0"}", timeout: nil
127
+ app_run "bundle check || bundle update", timeout: nil
128
+ app_run "bundle exec rake db:migrate db:test:clone"
129
+ @@installed = true
138
130
  end
139
131
 
140
132
  FileUtils.rm_rf "#{app_root}/bin"
141
- app_run "(gem list bundler | grep bundler) || gem install bundler", timeout: nil
142
- app_run "bundle check || bundle update", timeout: nil
143
- app_run "bundle exec rake db:migrate"
144
-
145
- @times = []
146
133
  end
147
134
 
148
135
  teardown do
149
- if pid = server_pid
150
- Process.kill('TERM', pid)
151
- end
152
-
136
+ app_run "#{spring} stop"
153
137
  File.write(@test, @test_contents)
154
138
  File.write(@controller, @controller_contents)
155
139
  end
156
140
 
157
141
  test "basic" do
158
- assert_successful_run test_command
159
- assert File.exist?(server_pidfile)
160
-
161
- assert_successful_run test_command
162
- assert_speedup
142
+ assert_speedup do
143
+ 2.times { app_run spring_test_command }
144
+ end
163
145
  end
164
146
 
165
147
  test "help message when called without arguments" do
166
- assert_stdout "spring", 'Usage: spring COMMAND [ARGS]'
148
+ assert_success spring, stdout: 'Usage: spring COMMAND [ARGS]'
167
149
  end
168
150
 
169
151
  test "test changes are picked up" do
170
- assert_successful_run test_command
171
-
172
- File.write(@test, @test_contents.sub("get :index", "raise 'omg'"))
173
- assert_stdout test_command, "RuntimeError: omg"
152
+ assert_speedup do
153
+ assert_success spring_test_command, stdout: "0 failures"
174
154
 
175
- assert_speedup
155
+ File.write(@test, @test_contents.sub("get :index", "raise 'omg'"))
156
+ assert_failure spring_test_command, stdout: "RuntimeError: omg"
157
+ end
176
158
  end
177
159
 
178
160
  test "code changes are picked up" do
179
- assert_successful_run test_command
161
+ assert_speedup do
162
+ assert_success spring_test_command, stdout: "0 failures"
180
163
 
181
- File.write(@controller, @controller_contents.sub("@posts = Post.all", "raise 'omg'"))
182
- assert_stdout test_command, "RuntimeError: omg"
183
-
184
- assert_speedup
164
+ File.write(@controller, @controller_contents.sub("@posts = Post.all", "raise 'omg'"))
165
+ assert_failure spring_test_command, stdout: "RuntimeError: omg"
166
+ end
185
167
  end
186
168
 
187
169
  test "code changes in pre-referenced app files are picked up" do
@@ -189,12 +171,12 @@ class AppTest < ActiveSupport::TestCase
189
171
  initializer = "#{app_root}/config/initializers/load_posts_controller.rb"
190
172
  File.write(initializer, "PostsController\n")
191
173
 
192
- assert_successful_run test_command
193
-
194
- File.write(@controller, @controller_contents.sub("@posts = Post.all", "raise 'omg'"))
195
- assert_stdout test_command, "RuntimeError: omg"
174
+ assert_speedup do
175
+ assert_success spring_test_command, stdout: "0 failures"
196
176
 
197
- assert_speedup
177
+ File.write(@controller, @controller_contents.sub("@posts = Post.all", "raise 'omg'"))
178
+ assert_failure spring_test_command, stdout: "RuntimeError: omg"
179
+ end
198
180
  ensure
199
181
  FileUtils.rm_f(initializer)
200
182
  end
@@ -205,7 +187,7 @@ class AppTest < ActiveSupport::TestCase
205
187
  application = "#{app_root}/config/application.rb"
206
188
  application_contents = File.read(application)
207
189
 
208
- assert_successful_run test_command
190
+ assert_success spring_test_command
209
191
 
210
192
  File.write(application, application_contents + <<-CODE)
211
193
  class Foo
@@ -218,10 +200,9 @@ class AppTest < ActiveSupport::TestCase
218
200
 
219
201
  await_reload
220
202
 
221
- assert_stdout test_command, "RuntimeError: omg"
222
- assert_stdout test_command, "RuntimeError: omg"
223
-
224
- assert_speedup from: 1
203
+ assert_speedup do
204
+ 2.times { assert_failure spring_test_command, stdout: "RuntimeError: omg" }
205
+ end
225
206
  ensure
226
207
  File.write(application, application_contents)
227
208
  end
@@ -232,50 +213,72 @@ class AppTest < ActiveSupport::TestCase
232
213
  application = "#{app_root}/config/application.rb"
233
214
  application_contents = File.read(application)
234
215
 
235
- assert_successful_run test_command
216
+ assert_success spring_test_command
236
217
 
237
218
  File.write(application, application_contents + "\nomg")
238
219
  await_reload
239
220
 
240
- assert_unsuccessful_run test_command
221
+ assert_failure spring_test_command
241
222
 
242
223
  File.write(application, application_contents)
243
224
  await_reload
244
225
 
245
- assert_successful_run test_command
226
+ assert_success spring_test_command
246
227
  ensure
247
228
  File.write(application, application_contents)
248
229
  end
249
230
  end
250
231
 
251
232
  test "stop command kills server" do
252
- assert_successful_run test_command
253
- assert_server_running
233
+ app_run spring_test_command
234
+ assert spring_env.server_running?, "The server should be running but it isn't"
254
235
 
255
- assert_successful_run 'spring stop'
256
- assert_server_not_running
236
+ assert_success "#{spring} stop"
237
+ assert !spring_env.server_running?, "The server should not be running but it is"
257
238
  end
258
239
 
259
240
  test "custom commands" do
260
- assert_stdout "spring custom", "omg"
241
+ assert_success "#{spring} custom", stdout: "omg"
261
242
  end
262
243
 
263
244
  test "runner alias" do
264
- assert_stdout "spring r 'puts 1'", "1"
245
+ assert_success "#{spring} r 'puts 1'", stdout: "1"
265
246
  end
266
247
 
267
248
  test "binstubs" do
268
- app_run "spring binstub rake"
269
- assert_successful_run "bin/spring help"
270
- assert_stdout "bin/rake -T", "rake db:migrate"
249
+ app_run "#{spring} binstub rake"
250
+ assert_success "bin/spring help"
251
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
252
+ end
253
+
254
+ test "after fork callback" do
255
+ begin
256
+ config_path = "#{app_root}/config/spring.rb"
257
+ config_contents = File.read(config_path)
258
+
259
+ File.write(config_path, config_contents + "\nSpring.after_fork { puts '!callback!' }")
260
+ assert_success "#{spring} r 'puts 2'", stdout: "!callback!\n2"
261
+ ensure
262
+ File.write(config_path, config_contents)
263
+ end
271
264
  end
272
265
 
273
266
  test "missing config/application.rb" do
274
267
  begin
275
268
  FileUtils.mv app_root.join("config/application.rb"), app_root.join("config/application.rb.bak")
276
- assert_stderr "spring rake -T", "unable to find your config/application.rb"
269
+ assert_failure "#{spring} rake -T", stderr: "unable to find your config/application.rb"
277
270
  ensure
278
271
  FileUtils.mv app_root.join("config/application.rb.bak"), app_root.join("config/application.rb")
279
272
  end
280
273
  end
274
+
275
+ test "piping" do
276
+ assert_success "#{spring} rake -T | grep db", stdout: "rake db:migrate"
277
+ end
278
+
279
+ test "status" do
280
+ assert_success "#{spring} status", stdout: "Spring is not running"
281
+ app_run "#{spring} runner ''"
282
+ assert_success "#{spring} status", stdout: "Spring is running"
283
+ end
281
284
  end