god 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/History.txt +26 -0
  2. data/Manifest.txt +15 -1
  3. data/Rakefile +2 -7
  4. data/bin/god +104 -16
  5. data/lib/god.rb +169 -37
  6. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  7. data/lib/god/condition.rb +1 -0
  8. data/lib/god/conditions/degrading_lambda.rb +47 -0
  9. data/lib/god/conditions/process_exits.rb +6 -2
  10. data/lib/god/conditions/tries.rb +33 -0
  11. data/lib/god/dependency_graph.rb +41 -0
  12. data/lib/god/errors.rb +6 -0
  13. data/lib/god/hub.rb +43 -20
  14. data/lib/god/logger.rb +44 -0
  15. data/lib/god/process.rb +91 -19
  16. data/lib/god/registry.rb +4 -0
  17. data/lib/god/server.rb +12 -2
  18. data/lib/god/timeline.rb +36 -0
  19. data/lib/god/watch.rb +27 -8
  20. data/test/configs/child_events/child_events.god +7 -2
  21. data/test/configs/child_polls/child_polls.god +3 -1
  22. data/test/configs/child_polls/simple_server.rb +1 -1
  23. data/test/configs/daemon_events/daemon_events.god +7 -3
  24. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  25. data/test/configs/daemon_polls/simple_server.rb +6 -0
  26. data/test/configs/degrading_lambda/degrading_lambda.god +33 -0
  27. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  28. data/test/configs/real.rb +1 -1
  29. data/test/configs/running_load/running_load.god +16 -0
  30. data/test/configs/stress/simple_server.rb +3 -0
  31. data/test/configs/stress/stress.god +15 -0
  32. data/test/configs/test.rb +14 -2
  33. data/test/helper.rb +12 -2
  34. data/test/test_conditions_tries.rb +46 -0
  35. data/test/test_dependency_graph.rb +62 -0
  36. data/test/test_god.rb +289 -33
  37. data/test/test_handlers_kqueue_handler.rb +11 -7
  38. data/test/test_hub.rb +18 -0
  39. data/test/test_logger.rb +55 -0
  40. data/test/test_process.rb +135 -17
  41. data/test/test_registry.rb +2 -1
  42. data/test/test_server.rb +35 -4
  43. data/test/test_timeline.rb +14 -2
  44. data/test/test_watch.rb +7 -0
  45. metadata +21 -4
  46. data/lib/god/conditions/timeline.rb +0 -17
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestDependencyGraph < Test::Unit::TestCase
4
+ def setup
5
+ @dg = DependencyGraph.new
6
+ end
7
+
8
+ # new
9
+
10
+ def test_new_should_accept_zero_arguments
11
+ assert @dg.instance_of?(DependencyGraph)
12
+ end
13
+
14
+ # add
15
+
16
+ def test_add_should_create_and_store_two_new_nodes
17
+ @dg.add('foo', 'bar')
18
+ assert_equal 2, @dg.nodes.size
19
+ assert @dg.nodes['foo'].instance_of?(DependencyGraph::Node)
20
+ assert @dg.nodes['bar'].instance_of?(DependencyGraph::Node)
21
+ end
22
+
23
+ def test_add_should_record_dependency
24
+ @dg.add('foo', 'bar')
25
+ assert_equal 1, @dg.nodes['foo'].dependencies.size
26
+ assert_equal @dg.nodes['bar'], @dg.nodes['foo'].dependencies.first
27
+ end
28
+
29
+ def test_add_should_ignore_dups
30
+ @dg.add('foo', 'bar')
31
+ @dg.add('foo', 'bar')
32
+ assert_equal 2, @dg.nodes.size
33
+ assert_equal 1, @dg.nodes['foo'].dependencies.size
34
+ end
35
+ end
36
+
37
+
38
+ class TestDependencyGraphNode < Test::Unit::TestCase
39
+ def setup
40
+ @foo = DependencyGraph::Node.new('foo')
41
+ @bar = DependencyGraph::Node.new('bar')
42
+ end
43
+
44
+ # new
45
+
46
+ def test_new_should_accept_zero_arguments
47
+ assert @foo.instance_of?(DependencyGraph::Node)
48
+ end
49
+
50
+ # add
51
+
52
+ def test_add_should_store_node_as_dependency
53
+ @foo.add(@bar)
54
+ assert_equal 1, @foo.dependencies.size
55
+ end
56
+
57
+ # has_node?
58
+
59
+ def test_has_node
60
+ assert @foo.has_node?(@foo)
61
+ end
62
+ end
data/test/test_god.rb CHANGED
@@ -3,6 +3,8 @@ require File.dirname(__FILE__) + '/helper'
3
3
  class TestGod < Test::Unit::TestCase
