mcproc 2016.2.20
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.
- checksums.yaml +7 -0
- data/Announce.txt +135 -0
- data/Gemfile +9 -0
- data/History.txt +469 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +185 -0
- data/TODO.md +37 -0
- data/bin/mcproc +134 -0
- data/doc/intro.asciidoc +20 -0
- data/doc/mcproc.asciidoc +1592 -0
- data/ext/god/.gitignore +5 -0
- data/ext/god/extconf.rb +56 -0
- data/ext/god/kqueue_handler.c +133 -0
- data/ext/god/netlink_handler.c +182 -0
- data/lib/god.rb +780 -0
- data/lib/god/behavior.rb +52 -0
- data/lib/god/behaviors/clean_pid_file.rb +21 -0
- data/lib/god/behaviors/clean_unix_socket.rb +21 -0
- data/lib/god/behaviors/notify_when_flapping.rb +51 -0
- data/lib/god/cli/command.rb +268 -0
- data/lib/god/cli/run.rb +170 -0
- data/lib/god/cli/version.rb +23 -0
- data/lib/god/compat19.rb +33 -0
- data/lib/god/condition.rb +96 -0
- data/lib/god/conditions/always.rb +36 -0
- data/lib/god/conditions/complex.rb +86 -0
- data/lib/god/conditions/cpu_usage.rb +80 -0
- data/lib/god/conditions/degrading_lambda.rb +52 -0
- data/lib/god/conditions/disk_usage.rb +32 -0
- data/lib/god/conditions/file_mtime.rb +28 -0
- data/lib/god/conditions/file_touched.rb +44 -0
- data/lib/god/conditions/flapping.rb +128 -0
- data/lib/god/conditions/http_response_code.rb +184 -0
- data/lib/god/conditions/lambda.rb +25 -0
- data/lib/god/conditions/memory_usage.rb +82 -0
- data/lib/god/conditions/process_exits.rb +66 -0
- data/lib/god/conditions/process_running.rb +63 -0
- data/lib/god/conditions/socket_responding.rb +142 -0
- data/lib/god/conditions/tries.rb +44 -0
- data/lib/god/configurable.rb +57 -0
- data/lib/god/contact.rb +114 -0
- data/lib/god/contacts/airbrake.rb +44 -0
- data/lib/god/contacts/campfire.rb +121 -0
- data/lib/god/contacts/email.rb +130 -0
- data/lib/god/contacts/hipchat.rb +117 -0
- data/lib/god/contacts/jabber.rb +75 -0
- data/lib/god/contacts/prowl.rb +57 -0
- data/lib/god/contacts/scout.rb +55 -0
- data/lib/god/contacts/sensu.rb +59 -0
- data/lib/god/contacts/slack.rb +98 -0
- data/lib/god/contacts/statsd.rb +46 -0
- data/lib/god/contacts/twitter.rb +51 -0
- data/lib/god/contacts/webhook.rb +74 -0
- data/lib/god/driver.rb +238 -0
- data/lib/god/errors.rb +24 -0
- data/lib/god/event_handler.rb +112 -0
- data/lib/god/event_handlers/dummy_handler.rb +13 -0
- data/lib/god/event_handlers/kqueue_handler.rb +17 -0
- data/lib/god/event_handlers/netlink_handler.rb +13 -0
- data/lib/god/logger.rb +109 -0
- data/lib/god/metric.rb +87 -0
- data/lib/god/process.rb +381 -0
- data/lib/god/registry.rb +32 -0
- data/lib/god/simple_logger.rb +59 -0
- data/lib/god/socket.rb +113 -0
- data/lib/god/sugar.rb +62 -0
- data/lib/god/sys_logger.rb +45 -0
- data/lib/god/system/portable_poller.rb +42 -0
- data/lib/god/system/process.rb +50 -0
- data/lib/god/system/slash_proc_poller.rb +92 -0
- data/lib/god/task.rb +552 -0
- data/lib/god/timeline.rb +25 -0
- data/lib/god/trigger.rb +43 -0
- data/lib/god/watch.rb +340 -0
- data/mcproc.gemspec +192 -0
- data/test/configs/child_events/child_events.god +44 -0
- data/test/configs/child_events/simple_server.rb +3 -0
- data/test/configs/child_polls/child_polls.god +37 -0
- data/test/configs/child_polls/simple_server.rb +12 -0
- data/test/configs/complex/complex.god +59 -0
- data/test/configs/complex/simple_server.rb +3 -0
- data/test/configs/contact/contact.god +118 -0
- data/test/configs/contact/simple_server.rb +3 -0
- data/test/configs/daemon_events/daemon_events.god +37 -0
- data/test/configs/daemon_events/simple_server.rb +8 -0
- data/test/configs/daemon_events/simple_server_stop.rb +11 -0
- data/test/configs/daemon_polls/daemon_polls.god +17 -0
- data/test/configs/daemon_polls/simple_server.rb +6 -0
- data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
- data/test/configs/degrading_lambda/tcp_server.rb +15 -0
- data/test/configs/keepalive/keepalive.god +9 -0
- data/test/configs/keepalive/keepalive.rb +12 -0
- data/test/configs/lifecycle/lifecycle.god +25 -0
- data/test/configs/matias/matias.god +50 -0
- data/test/configs/real.rb +59 -0
- data/test/configs/running_load/running_load.god +16 -0
- data/test/configs/stop_options/simple_server.rb +12 -0
- data/test/configs/stop_options/stop_options.god +39 -0
- data/test/configs/stress/simple_server.rb +3 -0
- data/test/configs/stress/stress.god +15 -0
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +26 -0
- data/test/configs/test.rb +61 -0
- data/test/configs/usr1_trapper.rb +10 -0
- data/test/helper.rb +172 -0
- data/test/suite.rb +6 -0
- data/test/test_airbrake.rb +14 -0
- data/test/test_behavior.rb +18 -0
- data/test/test_campfire.rb +22 -0
- data/test/test_condition.rb +52 -0
- data/test/test_conditions_disk_usage.rb +50 -0
- data/test/test_conditions_http_response_code.rb +109 -0
- data/test/test_conditions_process_running.rb +40 -0
- data/test/test_conditions_socket_responding.rb +176 -0
- data/test/test_conditions_tries.rb +67 -0
- data/test/test_contact.rb +109 -0
- data/test/test_driver.rb +26 -0
- data/test/test_email.rb +34 -0
- data/test/test_event_handler.rb +82 -0
- data/test/test_god.rb +710 -0
- data/test/test_god_system.rb +201 -0
- data/test/test_handlers_kqueue_handler.rb +16 -0
- data/test/test_hipchat.rb +23 -0
- data/test/test_jabber.rb +29 -0
- data/test/test_logger.rb +55 -0
- data/test/test_metric.rb +74 -0
- data/test/test_process.rb +263 -0
- data/test/test_prowl.rb +15 -0
- data/test/test_registry.rb +15 -0
- data/test/test_sensu.rb +11 -0
- data/test/test_slack.rb +57 -0
- data/test/test_socket.rb +34 -0
- data/test/test_statsd.rb +22 -0
- data/test/test_sugar.rb +42 -0
- data/test/test_system_portable_poller.rb +17 -0
- data/test/test_system_process.rb +30 -0
- data/test/test_task.rb +246 -0
- data/test/test_timeline.rb +37 -0
- data/test/test_trigger.rb +63 -0
- data/test/test_watch.rb +286 -0
- data/test/test_webhook.rb +22 -0
- metadata +475 -0
@@ -0,0 +1,201 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestGodSystem < MiniTest::Test
|
4
|
+
def assert_watch_running(watch_name)
|
5
|
+
assert_equal true, God.watches[watch_name].alive?
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_god_cleanup
|
9
|
+
old_terminate = God.method(:terminate)
|
10
|
+
# necessary cuz actual god terminate will do exit(0) will stops tests
|
11
|
+
God.class_eval do
|
12
|
+
def self.terminate
|
13
|
+
FileUtils.rm_f(self.pid) if self.pid
|
14
|
+
self.server.stop if self.server
|
15
|
+
end
|
16
|
+
end
|
17
|
+
begin
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
God.stop_all
|
21
|
+
God.terminate # use our monkeypatched terminate
|
22
|
+
God.watches.each do |name, w|
|
23
|
+
w.stop_signal = 'KILL'
|
24
|
+
w.action(:stop)
|
25
|
+
end
|
26
|
+
God.inited = false
|
27
|
+
God.terminate_timeout = ::God::TERMINATE_TIMEOUT_DEFAULT
|
28
|
+
God.internal_init # reset config, set running to false, etc.
|
29
|
+
# set termiante back to old method, for other tests
|
30
|
+
God.define_singleton_method(:terminate, old_terminate)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_start_running
|
35
|
+
with_god_cleanup do
|
36
|
+
God.start
|
37
|
+
assert_equal(God.running, true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_add_watch
|
42
|
+
with_god_cleanup do
|
43
|
+
God.start
|
44
|
+
God.watch do |w|
|
45
|
+
w.name = 'add_watch'
|
46
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
47
|
+
end
|
48
|
+
assert God.watches['add_watch'] != nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_start_watch
|
53
|
+
with_god_cleanup do
|
54
|
+
God.start
|
55
|
+
God.watch do |w|
|
56
|
+
w.name = 'start_watch'
|
57
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
58
|
+
end
|
59
|
+
God.watches['start_watch'].action(:start)
|
60
|
+
sleep 2
|
61
|
+
assert_equal true, God.watches['start_watch'].alive?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_start_watch
|
66
|
+
with_god_cleanup do
|
67
|
+
God.start
|
68
|
+
God.watch do |w|
|
69
|
+
w.name = 'start_watch'
|
70
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
71
|
+
end
|
72
|
+
God.watches['start_watch'].action(:start)
|
73
|
+
sleep 2
|
74
|
+
assert_equal true, God.watches['start_watch'].alive?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_stop_all_with_one
|
79
|
+
with_god_cleanup do
|
80
|
+
God.start
|
81
|
+
God.watch do |w|
|
82
|
+
w.name = 'start_watch'
|
83
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
84
|
+
end
|
85
|
+
God.watches['start_watch'].action(:start)
|
86
|
+
sleep 2
|
87
|
+
assert_equal true, God.watches['start_watch'].alive?
|
88
|
+
God.stop_all
|
89
|
+
assert_equal false, God.watches.any? { |name, w| w.alive? }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# default 10s timeout will expire before SIGKILL sent
|
94
|
+
def test_stop_all_with_non_killing_signal_long_timeout
|
95
|
+
with_god_cleanup do
|
96
|
+
God.start
|
97
|
+
God.watch do |w|
|
98
|
+
w.name = 'long_timeout'
|
99
|
+
w.stop_signal = 'USR1'
|
100
|
+
w.stop_timeout = ::God::STOP_TIMEOUT_DEFAULT + 1
|
101
|
+
w.start = File.join(GOD_ROOT, *%w[test configs usr1_trapper.rb])
|
102
|
+
end
|
103
|
+
God.watches['long_timeout'].action(:start)
|
104
|
+
sleep 2
|
105
|
+
assert_equal true, God.watches['long_timeout'].alive?
|
106
|
+
God.stop_all
|
107
|
+
assert_watch_running('long_timeout')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# use short timeout to send SIGKILL before 10s timeout
|
112
|
+
def test_stop_all_with_non_killing_signal_short_timeout
|
113
|
+
with_god_cleanup do
|
114
|
+
God.start
|
115
|
+
God.watch do |w|
|
116
|
+
w.name = 'short_timeout'
|
117
|
+
w.stop_signal = 'USR1'
|
118
|
+
w.stop_timeout = ::God::STOP_TIMEOUT_DEFAULT - 1
|
119
|
+
w.start = File.join(GOD_ROOT, *%w[test configs usr1_trapper.rb])
|
120
|
+
end
|
121
|
+
God.watches['short_timeout'].action(:start)
|
122
|
+
sleep 2
|
123
|
+
assert_equal true, God.watches['short_timeout'].alive?
|
124
|
+
God.stop_all
|
125
|
+
assert_equal false, God.watches.any? { |name, w| w.alive? }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# should be able to stop many simple watches within default timeout
|
130
|
+
def test_stop_all_with_many_watches
|
131
|
+
with_god_cleanup do
|
132
|
+
God.start
|
133
|
+
20.times do |i|
|
134
|
+
God.watch do |w|
|
135
|
+
w.name = "many_watches_#{i}"
|
136
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
137
|
+
end
|
138
|
+
God.watches["many_watches_#{i}"].action(:start)
|
139
|
+
end
|
140
|
+
while true do
|
141
|
+
all_running = God.watches.select{ |name, w| name =~ /many_watches_/ }.all?{ |name, w| w.alive? }
|
142
|
+
size = God.watches.size
|
143
|
+
break if all_running && size >= 20
|
144
|
+
sleep 2
|
145
|
+
end
|
146
|
+
God.stop_all
|
147
|
+
assert_equal false, God.watches.any? { |name, w| w.alive? }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# should be able to stop many simple watches within short timeout
|
152
|
+
def test_stop_all_with_many_watches_short_timeout
|
153
|
+
with_god_cleanup do
|
154
|
+
God.start
|
155
|
+
God.terminate_timeout = 1
|
156
|
+
100.times do |i|
|
157
|
+
God.watch do |w|
|
158
|
+
w.name = "tons_of_watches_#{i}"
|
159
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
160
|
+
w.keepalive
|
161
|
+
end
|
162
|
+
God.watches["tons_of_watches_#{i}"].action(:start)
|
163
|
+
end
|
164
|
+
while true do
|
165
|
+
all_running = God.watches.select{ |name, w| name =~ /tons_of_watches_/ }.all?{ |name, w| w.alive? }
|
166
|
+
size = God.watches.size
|
167
|
+
break if all_running && size >= 100
|
168
|
+
sleep 2
|
169
|
+
end
|
170
|
+
God.stop_all
|
171
|
+
assert_equal false, God.watches.any? { |name, w| w.alive? }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_god_terminate_with_many_watches_short_timeout
|
176
|
+
with_god_cleanup do
|
177
|
+
God.start
|
178
|
+
God.terminate_timeout = 1
|
179
|
+
100.times do |i|
|
180
|
+
God.watch do |w|
|
181
|
+
w.name = "tons_of_watches_#{i}"
|
182
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
183
|
+
w.keepalive
|
184
|
+
end
|
185
|
+
God.watches["tons_of_watches_#{i}"].action(:start)
|
186
|
+
end
|
187
|
+
while true do
|
188
|
+
all_running = God.watches.select{ |name, w| name =~ /tons_of_watches_/ }.all?{ |name, w| w.alive? }
|
189
|
+
size = God.watches.size
|
190
|
+
break if all_running && size >= 100
|
191
|
+
sleep 2
|
192
|
+
end
|
193
|
+
begin
|
194
|
+
God::CLI::Command.new('terminate', {port: 17165}, [])
|
195
|
+
rescue SystemExit
|
196
|
+
ensure
|
197
|
+
assert_equal false, God.watches.any? { |name, w| w.alive? }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
if God::EventHandler.event_system == "kqueue"
|
4
|
+
|
5
|
+
class TestHandlersKqueueHandler < Minitest::Test
|
6
|
+
def test_register_process
|
7
|
+
KQueueHandler.expects(:monitor_process).with(1234, 2147483648)
|
8
|
+
KQueueHandler.register_process(1234, [:proc_exit])
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_events_mask
|
12
|
+
assert_equal 2147483648, KQueueHandler.events_mask([:proc_exit])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestHipchat < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@hipchat = God::Contacts::Hipchat.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_exists
|
9
|
+
God::Contacts::Hipchat
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_notify
|
13
|
+
@hipchat.token = 'ee64d6e2337310af'
|
14
|
+
@hipchat.ssl = 'true'
|
15
|
+
@hipchat.room = 'testroom'
|
16
|
+
@hipchat.from = 'test'
|
17
|
+
|
18
|
+
time = Time.now
|
19
|
+
body = "[#{time.strftime('%H:%M:%S')}] host - msg"
|
20
|
+
Marshmallow::Connection.any_instance.expects(:speak).with('testroom', body)
|
21
|
+
@hipchat.notify('msg', time, 'prio', 'cat', 'host')
|
22
|
+
end
|
23
|
+
end
|
data/test/test_jabber.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/helper'
|
3
|
+
|
4
|
+
class TestJabber < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@jabber = God::Contacts::Jabber.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_notify
|
11
|
+
@jabber.host = 'talk.google.com'
|
12
|
+
@jabber.from_jid = 'god@jabber.org'
|
13
|
+
@jabber.password = 'secret'
|
14
|
+
@jabber.to_jid = 'dev@jabber.org'
|
15
|
+
|
16
|
+
time = Time.now
|
17
|
+
body = God::Contacts::Jabber.format.call('msg', time, 'prio', 'cat', 'host')
|
18
|
+
|
19
|
+
assert_equal "Message: msg\nHost: host\nPriority: prio\nCategory: cat\n", body
|
20
|
+
|
21
|
+
Jabber::Client.any_instance.expects(:connect).with('talk.google.com', 5222)
|
22
|
+
Jabber::Client.any_instance.expects(:auth).with('secret')
|
23
|
+
Jabber::Client.any_instance.expects(:send)
|
24
|
+
Jabber::Client.any_instance.expects(:close)
|
25
|
+
|
26
|
+
@jabber.notify('msg', Time.now, 'prio', 'cat', 'host')
|
27
|
+
assert_equal "sent jabber message to dev@jabber.org", @jabber.info
|
28
|
+
end
|
29
|
+
end
|
data/test/test_logger.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestLogger < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@log = God::Logger.new(StringIO.new('/dev/null'))
|
6
|
+
end
|
7
|
+
|
8
|
+
# log
|
9
|
+
|
10
|
+
def test_log_should_keep_logs_when_wanted
|
11
|
+
@log.watch_log_since('foo', Time.now)
|
12
|
+
@log.expects(:info).with("qux")
|
13
|
+
|
14
|
+
@log.log(stub(:name => 'foo'), :info, "qux")
|
15
|
+
|
16
|
+
assert_equal 1, @log.logs.size
|
17
|
+
assert_instance_of Time, @log.logs['foo'][0][0]
|
18
|
+
assert_match(/qux/, @log.logs['foo'][0][1])
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_log_should_send_to_syslog
|
22
|
+
SysLogger.expects(:log).with(:fatal, 'foo')
|
23
|
+
@log.log(stub(:name => 'foo'), :fatal, "foo")
|
24
|
+
end
|
25
|
+
|
26
|
+
# watch_log_since
|
27
|
+
|
28
|
+
def test_watch_log_since
|
29
|
+
t1 = Time.now
|
30
|
+
|
31
|
+
@log.watch_log_since('foo', t1)
|
32
|
+
|
33
|
+
@log.log(stub(:name => 'foo'), :info, "one")
|
34
|
+
@log.log(stub(:name => 'foo'), :info, "two")
|
35
|
+
|
36
|
+
assert_match(/one.*two/m, @log.watch_log_since('foo', t1))
|
37
|
+
|
38
|
+
t2 = Time.now
|
39
|
+
|
40
|
+
@log.log(stub(:name => 'foo'), :info, "three")
|
41
|
+
|
42
|
+
out = @log.watch_log_since('foo', t2)
|
43
|
+
|
44
|
+
assert(/one/ !~ out)
|
45
|
+
assert(/two/ !~ out)
|
46
|
+
assert_match(/three/, out)
|
47
|
+
end
|
48
|
+
|
49
|
+
# regular methods
|
50
|
+
|
51
|
+
def test_fatal
|
52
|
+
@log.fatal('foo')
|
53
|
+
assert_equal 0, @log.logs.size
|
54
|
+
end
|
55
|
+
end
|
data/test/test_metric.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestMetric < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@metric = Metric.new(stub(:interval => 10), nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
# watch
|
9
|
+
|
10
|
+
def test_watch
|
11
|
+
w = stub()
|
12
|
+
m = Metric.new(w, nil)
|
13
|
+
assert_equal w, m.watch
|
14
|
+
end
|
15
|
+
|
16
|
+
# destination
|
17
|
+
|
18
|
+
def test_destination
|
19
|
+
d = stub()
|
20
|
+
m = Metric.new(nil, d)
|
21
|
+
assert_equal d, m.destination
|
22
|
+
end
|
23
|
+
|
24
|
+
# condition
|
25
|
+
|
26
|
+
def test_condition_should_be_block_optional
|
27
|
+
@metric.condition(:fake_poll_condition)
|
28
|
+
assert_equal 1, @metric.conditions.size
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_poll_condition_should_inherit_interval_from_watch_if_not_specified
|
32
|
+
@metric.condition(:fake_poll_condition)
|
33
|
+
assert_equal 10, @metric.conditions.first.interval
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_poll_condition_should_abort_if_no_interval_and_no_watch_interval
|
37
|
+
metric = Metric.new(stub(:name => 'foo', :interval => nil), nil)
|
38
|
+
|
39
|
+
assert_abort do
|
40
|
+
metric.condition(:fake_poll_condition)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# This doesn't currently work:
|
45
|
+
#
|
46
|
+
# def test_condition_should_allow_generation_of_subclasses_of_poll_or_event
|
47
|
+
# metric = Metric.new(stub(:name => 'foo', :interval => 10), nil)
|
48
|
+
#
|
49
|
+
# assert_nothing_raised do
|
50
|
+
# metric.condition(:fake_poll_condition)
|
51
|
+
# metric.condition(:fake_event_condition)
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
|
55
|
+
def test_condition_should_abort_if_not_subclass_of_poll_or_event
|
56
|
+
metric = Metric.new(stub(:name => 'foo', :interval => 10), nil)
|
57
|
+
|
58
|
+
assert_abort do
|
59
|
+
metric.condition(:fake_condition) { |c| }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_condition_should_abort_on_invalid_condition
|
64
|
+
assert_abort do
|
65
|
+
@metric.condition(:fake_poll_condition) { |c| c.stubs(:valid?).returns(false) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_condition_should_abort_on_no_such_condition
|
70
|
+
assert_abort do
|
71
|
+
@metric.condition(:invalid) { }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
module God
|
4
|
+
class Process
|
5
|
+
# def fork
|
6
|
+
# raise "You forgot to stub fork"
|
7
|
+
# end
|
8
|
+
|
9
|
+
def exec(*args)
|
10
|
+
raise "You forgot to stub exec"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestProcessChild < Minitest::Test
|
16
|
+
def setup
|
17
|
+
God.internal_init
|
18
|
+
@p = God::Process.new
|
19
|
+
@p.name = 'foo'
|
20
|
+
@p.stubs(:test).returns true # so we don't try to mkdir_p
|
21
|
+
Process.stubs(:detach) # because we stub fork
|
22
|
+
|
23
|
+
::Process::Sys.stubs(:setuid).returns(true)
|
24
|
+
::Process::Sys.stubs(:setgid).returns(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
# valid?
|
28
|
+
|
29
|
+
def test_valid_should_return_true_if_auto_daemonized_and_log
|
30
|
+
@p.start = 'qux'
|
31
|
+
@p.log = 'bar'
|
32
|
+
|
33
|
+
assert @p.valid?
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_valid_should_return_true_if_auto_daemonized_and_no_stop
|
37
|
+
@p.start = 'qux'
|
38
|
+
@p.log = 'bar'
|
39
|
+
|
40
|
+
assert @p.valid?
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_valid_should_return_true_if_uid_exists
|
44
|
+
@p.start = 'qux'
|
45
|
+
@p.log = '/tmp/foo.log'
|
46
|
+
@p.uid = 'root'
|
47
|
+
|
48
|
+
::Process.stubs(:groups=)
|
49
|
+
::Process.stubs(:initgroups)
|
50
|
+
|
51
|
+
assert @p.valid?
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_valid_should_return_true_if_uid_does_not_exists
|
55
|
+
@p.start = 'qux'
|
56
|
+
@p.log = '/tmp/foo.log'
|
57
|
+
@p.uid = 'foobarbaz'
|
58
|
+
|
59
|
+
assert !@p.valid?
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_valid_should_return_true_if_gid_exists
|
63
|
+
@p.start = 'qux'
|
64
|
+
@p.log = '/tmp/foo.log'
|
65
|
+
@p.gid = Etc.getgrgid(::Process.gid).name
|
66
|
+
|
67
|
+
::Process.stubs(:groups=)
|
68
|
+
|
69
|
+
assert @p.valid?
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_valid_should_return_false_if_gid_does_not_exists
|
73
|
+
@p.start = 'qux'
|
74
|
+
@p.log = '/tmp/foo.log'
|
75
|
+
@p.gid = 'foobarbaz'
|
76
|
+
|
77
|
+
assert !@p.valid?
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_valid_should_return_true_if_dir_exists
|
81
|
+
@p.start = 'qux'
|
82
|
+
@p.log = '/tmp/foo.log'
|
83
|
+
@p.dir = '/tmp'
|
84
|
+
|
85
|
+
assert @p.valid?
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_valid_should_return_false_if_dir_does_not_exists
|
89
|
+
@p.start = 'qux'
|
90
|
+
@p.log = '/tmp/foo.log'
|
91
|
+
@p.dir = '/tmp/doesnotexist'
|
92
|
+
|
93
|
+
assert !@p.valid?
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_valid_should_return_false_if_dir_is_not_a_dir
|
97
|
+
@p.start = 'qux'
|
98
|
+
@p.log = '/tmp/foo.log'
|
99
|
+
@p.dir = '/etc/passwd'
|
100
|
+
|
101
|
+
assert !@p.valid?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_valid_should_return_false_with_bogus_chroot
|
105
|
+
@p.chroot = '/bogusroot'
|
106
|
+
|
107
|
+
assert !@p.valid?
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_valid_should_return_true_with_chroot_and_valid_log
|
111
|
+
@p.start = 'qux'
|
112
|
+
@p.chroot = Dir.pwd
|
113
|
+
@p.log = "#{@p.chroot}/foo.log"
|
114
|
+
|
115
|
+
File.expects(:exist?).with(@p.chroot).returns(true)
|
116
|
+
File.expects(:exist?).with(@p.log).returns(true)
|
117
|
+
File.expects(:exist?).with("#{@p.chroot}/dev/null").returns(true)
|
118
|
+
|
119
|
+
File.stubs(:writable?).with('/foo.log').returns(true)
|
120
|
+
|
121
|
+
::Dir.stubs(:chroot)
|
122
|
+
|
123
|
+
assert @p.valid?
|
124
|
+
end
|
125
|
+
|
126
|
+
# call_action
|
127
|
+
|
128
|
+
def test_call_action_should_write_pid
|
129
|
+
# Only for start, restart
|
130
|
+
[:start, :restart].each do |action|
|
131
|
+
@p.stubs(:test).returns true
|
132
|
+
IO.expects(:pipe).returns([StringIO.new('1234'), StringIO.new])
|
133
|
+
@p.expects(:fork)
|
134
|
+
Process.expects(:waitpid)
|
135
|
+
File.expects(:open).with(@p.default_pid_file, 'w')
|
136
|
+
@p.send("#{action}=", "run")
|
137
|
+
@p.call_action(action)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
###############################################################################
|
143
|
+
#
|
144
|
+
# Daemon
|
145
|
+
#
|
146
|
+
###############################################################################
|
147
|
+
|
148
|
+
class TestProcessDaemon < Minitest::Test
|
149
|
+
def setup
|
150
|
+
God.internal_init
|
151
|
+
@p = God::Process.new
|
152
|
+
@p.name = 'foo'
|
153
|
+
@p.pid_file = 'blah.pid'
|
154
|
+
@p.stubs(:test).returns true # so we don't try to mkdir_p
|
155
|
+
God::System::Process.stubs(:fetch_system_poller).returns(God::System::PortablePoller)
|
156
|
+
Process.stubs(:detach) # because we stub fork
|
157
|
+
end
|
158
|
+
|
159
|
+
# alive?
|
160
|
+
|
161
|
+
def test_alive_should_call_system_process_exists
|
162
|
+
File.expects(:read).with('blah.pid').times(2).returns('1234')
|
163
|
+
System::Process.any_instance.expects(:exists?).returns(false)
|
164
|
+
assert !@p.alive?
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_alive_should_return_false_if_no_such_file
|
168
|
+
File.expects(:read).with('blah.pid').raises(Errno::ENOENT)
|
169
|
+
assert !@p.alive?
|
170
|
+
end
|
171
|
+
|
172
|
+
# valid?
|
173
|
+
|
174
|
+
def test_valid_should_return_false_if_no_start
|
175
|
+
@p.name = 'foo'
|
176
|
+
@p.stop = 'baz'
|
177
|
+
assert !@p.valid?
|
178
|
+
end
|
179
|
+
|
180
|
+
# pid
|
181
|
+
|
182
|
+
def test_pid_should_return_integer_for_valid_pid_files
|
183
|
+
File.stubs(:read).returns("123")
|
184
|
+
assert_equal 123, @p.pid
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_pid_should_return_nil_for_missing_files
|
188
|
+
@p.pid_file = ''
|
189
|
+
assert_equal nil, @p.pid
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_pid_should_return_nil_for_invalid_pid_files
|
193
|
+
File.stubs(:read).returns("four score and seven years ago")
|
194
|
+
assert_equal nil, @p.pid
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_pid_should_retain_last_pid_value_if_pid_file_is_removed
|
198
|
+
File.stubs(:read).returns("123")
|
199
|
+
assert_equal 123, @p.pid
|
200
|
+
|
201
|
+
File.stubs(:read).raises(Errno::ENOENT)
|
202
|
+
assert_equal 123, @p.pid
|
203
|
+
|
204
|
+
File.stubs(:read).returns("246")
|
205
|
+
assert_equal 246, @p.pid
|
206
|
+
end
|
207
|
+
|
208
|
+
# default_pid_file
|
209
|
+
|
210
|
+
def test_default_pid_file
|
211
|
+
assert_equal File.join(God.pid_file_directory, 'foo.pid'), @p.default_pid_file
|
212
|
+
end
|
213
|
+
|
214
|
+
# unix socket
|
215
|
+
|
216
|
+
def test_unix_socket_should_return_path_specified
|
217
|
+
@p.unix_socket = '/path/to-socket'
|
218
|
+
assert_equal '/path/to-socket', @p.unix_socket
|
219
|
+
end
|
220
|
+
|
221
|
+
# umask
|
222
|
+
def test_umask_should_return_umask_specified
|
223
|
+
@p.umask = 002
|
224
|
+
assert_equal 002, @p.umask
|
225
|
+
end
|
226
|
+
|
227
|
+
# call_action
|
228
|
+
# These actually excercise call_action in the back at this point - Kev
|
229
|
+
|
230
|
+
def test_call_action_with_string_should_call_system
|
231
|
+
@p.start = "do something"
|
232
|
+
@p.expects(:fork)
|
233
|
+
Process.expects(:waitpid2).returns([123, 0])
|
234
|
+
@p.call_action(:start)
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_call_action_with_lambda_should_call
|
238
|
+
cmd = lambda { puts "Hi" }
|
239
|
+
cmd.expects(:call)
|
240
|
+
@p.start = cmd
|
241
|
+
@p.call_action(:start)
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_call_action_with_invalid_command_class_should_raise
|
245
|
+
@p.start = 5
|
246
|
+
@p.stop = 'baz'
|
247
|
+
|
248
|
+
assert @p.valid?
|
249
|
+
|
250
|
+
assert_raises NotImplementedError do
|
251
|
+
@p.call_action(:start)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# start!/stop!/restart!
|
256
|
+
|
257
|
+
def test_start_stop_restart_bang
|
258
|
+
[:start, :stop, :restart].each do |x|
|
259
|
+
@p.expects(:call_action).with(x)
|
260
|
+
@p.send("#{x}!")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|