spring 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
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"