mcproc 2016.2.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/Announce.txt +135 -0
  3. data/Gemfile +9 -0
  4. data/History.txt +469 -0
  5. data/LICENSE +22 -0
  6. data/README.md +37 -0
  7. data/Rakefile +185 -0
  8. data/TODO.md +37 -0
  9. data/bin/mcproc +134 -0
  10. data/doc/intro.asciidoc +20 -0
  11. data/doc/mcproc.asciidoc +1592 -0
  12. data/ext/god/.gitignore +5 -0
  13. data/ext/god/extconf.rb +56 -0
  14. data/ext/god/kqueue_handler.c +133 -0
  15. data/ext/god/netlink_handler.c +182 -0
  16. data/lib/god.rb +780 -0
  17. data/lib/god/behavior.rb +52 -0
  18. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  19. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  20. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  21. data/lib/god/cli/command.rb +268 -0
  22. data/lib/god/cli/run.rb +170 -0
  23. data/lib/god/cli/version.rb +23 -0
  24. data/lib/god/compat19.rb +33 -0
  25. data/lib/god/condition.rb +96 -0
  26. data/lib/god/conditions/always.rb +36 -0
  27. data/lib/god/conditions/complex.rb +86 -0
  28. data/lib/god/conditions/cpu_usage.rb +80 -0
  29. data/lib/god/conditions/degrading_lambda.rb +52 -0
  30. data/lib/god/conditions/disk_usage.rb +32 -0
  31. data/lib/god/conditions/file_mtime.rb +28 -0
  32. data/lib/god/conditions/file_touched.rb +44 -0
  33. data/lib/god/conditions/flapping.rb +128 -0
  34. data/lib/god/conditions/http_response_code.rb +184 -0
  35. data/lib/god/conditions/lambda.rb +25 -0
  36. data/lib/god/conditions/memory_usage.rb +82 -0
  37. data/lib/god/conditions/process_exits.rb +66 -0
  38. data/lib/god/conditions/process_running.rb +63 -0
  39. data/lib/god/conditions/socket_responding.rb +142 -0
  40. data/lib/god/conditions/tries.rb +44 -0
  41. data/lib/god/configurable.rb +57 -0
  42. data/lib/god/contact.rb +114 -0
  43. data/lib/god/contacts/airbrake.rb +44 -0
  44. data/lib/god/contacts/campfire.rb +121 -0
  45. data/lib/god/contacts/email.rb +130 -0
  46. data/lib/god/contacts/hipchat.rb +117 -0
  47. data/lib/god/contacts/jabber.rb +75 -0
  48. data/lib/god/contacts/prowl.rb +57 -0
  49. data/lib/god/contacts/scout.rb +55 -0
  50. data/lib/god/contacts/sensu.rb +59 -0
  51. data/lib/god/contacts/slack.rb +98 -0
  52. data/lib/god/contacts/statsd.rb +46 -0
  53. data/lib/god/contacts/twitter.rb +51 -0
  54. data/lib/god/contacts/webhook.rb +74 -0
  55. data/lib/god/driver.rb +238 -0
  56. data/lib/god/errors.rb +24 -0
  57. data/lib/god/event_handler.rb +112 -0
  58. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  59. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  60. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  61. data/lib/god/logger.rb +109 -0
  62. data/lib/god/metric.rb +87 -0
  63. data/lib/god/process.rb +381 -0
  64. data/lib/god/registry.rb +32 -0
  65. data/lib/god/simple_logger.rb +59 -0
  66. data/lib/god/socket.rb +113 -0
  67. data/lib/god/sugar.rb +62 -0
  68. data/lib/god/sys_logger.rb +45 -0
  69. data/lib/god/system/portable_poller.rb +42 -0
  70. data/lib/god/system/process.rb +50 -0
  71. data/lib/god/system/slash_proc_poller.rb +92 -0
  72. data/lib/god/task.rb +552 -0
  73. data/lib/god/timeline.rb +25 -0
  74. data/lib/god/trigger.rb +43 -0
  75. data/lib/god/watch.rb +340 -0
  76. data/mcproc.gemspec +192 -0
  77. data/test/configs/child_events/child_events.god +44 -0
  78. data/test/configs/child_events/simple_server.rb +3 -0
  79. data/test/configs/child_polls/child_polls.god +37 -0
  80. data/test/configs/child_polls/simple_server.rb +12 -0
  81. data/test/configs/complex/complex.god +59 -0
  82. data/test/configs/complex/simple_server.rb +3 -0
  83. data/test/configs/contact/contact.god +118 -0
  84. data/test/configs/contact/simple_server.rb +3 -0
  85. data/test/configs/daemon_events/daemon_events.god +37 -0
  86. data/test/configs/daemon_events/simple_server.rb +8 -0
  87. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  88. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  89. data/test/configs/daemon_polls/simple_server.rb +6 -0
  90. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  91. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  92. data/test/configs/keepalive/keepalive.god +9 -0
  93. data/test/configs/keepalive/keepalive.rb +12 -0
  94. data/test/configs/lifecycle/lifecycle.god +25 -0
  95. data/test/configs/matias/matias.god +50 -0
  96. data/test/configs/real.rb +59 -0
  97. data/test/configs/running_load/running_load.god +16 -0
  98. data/test/configs/stop_options/simple_server.rb +12 -0
  99. data/test/configs/stop_options/stop_options.god +39 -0
  100. data/test/configs/stress/simple_server.rb +3 -0
  101. data/test/configs/stress/stress.god +15 -0
  102. data/test/configs/task/logs/.placeholder +0 -0
  103. data/test/configs/task/task.god +26 -0
  104. data/test/configs/test.rb +61 -0
  105. data/test/configs/usr1_trapper.rb +10 -0
  106. data/test/helper.rb +172 -0
  107. data/test/suite.rb +6 -0
  108. data/test/test_airbrake.rb +14 -0
  109. data/test/test_behavior.rb +18 -0
  110. data/test/test_campfire.rb +22 -0
  111. data/test/test_condition.rb +52 -0
  112. data/test/test_conditions_disk_usage.rb +50 -0
  113. data/test/test_conditions_http_response_code.rb +109 -0
  114. data/test/test_conditions_process_running.rb +40 -0
  115. data/test/test_conditions_socket_responding.rb +176 -0
  116. data/test/test_conditions_tries.rb +67 -0
  117. data/test/test_contact.rb +109 -0
  118. data/test/test_driver.rb +26 -0
  119. data/test/test_email.rb +34 -0
  120. data/test/test_event_handler.rb +82 -0
  121. data/test/test_god.rb +710 -0
  122. data/test/test_god_system.rb +201 -0
  123. data/test/test_handlers_kqueue_handler.rb +16 -0
  124. data/test/test_hipchat.rb +23 -0
  125. data/test/test_jabber.rb +29 -0
  126. data/test/test_logger.rb +55 -0
  127. data/test/test_metric.rb +74 -0
  128. data/test/test_process.rb +263 -0
  129. data/test/test_prowl.rb +15 -0
  130. data/test/test_registry.rb +15 -0
  131. data/test/test_sensu.rb +11 -0
  132. data/test/test_slack.rb +57 -0
  133. data/test/test_socket.rb +34 -0
  134. data/test/test_statsd.rb +22 -0
  135. data/test/test_sugar.rb +42 -0
  136. data/test/test_system_portable_poller.rb +17 -0
  137. data/test/test_system_process.rb +30 -0
  138. data/test/test_task.rb +246 -0
  139. data/test/test_timeline.rb +37 -0
  140. data/test/test_trigger.rb +63 -0
  141. data/test/test_watch.rb +286 -0
  142. data/test/test_webhook.rb +22 -0
  143. 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
@@ -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
@@ -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
@@ -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