4
4
  def setup
5
5
  Server.stubs(:new).returns(true)
6
+ God.stubs(:setup).returns(true)
7
+ God.stubs(:validater).returns(true)
6
8
  God.reset
7
9
  end
8
10
 
@@ -17,18 +19,23 @@ class TestGod < Test::Unit::TestCase
17
19
  assert_equal Hash.new, God.watches
18
20
  end
19
21
 
20
- def test_init_should_kick_off_a_server_instance
21
- Server.expects(:new).returns(true)
22
- God.init
22
+ def test_init_should_abort_if_called_after_watch
23
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
24
+
25
+ assert_abort do
26
+ God.init { }
27
+ end
23
28
  end
24
29
 
25
30
  # pid_file_directory
26
31
 
27
32
  def test_pid_file_directory_should_return_default_if_not_set_explicitly
33
+ God.init
28
34
  assert_equal '/var/run/god', God.pid_file_directory
29
35
  end
30
36
 
31
37
  def test_pid_file_directory_equals_should_set
38
+ God.init
32
39
  God.pid_file_directory = '/foo'
33
40
  assert_equal '/foo', God.pid_file_directory
34
41
  end
@@ -37,7 +44,11 @@ class TestGod < Test::Unit::TestCase
37
44
 
38
45
  def test_watch_should_get_stored
39
46
  watch = nil
40
- God.watch { |w| watch = w }
47
+ God.watch do |w|
48
+ w.name = 'foo'
49
+ w.start = 'bar'
50
+ watch = w
51
+ end
41
52
 
42
53
  assert_equal 1, God.watches.size
43
54
  assert_equal watch, God.watches.values.first
@@ -45,71 +56,148 @@ class TestGod < Test::Unit::TestCase
45
56
  assert_equal 0, God.groups.size
46
57
  end
47
58
 
59
+ def test_watch_should_get_stored_in_pending_watches
60
+ watch = nil
61
+ God.watch do |w|
62
+ w.name = 'foo'
63
+ w.start = 'bar'
64
+ watch = w
65
+ end
66
+
67
+ assert_equal 1, God.pending_watches.size
68
+ assert_equal watch, God.pending_watches.first
69
+ end
70
+
48
71
  def test_watch_should_register_processes
49
72
  assert_nil God.registry['foo']
50
- God.watch { |w| w.name = 'foo' }
73
+ God.watch do |w|
74
+ w.name = 'foo'
75
+ w.start = 'bar'
76
+ end
51
77
  assert_kind_of God::Process, God.registry['foo']
52
78
  end
53
79
 
54
80
  def test_watch_should_get_stored_by_group
81
+ a = nil
82
+
55
83
  God.watch do |w|
84
+ a = w
56
85
  w.name = 'foo'
86
+ w.start = 'bar'
57
87
  w.group = 'test'
58
88
  end
59
89
 
60
- assert_equal({'test' => ['foo']}, God.groups)
90
+ assert_equal({'test' => [a]}, God.groups)
61
91
  end
62
92
 
63
93
  def test_watches_should_get_stored_by_group
94
+ a = nil
95
+ b = nil
96
+
64
97
  God.watch do |w|
98
+ a = w
65
99
  w.name = 'foo'
100
+ w.start = 'bar'
66
101
  w.group = 'test'
67
102
  end
68
103
 
