spring 0.0.8 → 1.0.0

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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +113 -0
  4. data/Gemfile +1 -3
  5. data/README.md +129 -187
  6. data/bin/spring +27 -0
  7. data/lib/spring/application.rb +121 -20
  8. data/lib/spring/application_manager.rb +21 -13
  9. data/lib/spring/client/binstub.rb +45 -41
  10. data/lib/spring/client/help.rb +4 -1
  11. data/lib/spring/client/rails.rb +8 -3
  12. data/lib/spring/client/run.rb +33 -10
  13. data/lib/spring/client/status.rb +2 -2
  14. data/lib/spring/client.rb +3 -3
  15. data/lib/spring/commands/rails.rb +60 -0
  16. data/lib/spring/commands/rake.rb +34 -0
  17. data/lib/spring/commands.rb +12 -195
  18. data/lib/spring/configuration.rb +6 -2
  19. data/lib/spring/env.rb +27 -18
  20. data/lib/spring/errors.rb +1 -1
  21. data/lib/spring/json.rb +626 -0
  22. data/lib/spring/server.rb +60 -29
  23. data/lib/spring/version.rb +1 -1
  24. data/lib/spring/watcher/abstract.rb +11 -7
  25. data/lib/spring/watcher/listen.rb +8 -10
  26. data/lib/spring/watcher/polling.rb +1 -1
  27. data/lib/spring/watcher.rb +17 -11
  28. data/spring.gemspec +1 -0
  29. data/test/acceptance/app_test.rb +270 -73
  30. data/test/apps/.gitignore +3 -0
  31. data/test/unit/client/help_test.rb +2 -0
  32. data/test/unit/commands_test.rb +8 -49
  33. data/test/unit/watcher_test.rb +22 -2
  34. metadata +18 -151
  35. data/lib/spring/client/start.rb +0 -17
  36. data/test/apps/rails-3-2/.gitignore +0 -18
  37. data/test/apps/rails-3-2/Gemfile +0 -9
  38. data/test/apps/rails-3-2/README.rdoc +0 -261
  39. data/test/apps/rails-3-2/Rakefile +0 -7
  40. data/test/apps/rails-3-2/app/assets/images/rails.png +0 -0
  41. data/test/apps/rails-3-2/app/assets/javascripts/application.js +0 -15
  42. data/test/apps/rails-3-2/app/assets/javascripts/posts.js.coffee +0 -3
  43. data/test/apps/rails-3-2/app/assets/stylesheets/application.css +0 -13
  44. data/test/apps/rails-3-2/app/assets/stylesheets/posts.css.scss +0 -3
  45. data/test/apps/rails-3-2/app/assets/stylesheets/scaffolds.css.scss +0 -69
  46. data/test/apps/rails-3-2/app/controllers/application_controller.rb +0 -3
  47. data/test/apps/rails-3-2/app/controllers/posts_controller.rb +0 -83
  48. data/test/apps/rails-3-2/app/helpers/application_helper.rb +0 -2
  49. data/test/apps/rails-3-2/app/helpers/posts_helper.rb +0 -2
  50. data/test/apps/rails-3-2/app/mailers/.gitkeep +0 -0
  51. data/test/apps/rails-3-2/app/models/.gitkeep +0 -0
  52. data/test/apps/rails-3-2/app/models/post.rb +0 -3
  53. data/test/apps/rails-3-2/app/views/layouts/application.html.erb +0 -14
  54. data/test/apps/rails-3-2/app/views/posts/_form.html.erb +0 -21
  55. data/test/apps/rails-3-2/app/views/posts/edit.html.erb +0 -6
  56. data/test/apps/rails-3-2/app/views/posts/index.html.erb +0 -23
  57. data/test/apps/rails-3-2/app/views/posts/new.html.erb +0 -5
  58. data/test/apps/rails-3-2/app/views/posts/show.html.erb +0 -10
  59. data/test/apps/rails-3-2/config/application.rb +0 -62
  60. data/test/apps/rails-3-2/config/boot.rb +0 -6
  61. data/test/apps/rails-3-2/config/database.yml +0 -25
  62. data/test/apps/rails-3-2/config/environment.rb +0 -5
  63. data/test/apps/rails-3-2/config/environments/development.rb +0 -37
  64. data/test/apps/rails-3-2/config/environments/production.rb +0 -67
  65. data/test/apps/rails-3-2/config/environments/test.rb +0 -37
  66. data/test/apps/rails-3-2/config/initializers/backtrace_silencers.rb +0 -7
  67. data/test/apps/rails-3-2/config/initializers/inflections.rb +0 -15
  68. data/test/apps/rails-3-2/config/initializers/mime_types.rb +0 -5
  69. data/test/apps/rails-3-2/config/initializers/secret_token.rb +0 -7
  70. data/test/apps/rails-3-2/config/initializers/session_store.rb +0 -8
  71. data/test/apps/rails-3-2/config/initializers/wrap_parameters.rb +0 -14
  72. data/test/apps/rails-3-2/config/locales/en.yml +0 -5
  73. data/test/apps/rails-3-2/config/routes.rb +0 -60
  74. data/test/apps/rails-3-2/config/spring.rb +0 -7
  75. data/test/apps/rails-3-2/config.ru +0 -4
  76. data/test/apps/rails-3-2/db/migrate/20121109171227_create_posts.rb +0 -9
  77. data/test/apps/rails-3-2/db/schema.rb +0 -22
  78. data/test/apps/rails-3-2/db/seeds.rb +0 -7
  79. data/test/apps/rails-3-2/lib/assets/.gitkeep +0 -0
  80. data/test/apps/rails-3-2/lib/tasks/.gitkeep +0 -0
  81. data/test/apps/rails-3-2/log/.gitkeep +0 -0
  82. data/test/apps/rails-3-2/public/404.html +0 -26
  83. data/test/apps/rails-3-2/public/422.html +0 -26
  84. data/test/apps/rails-3-2/public/500.html +0 -25
  85. data/test/apps/rails-3-2/public/favicon.ico +0 -0
  86. data/test/apps/rails-3-2/public/index.html +0 -241
  87. data/test/apps/rails-3-2/public/robots.txt +0 -5
  88. data/test/apps/rails-3-2/script/rails +0 -6
  89. data/test/apps/rails-3-2/test/fixtures/.gitkeep +0 -0
  90. data/test/apps/rails-3-2/test/fixtures/posts.yml +0 -7
  91. data/test/apps/rails-3-2/test/functional/.gitkeep +0 -0
  92. data/test/apps/rails-3-2/test/functional/posts_controller_test.rb +0 -49
  93. data/test/apps/rails-3-2/test/integration/.gitkeep +0 -0
  94. data/test/apps/rails-3-2/test/performance/browsing_test.rb +0 -12
  95. data/test/apps/rails-3-2/test/test_helper.rb +0 -13
  96. data/test/apps/rails-3-2/test/unit/.gitkeep +0 -0
  97. data/test/apps/rails-3-2/test/unit/helpers/posts_helper_test.rb +0 -4
  98. data/test/apps/rails-3-2/test/unit/post_test.rb +0 -7
  99. data/test/apps/rails-3-2/vendor/assets/javascripts/.gitkeep +0 -0
  100. data/test/apps/rails-3-2/vendor/assets/stylesheets/.gitkeep +0 -0
  101. data/test/apps/rails-3-2/vendor/plugins/.gitkeep +0 -0
