spring 0.0.10 → 0.0.11

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 (91) hide show
  1. data/.travis.yml +3 -0
  2. data/CHANGELOG.md +13 -2
  3. data/Gemfile +1 -1
  4. data/README.md +16 -11
  5. data/lib/spring/application.rb +97 -20
  6. data/lib/spring/application_manager.rb +16 -9
  7. data/lib/spring/client.rb +1 -1
  8. data/lib/spring/client/binstub.rb +1 -1
  9. data/lib/spring/client/rails.rb +8 -3
  10. data/lib/spring/client/run.rb +23 -6
  11. data/lib/spring/client/status.rb +2 -2
  12. data/lib/spring/commands.rb +3 -0
  13. data/lib/spring/commands/rails.rb +7 -0
  14. data/lib/spring/configuration.rb +1 -1
  15. data/lib/spring/env.rb +8 -2
  16. data/lib/spring/errors.rb +15 -1
  17. data/lib/spring/server.rb +27 -14
  18. data/lib/spring/version.rb +1 -1
  19. data/lib/spring/watcher.rb +1 -0
  20. data/lib/spring/watcher/abstract.rb +9 -7
  21. data/lib/spring/watcher/polling.rb +1 -1
  22. data/test/acceptance/app_test.rb +168 -86
  23. data/test/apps/.gitignore +3 -0
  24. data/test/unit/watcher_test.rb +12 -0
  25. metadata +4 -134
  26. data/test/apps/rails-3-2/.gitignore +0 -18
  27. data/test/apps/rails-3-2/Gemfile +0 -7
  28. data/test/apps/rails-3-2/README.rdoc +0 -261
  29. data/test/apps/rails-3-2/Rakefile +0 -7
  30. data/test/apps/rails-3-2/app/assets/images/rails.png +0 -0
  31. data/test/apps/rails-3-2/app/assets/javascripts/application.js +0 -15
  32. data/test/apps/rails-3-2/app/assets/javascripts/posts.js.coffee +0 -3
  33. data/test/apps/rails-3-2/app/assets/stylesheets/application.css +0 -13
  34. data/test/apps/rails-3-2/app/assets/stylesheets/posts.css.scss +0 -3
  35. data/test/apps/rails-3-2/app/assets/stylesheets/scaffolds.css.scss +0 -69
  36. data/test/apps/rails-3-2/app/controllers/application_controller.rb +0 -3
  37. data/test/apps/rails-3-2/app/controllers/posts_controller.rb +0 -83
  38. data/test/apps/rails-3-2/app/helpers/application_helper.rb +0 -2
  39. data/test/apps/rails-3-2/app/helpers/posts_helper.rb +0 -2
  40. data/test/apps/rails-3-2/app/mailers/.gitkeep +0 -0
  41. data/test/apps/rails-3-2/app/models/.gitkeep +0 -0
  42. data/test/apps/rails-3-2/app/models/post.rb +0 -3
  43. data/test/apps/rails-3-2/app/views/layouts/application.html.erb +0 -14
  44. data/test/apps/rails-3-2/app/views/posts/_form.html.erb +0 -21
  45. data/test/apps/rails-3-2/app/views/posts/edit.html.erb +0 -6
  46. data/test/apps/rails-3-2/app/views/posts/index.html.erb +0 -23
  47. data/test/apps/rails-3-2/app/views/posts/new.html.erb +0 -5
  48. data/test/apps/rails-3-2/app/views/posts/show.html.erb +0 -10
  49. data/test/apps/rails-3-2/config.ru +0 -4
  50. data/test/apps/rails-3-2/config/application.rb +0 -62
  51. data/test/apps/rails-3-2/config/boot.rb +0 -6
  52. data/test/apps/rails-3-2/config/database.yml +0 -25
  53. data/test/apps/rails-3-2/config/environment.rb +0 -5
  54. data/test/apps/rails-3-2/config/environments/development.rb +0 -37
  55. data/test/apps/rails-3-2/config/environments/production.rb +0 -67
  56. data/test/apps/rails-3-2/config/environments/test.rb +0 -37
  57. data/test/apps/rails-3-2/config/initializers/backtrace_silencers.rb +0 -7
  58. data/test/apps/rails-3-2/config/initializers/inflections.rb +0 -15
  59. data/test/apps/rails-3-2/config/initializers/mime_types.rb +0 -5
  60. data/test/apps/rails-3-2/config/initializers/secret_token.rb +0 -7
  61. data/test/apps/rails-3-2/config/initializers/session_store.rb +0 -8
  62. data/test/apps/rails-3-2/config/initializers/wrap_parameters.rb +0 -14
  63. data/test/apps/rails-3-2/config/locales/en.yml +0 -5
  64. data/test/apps/rails-3-2/config/routes.rb +0 -60
  65. data/test/apps/rails-3-2/config/spring.rb +0 -7
  66. data/test/apps/rails-3-2/db/migrate/20121109171227_create_posts.rb +0 -9
  67. data/test/apps/rails-3-2/db/schema.rb +0 -22
  68. data/test/apps/rails-3-2/db/seeds.rb +0 -7
  69. data/test/apps/rails-3-2/lib/assets/.gitkeep +0 -0
  70. data/test/apps/rails-3-2/lib/tasks/.gitkeep +0 -0
  71. data/test/apps/rails-3-2/log/.gitkeep +0 -0
  72. data/test/apps/rails-3-2/public/404.html +0 -26
  73. data/test/apps/rails-3-2/public/422.html +0 -26
  74. data/test/apps/rails-3-2/public/500.html +0 -25
  75. data/test/apps/rails-3-2/public/favicon.ico +0 -0
  76. data/test/apps/rails-3-2/public/index.html +0 -241
  77. data/test/apps/rails-3-2/public/robots.txt +0 -5
  78. data/test/apps/rails-3-2/script/rails +0 -6
  79. data/test/apps/rails-3-2/spec/dummy_spec.rb +0 -5
  80. data/test/apps/rails-3-2/test/fixtures/.gitkeep +0 -0
  81. data/test/apps/rails-3-2/test/fixtures/posts.yml +0 -7
  82. data/test/apps/rails-3-2/test/functional/.gitkeep +0 -0
  83. data/test/apps/rails-3-2/test/functional/posts_controller_test.rb +0 -49
  84. data/test/apps/rails-3-2/test/integration/.gitkeep +0 -0
  85. data/test/apps/rails-3-2/test/test_helper.rb +0 -13
  86. data/test/apps/rails-3-2/test/unit/.gitkeep +0 -0
  87. data/test/apps/rails-3-2/test/unit/helpers/posts_helper_test.rb +0 -4
  88. data/test/apps/rails-3-2/test/unit/post_test.rb +0 -7
  89. data/test/apps/rails-3-2/vendor/assets/javascripts/.gitkeep +0 -0
  90. data/test/apps/rails-3-2/vendor/assets/stylesheets/.gitkeep +0 -0
  91. data/test/apps/rails-3-2/vendor/plugins/.gitkeep +0 -0
