silver_spurs 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,509 @@
1
+ require 'spec_helper'
2
+ require 'logger'
3
+
4
+ describe SilverSpurs::Asyncifier do
5
+ before :each do
6
+ SilverSpurs::Asyncifier.logger = Logger.new('/dev/null')
7
+ end
8
+
9
+ describe :timeout do
10
+ it 'defaults to 60 minutes' do
11
+ SilverSpurs::Asyncifier.timeout.should eq 60 * 60
12
+ end
13
+ end
14
+
15
+ describe :logger do
16
+ before :each do
17
+ SilverSpurs::Asyncifier.logger = nil
18
+ end
19
+
20
+ it 'defaults to STDERR' do
21
+ logger_dbl = double('logger')
22
+ logger_dbl.stub(:level=)
23
+ Logger.should_receive(:new).with(STDERR).and_return logger_dbl
24
+
25
+ SilverSpurs::Asyncifier.instance.logger
26
+ end
27
+ end
28
+
29
+ describe :spawn_process do
30
+ before :each do
31
+ SilverSpurs::Asyncifier.instance.stub(:create_directory_tree)
32
+ Process.stub(:spawn)
33
+ File.stub(:open)
34
+ Process.stub(:detach)
35
+ end
36
+
37
+ it 'creates the directory tree' do
38
+ SilverSpurs::Asyncifier.instance.should_receive(:create_directory_tree)
39
+ SilverSpurs::Asyncifier.spawn_process('foo', 'echo foo')
40
+ end
41
+
42
+ it 'spawns the process' do
43
+ Process.should_receive(:spawn)
44
+ SilverSpurs::Asyncifier.spawn_process('foo', 'echo foo')
45
+ end
46
+
47
+ it 'writes the pid to the lock file' do
48
+ File.should_receive(:open)
49
+ SilverSpurs::Asyncifier.instance.should_receive(:pid_file_path)
50
+ SilverSpurs::Asyncifier.spawn_process('foo', 'echo foo')
51
+ end
52
+
53
+ it 'detaches the process' do
54
+ Process.should_receive(:detach)
55
+ SilverSpurs::Asyncifier.spawn_process('foo', 'echo foo')
56
+ end
57
+ end
58
+
59
+ describe :has_lock? do
60
+ context 'when there is no pid file' do
61
+ before :each do
62
+ File.stub(:exists?).and_return false
63
+ end
64
+
65
+ it 'returns false' do
66
+ SilverSpurs::Asyncifier.has_lock?('foo').should be_false
67
+ end
68
+
69
+ it 'checks for the pid file' do
70
+ SilverSpurs::Asyncifier.instance.should_receive(:pid_file_path)
71
+ SilverSpurs::Asyncifier.has_lock?('foo')
72
+ end
73
+ end
74
+
75
+ context 'when there is a pid file' do
76
+ before :each do
77
+ File.stub(:exists?).and_return true
78
+ File.stub(:read).and_return '1234'
79
+ end
80
+
81
+ it 'checks to see if the process is running' do
82
+ IO.should_receive(:popen).with('ps -o command -p 1234').and_return StringIO.new("1\n2")
83
+ SilverSpurs::Asyncifier.has_lock? '1234'
84
+ end
85
+
86
+ context 'when the process is running' do
87
+ before :each do
88
+ IO.stub(:popen).and_return StringIO.new("COMMAND\nknife whatever")
89
+ end
90
+
91
+ it 'returns true' do
92
+ SilverSpurs::Asyncifier.has_lock?('1234').should be_true
93
+ end
94
+ end
95
+
96
+ context 'when the process is not running' do
97
+ before :each do
98
+ IO.stub(:popen).and_return StringIO.new("COMMAND")
99
+ end
100
+
101
+ it 'returns false' do
102
+ SilverSpurs::Asyncifier.has_lock?('1234').should be_false
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ describe :success? do
111
+ before :each do
112
+ SilverSpurs::Asyncifier.instance.stub(:success_file_path).and_return 'success_file'
113
+ end
114
+
115
+ it 'checks for a success file' do
116
+ File.should_receive(:exists?).with('success_file').and_return false
117
+
118
+ SilverSpurs::Asyncifier.success?('foo')
119
+ end
120
+
121
+ context 'when the success file does not exist' do
122
+ before :each do
123
+ File.stub(:exists?).and_return false
124
+ end
125
+
126
+ it 'returns false' do
127
+ SilverSpurs::Asyncifier.success?('foo').should be_false
128
+ end
129
+ end
130
+
131
+ context 'when the success file exists' do
132
+ before :each do
133
+ SilverSpurs::Asyncifier.instance.stub(:pid_file_path).and_return 'pid_file'
134
+ File.stub(:exists?).with('success_file').and_return true
135
+ end
136
+
137
+ it 'checks to see if the pid file exists' do
138
+ File.should_receive(:exists?).twice.and_return(true, false)
139
+ SilverSpurs::Asyncifier.success? 'foo'
140
+ end
141
+
142
+ context 'when the pid file exists' do
143
+ before :each do
144
+ File.stub(:exists?).and_return(true, true)
145
+ end
146
+
147
+ it 'checks the modified time of the success and pid file' do
148
+ File.should_receive(:mtime).twice.and_return(Time.now)
149
+ SilverSpurs::Asyncifier.success? 'foo'
150
+ end
151
+
152
+ context 'when the success file is younger than the pid file' do
153
+ before :each do
154
+ File.stub(:mtime).and_return(Time.new(2013), Time.new(2012))
155
+ end
156
+
157
+ it 'should return true' do
158
+ SilverSpurs::Asyncifier.success?('foo').should be_true
159
+ end
160
+ end
161
+
162
+ context 'when the pid file is younger than the success file' do
163
+ before :each do
164
+ File.stub(:mtime).and_return(Time.new(2012), Time.new(2013))
165
+ end
166
+
167
+ it 'should return false' do
168
+ SilverSpurs::Asyncifier.success?('foo').should be_false
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+
176
+ end
177
+
178
+ describe :get_log do
179
+ before :each do
180
+ SilverSpurs::Asyncifier.instance.stub(:log_file_path).and_return 'log_file'
181
+ end
182
+
183
+ it 'checks to see if the log file exists' do
184
+ File.should_receive(:exists?).and_return false
185
+ SilverSpurs::Asyncifier.get_log 'foo'
186
+ end
187
+
188
+ context 'when the log file exists' do
189
+ before :each do
190
+ File.stub(:exists?).and_return true
191
+ end
192
+
193
+ it 'reads the log' do
194
+ File.stub(:read).and_return 'logs are cool'
195
+ SilverSpurs::Asyncifier.get_log('foo').should eq 'logs are cool'
196
+ end
197
+ end
198
+
199
+ context 'when the log file does not exist' do
200
+ before :each do
201
+ File.stub(:exists?).and_return false
202
+ end
203
+
204
+ it 'returns nil' do
205
+ SilverSpurs::Asyncifier.get_log('foo').should be_nil
206
+ end
207
+ end
208
+
209
+ end
210
+
211
+ describe :reap_orphaned_lock do
212
+ before :each do
213
+ SilverSpurs::Asyncifier.instance.stub(:pid_file_path).and_return 'pid_file'
214
+ end
215
+
216
+ it 'checks to see if the process is active' do
217
+ SilverSpurs::Asyncifier.instance.should_receive(:has_lock?).and_return true
218
+ SilverSpurs::Asyncifier.reap_orphaned_lock 'foo'
219
+ end
220
+
221
+ context 'when the process is still active' do
222
+ before :each do
223
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return true
224
+ end
225
+
226
+ it 'should not try to delete the lock' do
227
+ File.should_not_receive(:delete)
228
+ SilverSpurs::Asyncifier.reap_orphaned_lock 'foo'
229
+ end
230
+ end
231
+
232
+ context 'when the process is not active' do
233
+ before :each do
234
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return false
235
+ SilverSpurs::Asyncifier.instance.stub(:pid_file_path).and_return 'pid_file'
236
+ end
237
+
238
+ it 'should delete the lock file' do
239
+ File.should_receive(:delete).with('pid_file')
240
+ SilverSpurs::Asyncifier.reap_orphaned_lock 'foo'
241
+ end
242
+ end
243
+
244
+ end
245
+
246
+ describe :reap_process do
247
+ before :each do
248
+ SilverSpurs::Asyncifier.instance.stub(:sleep)
249
+ SilverSpurs::Asyncifier.instance.stub(:reap_orphaned_lock)
250
+ SilverSpurs::Asyncifier.instance.stub(:pid_file_path).and_return 'pid_file'
251
+ end
252
+
253
+ it 'checks to see if the process is active' do
254
+ SilverSpurs::Asyncifier.instance.should_receive(:has_lock?).and_return false
255
+ SilverSpurs::Asyncifier.reap_process 'foo'
256
+ end
257
+
258
+ it 'reaps the lock file' do
259
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return false
260
+ SilverSpurs::Asyncifier.instance.should_receive(:reap_orphaned_lock)
261
+ SilverSpurs::Asyncifier.reap_process 'foo'
262
+ end
263
+
264
+ context 'when the process is active' do
265
+ before :each do
266
+ File.stub(:read).and_return '1234'
267
+ Process.stub(:kill)
268
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return true
269
+ end
270
+
271
+ it 'kills the process' do
272
+ Process.should_receive(:kill)
273
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return(true, false)
274
+ SilverSpurs::Asyncifier.reap_process 'foo'
275
+ end
276
+
277
+ it 'checks to see if the process really died' do
278
+ SilverSpurs::Asyncifier.instance.should_receive(:has_lock?).twice.and_return(true, false)
279
+ SilverSpurs::Asyncifier.reap_process 'foo'
280
+ end
281
+
282
+ context 'when the process dies when asked nicely' do
283
+ before :each do
284
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return(true, false)
285
+ end
286
+
287
+ it 'just walks away' do
288
+ Process.should_receive(:kill).once
289
+ SilverSpurs::Asyncifier.reap_process 'foo'
290
+ end
291
+ end
292
+
293
+ context "when the process doesn't die after being asked nicely" do
294
+ before :each do
295
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return(true, true)
296
+ end
297
+
298
+ it 'kills the process with fire' do
299
+ Process.should_receive(:kill).twice
300
+ SilverSpurs::Asyncifier.reap_process 'foo'
301
+ end
302
+ end
303
+
304
+ end
305
+
306
+ context 'if the process is inactive' do
307
+ before :each do
308
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return false
309
+ end
310
+
311
+ it 'skips to reaping the lock file' do
312
+ File.should_not_receive(:read)
313
+ Process.should_not_receive(:kill)
314
+
315
+ SilverSpurs::Asyncifier.instance.should_receive(:reap_orphaned_lock)
316
+
317
+ SilverSpurs::Asyncifier.reap_process 'foo'
318
+ end
319
+ end
320
+
321
+ end
322
+
323
+ describe :reap_old_process do
324
+ before :each do
325
+ SilverSpurs::Asyncifier.instance.stub(:pid_file_path).and_return 'pid_file'
326
+ end
327
+
328
+ it 'checks if the process is active' do
329
+ SilverSpurs::Asyncifier.instance.should_receive(:has_lock?).and_return false
330
+ SilverSpurs::Asyncifier.reap_old_process 'foo'
331
+ end
332
+
333
+ context 'when the process is active' do
334
+ before :each do
335
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return true
336
+ end
337
+
338
+ context 'when the process is beyond the timeout window' do
339
+ before :each do
340
+ Time.stub(:now).and_return Time.new(2013)
341
+ SilverSpurs::Asyncifier.instance.stub(:timeout).and_return 100
342
+ File.stub(:mtime).and_return Time.new(2013) - 101
343
+ end
344
+
345
+ it 'reaps the process' do
346
+ SilverSpurs::Asyncifier.instance.should_receive(:reap_process)
347
+ SilverSpurs::Asyncifier.reap_old_process 'foo'
348
+ end
349
+ end
350
+
351
+ context 'when the process is within the timeout window' do
352
+ before :each do
353
+ Time.stub(:now).and_return Time.new(2013)
354
+ SilverSpurs::Asyncifier.instance.stub(:timeout).and_return 100
355
+ File.stub(:mtime).and_return Time.new(2013) - 99
356
+ end
357
+
358
+ it 'does not reap the process' do
359
+ SilverSpurs::Asyncifier.instance.should_not_receive(:reap_process)
360
+ SilverSpurs::Asyncifier.reap_old_process 'foo'
361
+ end
362
+ end
363
+
364
+ end
365
+
366
+ context 'when the process is not active' do
367
+ before :each do
368
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return false
369
+ end
370
+
371
+ it 'does not attempt to reap the process' do
372
+ SilverSpurs::Asyncifier.instance.should_not_receive :reap_process
373
+ SilverSpurs::Asyncifier.reap_old_process 'foo'
374
+ end
375
+ end
376
+
377
+ end
378
+
379
+ describe :exists? do
380
+ context 'when the process is active' do
381
+ before :each do
382
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return true
383
+ end
384
+
385
+ it 'returns true' do
386
+ SilverSpurs::Asyncifier.exists?('foo').should be_true
387
+ end
388
+
389
+ end
390
+
391
+ context 'when the process is not active' do
392
+ before :each do
393
+ SilverSpurs::Asyncifier.instance.stub(:has_lock?).and_return false
394
+ SilverSpurs::Asyncifier.instance.stub(:log_file_path).and_return 'log_file'
395
+ end
396
+
397
+ context 'if the log file exists' do
398
+ before :each do
399
+ File.stub(:exists?).and_return true
400
+ end
401
+
402
+ it 'returns true' do
403
+ SilverSpurs::Asyncifier.exists?('foo').should be_true
404
+ end
405
+ end
406
+
407
+ context 'if the log file does not exist' do
408
+ before :each do
409
+ File.stub(:exists?).and_return false
410
+ end
411
+
412
+ it 'returns false' do
413
+ SilverSpurs::Asyncifier.exists?('foo').should be_false
414
+ end
415
+ end
416
+
417
+ end
418
+
419
+ end
420
+
421
+ describe :log_file_path do
422
+ it 'builds a path in the base directory' do
423
+ SilverSpurs::Asyncifier.instance.should_receive(:base_path).and_return 'base_path'
424
+ File.should_receive(:join)
425
+ SilverSpurs::Asyncifier.instance.send(:log_file_path, 'foo')
426
+ end
427
+
428
+ it 'returns a file name' do
429
+ SilverSpurs::Asyncifier.instance.send(:log_file_path, 'foo').should be_a_kind_of(String)
430
+ end
431
+ end
432
+
433
+ describe :success_file_path do
434
+ it 'builds a path in the base directory' do
435
+ SilverSpurs::Asyncifier.instance.should_receive(:base_path).and_return 'base_path'
436
+ File.should_receive(:join)
437
+ SilverSpurs::Asyncifier.instance.send(:success_file_path, 'foo')
438
+ end
439
+
440
+ it 'returns a file name' do
441
+ SilverSpurs::Asyncifier.instance.send(:success_file_path, 'foo').should be_a_kind_of(String)
442
+ end
443
+ end
444
+
445
+ describe :pid_file_path do
446
+ it 'builds a path in the base directory' do
447
+ SilverSpurs::Asyncifier.instance.should_receive(:base_path).and_return 'base_path'
448
+ File.should_receive(:join)
449
+ SilverSpurs::Asyncifier.instance.send(:pid_file_path, 'foo')
450
+ end
451
+
452
+ it 'returns a file name' do
453
+ SilverSpurs::Asyncifier.instance.send(:pid_file_path, 'foo').should be_a_kind_of(String)
454
+ end
455
+ end
456
+
457
+ describe :create_directory_tree do
458
+ it 'checks to see if the base path already exists' do
459
+ Dir.should_receive(:exists?).at_least(:once).and_return true
460
+ SilverSpurs::Asyncifier.instance.send(:create_directory_tree)
461
+ end
462
+
463
+ context 'if the base path already exists' do
464
+ before :each do
465
+ Dir.stub(:exists?).and_return true
466
+ end
467
+
468
+ it 'does not create the base directory' do
469
+ Dir.should_not_receive(:mkdir)
470
+ SilverSpurs::Asyncifier.instance.send(:create_directory_tree)
471
+ end
472
+ end
473
+
474
+ context 'if the base path does not exist' do
475
+ before :each do
476
+ Dir.stub(:exists?).and_return(false, true)
477
+ end
478
+
479
+ it 'creates the base directory' do
480
+ Dir.should_receive(:mkdir)
481
+ SilverSpurs::Asyncifier.instance.send(:create_directory_tree)
482
+ end
483
+ end
484
+
485
+ context 'if a directory exists' do
486
+ before :each do
487
+ Dir.stub(:exists?).and_return true
488
+ end
489
+
490
+ it 'does not create the directory' do
491
+ Dir.should_not_receive(:mkdir)
492
+ SilverSpurs::Asyncifier.instance.send(:create_directory_tree)
493
+ end
494
+ end
495
+
496
+ context 'if a directory does not exist' do
497
+ before :each do
498
+ Dir.stub(:exists?).and_return(true, false)
499
+ end
500
+
501
+ it 'creates the directory' do
502
+ Dir.should_receive(:mkdir).exactly(3).times
503
+ SilverSpurs::Asyncifier.instance.send(:create_directory_tree)
504
+ end
505
+ end
506
+
507
+ end
508
+
509
+ end