69
104
  God.watch do |w|
105
+ b = w
70
106
  w.name = 'bar'
107
+ w.start = 'baz'
71
108
  w.group = 'test'
72
109
  end
73
110
 
74
- assert_equal({'test' => ['foo', 'bar']}, God.groups)
111
+ assert_equal({'test' => [a, b]}, God.groups)
75
112
  end
76
113
 
77
114
  def test_watch_should_allow_multiple_watches
78
- God.watch { |w| w.name = 'foo' }
115
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
79
116
 
80
117
  assert_nothing_raised do
81
- God.watch { |w| w.name = 'bar' }
118
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
82
119
  end
83
120
  end
84
121
 
85
122
  def test_watch_should_disallow_duplicate_watch_names
86
- God.watch { |w| w.name = 'foo' }
123
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
87
124
 
88
125
  assert_abort do
89
- God.watch { |w| w.name = 'foo' }
126
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
90
127
  end
91
128
  end
92
129
 
93
130
  def test_watch_should_disallow_identical_watch_and_group_names
94
- God.watch { |w| w.name = 'foo'; w.group = 'bar' }
131
+ God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
95
132
 
96
133
  assert_abort do
97
- God.watch { |w| w.name = 'bar' }
134
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
98
135
  end
99
136
  end
100
137
 
101
138
  def test_watch_should_disallow_identical_watch_and_group_names_other_way
102
- God.watch { |w| w.name = 'bar' }
139
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
103
140
 
104
141
  assert_abort do
105
- God.watch { |w| w.name = 'foo'; w.group = 'bar' }
142
+ God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
143
+ end
144
+ end
145
+
146
+ def test_watch_should_unwatch_new_watch_if_running_and_duplicate_watch
147
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
148
+ God.running = true
149
+
150
+ assert_nothing_raised do
151
+ no_stdout do
152
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
153
+ end
154
+ end
155
+ end
156
+
157
+ # unwatch
158
+
159
+ def test_unwatch_should_unmonitor_watch
160
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
161
+ w = God.watches['bar']
162
+ w.expects(:unmonitor)
163
+ God.unwatch(w)
164
+ end
165
+
166
+ def test_unwatch_should_unregister_watch
167
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
168
+ w = God.watches['bar']
169
+ w.expects(:unregister!)
170
+ no_stdout do
171
+ God.unwatch(w)
172
+ end
173
+ end
174
+
175
+ def test_unwatch_should_remove_same_name_watches
176
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
177
+ w = God.watches['bar']
178
+ no_stdout do
179
+ God.unwatch(w)
180
+ end
181
+ assert_equal 0, God.watches.size
182
+ end
183
+
184
+ def test_unwatch_should_remove_from_group
185
+ God.watch do |w|
186
+ w.name = 'bar'
187
+ w.start = 'baz'
188
+ w.group = 'test'
189
+ end
190
+ w = God.watches['bar']
191
+ no_stdout do
192
+ God.unwatch(w)
106
193
  end
194
+ assert !God.groups[w.group].include?(w)
107
195
  end
108
196
 
109
197
  # control
110
198
 
111
199
  def test_control_should_monitor_on_start
112
- God.watch { |w| w.name = 'foo' }
200
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
113
201
 
114
202
  w = God.watches['foo']
115
203
  w.expects(:monitor)
@@ -117,7 +205,7 @@ class TestGod < Test::Unit::TestCase
117
205
  end
118
206
 
119
207
  def test_control_should_move_to_restart_on_restart
120
- God.watch { |w| w.name = 'foo' }
208
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
121
209
 
122
210
  w = God.watches['foo']
123
211
  w.expects(:move).with(:restart)
@@ -125,7 +213,7 @@ class TestGod < Test::Unit::TestCase
125
213
  end
126
214
 
127
215
  def test_control_should_unmonitor_and_stop_on_stop
128
- God.watch { |w| w.name = 'foo' }
216
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
129
217
 
130
218
  w = God.watches['foo']
131
219
  w.expects(:unmonitor).returns(w)
