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
# File 'lib/spring/test/application.rb', line 10

def initialize(root)
  @root       = Pathname.new(root)
  @spring_env = Spring::Env.new(root)
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


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

def application_config
  path "config/application.rb"
end

#await_reloadObject


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

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


202
203
204
205
# File 'lib/spring/test/application.rb', line 202

def bundle
  run! "(gem list bundler | grep bundler) || gem install bundler", timeout: nil, retry: 2
  run! "bundle check || bundle update --retry=2", timeout: nil
end

#controllerObject


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

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

#debug(artifacts) ⇒ Object


172
173
174
175
176
# File 'lib/spring/test/application.rb', line 172

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

#dump_streams(command, streams) ⇒ Object


158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/spring/test/application.rb', line 158

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


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

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)

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

def exists?
  root.exist?
end

#first_timeObject


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

def first_time
  @times.first
end

#gem_homeObject


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

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

#gemfileObject


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

def gemfile
  path "Gemfile"
end

#last_timeObject


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

def last_time
  @times.last
end

#log_fileObject


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

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

#path(addition) ⇒ Object


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

def path(addition)
  root.join addition
end

#rails_versionObject


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

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

#read_stream(stream) ⇒ Object


150
151
152
153
154
155
156
# File 'lib/spring/test/application.rb', line 150

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

#read_streamsObject


142
143
144
145
146
147
148
# File 'lib/spring/test/application.rb', line 142

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

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


91
92
93
94
95
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
# File 'lib/spring/test/application.rb', line 91

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 => e
  raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
end

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


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/spring/test/application.rb', line 186

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


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

def spring
  gem_home.join "bin/spring"
end

#spring_configObject


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

def spring_config
  path "config/spring.rb"
end

#spring_test_commandObject


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

def spring_test_command
  "#{rails_version.test_command} #{test}"
end

#stderrObject


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

def stderr
  @stderr ||= IO.pipe
end

#stdoutObject


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

def stdout
  @stdout ||= IO.pipe
end

#stop_springObject


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

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

#testObject


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

def test
  path "test/#{rails_version.controller_tests_dir}/posts_controller_test.rb"
end

#timing_ratioObject


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

def timing_ratio
  last_time / first_time
end

#user_homeObject


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

def user_home
  path "user_home"
end

#with_timingObject


123
124
125
126
127
128
# File 'lib/spring/test/application.rb', line 123

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