@@ -1,19 +1,34 @@
1
+ # encoding: utf-8
1
2
  require 'helper'
2
3
  require 'io/wait'
3
4
  require "timeout"
4
5
  require "spring/sid"
5
6
  require "spring/env"
6
- require "pty"
7
7
 
8
8
  class AppTest < ActiveSupport::TestCase
9
+ DEFAULT_SPEEDUP = 0.8
10
+ DEFAULT_TIMEOUT = ENV['CI'] ? 30 : 10
11
+
12
+ def rails_version
13
+ ENV['RAILS_VERSION'] || '~> 4.0.0'
14
+ end
15
+
16
+ def rails_3?
17
+ rails_version.split(" ").last =~ /^3/
18
+ end
19
+
9
20
  def app_root
10
- Pathname.new("#{TEST_ROOT}/apps/rails-3-2")
21
+ Pathname.new("#{TEST_ROOT}/apps/rails-#{rails_version.scan(/\d/)[0..1].join("-")}")
11
22
  end
12
23
 
13
24
  def gem_home
14
25
  app_root.join "vendor/gems/#{RUBY_VERSION}"
15
26
  end
16
27
 
28
+ def user_home
29
+ app_root.join "user_home"
30
+ end
31
+
17
32
  def spring
18
33
  gem_home.join "bin/spring"