@@ -134,7 +222,7 @@ class TestGod < Test::Unit::TestCase
134
222
  end
135
223
 
136
224
  def test_control_should_unmonitor_on_unmonitor
137
- God.watch { |w| w.name = 'foo' }
225
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
138
226
 
139
227
  w = God.watches['foo']
140
228
  w.expects(:unmonitor).returns(w)
@@ -142,23 +230,152 @@ class TestGod < Test::Unit::TestCase
142
230
  end
143
231
 
144
232
  def test_control_should_raise_on_invalid_command
145
- God.watch { |w| w.name = 'foo' }
233
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
146
234
 
147
235
  assert_raise InvalidCommandError do
148
236
  God.control('foo', 'invalid')
149
237
  end
150
238
  end
151
239
 
152
- # start
240
+ def test_control_should_operate_on_each_watch_in_group
241
+ God.watch do |w|
242
+ w.name = 'foo1'
243
+ w.start = 'go'
244
+ w.group = 'bar'
245
+ end
246
+
247
+ God.watch do |w|
248
+ w.name = 'foo2'
249
+ w.start = 'go'
250
+ w.group = 'bar'
251
+ end
252
+
253
+ God.watches['foo1'].expects(:monitor)
254
+ God.watches['foo2'].expects(:monitor)
255
+
256
+ God.control('bar', 'start')
257
+ end
153
258
 
154
- def test_start_should_check_for_at_least_one_watch
155
- assert_abort do
156
- God.start
259
+ # stop_all
260
+
261
+ # terminate
262
+
263
+ def test_terminate_should_exit
264
+ God.expects(:exit!).with(0)
265
+ God.terminate
266
+ end
267
+
268
+ # status
269
+
270
+ def test_status_should_show_state
271
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
272
+
273
+ w = God.watches['foo']
274
+ w.state = :up
275
+ assert_equal({'foo' => {:state => :up}}, God.status)
276
+ end
277
+
278
+ def test_status_should_show_unmonitored_for_nil_state
279
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
280
+
281
+ w = God.watches['foo']
282
+ assert_equal({'foo' => {:state => :unmonitored}}, God.status)
283
+ end
284
+
285
+ # running_load
286
+
287
+ def test_running_load_should_eval_code
288
+ code = <<-EOF
289
+ God.watch do |w|
290
+ w.name = 'foo'
291
+ w.start = 'go'
292
+ end
293
+ EOF
294
+
295
+ no_stdout do
296
+ God.running_load(code)
297
+ end
298
+
299
+ assert_equal 1, God.watches.size
300
+ end
301
+
302
+ def test_running_load_should_monitor_new_watches
303
+ code = <<-EOF
304
+ God.watch do |w|
305
+ w.name = 'foo'
306
+ w.start = 'go'
307
+ end
308
+ EOF
309
+
310
+ Watch.any_instance.expects(:monitor)
311
+ no_stdout do
312
+ God.running_load(code)
313
+ end
314
+ end
315
+
316
+ def test_running_load_should_not_monitor_new_watches_with_autostart_false
317
+ code = <<-EOF
318
+ God.watch do |w|
319
+ w.name = 'foo'
320
+ w.start = 'go'
321
+ w.autostart = false
322
+ end
323
+ EOF
324
+
325
+ Watch.any_instance.expects(:monitor).never
326
+ no_stdout do
327
+ God.running_load(code)
328
+ end
329
+ end
330
+
331
+ def test_running_load_should_return_array_of_affected_watches
332
+ code = <<-EOF
333
+ God.watch do |w|
334
+ w.name = 'foo'
335
+ w.start = 'go'
336
+ end
337
+ EOF
338
+
339
+ w = nil
340
+ no_stdout do
341
+ w = God.running_load(code)
157
342
  end