@@ -21,8 +21,8 @@ module Spring
21
21
  end
22
22
 
23
23
  def application_pids
24
- candidates = `ps -a -o ppid= -o pid=`.lines
25
- candidates.select { |l| l =~ /^#{env.pid} / }
24
+ candidates = `ps -A -o ppid= -o pid=`.lines
25
+ candidates.select { |l| l =~ /^(\s+)?#{env.pid} / }
26
26
  .map { |l| l.split(" ").last }
27
27
  end
28
28
  end
@@ -31,6 +31,9 @@ module Spring
31
31
 
32
32
  # Load custom commands, if any.
33
33
  # needs to be at the end to allow modification of existing commands.
34
+ config = File.expand_path("~/.spring.rb")
35
+ require config if File.exist?(config)
36
+
34
37
  config = File.expand_path("./config/spring.rb")
35
38
  require config if File.exist?(config)
36
39
  end
@@ -28,6 +28,12 @@ module Spring
28
28
  end
29
29
  end
30
30
 
31
+ class RailsDestroy < Rails
32
+ def command_name
33
+ "destroy"
34
+ end
35
+ end
36
+
31
37
  class RailsRunner < Rails
32
38
  def env(tail)
33
39
  previous_option = nil
@@ -48,6 +54,7 @@ module Spring
48
54
 
49
55
  Spring.register_command "rails_console", RailsConsole.new
50
56
  Spring.register_command "rails_generate", RailsGenerate.new
57
+ Spring.register_command "rails_destroy", RailsDestroy.new
51
58
  Spring.register_command "rails_runner", RailsRunner.new
52
59
  end
53
60
  end
@@ -16,7 +16,7 @@ module Spring
16
16
  after_fork_callbacks << block
17
17
  end
18
18
 
19
- def verify_environment!
19
+ def verify_environment
20
20
  application_root_path
21
21
  end
22
22
 
@@ -8,10 +8,11 @@ module Spring
8
8
  IGNORE_SIGNALS = %w(INT QUIT)
9
9
 
10
10
  class Env
11
- attr_reader :root
11
+ attr_reader :root, :log_file
12
12
 
13
13
  def initialize(root = nil)
14
- @root = root || Pathname.new(File.expand_path('.'))
14
+ @root = root || Pathname.new(File.expand_path('.'))
15
+ @log_file = File.open(ENV["SPRING_LOG"] || "/dev/null", "a")
15
16
  end
16
17
 
17
18
  def version
@@ -63,6 +64,11 @@ module Spring
63
64
  [Bundler.default_lockfile, Bundler.default_gemfile].select(&:exist?).map(&:mtime).max
64
65
  end
65
66
 
67
+ def log(message)
68
+ log_file.puts "[#{Time.now}] #{message}"
69
+ log_file.flush
70
+ end
71
+
66
72
  private
67
73
 
68
74
  def default_tmp_path
@@ -1,7 +1,7 @@
1
1
  module Spring
2
2
  class ClientError < StandardError; end
3
3
 
4
- class UnknownProject < ClientError
4
+ class UnknownProject < StandardError
5
5
  attr_reader :current_dir
6
6
 
7
7
  def initialize(current_dir)
@@ -15,6 +15,20 @@ module Spring
15
15
  end
16
16
  end
17
17
 
18
+ class TmpUnwritable < StandardError
19
+ attr_reader :tmp_path
20
+
21
+ def initialize(tmp_path)
22
+ @tmp_path = tmp_path
23
+ end
24
+
25
+ def message
26
+ "Spring is unable to create a socket file at #{tmp_path}. You may need to " \
27
+ "set the SPRING_TMP_PATH environment variable to use a different path. See " \
28
+ "the documentation for details."
29
+ end
30
+ end
31
+
18
32
  class MissingApplication < ClientError
19
33
  attr_reader :project_root
20
34
 
@@ -1,6 +1,7 @@
1
1
  require "socket"
2
2
  require "thread"
3
3
 
4
+ require "spring/configuration"
4
5
  require "spring/env"
5
6
  require "spring/application_manager"
6
7
  require "spring/process_title_updater"
@@ -28,20 +29,33 @@ module Spring
28
29
  @mutex = Mutex.new
29
30
  end
30
31
 
32
+ def log(message)
33
+ env.log "[server] #{message}"
34
+ end
35
+
31
36
  def boot
37
+ Spring.verify_environment
38
+
32
39
  write_pidfile
33
40
  set_pgid
34
41
  ignore_signals
35
42
  set_exit_hook
36
- redirect_output
37
43
  set_process_title
38
44
  watch_bundle
45
+ start_server
46
+ end
39
47
 
48
+ def start_server
40
49
  server = UNIXServer.open(env.socket_name)
50
+ log "started on #{env.socket_name}"
51
+ rescue Errno::EPERM
52
+ raise TmpUnwritable.new(env.tmp_path)
53
+ else
41
54
  loop { serve server.accept }
42
55
  end
43
56
 
44
57
  def serve(client)
58
+ log "accepted client"
45
59
  client.puts env.version
46
60
 
47
61
  app_client = client.recv_io
@@ -50,13 +64,17 @@ module Spring
50
64
  args, default_rails_env = command.values_at('args', 'default_rails_env')
51
65
 
52
66
  if Spring.command?(args.first)
67
+ log "running command #{args.first}"
53
68
  client.puts
54
69
  client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
55
70
  else
71
+ log "command not found #{args.first}"
56
72
  client.close
57
73
  end
58
74
  rescue SocketError => e
59
75
  raise e unless client.eof?
76
+ ensure
77
+ redirect_output
60
78
  end
61
79
 
62
80
  def rails_env_for(args, default_rails_env)
@@ -93,7 +111,9 @@ module Spring
93
111
  @applications.values.each(&:stop)
94
112
 
95
113
  [env.socket_path, env.pidfile_path].each do |path|
96
- path.unlink if path.exist?
114
+ if path.exist?
115
+ path.unlink rescue nil
116
+ end
97
117
  end
98
118
  end
99
119
 
@@ -107,19 +127,12 @@ module Spring
107
127
  end
108
128
  end
109
129
 
110
- # We can't leave STDOUT, STDERR as they as because then they will
111
- # never get closed for the lifetime of the server. This means that
112
- # piping, e.g. "spring rake -T | grep db" won't work correctly
113
- # because grep will hang while waiting for its stdin to reach EOF.
114
- #
115
- # However we do want server output to go to the terminal in case
116
- # there are exceptions etc, so we just open the current terminal
117
- # device directly.
130
+ # We need to redirect STDOUT and STDERR, otherwise the server will
131
+ # keep the original FDs open which would break piping. (e.g.
132
+ # `spring rake -T | grep db` would hang forever because the server
133
+ # would keep the stdout FD open.)
118
134
  def redirect_output
119
- # ruby doesn't expose ttyname()
120
- file = open(STDIN.tty? ? `tty`.chomp : "/dev/null", "a")
121
- STDOUT.reopen(file)
122
- STDERR.reopen(file)
135
+ [STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
123
136
  end
124
137
 
125
138
  def set_process_title
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "0.0.10"
2
+ VERSION = "0.0.11"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require "spring/watcher/abstract"
2
+ require "spring/configuration"
2
3
 
3
4
  module Spring
4
5
  class << self
@@ -38,15 +38,17 @@ module Spring
38
38
 
39
39
  items = items.select(&:exist?)
40
40
 
41
- items.each do |item|
42
- if item.directory?
43
- directories << item.realpath.to_s
44
- else
45
- files << item.realpath.to_s
41
+ synchronize {
42
+ items.each do |item|
43
+ if item.directory?
44
+ directories << item.realpath.to_s
45
+ else
46
+ files << item.realpath.to_s
47
+ end
46
48
  end
47
- end
48
49
 
49
- subjects_changed
50
+ subjects_changed
51
+ }
50
52
  end
51
53
 
52
54
  def stale?
@@ -5,7 +5,7 @@ module Spring
5
5
 
6
6
  def initialize(root, latency)
7
7
  super
8
- @mtime = nil
8
+ @mtime = 0
9
9
  @poller = nil
10
10
  end
11
11
 
@@ -4,22 +4,31 @@ require 'io/wait'
4
4
  require "timeout"
5
5
  require "spring/sid"
6
6
  require "spring/env"
7
- require "pty"
8
7
 
9
8
  class AppTest < ActiveSupport::TestCase
10
- # Runtimes on the CI tend to be a bit more volatile, so make
11
- # the ratio more permissive
12
- DEFAULT_SPEEDUP = ENV['CI'] ? 0.8 : 0.6
9
+ DEFAULT_SPEEDUP = 0.8
13
10
  DEFAULT_TIMEOUT = ENV['CI'] ? 30 : 10
14
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
+
15
20
  def app_root
16
- Pathname.new("#{TEST_ROOT}/apps/rails-3-2")
21
+ Pathname.new("#{TEST_ROOT}/apps/rails-#{rails_version.scan(/\d/)[0..1].join("-")}")
17
22
  end
18
23
 
19
24
  def gem_home
20
25
  app_root.join "vendor/gems/#{RUBY_VERSION}"
21
26
  end
22
27
 
28
+ def user_home
29
+ app_root.join "user_home"
30
+ end
31
+
23
32
  def spring
24
33
  gem_home.join "bin/spring"
25
34
  end
@@ -36,8 +45,19 @@ class AppTest < ActiveSupport::TestCase
36
45
  @stderr ||= IO.pipe
37
46
  end
38
47
 
48
+ def log_file
49
+ @log_file ||= File.open("/tmp/spring.log", "w+")
50
+ end
51
+
39
52
  def env
40
- @env ||= {"GEM_HOME" => gem_home.to_s, "GEM_PATH" => ""}
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
+ }
41
61
  end
42
62
 
43
63
  def app_run(command, opts = {})
@@ -56,107 +76,157 @@ class AppTest < ActiveSupport::TestCase
56
76
 
57
77
  _, status = Timeout.timeout(opts.fetch(:timeout, DEFAULT_TIMEOUT)) { Process.wait2 }
58
78
 
59
- stdout, stderr = read_streams
60
- 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"]
61
87
 
62
88
  @times << (Time.now - start_time) if @times
63
89
 
64
- {
65
- status: status,
66
- stdout: stdout,
67
- stderr: stderr,
68
- }
90
+ output.merge(status: status, command: command)
69
91
  rescue Timeout::Error => e
70
- raise e, "Output:\n\n#{dump_streams(command, *read_streams)}"
92
+ raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
71
93
  end
72
94
 
73
95
  def read_streams
74
- [stdout, stderr].map(&:first).map do |stream|
75
- output = ""
76
- output << stream.readpartial(10240) while IO.select([stream], [], [], 0.5)
77
- 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)
78
107
  end
108
+ output
79
109
  end
80
110
 
81
- def dump_streams(command, stdout, stderr)
111
+ def dump_streams(command, streams)
82
112
  output = "$ #{command}\n"
83
113
 
84
- unless stdout.chomp.empty?
85
- output << "--- stdout ---\n"
86
- output << "#{stdout.chomp}\n"
87
- end
88
-
89
- unless stderr.chomp.empty?
90
- output << "--- stderr ---\n"
91
- 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
92
119
  end
93
120
 
94
121
  output << "\n"
95
122
  output
96
123
  end
97
124
 
125
+ def alive?(pid)
126
+ Process.kill 0, pid
127
+ true
128
+ rescue Errno::ESRCH
129
+ false
130
+ end
131
+
98
132
  def await_reload
99
- 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)
100
144
  end
