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.
- data/.travis.yml +3 -0
- data/CHANGELOG.md +13 -2
- data/Gemfile +1 -1
- data/README.md +16 -11
- data/lib/spring/application.rb +97 -20
- data/lib/spring/application_manager.rb +16 -9
- data/lib/spring/client.rb +1 -1
- data/lib/spring/client/binstub.rb +1 -1
- data/lib/spring/client/rails.rb +8 -3
- data/lib/spring/client/run.rb +23 -6
- data/lib/spring/client/status.rb +2 -2
- data/lib/spring/commands.rb +3 -0
- data/lib/spring/commands/rails.rb +7 -0
- data/lib/spring/configuration.rb +1 -1
- data/lib/spring/env.rb +8 -2
- data/lib/spring/errors.rb +15 -1
- data/lib/spring/server.rb +27 -14
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher.rb +1 -0
- data/lib/spring/watcher/abstract.rb +9 -7
- data/lib/spring/watcher/polling.rb +1 -1
- data/test/acceptance/app_test.rb +168 -86
- data/test/apps/.gitignore +3 -0
- data/test/unit/watcher_test.rb +12 -0
- metadata +4 -134
- data/test/apps/rails-3-2/.gitignore +0 -18
- data/test/apps/rails-3-2/Gemfile +0 -7
- data/test/apps/rails-3-2/README.rdoc +0 -261
- data/test/apps/rails-3-2/Rakefile +0 -7
- data/test/apps/rails-3-2/app/assets/images/rails.png +0 -0
- data/test/apps/rails-3-2/app/assets/javascripts/application.js +0 -15
- data/test/apps/rails-3-2/app/assets/javascripts/posts.js.coffee +0 -3
- data/test/apps/rails-3-2/app/assets/stylesheets/application.css +0 -13
- data/test/apps/rails-3-2/app/assets/stylesheets/posts.css.scss +0 -3
- data/test/apps/rails-3-2/app/assets/stylesheets/scaffolds.css.scss +0 -69
- data/test/apps/rails-3-2/app/controllers/application_controller.rb +0 -3
- data/test/apps/rails-3-2/app/controllers/posts_controller.rb +0 -83
- data/test/apps/rails-3-2/app/helpers/application_helper.rb +0 -2
- data/test/apps/rails-3-2/app/helpers/posts_helper.rb +0 -2
- data/test/apps/rails-3-2/app/mailers/.gitkeep +0 -0
- data/test/apps/rails-3-2/app/models/.gitkeep +0 -0
- data/test/apps/rails-3-2/app/models/post.rb +0 -3
- data/test/apps/rails-3-2/app/views/layouts/application.html.erb +0 -14
- data/test/apps/rails-3-2/app/views/posts/_form.html.erb +0 -21
- data/test/apps/rails-3-2/app/views/posts/edit.html.erb +0 -6
- data/test/apps/rails-3-2/app/views/posts/index.html.erb +0 -23
- data/test/apps/rails-3-2/app/views/posts/new.html.erb +0 -5
- data/test/apps/rails-3-2/app/views/posts/show.html.erb +0 -10
- data/test/apps/rails-3-2/config.ru +0 -4
- data/test/apps/rails-3-2/config/application.rb +0 -62
- data/test/apps/rails-3-2/config/boot.rb +0 -6
- data/test/apps/rails-3-2/config/database.yml +0 -25
- data/test/apps/rails-3-2/config/environment.rb +0 -5
- data/test/apps/rails-3-2/config/environments/development.rb +0 -37
- data/test/apps/rails-3-2/config/environments/production.rb +0 -67
- data/test/apps/rails-3-2/config/environments/test.rb +0 -37
- data/test/apps/rails-3-2/config/initializers/backtrace_silencers.rb +0 -7
- data/test/apps/rails-3-2/config/initializers/inflections.rb +0 -15
- data/test/apps/rails-3-2/config/initializers/mime_types.rb +0 -5
- data/test/apps/rails-3-2/config/initializers/secret_token.rb +0 -7
- data/test/apps/rails-3-2/config/initializers/session_store.rb +0 -8
- data/test/apps/rails-3-2/config/initializers/wrap_parameters.rb +0 -14
- data/test/apps/rails-3-2/config/locales/en.yml +0 -5
- data/test/apps/rails-3-2/config/routes.rb +0 -60
- data/test/apps/rails-3-2/config/spring.rb +0 -7
- data/test/apps/rails-3-2/db/migrate/20121109171227_create_posts.rb +0 -9
- data/test/apps/rails-3-2/db/schema.rb +0 -22
- data/test/apps/rails-3-2/db/seeds.rb +0 -7
- data/test/apps/rails-3-2/lib/assets/.gitkeep +0 -0
- data/test/apps/rails-3-2/lib/tasks/.gitkeep +0 -0
- data/test/apps/rails-3-2/log/.gitkeep +0 -0
- data/test/apps/rails-3-2/public/404.html +0 -26
- data/test/apps/rails-3-2/public/422.html +0 -26
- data/test/apps/rails-3-2/public/500.html +0 -25
- data/test/apps/rails-3-2/public/favicon.ico +0 -0
- data/test/apps/rails-3-2/public/index.html +0 -241
- data/test/apps/rails-3-2/public/robots.txt +0 -5
- data/test/apps/rails-3-2/script/rails +0 -6
- data/test/apps/rails-3-2/spec/dummy_spec.rb +0 -5
- data/test/apps/rails-3-2/test/fixtures/.gitkeep +0 -0
- data/test/apps/rails-3-2/test/fixtures/posts.yml +0 -7
- data/test/apps/rails-3-2/test/functional/.gitkeep +0 -0
- data/test/apps/rails-3-2/test/functional/posts_controller_test.rb +0 -49
- data/test/apps/rails-3-2/test/integration/.gitkeep +0 -0
- data/test/apps/rails-3-2/test/test_helper.rb +0 -13
- data/test/apps/rails-3-2/test/unit/.gitkeep +0 -0
- data/test/apps/rails-3-2/test/unit/helpers/posts_helper_test.rb +0 -4
- data/test/apps/rails-3-2/test/unit/post_test.rb +0 -7
- data/test/apps/rails-3-2/vendor/assets/javascripts/.gitkeep +0 -0
- data/test/apps/rails-3-2/vendor/assets/stylesheets/.gitkeep +0 -0
- data/test/apps/rails-3-2/vendor/plugins/.gitkeep +0 -0
data/lib/spring/client/status.rb
CHANGED
|
@@ -21,8 +21,8 @@ module Spring
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def application_pids
|
|
24
|
-
candidates = `ps -
|
|
25
|
-
candidates.select { |l| l =~
|
|
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
|
data/lib/spring/commands.rb
CHANGED
|
@@ -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
|
data/lib/spring/configuration.rb
CHANGED
data/lib/spring/env.rb
CHANGED
|
@@ -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
|
|
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
|
data/lib/spring/errors.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Spring
|
|
2
2
|
class ClientError < StandardError; end
|
|
3
3
|
|
|
4
|
-
class UnknownProject <
|
|
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
|
|
data/lib/spring/server.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
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
|
-
|
|
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
|
data/lib/spring/version.rb
CHANGED
data/lib/spring/watcher.rb
CHANGED
|
@@ -38,15 +38,17 @@ module Spring
|
|
|
38
38
|
|
|
39
39
|
items = items.select(&:exist?)
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
50
|
+
subjects_changed
|
|
51
|
+
}
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def stale?
|
data/test/acceptance/app_test.rb
CHANGED
|
@@ -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
|
-
|
|
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-
|
|
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 ||= {
|
|
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
|
-
|
|
60
|
-
|
|
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,
|
|
92
|
+
raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
|
|
71
93
|
end
|
|
72
94
|
|
|
73
95
|
def read_streams
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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,
|
|
111
|
+
def dump_streams(command, streams)
|
|
82
112
|
output = "$ #{command}\n"
|
|
83
113
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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}'
|
|
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#{
|
|
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#{
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
307
|
+
File.write(gemfile, gemfile_contents + "\ngem 'listen', '~> 1.0'")
|
|
240
308
|
|
|
241
|
-
|
|
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
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 "
|
|
431
|
+
assert_success %(#{spring} rails runner 'require "sqlite3"')
|
|
350
432
|
|
|
351
|
-
File.write(gemfile, gemfile_contents.sub(%{gem '
|
|
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 "
|
|
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"
|