19
34
  end
@@ -30,12 +45,27 @@ class AppTest < ActiveSupport::TestCase
30
45
  @stderr ||= IO.pipe
31
46
  end
32
47
 
48
+ def log_file
49
+ @log_file ||= File.open("/tmp/spring.log", "w+")
50
+ end
51
+
52
+ def env
53
+ @env ||= {
54
+ "GEM_HOME" => gem_home.to_s,
55
+ "GEM_PATH" => "",
56
+ "HOME" => user_home.to_s,
57
+ "RAILS_ENV" => nil,
58
+ "RACK_ENV" => nil,
59
+ "SPRING_LOG" => log_file.path
60
+ }
61
+ end
62
+
33
63
  def app_run(command, opts = {})
34
64
  start_time = Time.now
35
65
 
36
66
  Bundler.with_clean_env do
37
67
  Process.spawn(
38
- { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => "" },
68
+ env,
39
69
  command.to_s,
40
70
  out: stdout.last,
41
71
  err: stderr.last,
@@ -44,106 +74,173 @@ class AppTest < ActiveSupport::TestCase
44
74
  )
45
75
  end
46
76
 
47
- _, status = Timeout.timeout(opts.fetch(:timeout, 10)) { Process.wait2 }
77
+ _, status = Timeout.timeout(opts.fetch(:timeout, DEFAULT_TIMEOUT)) { Process.wait2 }
48
78
 
49
- stdout, stderr = read_streams
50
- puts dump_streams(command, stdout, stderr) if ENV["SPRING_DEBUG"]
79
+ if pid = spring_env.pid
80
+ @server_pid = pid
81
+ lines = `ps -A -o ppid= -o pid= | egrep '^\\s*#{@server_pid}'`.lines
82
+ @application_pids = lines.map { |l| l.split.last.to_i }
83
+ end
84
+
85
+ output = read_streams
86
+ puts dump_streams(command, output) if ENV["SPRING_DEBUG"]
51
87
 
52
88
  @times << (Time.now - start_time) if @times
53
89
 
54
- {
55
- status: status,
56
- stdout: stdout,
57
- stderr: stderr,
58
- }
90
+ output.merge(status: status, command: command)
59
91
  rescue Timeout::Error => e
60
- raise e, "Output:\n\n#{dump_streams(command, *read_streams)}"
92
+ raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
61
93
  end
62
94
 
63
95
  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
96
+ {
97
+ stdout: read_stream(stdout.first),
98
+ stderr: read_stream(stderr.first),
99
+ log: read_stream(log_file)
100
+ }
101
+ end
102
+
103
+ def read_stream(stream)
104
+ output = ""
105
+ while IO.select([stream], [], [], 0.5) && !stream.eof?
106
+ output << stream.readpartial(10240)
68
107
  end
108
+ output
69
109
  end
70
110
 
71
- def dump_streams(command, stdout, stderr)
111
+ def dump_streams(command, streams)
72
112
  output = "$ #{command}\n"
73
113
 
74
- unless stdout.chomp.empty?
75
- output << "--- stdout ---\n"
76
- output << "#{stdout.chomp}\n"
77
- end
78
-
79
- unless stderr.chomp.empty?
80
- output << "--- stderr ---\n"
81
- output << "#{stderr.chomp}\n"
114
+ streams.each do |name, stream|
115
+ unless stream.chomp.empty?
116
+ output << "--- #{name} ---\n"
117
+ output << "#{stream.chomp}\n"
118
+ end
82
119
  end
83
120
 
84
121
  output << "\n"
85
122
  output
86
123
  end
87
124
 
125
+ def alive?(pid)
126
+ Process.kill 0, pid
127
+ true
128
+ rescue Errno::ESRCH
129
+ false
130
+ end
131
+
88
132
  def await_reload