101
145
 
102
146
  def assert_output(artifacts, expected)
103
147
  expected.each do |stream, output|
104
148
  assert artifacts[stream].include?(output),
105
- "expected #{stream} to include '#{output}', but it was:\n\n#{artifacts[stream]}"
149
+ "expected #{stream} to include '#{output}'.\n\n#{debug(artifacts)}"
106
150
  end
107
151
  end
108
152
 
109
153
  def assert_success(command, expected_output = nil)
110
- artifacts = app_run(command)
111
- assert artifacts[:status].success?, "expected successful exit status\n\n#{dump_streams(command, *artifacts.values_at(:stdout, :stderr))}"
154
+ artifacts = app_run(*Array(command))
155
+ assert artifacts[:status].success?, "expected successful exit status\n\n#{debug(artifacts)}"
112
156
  assert_output artifacts, expected_output if expected_output
113
157
  end
114
158
 
115
159
  def assert_failure(command, expected_output = nil)
116
- artifacts = app_run(command)
117
- assert !artifacts[:status].success?, "expected unsuccessful exit status\n\n#{dump_streams(command, *artifacts.values_at(:stdout, :stderr))}"
160
+ artifacts = app_run(*Array(command))
161
+ assert !artifacts[:status].success?, "expected unsuccessful exit status\n\n#{debug(artifacts)}"
118
162
  assert_output artifacts, expected_output if expected_output