343
+ assert_equal 1, w.size
344
+ assert_equal 'foo', w.first.name
345
+ end
346
+
347
+ def test_running_load_should_clear_pending_watches
348
+ code = <<-EOF
349
+ God.watch do |w|
350
+ w.name = 'foo'
351
+ w.start = 'go'
352
+ end
353
+ EOF
354
+
355
+ no_stdout do
356
+ God.running_load(code)
357
+ end
358
+ assert_equal 0, God.pending_watches.size
359
+ end
360
+
361
+ # load
362
+
363
+ def test_load_should_collect_and_load_globbed_path
364
+ Dir.expects(:[]).with('/path/to/*.thing').returns(['a', 'b'])
365
+ Kernel.expects(:load).with('a').once
366
+ Kernel.expects(:load).with('b').once
367
+ God.load('/path/to/*.thing')
158
368
  end
159
369
 
370
+ # start
371
+
372
+ def test_start_should_kick_off_a_server_instance
373
+ Server.expects(:new).returns(true)
374
+ God.start
375
+ end
376
+
160
377
  def test_start_should_start_event_handler
161
- God.watch { |w| w.name = 'foo' }
378
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
162
379
  Timer.any_instance.expects(:join)
163
380
  EventHandler.expects(:start).once
164
381
  no_stdout do
@@ -169,6 +386,7 @@ class TestGod < Test::Unit::TestCase
169
386
  def test_start_should_begin_monitoring_autostart_watches
170
387
  God.watch do |w|
171
388
  w.name = 'foo'
389
+ w.start = 'go'
172
390
  end
173
391
 
174
392
  Timer.any_instance.expects(:join)
@@ -179,6 +397,7 @@ class TestGod < Test::Unit::TestCase
179
397
  def test_start_should_not_begin_monitoring_non_autostart_watches
180
398
  God.watch do |w|
181
399
  w.name = 'foo'
400
+ w.start = 'go'
182
401
  w.autostart = false
183
402
  end
184
403
 
@@ -188,7 +407,7 @@ class TestGod < Test::Unit::TestCase
188
407
  end
189
408
 
190
409
  def test_start_should_get_and_join_timer
191
- God.watch { |w| w.name = 'foo' }
410
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
192
411
  Timer.any_instance.expects(:join)
193
412
  no_stdout do
194
413
  God.start
@@ -201,13 +420,50 @@ class TestGod < Test::Unit::TestCase
201
420
  God.expects(:start).once
202
421
  God.at_exit_orig
203
422
  end
423
+ end
424
+
425
+
426
+ class TestGodOther < Test::Unit::TestCase
427
+ def setup
428
+ Server.stubs(:new).returns(true)
429
+ God.internal_init
430
+ God.reset
431
+ end
204
432
 
205
- # load
433
+ def teardown
434
+ Timer.get.timer.kill
435
+ end
206
436
 
207
- def test_load_should_collect_and_load_globbed_path
208
- Dir.expects(:[]).with('/path/to/*.thing').returns(['a', 'b'])
209
- Kernel.expects(:load).with('a').once
210
- Kernel.expects(:load).with('b').once
211
- God.load('/path/to/*.thing')
437
+ # setup
438
+
439
+ def test_setup_should_create_pid_file_directory_if_it_doesnt_exist
440
+ God.expects(:test).returns(false)
441
+ FileUtils.expects(:mkdir_p).with(God.pid_file_directory)
442
+ God.setup
212
443
  end
213
- end
444
+
445
+ def test_setup_should_raise_if_no_permissions_to_create_pid_file_directory
446
+ God.expects(:test).returns(false)
447
+ FileUtils.expects(:mkdir_p).raises(Errno::EACCES)
448
+
449
+ assert_abort do
450
+ God.setup
451
+ end
452
+ end
453
+
454
+ # validate
455
+
456
+ def test_validate_should_abort_if_pid_file_directory_is_unwriteable
457
+ God.expects(:test).returns(false)
458
+ assert_abort do
459
+ God.validater
460
+ end
461
+ end
462
+
463
+ def test_validate_should_not_abort_if_pid_file_directory_is_writeable
464
+ God.expects(:test).returns(true)
465
+ assert_nothing_raised do
466
+ God.validater
467
+ end
468
+ end
469
+ end