Class: Spring::Test::Application

Inherits:
Object
  • Object
show all
Defined in:
lib/spring/test/application.rb

Constant Summary collapse

DEFAULT_TIMEOUT =
ENV['CI'] ? 30 : 10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ Application

Returns a new instance of Application.



10
11
12
13
14
# File 'lib/spring/test/application.rb', line 10

def initialize(root)
  @root       = Pathname.new(root)
  @spring_env = Spring::Env.new(root: root)
  @times      = nil
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



8
9
10
# File 'lib/spring/test/application.rb', line 8

def root
  @root
end

#spring_envObject (readonly)

Returns the value of attribute spring_env.



8
9
10
# File 'lib/spring/test/application.rb', line 8

def spring_env
  @spring_env
end

Instance Method Details

#application_configObject



84
85
86
# File 'lib/spring/test/application.rb', line 84

def application_config
  path "config/application.rb"
end

#await_reloadObject



183
184
185
186
187
188
189
# File 'lib/spring/test/application.rb', line 183

def await_reload
  raise "no pid" if @application_pids.nil? || @application_pids.empty?

  Timeout.timeout(DEFAULT_TIMEOUT) do
    sleep 0.1 while @application_pids.any? { |p| process_alive?(p) }
  end
end

#bundleObject



207
208
209
210
211
212
213
# File 'lib/spring/test/application.rb', line 207

def bundle
  # Version restriction is a workaround for https://github.com/bundler/bundler/pull/4981
  # The problem breaks our tests on Ruby 2.2
  # We can remove once it's fixed
  run! "(gem list bundler | grep bundler) || gem install bundler --version '~> 1.12.0'", timeout: nil, retry: 2
  run! "bundle check || bundle update --retry=2", timeout: nil
end

#controllerObject



80
81
82
# File 'lib/spring/test/application.rb', line 80

def controller
  path "app/controllers/posts_controller.rb"
end

#debug(artifacts) ⇒ Object



177
178
179
180
181
# File 'lib/spring/test/application.rb', line 177

def debug(artifacts)
  artifacts = artifacts.dup
  artifacts.delete :status
  dump_streams(artifacts.delete(:command), artifacts)
end

#dump_streams(command, streams) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/spring/test/application.rb', line 163

def dump_streams(command, streams)
  output = "$ #{command}\n"

  streams.each do |name, stream|
    unless stream.chomp.empty?
      output << "--- #{name} ---\n"
      output << "#{stream.chomp}\n"
    end
  end

  output << "\n"
  output
end

#envObject



32
33
34
35
36
37
38
39
40
41
# File 'lib/spring/test/application.rb', line 32

def env
  @env ||= {
    "GEM_HOME"   => gem_home.to_s,
    "GEM_PATH"   => gem_home.to_s,
    "HOME"       => user_home.to_s,
    "RAILS_ENV"  => nil,
    "RACK_ENV"   => nil,
    "SPRING_LOG" => log_file.path
  }
end

#exists?Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/spring/test/application.rb', line 16

def exists?
  root.exist?
end

#first_timeObject



139
140
141
# File 'lib/spring/test/application.rb', line 139

def first_time
  @times.first
end

#gem_homeObject



51
52
53
# File 'lib/spring/test/application.rb', line 51

def gem_home
  path "../gems/#{RUBY_VERSION}"
end

#gemfileObject



47
48
49
# File 'lib/spring/test/application.rb', line 47

def gemfile
  path "Gemfile"
end

#insert_into_test(code) ⇒ Object



215
216
217
# File 'lib/spring/test/application.rb', line 215

def insert_into_test(code)
  File.write(test, test.read.sub(/^\s*get .+$/, code))
end

#last_timeObject



135
136
137
# File 'lib/spring/test/application.rb', line 135

def last_time
  @times.last
end

#log_fileObject



28
29
30
# File 'lib/spring/test/application.rb', line 28

def log_file
  @log_file ||= path("tmp/spring.log").open("w+")
end

#path(addition) ⇒ Object