119
163
  end
120
164
 
121
165
  def assert_speedup(ratio = DEFAULT_SPEEDUP)
122
- @times = []
123
- yield
124
- assert (@times.last / @times.first) < ratio, "#{@times.last} was not less than #{ratio} of #{@times.first}"
125
- @times = nil
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
126
174
  end
127
175
 
128
176
  def spring_test_command
129
177
  "#{spring} testunit #{@test}"
130
178
  end
131
179
 
132
- @@installed = false
180
+ def generate_app
181
+ Bundler.with_clean_env do
182
+ assert system("(gem list rails --installed --version '#{rails_version}' || " \
183
+ "gem install rails --version '#{rails_version}') > /dev/null")
133
184
 
134
- setup do
135
- @test = "#{app_root}/test/functional/posts_controller_test.rb"
136
- @test_contents = File.read(@test)
137
- @spec = "#{app_root}/spec/dummy_spec.rb"
138
- @spec_contents = File.read(@spec)
139
- @controller = "#{app_root}/app/controllers/posts_controller.rb"
140
- @controller_contents = File.read(@controller)
185
+ # Have to shell out otherwise bundler prevents us finding the gem
186
+ version = `ruby -e 'puts Gem::Specification.find_by_name("rails", "#{rails_version}").version'`.chomp
187
+
188
+ assert system("rails _#{version}_ new #{app_root} --skip-bundle --skip-javascript --skip-sprockets > /dev/null")
141
189
 
