-
Notifications
You must be signed in to change notification settings - Fork 548
/
utils_spec.rb
335 lines (294 loc) · 9.07 KB
/
utils_spec.rb
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
require 'support/config'
require 'tmpdir'
require 'fileutils'
require 'stringio'
require 'phusion_passenger/message_channel'
require 'phusion_passenger/utils'
include PhusionPassenger
shared_examples_for "a pseudo stderr created by #report_app_init_status" do
before :each do
@sink = StringIO.new
@temp_channel = MessageChannel.new(StringIO.new)
end
after :each do
File.unlink("output.tmp") rescue nil
end
it "redirects everything written to the pseudo STDERR/$stderr to the sink" do
report_app_init_status(@temp_channel, @sink) do
STDERR.puts "Something went wrong!"
$stderr.puts "Something went wrong again!"
raise StandardError, ":-(" if @raise_error
end
@sink.string.should =~ /Something went wrong!/
@sink.string.should =~ /Something went wrong again!/
end
it "redirects reopen operations on the pseudo stderr to the sink" do
@sink.should_receive(:reopen).with("output.tmp", "w")
report_app_init_status(@temp_channel, @sink) do
STDERR.reopen("output.tmp", "w")
raise StandardError, ":-(" if @raise_error
end
end
specify "after the function has finished, every operation on the old pseudo stderr object will still be redirected to the sink" do
pseudo_stderr = nil
report_app_init_status(@temp_channel, @sink) do
pseudo_stderr = STDERR
raise StandardError, ":-(" if @raise_error
end
pseudo_stderr.puts "hello world"
@sink.string.should =~ /hello world/
@sink.should_receive(:reopen).with("output.tmp", "w")
pseudo_stderr.reopen("output.tmp", "w")
end
specify "after the function has finished, every output operation on the old pseudo stderr object will not be buffered" do
pseudo_stderr = nil
report_app_init_status(@temp_channel, @sink) do
pseudo_stderr = STDERR
pseudo_stderr.instance_variable_get(:@buffer).should_not be_nil
raise StandardError, ":-(" if @raise_error
end
pseudo_stderr.instance_variable_get(:@buffer).should be_nil
end
end
describe Utils do
include Utils
specify "#close_all_io_objects_for_fds closes all IO objects that are associated with the given file descriptors" do
filename = "#{Dir.tmpdir}/passenger_test.#{Process.pid}.txt"
begin
pid = safe_fork('utils_spec') do
a, b = IO.pipe
close_all_io_objects_for_fds([0, 1, 2])
File.open(filename, "w") do |f|
f.write("#{a.closed?}, #{b.closed?}")
end
end
Process.waitpid(pid) rescue nil
File.read(filename).should == "true, true"
ensure
File.unlink(filename) rescue nil
end
end
describe "#report_app_init_status" do
it "reports normal errors, which #unmarshal_and_raise_errors raises" do
a, b = IO.pipe
begin
pid = safe_fork('utils_spec') do
a.close
report_app_init_status(MessageChannel.new(b)) do
raise RuntimeError, "hello world"
end
end
b.close
lambda { unmarshal_and_raise_errors(MessageChannel.new(a)) }.should raise_error(/hello world/)
ensure
a.close rescue nil
b.close rescue nil
end
end
it "reports SystemExit errors, which #unmarshal_and_raise_errors raises" do
a, b = IO.pipe
begin
pid = safe_fork('utils_spec') do
a.close
report_app_init_status(MessageChannel.new(b)) do
exit
end
end
b.close
lambda { unmarshal_and_raise_errors(MessageChannel.new(a)) }.should raise_error(/exited during startup/)
ensure
a.close rescue nil
b.close rescue nil
end
end
it "returns whether the block succeeded" do
channel = MessageChannel.new(StringIO.new)
success = report_app_init_status(channel) do
false
end
success.should be_true
success = report_app_init_status(channel) do
raise StandardError, "hi"
end
success.should be_false
end
it "reports all data written to STDERR and $stderr" do
a, b = IO.pipe
begin
pid = safe_fork('utils_spec') do
a.close
report_app_init_status(MessageChannel.new(b), nil) do
STDERR.puts "Something went wrong!"
$stderr.puts "Something went wrong again!"
exit
end
end
b.close
begin
unmarshal_and_raise_errors(MessageChannel.new(a))
violated "No exception raised"
rescue AppInitError => e
e.stderr.should =~ /Something went wrong!/
e.stderr.should =~ /Something went wrong again!/
end
ensure
a.close rescue nil
b.close rescue nil
end
end
it "reports all data written to STDERR and $stderr even if it was reopened" do
a, b = IO.pipe
begin
pid = safe_fork('utils_spec') do
a.close
report_app_init_status(MessageChannel.new(b), nil) do
STDERR.puts "Something went wrong!"
STDERR.reopen("output.tmp", "w")
STDERR.puts "Something went wrong again!"
STDERR.flush
$stderr.puts "Something went wrong yet again!"
$stderr.flush
exit
end
end
b.close
begin
unmarshal_and_raise_errors(MessageChannel.new(a))
violated "No exception raised"
rescue AppInitError => e
e.stderr.should =~ /Something went wrong!/
e.stderr.should =~ /Something went wrong again!/
e.stderr.should =~ /Something went wrong yet again!/
end
file_contents = File.read("output.tmp")
file_contents.should =~ /Something went wrong again!/
file_contents.should =~ /Something went wrong yet again!/
ensure
a.close rescue nil
b.close rescue nil
File.unlink("output.tmp") rescue nil
end
end
describe "if the block failed" do
before :each do
@raise_error = true
end
it_should_behave_like "a pseudo stderr created by #report_app_init_status"
end
describe "if the block succeeded" do
it_should_behave_like "a pseudo stderr created by #report_app_init_status"
end
end
specify "#safe_fork with double_fork == false reseeds the pseudo-random number generator" do
a, b = IO.pipe
begin
pid = safe_fork do
b.puts(rand)
end
Process.waitpid(pid) rescue nil
pid = safe_fork do
b.puts(rand)
end
Process.waitpid(pid) rescue nil
first_num = a.readline
second_num = a.readline
first_num.should_not == second_num
ensure
a.close rescue nil
b.close rescue nil
end
end
specify "#safe_fork with double_fork == true reseeds the pseudo-random number generator" do
a, b = IO.pipe
begin
# Seed the pseudo-random number generator here
# so that it doesn't happen in the child processes.
srand
safe_fork(self.class, true) do
b.puts(rand)
end
safe_fork(self.class, true) do
b.puts(rand)
end
first_num = a.readline
second_num = a.readline
first_num.should_not == second_num
ensure
a.close rescue nil
b.close rescue nil
end
end
describe "#unmarshal_and_raise_errors" do
before :each do
@a, @b = IO.pipe
@report_channel = MessageChannel.new(@a)
report_app_init_status(MessageChannel.new(@b)) do
raise StandardError, "Something went wrong!"
end
end
after :each do
@a.close rescue nil
@b.close rescue nil
end
it "prints the exception information to the 'print_exception' argument using #puts, if 'print_exception' responds to that" do
buffer = StringIO.new
lambda { unmarshal_and_raise_errors(@report_channel, buffer) }.should raise_error(AppInitError)
buffer.string.should =~ /Something went wrong!/
buffer.string.should =~ /utils\.rb/
buffer.string.should =~ /utils_spec\.rb/
end
it "appends the exception information to the file pointed to by 'print_exception', if 'print_exception' responds to #to_str" do
begin
lambda { unmarshal_and_raise_errors(@report_channel, "exception.txt") }.should raise_error(AppInitError)
data = File.read('exception.txt')
data.should =~ /Something went wrong!/
data.should =~ /utils\.rb/
data.should =~ /utils_spec\.rb/
ensure
File.unlink('exception.txt') rescue nil
end
end
end
specify "#to_boolean works" do
to_boolean(nil).should be_false
to_boolean(false).should be_false
to_boolean(true).should be_true
to_boolean(1).should be_true
to_boolean(0).should be_true
to_boolean("").should be_true
to_boolean("true").should be_true
to_boolean("false").should be_false
to_boolean("bla bla").should be_true
end
describe "#passenger_tmpdir" do
before :each do
@old_passenger_tmpdir = Utils.passenger_tmpdir
Utils.passenger_tmpdir = nil
end
after :each do
Utils.passenger_tmpdir = @old_passenger_tmpdir
end
it "returns a directory under Dir.tmpdir if Utils.passenger_tmpdir is nil" do
File.dirname(passenger_tmpdir(false)).should == Dir.tmpdir
end
it "returns a directory under Dir.tmpdir if Utils.passenger_tmpdir is an empty string" do
Utils.passenger_tmpdir = ''
File.dirname(passenger_tmpdir(false)).should == Dir.tmpdir
end
it "returns Utils.passenger_tmpdir if it's set" do
Utils.passenger_tmpdir = '/foo'
passenger_tmpdir(false).should == '/foo'
end
it "creates the directory if it doesn't exist, if the 'create' argument is true" do
Utils.passenger_tmpdir = 'utils_spec.tmp'
passenger_tmpdir
begin
File.directory?('utils_spec.tmp').should be_true
ensure
FileUtils.chmod_R(0777, 'utils_spec.tmp')
FileUtils.rm_rf('utils_spec.tmp')
end
end
end
######################
end