43
44
45
# File 'lib/spring/test/application.rb', line 43

def path(addition)
  root.join addition
end

#rails_versionObject



63
64
65
# File 'lib/spring/test/application.rb', line 63

def rails_version
  @rails_version ||= RailsVersion.new(gemfile.read.match(/gem 'rails', '(.*)'/)[1])
end

#read_stream(stream) ⇒ Object



155
156
157
158
159
160
161
# File 'lib/spring/test/application.rb', line 155

def read_stream(stream)
  output = ""
  while IO.select([stream], [], [], 0.5) && !stream.eof?
    output << stream.readpartial(10240)
  end
  output
end

#read_streamsObject



147
148
149
150
151
152
153
# File 'lib/spring/test/application.rb', line 147

def read_streams
  {
    stdout: read_stream(stdout.first),
    stderr: read_stream(stderr.first),
    log:    read_stream(log_file)
  }
end

#run(command, opts = {}) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/spring/test/application.rb', line 96

def run(command, opts = {})
  start_time = Time.now

  Bundler.with_clean_env do
    Process.spawn(
      env,
      command.to_s,
      out:   stdout.last,
      err:   stderr.last,
      in:    :close,
      chdir: root.to_s,
    )
  end

  _, status = Timeout.timeout(opts.fetch(:timeout, DEFAULT_TIMEOUT)) { Process.wait2 }

  if pid = spring_env.pid
    @server_pid = pid
    lines = `ps -A -o ppid= -o pid= | egrep '^\\s*#{@server_pid}'`.lines
    @application_pids = lines.map { |l| l.split.last.to_i }
  end

  output = read_streams
  puts dump_streams(command, output) if ENV["SPRING_DEBUG"]

  @times << (Time.now - start_time) if @times

  output.merge(status: status, command: command)
rescue Timeout::Error
  raise Timeout::Error, "While running command:\n\n#{dump_streams(command, read_streams)}"
end

#run!(command, options = {}) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/spring/test/application.rb', line 191

def run!(command, options = {})
  attempts  = (options.delete(:retry) || 0) + 1
  artifacts = nil

  until attempts == 0 || artifacts && artifacts[:status].success?
    artifacts = run(command, options)
    attempts -= 1
  end

  if artifacts[:status].success?
    artifacts
  else
    raise "command failed\n\n#{debug(artifacts)}"
  end
end

#springObject



59
60
61
# File 'lib/spring/test/application.rb', line 59

def spring
  gem_home.join "bin/spring"
end

#spring_client_configObject



92
93
94
# File 'lib/spring/test/application.rb', line 92

def spring_client_config
  path "config/spring_client.rb"
end

#spring_configObject



88
89
90
# File 'lib/spring/test/application.rb', line 88

def spring_config
  path "config/spring.rb"
end

#spring_test_commandObject



67
68
69
# File 'lib/spring/test/application.rb', line 67

def spring_test_command
  "bin/rake test #{test}"
end

#stderrObject



24
25
26
# File 'lib/spring/test/application.rb', line 24

def stderr
  @stderr ||= IO.pipe
end

#stdoutObject



20
21
22
# File 'lib/spring/test/application.rb', line 20

def stdout
  @stdout ||= IO.pipe
end

#stop_springObject



71
72
73
74
# File 'lib/spring/test/application.rb', line 71

def stop_spring
  run "#{spring} stop"
rescue Errno::ENOENT
end

#testObject



76
77
78
# File 'lib/spring/test/application.rb', line 76

def test
  path "test/controllers/posts_controller_test.rb"
end

#timing_ratioObject



143
144
145
# File 'lib/spring/test/application.rb', line 143

def timing_ratio
  last_time / first_time
end

#user_homeObject



55
56
57
# File 'lib/spring/test/application.rb', line 55

def user_home
  path "user_home"
end

#with_timingObject



128
129
130
131
132
133
# File 'lib/spring/test/application.rb', line 128

def with_timing
  @times = []
  yield
ensure
  @times = nil
end