142
- unless @@installed
143
190
  FileUtils.mkdir_p(gem_home)
144
- system "gem build spring.gemspec 2>/dev/null 1>/dev/null"
145
- app_run "gem install ../../../spring-#{Spring::VERSION}.gem"
146
- app_run "(gem list bundler | grep bundler) || gem install bundler #{'--pre' if RUBY_VERSION >= "2.0"}", timeout: nil
147
- app_run "bundle check || bundle update", timeout: nil
148
- app_run "bundle exec rake db:migrate db:test:clone"
149
- @@installed = true
191
+ FileUtils.mkdir_p(user_home)
192
+ FileUtils.rm_rf("#{app_root}/test/performance/")
193
+ end
194
+ end
195
+
196
+ def install
197
+ generate_app unless app_root.exist?
198
+
199
+ assert system("gem build spring.gemspec 2>/dev/null 1>/dev/null")
200
+
201
+ assert_success "gem install ../../../spring-#{Spring::VERSION}.gem"
202
+ assert_success ["(gem list bundler | grep bundler) || gem install bundler", timeout: nil]
203
+ assert_success ["bundle check || bundle update", timeout: nil]
204
+
205
+ unless File.exist?(@controller)
206
+ assert_success "bundle exec rails g scaffold post title:string"
150
207
  end
