mojombo-god 0.7.7

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.
Files changed (108) hide show
  1. data/History.txt +255 -0
  2. data/Manifest.txt +107 -0
  3. data/README.txt +59 -0
  4. data/Rakefile +35 -0
  5. data/bin/god +127 -0
  6. data/examples/events.god +84 -0
  7. data/examples/gravatar.god +54 -0
  8. data/examples/single.god +66 -0
  9. data/ext/god/extconf.rb +55 -0
  10. data/ext/god/kqueue_handler.c +123 -0
  11. data/ext/god/netlink_handler.c +167 -0
  12. data/init/god +42 -0
  13. data/lib/god.rb +644 -0
  14. data/lib/god/behavior.rb +52 -0
  15. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  16. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  17. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  18. data/lib/god/cli/command.rb +206 -0
  19. data/lib/god/cli/run.rb +177 -0
  20. data/lib/god/cli/version.rb +23 -0
  21. data/lib/god/condition.rb +96 -0
  22. data/lib/god/conditions/always.rb +23 -0
  23. data/lib/god/conditions/complex.rb +86 -0
  24. data/lib/god/conditions/cpu_usage.rb +80 -0
  25. data/lib/god/conditions/degrading_lambda.rb +52 -0
  26. data/lib/god/conditions/disk_usage.rb +27 -0
  27. data/lib/god/conditions/flapping.rb +128 -0
  28. data/lib/god/conditions/http_response_code.rb +168 -0
  29. data/lib/god/conditions/lambda.rb +25 -0
  30. data/lib/god/conditions/memory_usage.rb +82 -0
  31. data/lib/god/conditions/process_exits.rb +72 -0
  32. data/lib/god/conditions/process_running.rb +74 -0
  33. data/lib/god/conditions/tries.rb +44 -0
  34. data/lib/god/configurable.rb +57 -0
  35. data/lib/god/contact.rb +106 -0
  36. data/lib/god/contacts/email.rb +95 -0
  37. data/lib/god/dependency_graph.rb +41 -0
  38. data/lib/god/diagnostics.rb +37 -0
  39. data/lib/god/driver.rb +108 -0
  40. data/lib/god/errors.rb +24 -0
  41. data/lib/god/event_handler.rb +111 -0
  42. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  43. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  44. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  45. data/lib/god/logger.rb +120 -0
  46. data/lib/god/metric.rb +59 -0
  47. data/lib/god/process.rb +325 -0
  48. data/lib/god/registry.rb +32 -0
  49. data/lib/god/simple_logger.rb +53 -0
  50. data/lib/god/socket.rb +96 -0
  51. data/lib/god/sugar.rb +47 -0
  52. data/lib/god/system/portable_poller.rb +42 -0
  53. data/lib/god/system/process.rb +42 -0
  54. data/lib/god/system/slash_proc_poller.rb +82 -0
  55. data/lib/god/task.rb +487 -0
  56. data/lib/god/timeline.rb +25 -0
  57. data/lib/god/trigger.rb +43 -0
  58. data/lib/god/watch.rb +183 -0
  59. data/test/configs/child_events/child_events.god +44 -0
  60. data/test/configs/child_events/simple_server.rb +3 -0
  61. data/test/configs/child_polls/child_polls.god +37 -0
  62. data/test/configs/child_polls/simple_server.rb +12 -0
  63. data/test/configs/complex/complex.god +59 -0
  64. data/test/configs/complex/simple_server.rb +3 -0
  65. data/test/configs/contact/contact.god +74 -0
  66. data/test/configs/contact/simple_server.rb +3 -0
  67. data/test/configs/daemon_events/daemon_events.god +37 -0
  68. data/test/configs/daemon_events/simple_server.rb +8 -0
  69. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  70. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  71. data/test/configs/daemon_polls/simple_server.rb +6 -0
  72. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  73. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  74. data/test/configs/matias/matias.god +50 -0
  75. data/test/configs/real.rb +59 -0
  76. data/test/configs/running_load/running_load.god +16 -0
  77. data/test/configs/stress/simple_server.rb +3 -0
  78. data/test/configs/stress/stress.god +15 -0
  79. data/test/configs/task/logs/.placeholder +0 -0
  80. data/test/configs/task/task.god +26 -0
  81. data/test/configs/test.rb +61 -0
  82. data/test/helper.rb +151 -0
  83. data/test/suite.rb +6 -0
  84. data/test/test_behavior.rb +21 -0
  85. data/test/test_condition.rb +50 -0
  86. data/test/test_conditions_disk_usage.rb +56 -0
  87. data/test/test_conditions_http_response_code.rb +109 -0
  88. data/test/test_conditions_process_running.rb +44 -0
  89. data/test/test_conditions_tries.rb +67 -0
  90. data/test/test_contact.rb +109 -0
  91. data/test/test_dependency_graph.rb +62 -0
  92. data/test/test_driver.rb +11 -0
  93. data/test/test_event_handler.rb +80 -0
  94. data/test/test_god.rb +598 -0
  95. data/test/test_handlers_kqueue_handler.rb +16 -0
  96. data/test/test_logger.rb +63 -0
  97. data/test/test_metric.rb +72 -0
  98. data/test/test_process.rb +246 -0
  99. data/test/test_registry.rb +15 -0
  100. data/test/test_socket.rb +42 -0
  101. data/test/test_sugar.rb +42 -0
  102. data/test/test_system_portable_poller.rb +17 -0
  103. data/test/test_system_process.rb +30 -0
  104. data/test/test_task.rb +262 -0
  105. data/test/test_timeline.rb +37 -0
  106. data/test/test_trigger.rb +59 -0
  107. data/test/test_watch.rb +279 -0
  108. metadata +186 -0