89
- sleep 0.4
133
+ raise "no pid" if @application_pids.nil? || @application_pids.empty?
134
+
135
+ Timeout.timeout(DEFAULT_TIMEOUT) do
136
+ sleep 0.1 while @application_pids.any? { |p| alive?(p) }
137
+ end
138
+ end
139
+
140
+ def debug(artifacts)
141
+ artifacts = artifacts.dup
142
+ artifacts.delete :status
143
+ dump_streams(artifacts.delete(:command), artifacts)
90
144
  end
91
145
 
92
146
  def assert_output(artifacts, expected)
93
147
  expected.each do |stream, output|
94
148
  assert artifacts[stream].include?(output),
95
- "expected #{stream} to include '#{output}', but it was:\n\n#{artifacts[stream]}"
149
+ "expected #{stream} to include '#{output}'.\n\n#{debug(artifacts)}"
96
150
  end
97
151
  end
98
152
 
99
153
  def assert_success(command, expected_output = nil)
100
- artifacts = app_run(command)
101
- assert artifacts[:status].success?, "expected successful exit status"
154
+ artifacts = app_run(*Array(command))
155
+ assert artifacts[:status].success?, "expected successful exit status\n\n#{debug(artifacts)}"
102
156
  assert_output artifacts, expected_output if expected_output
103
157
  end
104
158
 
105
159
  def assert_failure(command, expected_output = nil)
106
- artifacts = app_run(command)
107
- assert !artifacts[:status].success?, "expected unsuccessful exit status"
160
+ artifacts = app_run(*Array(command))
161
+ assert !artifacts[:status].success?, "expected unsuccessful exit status\n\n#{debug(artifacts)}"
108
162
  assert_output artifacts, expected_output if expected_output
109
163
  end
110
164
 
111
- def assert_speedup(ratio = 0.6)
112
- @times = []
113
- yield
114
- assert (@times.last / @times.first) < ratio, "#{@times.last} was not less than #{ratio} of #{@times.first}"
115
- @times = nil
165
+ def assert_speedup(ratio = DEFAULT_SPEEDUP)
166
+ if ENV['CI']
167
+ yield
168
+ else
169
+ @times = []
170
+ yield
171
+ assert (@times.last / @times.first) < ratio, "#{@times.last} was not less than #{ratio} of #{@times.first}"
172
+ @times = nil
173
+ end
116
174
  end
117
175
 
118
176
  def spring_test_command
119
- "#{spring} testunit #{@test}"
177
+ "#{spring} #{rails_3? ? 'testunit' : 'rake test'} #{@test}"
120
178
  end
121
179
 
122
- @@installed = false
180
+ def generate_app
181
+ Bundler.with_clean_env do
182
+ # Sporadic SSL errors keep causing test failures so there are anti-SSL workarounds here
123
183
 
124
- setup do
125
- @test = "#{app_root}/test/functional/posts_controller_test.rb"
126
- @test_contents = File.read(@test)
127
- @controller = "#{app_root}/app/controllers/posts_controller.rb"
128
- @controller_contents = File.read(@controller)
184
+ assert system("(gem list rails --installed --version '#{rails_version}' || " \
185
+ "gem install rails --clear-sources --source http://rubygems.org --version '#{rails_version}') > /dev/null")
186
+
187
+ # Have to shell out otherwise bundler prevents us finding the gem
188
+ version = `ruby -e 'puts Gem::Specification.find_by_name("rails", "#{rails_version}").version'`.chomp
189
+
190
+ assert system("rails _#{version}_ new #{app_root} --skip-bundle --skip-javascript --skip-sprockets > /dev/null")
129
191
 
130
- unless @@installed
131
192
  FileUtils.mkdir_p(gem_home)