151
208
 
152
- FileUtils.rm_rf "#{app_root}/bin"
209
+ assert_success "bundle exec rake db:migrate db:test:clone"
210
+ @@installed = true
211
+ end
212
+
213
+ @@installed = false
214
+
215
+ setup do
216
+ @test = "#{app_root}/test/#{rails_3? ? 'functional' : 'controllers'}/posts_controller_test.rb"
217
+ @controller = "#{app_root}/app/controllers/posts_controller.rb"
218
+
219
+ install unless @@installed
220
+
221
+ @test_contents = File.read(@test)
222
+ @controller_contents = File.read(@controller)
153
223
  end
154
224
 
155
225
  teardown do
156
226
  app_run "#{spring} stop"
157
- File.write(@test, @test_contents)
158
- File.write(@spec, @spec_contents)
227
+ File.write(@test, @test_contents)
159
228
  File.write(@controller, @controller_contents)
229
+ FileUtils.rm_f("#{app_root}/config/spring.rb")
160
230
  end
161
231
 
162
232
  test "basic" do
@@ -219,15 +289,13 @@ class AppTest < ActiveSupport::TestCase
219
289
  File.write(@test, @test_contents.sub("get :index", "Foo.omg"))
220
290
 
221
291
  await_reload
222
-
223
- assert_speedup do
224
- 2.times { assert_failure spring_test_command, stdout: "RuntimeError: omg" }
225
- end
292
+ assert_failure spring_test_command, stdout: "RuntimeError: omg"
226
293
  ensure
