/
daemon_spec.rb
173 lines (153 loc) · 4.72 KB
/
daemon_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
require 'daemon_controller'
require 'benchmark'
require 'socket'
# A thread which doesn't execute its block until the
# 'go!' method has been called.
class WaitingThread < Thread
def initialize
super do
@mutex = Mutex.new
@cond = ConditionVariable.new
@go = false
@mutex.synchronize do
while !@go
@cond.wait(@mutex)
end
end
yield
end
end
def go!
@mutex.synchronize do
@go = true
@cond.broadcast
end
end
end
module TestHelpers
def new_controller(options = {})
start_command = './echo_server.rb -l echo_server.log -P echo_server.pid'
if options[:wait1]
start_command << " --wait1 #{options[:wait1]}"
end
if options[:wait2]
start_command << " --wait2 #{options[:wait2]}"
end
new_options = {
:identifier => 'My Test Daemon',
:start_command => start_command,
:ping_command => proc do
begin
TCPSocket.new(localhost, 3230)
true
rescue
false
end
end,
:pid_file => 'echo_server.pid',
:log_file => 'echo_server.log'
}.merge(options)
@controller = DaemonController.new(new_options)
end
def write_file(filename, contents)
File.open(filename, 'w') do |f|
f.write(contents)
end
end
end
describe DaemonController, "#start" do
before :each do
new_controller
end
include TestHelpers
it "raises AlreadyStarted if the daemon is already running" do
@controller.should_receive(:daemon_is_running?).and_return(true)
lambda { @controller.start }.should raise_error(DaemonController::AlreadyStarted)
end
it "deletes existing PID file before starting the daemon" do
write_file('echo_server.pid', '1234')
@controller.should_receive(:daemon_is_running?).and_return(false)
@controller.should_receive(:spawn_daemon)
@controller.should_receive(:wait_until_pid_file_is_available)
@controller.should_receive(:wait_until_daemon_responds_to_ping_or_has_exited).and_return(true)
@controller.start
File.exist?('echo_server.pid').should be_false
end
it "blocks until the daemon has written to its PID file" do
thread = WaitingThread.new do
sleep 0.15
write_file('echo_server.pid', '1234')
end
@controller.should_receive(:daemon_is_running?).and_return(false)
@controller.should_receive(:spawn_daemon).and_return do
thread.go!
end
@controller.should_receive(:wait_until_daemon_responds_to_ping_or_has_exited).and_return(true)
begin
result = Benchmark.measure do
@controller.start
end
(0.15 .. 0.30).should === result.real
ensure
thread.join
end
end
it "blocks until the daemon can be pinged" do
ping_ok = false
running = false
new_controller(:ping_command => lambda { ping_ok })
thread = WaitingThread.new do
sleep 0.15
ping_ok = true
end
@controller.should_receive(:daemon_is_running?).at_least(:once).and_return do
running
end
@controller.should_receive(:spawn_daemon).and_return do
thread.go!
running = true
end
@controller.should_receive(:wait_until_pid_file_is_available)
begin
result = Benchmark.measure do
@controller.start
end
(0.15 .. 0.30).should === result.real
ensure
thread.join
end
end
it "raises StartTimeout if the daemon doesn't start in time"
it "raises StartError if the daemon exits with an error before forking"
it "raises StartError if the daemon exits with an error after forking"
specify "the daemon's error output before forking is made available in the exception"
specify "the daemon's error output after forking is made available in the exception"
it "waits until no other process is starting, stopping or reading process information from a daemon with the same identifier"
describe "if ping command a command" do
it "checks whether the ping command exits with 0 to check whether the server can be pinged"
it "raises an exception with the ping command's error message if the ping command exits with non-0"
end
describe "if ping command is a proc" do
it "calls the ping proc to check whether the server can be pinged"
it "forwards exceptions raised by the ping proc"
end
end
describe DaemonController, "#stop" do
it "raises no exception if the daemon is not running"
it "waits until no other process is starting, stopping or reading process information from a daemon with the same identifier"
describe "if stop command was given" do
it "kills the daemon with the stop command"
it "raises an error if the stop command exits with an error"
it "makes the stop command's error message available in the exception"
end
describe "if no stop command was given" do
it "kills the daemon by sending the pid in the pid file a signal"
it "raises StopError if the daemon cannot be signalled"
end
end
describe DaemonController, "#connect" do
end
describe DaemonController, "#running?" do
end
describe DaemonController, "#pid" do
end