data/test/suite.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+
3
+ tests = Dir["#{File.dirname(__FILE__)}/test_*.rb"]
4
+ tests.each do |file|
5
+ require file
6
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestBehavior < Test::Unit::TestCase
4
+ def test_generate_should_return_an_object_corresponding_to_the_given_type
5
+ assert_equal Behaviors::FakeBehavior, Behavior.generate(:fake_behavior, nil).class
6
+ end
7
+
8
+ def test_generate_should_raise_on_invalid_type
9
+ assert_raise NoSuchBehaviorError do
10
+ Behavior.generate(:foo, nil)
11
+ end
12
+ end
13
+
14
+ def test_complain
15
+ Syslog.expects(:err).with('foo')
16
+ # Kernel.expects(:puts).with('foo')
17
+ no_stdout do
18
+ assert !Behavior.allocate.bypass.complain('foo')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class BadlyImplementedCondition < PollCondition
4
+ end
5
+
6
+ class TestCondition < Test::Unit::TestCase
7
+
8
+ # generate
9
+
10
+ def test_generate_should_return_an_object_corresponding_to_the_given_type
11
+ assert_equal Conditions::ProcessRunning, Condition.generate(:process_running, nil).class
12
+ end
13
+
14
+ def test_generate_should_raise_on_invalid_type
15
+ assert_raise NoSuchConditionError do
16
+ Condition.generate(:foo, nil)
17
+ end
18
+ end
19
+
20
+ def test_generate_should_abort_on_event_condition_without_loaded_event_system
21
+ God::EventHandler.stubs(:operational?).returns(false)
22
+ assert_abort do
23
+ God::EventHandler.start
24
+ Condition.generate(:process_exits, nil).class
25
+ end
26
+ end
27
+
28
+ def test_generate_should_return_a_good_error_message_for_invalid_types
29
+ emsg = "No Condition found with the class name God::Conditions::FooBar"
30
+ rmsg = nil
31
+
32
+ begin
33
+ Condition.generate(:foo_bar, nil)
34
+ rescue => e
35
+ rmsg = e.message
36
+ end
37
+
38
+ assert_equal emsg, rmsg
39
+ end
40
+
41
+ # test
42
+
43
+ def test_test_should_raise_if_not_defined_in_subclass
44
+ c = BadlyImplementedCondition.new
45
+
46
+ assert_raise AbstractMethodNotOverriddenError do
47
+ c.test
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestConditionsDiskUsage < Test::Unit::TestCase
4
+ # valid?
5
+
6
+ def test_valid_should_return_false_if_no_above_given
7
+ c = Conditions::DiskUsage.new
8
+ c.mount_point = '/'
9
+ c.watch = stub(:name => 'foo')
10
+
11
+ no_stdout do
12
+ assert_equal false, c.valid?
13
+ end
14
+ end
15
+
16
+ def test_valid_should_return_false_if_no_mount_point_given
17
+ c = Conditions::DiskUsage.new
18
+ c.above = 90
19
+ c.watch = stub(:name => 'foo')
20
+
21
+ no_stdout do
22
+ assert_equal false, c.valid?
23
+ end
24
+ end
25
+
26
+ def test_valid_should_return_true_if_required_options_all_set
27
+ c = Conditions::DiskUsage.new
28
+ c.above = 90
29
+ c.mount_point = '/'
30
+ c.watch = stub(:name => 'foo')
31
+
32
+ assert_equal true, c.valid?
33
+ end
34
+
35
+ # test
36
+
37
+ def test_test_should_return_true_if_above_limit
38
+ c = Conditions::DiskUsage.new
39
+ c.above = 90
40
+ c.mount_point = '/'
41
+
42
+ c.expects(:`).returns('91')
43
+
44
+ assert_equal true, c.test
45
+ end
46
+
47
+ def test_test_should_return_false_if_below_limit
48
+ c = Conditions::DiskUsage.new
49
+ c.above = 90
50
+ c.mount_point = '/'
51
+
52
+ c.expects(:`).returns('90')
53
+
54
+ assert_equal false, c.test
55
+ end
56
+ end
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestHttpResponseCode < Test::Unit::TestCase
4
+ def valid_condition
5
+ c = Conditions::HttpResponseCode.new()
6
+ c.watch = stub(:name => 'foo')
7
+ c.host = 'localhost'
8
+ c.port = 8080
9
+ c.path = '/'
10
+ c.timeout = 10
11
+ c.code_is = 200
12
+ c.times = 1
13
+ yield(c) if block_given?
14
+ c.prepare
15
+ c
16
+ end
17
+
18
+ # valid?
19
+
20
+ def test_valid_condition_is_valid
21
+ c = valid_condition
22
+ assert c.valid?
23
+ end
24
+
25
+ def test_valid_should_return_false_if_both_code_is_and_code_is_not_are_set
26
+ c = valid_condition do |cc|
27
+ cc.code_is_not = 500
28
+ end
29
+ no_stdout { assert !c.valid? }
30
+ end
31
+
32
+ def test_valid_should_return_false_if_no_host_set
33
+ c = valid_condition do |cc|
34
+ cc.host = nil
35
+ end
36
+ no_stdout { assert !c.valid? }
37
+ end
38
+
39
+ # test
40
+
41
+ def test_test_should_return_false_if_code_is_is_set_to_200_but_response_is_500
42
+ c = valid_condition
43
+ Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 500)))
44
+ assert_equal false, c.test
45
+ end
46
+
47
+ def test_test_should_return_false_if_code_is_not_is_set_to_200_and_response_is_200
48
+ c = valid_condition do |cc|
49
+ cc.code_is = nil
50
+ cc.code_is_not = [200]
51
+ end
52
+ Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 200)))
53
+ assert_equal false, c.test
54
+ end
55
+
56
+ def test_test_should_return_true_if_code_is_is_set_to_200_and_response_is_200
57
+ c = valid_condition
58
+ Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 200)))
59
+ assert_equal true, c.test
60
+ end
61
+
62
+ def test_test_should_return_false_if_code_is_not_is_set_to_200_but_response_is_500
63
+ c = valid_condition do |cc|
64
+ cc.code_is = nil
65
+ cc.code_is_not = [200]
66
+ end
67
+ Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 500)))
68
+ assert_equal true, c.test
69
+ end
70
+
71
+ def test_test_should_return_false_if_code_is_is_set_to_200_but_response_times_out
72
+ c = valid_condition
73
+ Net::HTTP.expects(:start).raises(Timeout::Error, '')
74
+ assert_equal false, c.test
75
+ end
76
+
77
+ def test_test_should_return_true_if_code_is_not_is_set_to_200_and_response_times_out
78
+ c = valid_condition do |cc|
79
+ cc.code_is = nil
80
+ cc.code_is_not = [200]
81
+ end
82
+ Net::HTTP.expects(:start).raises(Timeout::Error, '')
83
+ assert_equal true, c.test
84
+ end
85
+
86
+ def test_test_should_return_false_if_code_is_is_set_to_200_but_cant_connect
87
+ c = valid_condition
88
+ Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
89
+ assert_equal false, c.test
90
+ end
91
+
92
+ def test_test_should_return_true_if_code_is_not_is_set_to_200_and_cant_connect
93
+ c = valid_condition do |cc|
94
+ cc.code_is = nil
95
+ cc.code_is_not = [200]
96
+ end
97
+ Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
98
+ assert_equal true, c.test
99
+ end
100
+
101
+ def test_test_should_return_true_if_code_is_is_set_to_200_and_response_is_200_twice_for_times_two_of_two
102
+ c = valid_condition do |cc|
103
+ cc.times = [2, 2]
104
+ end
105
+ Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 200))).times(2)
106
+ assert_equal false, c.test
107
+ assert_equal true, c.test
108
+ end
109
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestConditionsProcessRunning < Test::Unit::TestCase
4
+ def test_missing_pid_file_returns_opposite
5
+ [true, false].each do |r|
6
+ c = Conditions::ProcessRunning.new
7
+ c.running = r
8
+
9
+ c.stubs(:watch).returns(stub(:pid => 123, :name => 'foo'))
10
+
11
+ # no_stdout do
12
+ assert_equal !r, c.test
13
+ # end
14
+ end
15
+ end
16
+
17
+ def test_not_running_returns_opposite
18
+ [true, false].each do |r|
19
+ c = Conditions::ProcessRunning.new
20
+ c.running = r
21
+
22
+ File.stubs(:exist?).returns(true)
23
+ c.stubs(:watch).returns(stub(:pid => 123))
24
+ File.stubs(:read).returns('5')
25
+ System::Process.any_instance.stubs(:exists?).returns(false)
26
+
27
+ assert_equal !r, c.test
28
+ end
29
+ end
30
+
31
+ def test_running_returns_same
32
+ [true, false].each do |r|
33
+ c = Conditions::ProcessRunning.new
34
+ c.running = r
35
+
36
+ File.stubs(:exist?).returns(true)
37
+ c.stubs(:watch).returns(stub(:pid => 123))
38
+ File.stubs(:read).returns('5')
39
+ System::Process.any_instance.stubs(:exists?).returns(true)
40
+
41
+ assert_equal r, c.test
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,67 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestConditionsTries < Test::Unit::TestCase
4
+ # valid?
5
+
6
+ def test_valid_should_return_false_if_times_not_set
7
+ c = Conditions::Tries.new
8
+ c.watch = stub(:name => 'foo')
9
+ no_stdout { assert !c.valid? }
10
+ end
11
+ end
12
+
13
+
14
+ class TestConditionsTries < Test::Unit::TestCase
15
+ def setup
16
+ @c = Conditions::Tries.new
17
+ @c.times = 3
18
+ @c.prepare
19
+ end
20
+
21
+ # prepare
22
+
23
+ def test_prepare_should_create_timeline
24
+ assert 3, @c.instance_variable_get(:@timeline).instance_variable_get(:@max_size)
25
+ end
26
+
27
+ # test
28
+
29
+ def test_test_should_return_true_if_called_three_times_within_one_second
30
+ assert !@c.test
31
+ assert !@c.test
32
+ assert @c.test
33
+ end
34
+
35
+ # reset
36
+
37
+ def test_test_should_return_false_on_fourth_call_if_called_three_times_within_one_second
38
+ 3.times { @c.test }
39
+ @c.reset
40
+ assert !@c.test
41
+ end
42
+ end
43
+
44
+
45
+ class TestConditionsTriesWithin < Test::Unit::TestCase
46
+ def setup
47
+ @c = Conditions::Tries.new
48
+ @c.times = 3
49
+ @c.within = 1.seconds
50
+ @c.prepare
51
+ end
52
+
53
+ # test
54
+
55
+ def test_test_should_return_true_if_called_three_times_within_one_second
56
+ assert !@c.test
57
+ assert !@c.test
58
+ assert @c.test
59
+ end
60
+
61
+ def test_test_should_return_false_if_called_three_times_within_two_seconds
62
+ assert !@c.test
63
+ assert !@c.test
64
+ assert sleep(1.1)
65
+ assert !@c.test
66
+ end
67
+ end
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestContact < Test::Unit::TestCase
4
+ def test_exists
5
+ God::Contact
6
+ end
7
+
8
+ # generate
9
+
10
+ def test_generate_should_raise_on_invalid_kind
11
+ assert_raise(NoSuchContactError) do
12
+ Contact.generate(:invalid)
13
+ end
14
+ end
15
+
16
+ def test_generate_should_abort_on_invalid_contact
17
+ assert_abort do
18
+ Contact.generate(:invalid_contact)
19
+ end
20
+ end
21
+
22
+ # normalize
23
+
24
+ def test_normalize_should_accept_a_string
25
+ input = 'tom'
26
+ output = {:contacts => ['tom']}
27
+ assert_equal(output, Contact.normalize(input))
28
+ end
29
+
30
+ def test_normalize_should_accept_an_array_of_strings
31
+ input = ['tom', 'kevin']
32
+ output = {:contacts => ['tom', 'kevin']}
33
+ assert_equal(output, Contact.normalize(input))
34
+ end
35
+
36
+ def test_normalize_should_accept_a_hash_with_contacts_string
37
+ input = {:contacts => 'tom'}
38
+ output = {:contacts => ['tom']}
39
+ assert_equal(output, Contact.normalize(input))
40
+ end
41
+
42
+ def test_normalize_should_accept_a_hash_with_contacts_array_of_strings
43
+ input = {:contacts => ['tom', 'kevin']}
44
+ output = {:contacts => ['tom', 'kevin']}
45
+ assert_equal(output, Contact.normalize(input))
46
+ end
47
+
48
+ def test_normalize_should_stringify_priority
49
+ input = {:contacts => 'tom', :priority => 1}
50
+ output = {:contacts => ['tom'], :priority => '1'}
51
+ assert_equal(output, Contact.normalize(input))
52
+ end
53
+
54
+ def test_normalize_should_stringify_category
55
+ input = {:contacts => 'tom', :category => :product}
56
+ output = {:contacts => ['tom'], :category => 'product'}
57
+ assert_equal(output, Contact.normalize(input))
58
+ end
59
+
60
+ def test_normalize_should_raise_on_non_string_array_hash
61
+ input = 1
62
+ assert_raise ArgumentError do
63
+ Contact.normalize(input)
64
+ end
65
+ end
66
+
67
+ def test_normalize_should_raise_on_non_string_array_contacts_key
68
+ input = {:contacts => 1}
69
+ assert_raise ArgumentError do
70
+ Contact.normalize(input)
71
+ end
72
+ end
73
+
74
+ def test_normalize_should_raise_on_non_string_containing_array
75
+ input = [1]
76
+ assert_raise ArgumentError do
77
+ Contact.normalize(input)
78
+ end
79
+ end
80
+
81
+ def test_normalize_should_raise_on_non_string_containing_array_contacts_key
82
+ input = {:contacts => [1]}
83
+ assert_raise ArgumentError do
84
+ Contact.normalize(input)
85
+ end
86
+ end
87
+
88
+ def test_normalize_should_raise_on_absent_contacts_key
89
+ input = {}
90
+ assert_raise ArgumentError do
91
+ Contact.normalize(input)
92
+ end
93
+ end
94
+
95
+ def test_normalize_should_raise_on_extra_keys
96
+ input = {:contacts => ['tom'], :priority => 1, :category => 'product', :extra => 'foo'}
97
+ assert_raise ArgumentError do
98
+ Contact.normalize(input)
99
+ end
100
+ end
101
+
102
+ # notify
103
+
104
+ def test_notify_should_be_abstract
105
+ assert_raise(AbstractMethodNotOverriddenError) do
106
+ Contact.new.notify(:a, :b, :c, :d, :e)
107
+ end
108
+ end
109
+ end