227
294
  File.write(application, application_contents)
228
295
  end
229
296
 
230
297
  test "app gets reloaded when preloaded files change (polling watcher)" do
298
+ env["RAILS_ENV"] = "test"
231
299
  assert_success "#{spring} rails runner 'puts Spring.watcher.class'", stdout: "Polling"
232
300
  assert_app_reloaded
233
301
  end
@@ -236,18 +304,17 @@ class AppTest < ActiveSupport::TestCase
236
304
  begin
237
305
  gemfile = app_root.join("Gemfile")
238
306
  gemfile_contents = gemfile.read
239
- File.write(gemfile, gemfile_contents.sub(%{# gem 'listen'}, %{gem 'listen'}))
307
+ File.write(gemfile, gemfile_contents + "\ngem 'listen', '~> 1.0'")
240
308
 
241
- config_path = "#{app_root}/config/spring.rb"
242
- config_contents = File.read(config_path)
243
- File.write(config_path,config_contents + "\nSpring.watch_method = :listen")
309
+ File.write("#{app_root}/config/spring.rb", "Spring.watch_method = :listen")
244
310
 
245
- app_run "bundle install", timeout: nil
311
+ assert_success ["bundle install", timeout: nil]
246
312
 
313
+ env["RAILS_ENV"] = "test"
247
314
  assert_success "#{spring} rails runner 'puts Spring.watcher.class'", stdout: "Listen"
315
+
248
316
  assert_app_reloaded
249
317
  ensure
250
- File.write(config_path,config_contents)
251
318
  File.write(gemfile, gemfile_contents)
252
319
  assert_success "bundle check"
253
320
  end
@@ -266,8 +333,6 @@ class AppTest < ActiveSupport::TestCase
266
333
  assert_failure spring_test_command
267
334
 
268
335
  File.write(application, application_contents)
269
- await_reload
270
-
271
336
  assert_success spring_test_command
272
337
  ensure
273
338
  File.write(application, application_contents)
@@ -283,32 +348,55 @@ class AppTest < ActiveSupport::TestCase
283
348
  end
284
349
 
285
350
  test "custom commands" do
351
+ File.write("#{app_root}/config/spring.rb", <<-CODE)
352
+ class CustomCommand
353
+ def call
354
+ puts "omg"
355
+ end
356
+ end
357
+
358
+ Spring.register_command "custom", CustomCommand.new
359
+ CODE
360
+
286
361
  assert_success "#{spring} custom", stdout: "omg"
287
362
  end
288
363
 
289
364
  test "binstubs" do
290
- app_run "#{spring} binstub rake"
291
- app_run "#{spring} binstub rails"
292
- assert_success "bin/spring help"
293
- assert_success "bin/rake -T", stdout: "rake db:migrate"
294
- assert_success "bin/rails runner 'puts %(omg)'", stdout: "omg"
365
+ begin
366
+ FileUtils.mv "#{app_root}/bin", "#{app_root}/bin~" if File.exist?("#{app_root}/bin")
367
+
368
+ app_run "#{spring} binstub rake"
369
+ app_run "#{spring} binstub rails"
370
+ assert_success "bin/spring help"
371
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
372
+ assert_success "bin/rails runner 'puts %(omg)'", stdout: "omg"
373
+ assert_success "bin/rails server --help", stdout: "Usage: rails server"
374
+ ensure
375
+ if File.exist?("#{app_root}/bin~")
376
+ FileUtils.rm_rf "#{app_root}/bin"
377
+ FileUtils.mv "#{app_root}/bin~", "#{app_root}/bin"
378
+ end
379
+ end
295
380
  end
296
381
 
297
382
  test "after fork callback" do
298
- begin
299
- config_path = "#{app_root}/config/spring.rb"
300
- config_contents = File.read(config_path)
383
+ File.write("#{app_root}/config/spring.rb", "Spring.after_fork { puts '!callback!' }")
384
+ assert_success "#{spring} rails runner 'puts 2'", stdout: "!callback!\n2"
385
+ end
301
386
 
302
- File.write(config_path, config_contents + "\nSpring.after_fork { puts '!callback!' }")
387
+ test "global config file evaluated" do
388
+ begin
389
+ File.write("#{user_home}/.spring.rb", "Spring.after_fork { puts '!callback!' }")
303
390
  assert_success "#{spring} rails runner 'puts 2'", stdout: "!callback!\n2"
304
391
  ensure
305
- File.write(config_path, config_contents)
392
+ FileUtils.rm_r("#{user_home}/.spring.rb")
306
393
  end
307
394
  end
308
395
 
309
396
  test "missing config/application.rb" do
310
397
  begin
311
398
  FileUtils.mv app_root.join("config/application.rb"), app_root.join("config/application.rb.bak")
399
+
312
400
  assert_failure "#{spring} rake -T", stderr: "unable to find your config/application.rb"
313
401
  ensure
314
402
  FileUtils.mv app_root.join("config/application.rb.bak"), app_root.join("config/application.rb")
@@ -335,24 +423,18 @@ class AppTest < ActiveSupport::TestCase
335
423
  assert_success "#{spring} rake -p 'Rails.env'", stdout: "production"
336
424
  end
337
425
 
338
- test "exit code for failing specs" do
339
- assert_success "#{spring} rspec"
340
- File.write(@spec, @spec_contents.sub("true.should be_true", "false.should be_true"))
341
- assert_failure "#{spring} rspec"
342
- end
343
-
344
426
  test "changing the Gemfile restarts the server" do
345
427
  begin
346
428
  gemfile = app_root.join("Gemfile")
347
429
  gemfile_contents = gemfile.read
348
430
 
349
- assert_success %(#{spring} rails runner 'require "rspec"')
431
+ assert_success %(#{spring} rails runner 'require "sqlite3"')
350
432
 
351
- File.write(gemfile, gemfile_contents.sub(%{gem 'rspec'}, %{# gem 'rspec'}))
433
+ File.write(gemfile, gemfile_contents.sub(%{gem 'sqlite3'}, %{# gem 'sqlite3'}))
352
434
  app_run "bundle check"
353
435
 
354
436
  await_reload
355
- assert_failure %(#{spring} rails runner 'require "rspec"'), stderr: "cannot load such file -- rspec"
437
+ assert_failure %(#{spring} rails runner 'require "sqlite3"'), stderr: "sqlite3"
356
438
  ensure
357
439
  File.write(gemfile, gemfile_contents)
358
440
  assert_success "bundle check"