132
- system "gem build spring.gemspec 2>/dev/null 1>/dev/null"
133
- app_run "gem install ../../../spring-#{Spring::VERSION}.gem"
134
- app_run "(gem list bundler | grep bundler) || gem install bundler #{'--pre' if RUBY_VERSION >= "2.0"}", timeout: nil
135
- app_run "bundle check || bundle update", timeout: nil
136
- app_run "bundle exec rake db:migrate db:test:clone"
137
- @@installed = true
193
+ FileUtils.mkdir_p(user_home)
194
+ FileUtils.rm_rf("#{app_root}/test/performance/")
195
+
196
+ if rails_3?
197
+ File.write(
198
+ "#{app_root}/Gemfile",
199
+ File.read("#{app_root}/Gemfile") + "gem 'spring-commands-testunit'\n"
200
+ )
201
+ end
202
+
203
+ File.write(
204
+ "#{app_root}/Gemfile",
205
+ File.read("#{app_root}/Gemfile").sub("https://rubygems.org", "http://rubygems.org")
206
+ )
207
+ end
208
+ end
209
+
210
+ def install
211
+ generate_app unless app_root.exist?
212
+
213
+ assert system("gem build spring.gemspec 2>/dev/null 1>/dev/null")
214
+
215
+ assert_success ["gem install ../../../spring-#{Spring::VERSION}.gem", timeout: nil]
216
+ assert_success ["(gem list bundler | grep bundler) || gem install bundler", timeout: nil]
217
+ assert_success ["bundle check || bundle update", timeout: nil]
218
+
219
+ unless File.exist?(@controller)
220
+ assert_success "bundle exec rails g scaffold post title:string"
138
221
  end
139
222
 
140
- FileUtils.rm_rf "#{app_root}/bin"
223
+ assert_success "bundle exec rake db:migrate db:test:clone"
224
+ @@installed = true
225
+ end
226
+
227
+ @@installed = false
228
+
229
+ setup do
230
+ @test = "#{app_root}/test/#{rails_3? ? 'functional' : 'controllers'}/posts_controller_test.rb"
231
+ @controller = "#{app_root}/app/controllers/posts_controller.rb"
232
+
233
+ install unless @@installed
234
+
235
+ @test_contents = File.read(@test)
236
+ @controller_contents = File.read(@controller)
141
237
  end
142
238
 
143
239
  teardown do
144
240
  app_run "#{spring} stop"
145
- File.write(@test, @test_contents)
241
+ File.write(@test, @test_contents)
146
242
  File.write(@controller, @controller_contents)
243
+ FileUtils.rm_f("#{app_root}/config/spring.rb")
147
244
  end
148
245
 
149
246
  test "basic" do
@@ -206,15 +303,13 @@ class AppTest < ActiveSupport::TestCase
206
303
  File.write(@test, @test_contents.sub("get :index", "Foo.omg"))
207
304
 
208
305
  await_reload
209
-
210
- assert_speedup do
211
- 2.times { assert_failure spring_test_command, stdout: "RuntimeError: omg" }
212
- end
306
+ assert_failure spring_test_command, stdout: "RuntimeError: omg"
213
307
  ensure
214
308
  File.write(application, application_contents)
215
309
  end
216
310
 
217
311
  test "app gets reloaded when preloaded files change (polling watcher)" do
312
+ env["RAILS_ENV"] = "test"
218
313
  assert_success "#{spring} rails runner 'puts Spring.watcher.class'", stdout: "Polling"
219
314
  assert_app_reloaded
220
315
  end
@@ -223,10 +318,15 @@ class AppTest < ActiveSupport::TestCase
223
318
  begin
224
319
  gemfile = app_root.join("Gemfile")
225
320
  gemfile_contents = gemfile.read
