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