1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
|
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'yaml'
require 'etc'
module PhusionPassenger
shared_examples_for "a spawner" do
def ping_app(app, connect_password)
if app.server_sockets[:main][1] == "unix"
client = UNIXSocket.new(app.server_sockets[:main][0])
else
addr, port = app.server_sockets[:main][0].split(/:/)
client = TCPSocket.new(addr, port.to_i)
end
begin
channel = MessageChannel.new(client)
channel.write_scalar("REQUEST_METHOD\0PING\0PASSENGER_CONNECT_PASSWORD\0#{connect_password}\0")
return client.read
ensure
client.close
end
end
it "returns a valid AppProcess object" do
app = spawn_some_application
lambda { Process.kill(0, app.pid) }.should_not raise_error
end
it "sets the working directory of the app to its app root" do
before_start %q{
File.touch("cwd.txt")
}
app = spawn_some_application
File.exist?("#{app.app_root}/cwd.txt").should be_true
end
it "sets ENV['RAILS_ENV'] and ENV['RACK_ENV']" do
before_start %q{
File.write("rails_env.txt", ENV['RAILS_ENV'])
File.write("rack_env.txt", ENV['RACK_ENV'])
}
app = spawn_some_application("environment" => "staging")
File.read("#{app.app_root}/rails_env.txt").should == "staging"
File.read("#{app.app_root}/rack_env.txt").should == "staging"
end
it "sets ENV['RAILS_RELATIVE_URL_ROOT'] and ENV['RACK_BASE_URI'] if the 'base_uri' option is set to a valid value" do
before_start %q{
File.write("rails_relative_url_root.txt", ENV['RAILS_RELATIVE_URL_ROOT'])
File.write("rack_base_uri.txt", ENV['RACK_BASE_URI'])
}
app = spawn_some_application("base_uri" => "/foo")
File.read("#{app.app_root}/rails_relative_url_root.txt").should == "/foo"
File.read("#{app.app_root}/rack_base_uri.txt").should == "/foo"
end
it "doesn't set ENV['RAILS_RELATIVE_URL_ROOT'] and ENV['RACK_BASE_URI'] if 'base_uri' is not given" do
before_start %q{
if ENV['RAILS_RELATIVE_URL_ROOT']
File.touch("rails_relative_url_root.txt")
end
if ENV['RACK_BASE_URI']
File.touch("rack_base_uri.txt")
end
}
app = spawn_some_application
File.exist?("#{app.app_root}/rails_relative_url_root.txt").should be_false
File.exist?("#{app.app_root}/rack_base_uri.txt").should be_false
end
it "doesn't set ENV['RAILS_RELATIVE_URL_ROOT'] and ENV['RACK_BASE_URI'] if 'base_uri' is empty" do
before_start %q{
if ENV['RAILS_RELATIVE_URL_ROOT']
File.touch("rails_relative_url_root.txt")
end
if ENV['RACK_BASE_URI']
File.touch("rack_base_uri.txt")
end
}
app = spawn_some_application("base_uri" => "")
File.exist?("#{app.app_root}/rails_relative_url_root.txt").should be_false
File.exist?("#{app.app_root}/rack_base_uri.txt").should be_false
end
it "doesn't set ENV['RAILS_RELATIVE_URL_ROOT'] and ENV['RACK_BASE_URI'] if 'base_uri' is '/'" do
before_start %q{
if ENV['RAILS_RELATIVE_URL_ROOT']
File.touch("rails_relative_url_root.txt")
end
if ENV['RACK_BASE_URI']
File.touch("rack_base_uri.txt")
end
}
app = spawn_some_application("base_uri" => "/")
File.exist?("#{app.app_root}/rails_relative_url_root.txt").should be_false
File.exist?("#{app.app_root}/rack_base_uri.txt").should be_false
end
it "sets the environment variables in the 'environment_variables' option" do
before_start %q{
File.open("env.txt", "w") do |f|
f.puts
ENV.each_pair do |key, value|
f.puts("#{key} = #{value}")
end
end
}
env_vars_string = "PATH\0/usr/bin:/opt/sw/bin\0FOO\0foo bar!\0"
options = { "environment_variables" => [env_vars_string].pack("m") }
app = spawn_some_application(options)
contents = File.read("#{app.app_root}/env.txt")
contents.should =~ %r(\nPATH = /usr/bin:/opt/sw/bin\n)
contents.should =~ %r(\nFOO = foo bar\!\n)
end
it "does not cache things like the connect password" do
app1 = spawn_some_application("connect_password" => "1234")
app2 = spawn_some_application("connect_password" => "5678")
ping_app(app1, "1234").should == "pong"
ping_app(app2, "5678").should == "pong"
end
it "calls the starting_worker_process event after the startup file has been loaded" do
after_start %q{
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
PhusionPassenger.on_event(:starting_worker_process) do
::File.append(history_file, "worker_process_started\n")
end
::File.append(history_file, "end of startup file\n");
}
spawn_some_application.close
app = spawn_some_application
app.close
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
eventually do
contents = File.read(history_file)
lines = contents.split("\n")
lines[0] == "end of startup file" &&
lines.count("worker_process_started") == 2
end
end
it "calls the stopping_worker_process event" do
after_start %q{
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
PhusionPassenger.on_event(:stopping_worker_process) do
::File.append(history_file, "worker_process_stopped\n")
end
::File.append(history_file, "end of startup file\n");
}
spawn_some_application.close
app = spawn_some_application
app.close
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
eventually do
contents = File.read(history_file)
lines = contents.split("\n")
lines[0] == "end of startup file" &&
lines.count("worker_process_stopped") == 2
end
end
it "calls #at_exit blocks upon exiting" do
before_start %q{
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
at_exit do
File.open(history_file, "a") do |f|
f.puts "at_exit 1"
end
end
at_exit do
File.open(history_file, "a") do |f|
f.puts "at_exit 2"
end
end
}
spawn_some_application.close
history_file = "#{PhusionPassenger::Utils.passenger_tmpdir}/history.txt"
eventually do
File.exist?(history_file) &&
File.read(history_file) ==
"at_exit 2\n" +
"at_exit 1\n"
end
end
it "lowers privilege using Utils#lower_privilege" do
filename = "#{PhusionPassenger::Utils.passenger_tmpdir}/called.txt"
PhusionPassenger::Utils.stub!(:lower_privilege_called).and_return do
File.touch(filename)
end
spawn_some_application.close
eventually do
File.exist?(filename).should be_true
end
end
describe "error handling" do
it "raises an AppInitError if the spawned app raises a standard exception during startup" do
before_start %q{
raise 'This is a dummy exception.'
}
begin
spawn_some_application("print_exceptions" => false)
violated "Spawning the application should have raised an AppInitError."
rescue AppInitError => e
e.child_exception.message.should == "This is a dummy exception."
end
end
it "raises an AppInitError if the spawned app raises a custom-defined exception during startup" do
before_start %q{
class MyError < StandardError
end
raise MyError, "This is a custom exception."
}
begin
spawn_some_application("print_exceptions" => false)
violated "Spawning the application should have raised an AppInitError."
rescue AppInitError => e
e.child_exception.message.should == "This is a custom exception. (MyError)"
end
end
it "raises an AppInitError if the spawned app calls exit() during startup" do
before_start %q{
exit
}
begin
spawn_some_application("print_exceptions" => false).close
violated "Spawning the application should have raised an AppInitError."
rescue AppInitError => e
e.child_exception.class.should == SystemExit
end
end
it "prints the exception to STDERR if the spawned app raised an error" do
old_stderr = STDERR
file = File.new('output.tmp', 'w+')
begin
Object.send(:remove_const, "STDERR") rescue nil
Object.const_set("STDERR", file)
before_start %q{
def dummy_function
raise 'This is a dummy exception.'
end
dummy_function
}
block = lambda { spawn_some_application }
block.should raise_error(AppInitError)
file.rewind
data = file.read
data.should =~ /This is a dummy exception/
data.should =~ /dummy_function/
ensure
Object.send(:remove_const, "STDERR") rescue nil
Object.const_set("STDERR", old_stderr)
file.close rescue nil
File.unlink('output.tmp') rescue nil
end
end
end
end
end # module PhusionPassenger
|