226
- File.write(gemfile, gemfile_contents.sub(%{# gem 'listen'}, %{gem 'listen'}))
227
- app_run "bundle install", timeout: nil
321
+ File.write(gemfile, gemfile_contents + "\ngem 'listen', '~> 1.0'")
322
+
323
+ File.write("#{app_root}/config/spring.rb", "Spring.watch_method = :listen")
228
324
 
325
+ assert_success ["bundle install", timeout: nil]
326
+
327
+ env["RAILS_ENV"] = "test"
229
328
  assert_success "#{spring} rails runner 'puts Spring.watcher.class'", stdout: "Listen"
329
+
230
330
  assert_app_reloaded
231
331
  ensure
232
332
  File.write(gemfile, gemfile_contents)
@@ -247,8 +347,6 @@ class AppTest < ActiveSupport::TestCase
247
347
  assert_failure spring_test_command
248
348
 
249
349
  File.write(application, application_contents)
250
- await_reload
251
-
252
350
  assert_success spring_test_command
253
351
  ensure
254
352
  File.write(application, application_contents)
@@ -264,32 +362,61 @@ class AppTest < ActiveSupport::TestCase
264
362
  end
265
363
 
266
364
  test "custom commands" do
365
+ File.write("#{app_root}/config/spring.rb", <<-CODE)
366
+ class CustomCommand
367
+ def call
368
+ puts "omg"
369
+ end
370
+ end
371
+
372
+ Spring.register_command "custom", CustomCommand.new
373
+ CODE
374
+
267
375
  assert_success "#{spring} custom", stdout: "omg"
268
376
  end
269
377
 
270
378
  test "binstubs" do
271
- app_run "#{spring} binstub rake"
272
- app_run "#{spring} binstub rails"
273
- assert_success "bin/spring help"
274
- assert_success "bin/rake -T", stdout: "rake db:migrate"
275
- assert_success "bin/rails runner 'puts %(omg)'", stdout: "omg"
379
+ begin
380
+ FileUtils.mv "#{app_root}/bin", "#{app_root}/bin~" if File.exist?("#{app_root}/bin")
381
+
382
+ app_run "#{spring} binstub rake"
383
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
384
+
385
+ app_run "#{spring} binstub rake rails"
386
+ assert_success "bin/rails runner 'puts %(omg)'", stdout: "omg"
387
+ assert_success "bin/rails server --help", stdout: "Usage: rails server"
388
+
389
+ FileUtils.rm ["#{app_root}/bin/rails", "#{app_root}/bin/rake"]
390
+
391
+ app_run "#{spring} binstub --all"
392
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
393
+ assert_success "bin/rails runner 'puts %(omg)'", stdout: "omg"
394
+ ensure
395
+ if File.exist?("#{app_root}/bin~")
396
+ FileUtils.rm_rf "#{app_root}/bin"
397
+ FileUtils.mv "#{app_root}/bin~", "#{app_root}/bin"
398
+ end
399
+ end
276
400
  end
277
401
 
278
402
  test "after fork callback" do
279
- begin
280
- config_path = "#{app_root}/config/spring.rb"
281
- config_contents = File.read(config_path)
403
+ File.write("#{app_root}/config/spring.rb", "Spring.after_fork { puts '!callback!' }")
404
+ assert_success "#{spring} rails runner 'puts 2'", stdout: "!callback!\n2"
405
+ end
282
406
 
283
- File.write(config_path, config_contents + "\nSpring.after_fork { puts '!callback!' }")
407
+ test "global config file evaluated" do
408
+ begin
409
+ File.write("#{user_home}/.spring.rb", "Spring.after_fork { puts '!callback!' }")
284
410
  assert_success "#{spring} rails runner 'puts 2'", stdout: "!callback!\n2"
285
411
  ensure
286
- File.write(config_path, config_contents)
412
+ FileUtils.rm_r("#{user_home}/.spring.rb")
287
413
  end
288
414
  end
289
415
 
290
416
  test "missing config/application.rb" do
291
417
  begin
292
418
  FileUtils.mv app_root.join("config/application.rb"), app_root.join("config/application.rb.bak")
419
+
293
420
  assert_failure "#{spring} rake -T", stderr: "unable to find your config/application.rb"
294
421
  ensure
295
422
  FileUtils.mv app_root.join("config/application.rb.bak"), app_root.join("config/application.rb")
@@ -307,8 +434,78 @@ class AppTest < ActiveSupport::TestCase
307
434
  end
308
435
 
309
436
  test "runner command sets Rails environment from command-line options" do
310
- # Not using "test" environment here to avoid false positives on Travis (where "test" is default)
311
- assert_success "#{spring} rails runner -e staging 'puts Rails.env'", stdout: "staging"
312
- assert_success "#{spring} rails runner --environment=staging 'puts Rails.env'", stdout: "staging"
437
+ assert_success "#{spring} rails runner -e production 'puts Rails.env'", stdout: "production"
438
+ assert_success "#{spring} rails runner --environment=production 'puts Rails.env'", stdout: "production"
439
+ end
440
+
441
+ test "forcing rails env via environment variable" do
442
+ env['RAILS_ENV'] = 'production'
443
+ assert_success "#{spring} rake -p 'Rails.env'", stdout: "production"
444
+ end
445
+
446
+ test "setting env vars with rake" do
447
+ begin
448
+ File.write("#{app_root}/lib/tasks/env.rake", <<-'CODE')
449
+ task :print_rails_env => :environment do
450
+ puts Rails.env
451
+ end
452
+
453
+ task :print_env do
454
+ ENV.each { |k, v| puts "#{k}=#{v}" }
455
+ end
456
+
457
+ task(:default).clear.enhance [:print_rails_env]
458
+ CODE
459
+
460
+ assert_success "#{spring} rake RAILS_ENV=test print_rails_env", stdout: "test"
461
+ assert_success "#{spring} rake FOO=bar print_env", stdout: "FOO=bar"
462
+ assert_success "#{spring} rake", stdout: "test"
463
+ ensure
464
+ FileUtils.rm_f("#{app_root}/lib/tasks/env.rake")
465
+ end
466
+ end
467
+
468
+ test "changing the Gemfile restarts the server" do
469
+ begin
470
+ gemfile = app_root.join("Gemfile")
471
+ gemfile_contents = gemfile.read
472
+
473
+ assert_success %(#{spring} rails runner 'require "sqlite3"')
474
+
475
+ File.write(gemfile, gemfile_contents.sub(%{gem 'sqlite3'}, %{# gem 'sqlite3'}))
476
+ app_run "bundle check"
477
+
478
+ await_reload
479
+ assert_failure %(#{spring} rails runner 'require "sqlite3"'), stderr: "sqlite3"
480
+ ensure
481
+ File.write(gemfile, gemfile_contents)
482
+ assert_success "bundle check"
483
+ end
484
+ end
485
+
486
+ test "changing the environment between runs" do
487
+ begin
488
+ application = "#{app_root}/config/application.rb"
489
+ application_contents = File.read(application)
490
+
491
+ File.write(application, "#{application_contents}\nENV['BAR'] = 'bar'")
492
+
493
+ env["OMG"] = "1"
494
+ env["FOO"] = "1"
495
+ env["RUBYOPT"] = "-rubygems"
496
+
497
+ assert_success %(#{spring} rails runner 'p ENV["OMG"]'), stdout: "1"
498
+ assert_success %(#{spring} rails runner 'p ENV["BAR"]'), stdout: "bar"
499
+ assert_success %(#{spring} rails runner 'p ENV.key?("BUNDLE_GEMFILE")'), stdout: "true"
500
+ assert_success %(#{spring} rails runner 'p ENV["RUBYOPT"]'), stdout: "bundler"
501
+
502
+ env["OMG"] = "2"
503
+ env.delete "FOO"
504
+
505
+ assert_success %(#{spring} rails runner 'p ENV["OMG"]'), stdout: "2"
506
+ assert_success %(#{spring} rails runner 'p ENV.key?("FOO")'), stdout: "false"
507
+ ensure
508
+ File.write(application, application_contents)
509
+ end
313
510
  end
314
511
  end
@@ -0,0 +1,3 @@
1
+ *
2
+ !template.rb
3
+ !.gitignore
@@ -41,6 +41,8 @@ class HelpTest < ActiveSupport::TestCase
41
41
 
42
42
  test "formatted_help generates expected output" do
43
43
  expected_output = <<-EOF
44
+ Version: #{Spring::VERSION}
45
+
44
46
  Usage: spring COMMAND [ARGS]
45
47
 
46
48
  Commands for spring itself:
@@ -2,55 +2,6 @@ require "helper"
2
2
  require "spring/commands"
3
3
 
4
4
  class CommandsTest < ActiveSupport::TestCase
5
- test "test command needs a test name" do
6
- begin
7
- real_stderr = $stderr
8
- $stderr = StringIO.new('')
9
-
10
- command = Spring::Commands::TestUnit.new
11
- command.call([])
12
-
13
- assert_equal "you need to specify what test to run: spring test TEST_NAME\n", $stderr.string
14
- ensure
15
- $stderr = real_stderr
16
- end
17
- end
18
-
19
- test 'children of Command have inheritable accessor named "preload"' do
20
- command1, command2 = 2.times.map { Class.new(Spring::Commands::Command) }
21
-
22
- command1.preloads << "foo"
23
- assert_equal ["foo"], command1.preloads
24
- assert_equal [], command2.preloads
25
-
26
- command2.preloads << "bar"
27
- assert_equal ["foo"], command1.preloads
28
- assert_equal ["bar"], command2.preloads
29
-
30
- command1.preloads = ["omg"]
31
- assert_equal ["omg"], command1.preloads
32
- assert_equal ["bar"], command2.preloads
33
-
34
- command3 = Class.new(command1)
35
- command3.preloads << "foo"
36
- assert_equal ["omg", "foo"], command3.preloads
37
- assert_equal ["omg"], command1.preloads
38
- end
39
-
40
- test "prints error message when preloaded file does not exist" do
41
- begin
42
- original_stderr = $stderr
43
- $stderr = StringIO.new('')
44
- my_command_class = Class.new(Spring::Commands::Command)
45
- my_command_class.preloads = %w(i_do_not_exist)
46
-
47
- my_command_class.new.setup
48
- assert_match /The #<Class:0x[0-9a-f]+> command tried to preload i_do_not_exist but could not find it./, $stderr.string
49
- ensure
50
- $stderr = original_stderr
51
- end
52
- end
53
-
54
5
  test 'console command sets rails environment from command-line option' do
55
6
  command = Spring::Commands::RailsConsole.new
56
7
  assert_equal 'test', command.env(['test'])
@@ -75,4 +26,12 @@ class CommandsTest < ActiveSupport::TestCase
75
26
  command = Spring::Commands::RailsRunner.new
76
27
  assert_nil command.env(['puts 1+1'])
77
28
  end
29
+
30
+ test "rake command has configurable environments" do
31
+ command = Spring::Commands::Rake.new
32
+ assert_nil command.env(["foo"])
33
+ assert_equal "test", command.env(["test"])
34
+ assert_equal "test", command.env(["test:models"])
35
+ assert_nil command.env(["test_foo"])
36
+ end
78
37
  end
@@ -3,7 +3,8 @@ require "tmpdir"
3
3
  require "fileutils"
4
4
  require "active_support/core_ext/numeric/time"
5
5
  require "spring/watcher"
6
- require "listen"
6
+ require "spring/watcher/polling"
7
+ require "spring/watcher/listen"
7
8
 
8
9
  module WatcherTests
9
10
  LATENCY = 0.001
@@ -41,6 +42,18 @@ module WatcherTests
41
42
  assert !watcher.stale?
42
43
  end
43
44
 
45
+ def test_starting_with_no_file
46
+ file = "#{@dir}/omg"
47
+ touch file, Time.now - 2.seconds
48
+
49
+ watcher.start
50
+ watcher.add file
51
+
52
+ assert_not_stale
53
+ touch file, Time.now
54
+ assert_stale
55
+ end
56
+
44
57
  def test_is_stale_when_a_watched_file_is_updated
45
58
  file = "#{@dir}/omg"
46
59
  touch file, Time.now - 2.seconds
@@ -114,12 +127,14 @@ module WatcherTests
114
127
  watcher.add file
115
128
  watcher.start
116
129
 
130
+ io = watcher.to_io
131
+
117
132
  Thread.new {
118
133
  sleep LATENCY * 3
119
134
  touch file, Time.now
120
135
  }
121
136
 
122
- assert IO.select([watcher], [], [], 1), "IO.select timed out before watcher was readable"
137
+ assert IO.select([io], [], [], 1), "IO.select timed out before watcher was readable"
123
138
  assert watcher.stale?
124
139
  end
125
140
 
@@ -134,6 +149,11 @@ module WatcherTests
134
149
  watcher.add "./foo"
135
150
  assert_equal ["#{dir}/foo"], watcher.files.to_a
136
151
  end
152
+
153
+ def test_add_non_existant_file
154
+ watcher.add './foobar'
155
+ assert watcher.files.empty?
156
+ end
137
157
  end
138
158
 
139
159
  class ListenWatcherTest < ActiveSupport::TestCase