firenxis-god 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/Announce.txt +135 -0
  2. data/History.txt +393 -0
  3. data/README.txt +59 -0
  4. data/Rakefile +142 -0
  5. data/bin/god +132 -0
  6. data/ext/god/.gitignore +5 -0
  7. data/ext/god/extconf.rb +55 -0
  8. data/ext/god/kqueue_handler.c +125 -0
  9. data/ext/god/netlink_handler.c +168 -0
  10. data/god.gemspec +164 -0
  11. data/lib/god.rb +701 -0
  12. data/lib/god/behavior.rb +52 -0
  13. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  14. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  15. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  16. data/lib/god/cli/command.rb +256 -0
  17. data/lib/god/cli/run.rb +172 -0
  18. data/lib/god/cli/version.rb +23 -0
  19. data/lib/god/compat19.rb +36 -0
  20. data/lib/god/condition.rb +96 -0
  21. data/lib/god/conditions/always.rb +23 -0
  22. data/lib/god/conditions/complex.rb +86 -0
  23. data/lib/god/conditions/cpu_usage.rb +80 -0
  24. data/lib/god/conditions/degrading_lambda.rb +52 -0
  25. data/lib/god/conditions/disk_usage.rb +32 -0
  26. data/lib/god/conditions/file_mtime.rb +28 -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 +114 -0
  36. data/lib/god/contacts/campfire.rb +121 -0
  37. data/lib/god/contacts/email.rb +136 -0
  38. data/lib/god/contacts/jabber.rb +75 -0
  39. data/lib/god/contacts/prowl.rb +57 -0
  40. data/lib/god/contacts/scout.rb +55 -0
  41. data/lib/god/contacts/twitter.rb +51 -0
  42. data/lib/god/contacts/webhook.rb +73 -0
  43. data/lib/god/dependency_graph.rb +41 -0
  44. data/lib/god/diagnostics.rb +37 -0
  45. data/lib/god/driver.rb +206 -0
  46. data/lib/god/errors.rb +24 -0
  47. data/lib/god/event_handler.rb +108 -0
  48. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  49. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  50. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  51. data/lib/god/logger.rb +109 -0
  52. data/lib/god/metric.rb +59 -0
  53. data/lib/god/process.rb +363 -0
  54. data/lib/god/registry.rb +32 -0
  55. data/lib/god/simple_logger.rb +59 -0
  56. data/lib/god/socket.rb +107 -0
  57. data/lib/god/sugar.rb +47 -0
  58. data/lib/god/sys_logger.rb +45 -0
  59. data/lib/god/system/portable_poller.rb +42 -0
  60. data/lib/god/system/process.rb +50 -0
  61. data/lib/god/system/slash_proc_poller.rb +92 -0
  62. data/lib/god/task.rb +503 -0
  63. data/lib/god/timeline.rb +25 -0
  64. data/lib/god/trigger.rb +43 -0
  65. data/lib/god/watch.rb +188 -0
  66. data/test/configs/child_events/child_events.god +44 -0
  67. data/test/configs/child_events/simple_server.rb +3 -0
  68. data/test/configs/child_polls/child_polls.god +37 -0
  69. data/test/configs/child_polls/simple_server.rb +12 -0
  70. data/test/configs/complex/complex.god +59 -0
  71. data/test/configs/complex/simple_server.rb +3 -0
  72. data/test/configs/contact/contact.god +108 -0
  73. data/test/configs/contact/simple_server.rb +3 -0
  74. data/test/configs/daemon_events/daemon_events.god +37 -0
  75. data/test/configs/daemon_events/simple_server.rb +8 -0
  76. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  77. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  78. data/test/configs/daemon_polls/simple_server.rb +6 -0
  79. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  80. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  81. data/test/configs/lifecycle/lifecycle.god +25 -0
  82. data/test/configs/matias/matias.god +50 -0
  83. data/test/configs/real.rb +59 -0
  84. data/test/configs/running_load/running_load.god +16 -0
  85. data/test/configs/stop_options/simple_server.rb +12 -0
  86. data/test/configs/stop_options/stop_options.god +39 -0
  87. data/test/configs/stress/simple_server.rb +3 -0
  88. data/test/configs/stress/stress.god +15 -0
  89. data/test/configs/task/logs/.placeholder +0 -0
  90. data/test/configs/task/task.god +26 -0
  91. data/test/configs/test.rb +61 -0
  92. data/test/helper.rb +141 -0
  93. data/test/suite.rb +6 -0
  94. data/test/test_behavior.rb +18 -0
  95. data/test/test_campfire.rb +23 -0
  96. data/test/test_condition.rb +50 -0
  97. data/test/test_conditions_disk_usage.rb +50 -0
  98. data/test/test_conditions_http_response_code.rb +109 -0
  99. data/test/test_conditions_process_running.rb +40 -0
  100. data/test/test_conditions_tries.rb +67 -0
  101. data/test/test_contact.rb +109 -0
  102. data/test/test_dependency_graph.rb +62 -0
  103. data/test/test_driver.rb +11 -0
  104. data/test/test_email.rb +34 -0
  105. data/test/test_event_handler.rb +80 -0
  106. data/test/test_god.rb +570 -0
  107. data/test/test_handlers_kqueue_handler.rb +16 -0
  108. data/test/test_jabber.rb +29 -0
  109. data/test/test_logger.rb +55 -0
  110. data/test/test_metric.rb +72 -0
  111. data/test/test_process.rb +247 -0
  112. data/test/test_prowl.rb +15 -0
  113. data/test/test_registry.rb +15 -0
  114. data/test/test_socket.rb +34 -0
  115. data/test/test_sugar.rb +42 -0
  116. data/test/test_system_portable_poller.rb +17 -0
  117. data/test/test_system_process.rb +30 -0
  118. data/test/test_task.rb +246 -0
  119. data/test/test_timeline.rb +37 -0
  120. data/test/test_trigger.rb +59 -0
  121. data/test/test_watch.rb +279 -0
  122. data/test/test_webhook.rb +15 -0
  123. metadata +362 -0
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSocket < Test::Unit::TestCase
4
+ def setup
5
+ silence_warnings do
6
+ Object.const_set(:DRb, stub_everything)
7
+ end
8
+ end
9
+
10
+ def test_should_start_a_drb_server
11
+ DRb.expects(:start_service)
12
+ God::Socket.new
13
+ end
14
+
15
+ def test_should_use_supplied_port_and_host
16
+ DRb.expects(:start_service).with { |uri, object| uri == "drbunix:///tmp/god.9999.sock" && object.is_a?(God::Socket) }
17
+ server = God::Socket.new(9999)
18
+ end
19
+
20
+ def test_should_forward_foreign_method_calls_to_god
21
+ server = nil
22
+ server = God::Socket.new
23
+ God.expects(:send).with(:something_random)
24
+ server.something_random
25
+ end
26
+
27
+ # ping
28
+
29
+ def test_ping_should_return_true
30
+ server = nil
31
+ server = God::Socket.new
32
+ assert server.ping
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSugar < Test::Unit::TestCase
4
+ def test_seconds
5
+ assert_equal 1, 1.seconds
6
+ assert_equal 1, 1.second
7
+ end
8
+
9
+ def test_minutes
10
+ assert_equal 60, 1.minutes
11
+ assert_equal 60, 1.minute
12
+ end
13
+
14
+ def test_hours
15
+ assert_equal 3600, 1.hours
16
+ assert_equal 3600, 1.hour
17
+ end
18
+
19
+ def test_days
20
+ assert_equal 86400, 1.days
21
+ assert_equal 86400, 1.day
22
+ end
23
+
24
+ def test_kilobytes
25
+ assert_equal 1, 1.kilobytes
26
+ assert_equal 1, 1.kilobyte
27
+ end
28
+
29
+ def test_megabytes
30
+ assert_equal 1024, 1.megabytes
31
+ assert_equal 1024, 1.megabyte
32
+ end
33
+
34
+ def test_gigabytes
35
+ assert_equal 1024 ** 2, 1.gigabytes
36
+ assert_equal 1024 ** 2, 1.gigabyte
37
+ end
38
+
39
+ def test_percent
40
+ assert_equal 1, 1.percent
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSystemPortablePoller < Test::Unit::TestCase
4
+ def setup
5
+ pid = Process.pid
6
+ @process = System::PortablePoller.new(pid)
7
+ end
8
+
9
+ def test_time_string_to_seconds
10
+ assert_equal 0, @process.bypass.time_string_to_seconds('0:00:00')
11
+ assert_equal 0, @process.bypass.time_string_to_seconds('0:00:55')
12
+ assert_equal 27, @process.bypass.time_string_to_seconds('0:27:32')
13
+ assert_equal 75, @process.bypass.time_string_to_seconds('1:15:13')
14
+ assert_equal 735, @process.bypass.time_string_to_seconds('12:15:13')
15
+ end
16
+ end
17
+
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSystemProcess < Test::Unit::TestCase
4
+ def setup
5
+ pid = Process.pid
6
+ @process = System::Process.new(pid)
7
+ end
8
+
9
+ def test_exists_should_return_true_for_running_process
10
+ assert_equal true, @process.exists?
11
+ end
12
+
13
+ def test_exists_should_return_false_for_non_existant_process
14
+ assert_equal false, System::Process.new(9999999).exists?
15
+ end
16
+
17
+ def test_memory
18
+ assert_kind_of Integer, @process.memory
19
+ assert @process.memory > 0
20
+ end
21
+
22
+ def test_percent_memory
23
+ assert_kind_of Float, @process.percent_memory
24
+ end
25
+
26
+ def test_percent_cpu
27
+ assert_kind_of Float, @process.percent_cpu
28
+ end
29
+ end
30
+
data/test/test_task.rb ADDED
@@ -0,0 +1,246 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTask < Test::Unit::TestCase
4
+ def setup
5
+ God.internal_init
6
+ @task = Task.new
7
+ @task.name = 'foo'
8
+ @task.valid_states = [:foo, :bar]
9
+ @task.initial_state = :foo
10
+ @task.interval = 5
11
+ @task.prepare
12
+ end
13
+
14
+ # valid?
15
+
16
+ def test_valid_should_return_false_if_no_name
17
+ @task.name = nil
18
+ assert !@task.valid?
19
+ end
20
+
21
+ def test_valid_should_return_false_if_no_valid_states
22
+ @task.valid_states = nil
23
+ assert !@task.valid?
24
+ end
25
+
26
+ def test_valid_should_return_false_if_no_initial_state
27
+ @task.initial_state = nil
28
+ assert !@task.valid?
29
+ end
30
+
31
+ # transition
32
+
33
+ def test_transition_should_be_always_if_no_block_was_given
34
+ @task.transition(:foo, :bar)
35
+
36
+ assert 1, @task.metrics.size
37
+ assert Conditions::Always, @task.metrics.keys.first.class
38
+ end
39
+
40
+ # method_missing
41
+
42
+ def test_method_missing_should_create_accessor_for_states
43
+ assert_nothing_raised do
44
+ @task.foo = 'testing'
45
+ end
46
+ end
47
+
48
+ def test_method_missing_should_raise_for_non_states
49
+ assert_raise NoMethodError do
50
+ @task.baz = 5
51
+ end
52
+ end
53
+
54
+ def test_method_missing_should_raise_for_non_setters
55
+ assert_raise NoMethodError do
56
+ @task.baz
57
+ end
58
+ end
59
+
60
+ # action
61
+
62
+ def test_action_should_send_string_commands_to_system
63
+ @task.foo = 'foo'
64
+ @task.driver.stubs(:in_driver_context?).returns(true)
65
+ @task.expects(:system).with('foo')
66
+ @task.action(:foo, nil)
67
+ end
68
+
69
+ def test_action_should_call_lambda_commands
70
+ @task.foo = lambda { }
71
+ @task.driver.stubs(:in_driver_context?).returns(true)
72
+ @task.foo.expects(:call)
73
+ @task.action(:foo, nil)
74
+ end
75
+
76
+ def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
77
+ @task.driver.stubs(:in_driver_context?).returns(true)
78
+ assert_raise NotImplementedError do
79
+ @task.foo = 7
80
+ @task.action(:foo, nil)
81
+ end
82
+ end
83
+
84
+ def test_action_from_outside_driver_should_send_message_to_driver
85
+ @task.foo = 'foo'
86
+ @task.driver.expects(:message).with(:action, [:foo, nil])
87
+ @task.action(:foo, nil)
88
+ end
89
+
90
+ # attach
91
+
92
+ def test_attach_should_schedule_for_poll_condition
93
+ c = Conditions::FakePollCondition.new
94
+ @task.driver.expects(:schedule).with(c, 0)
95
+ @task.attach(c)
96
+ end
97
+
98
+ def test_attach_should_regsiter_for_event_condition
99
+ c = Conditions::FakeEventCondition.new
100
+ c.expects(:register)
101
+ @task.attach(c)
102
+ end
103
+
104
+ # detach
105
+
106
+ def test_detach_should_reset_poll_condition
107
+ c = Conditions::FakePollCondition.new
108
+ c.expects(:reset)
109
+ c.expects(:deregister).never
110
+ @task.detach(c)
111
+ end
112
+
113
+ def test_detach_should_deregister_event_conditions
114
+ c = Conditions::FakeEventCondition.new
115
+ c.expects(:deregister).once
116
+ @task.detach(c)
117
+ end
118
+
119
+ # trigger
120
+
121
+ def test_trigger_should_send_message_to_driver
122
+ c = Conditions::FakePollCondition.new
123
+ @task.driver.expects(:message).with(:handle_event, [c])
124
+ @task.trigger(c)
125
+ end
126
+
127
+ # handle_poll
128
+
129
+ def test_handle_poll_no_change_should_reschedule
130
+ c = Conditions::FakePollCondition.new
131
+ c.watch = @task
132
+ c.interval = 10
133
+
134
+ m = Metric.new(@task, {true => :up})
135
+ @task.directory[c] = m
136
+
137
+ c.expects(:test).returns(false)
138
+ @task.driver.expects(:schedule)
139
+ @task.handle_poll(c)
140
+ end
141
+
142
+ def test_handle_poll_change_should_move
143
+ c = Conditions::FakePollCondition.new
144
+ c.watch = @task
145
+ c.interval = 10
146
+
147
+ m = Metric.new(@task, {true => :up})
148
+ @task.directory[c] = m
149
+
150
+ c.expects(:test).returns(true)
151
+ @task.expects(:move).with(:up)
152
+ @task.handle_poll(c)
153
+ end
154
+
155
+ def test_handle_poll_should_use_overridden_transition
156
+ c = Conditions::Tries.new
157
+ c.watch = @task
158
+ c.times = 1
159
+ c.transition = :start
160
+ c.prepare
161
+
162
+ m = Metric.new(@task, {true => :up})
163
+ @task.directory[c] = m
164
+
165
+ @task.expects(:move).with(:start)
166
+ @task.handle_poll(c)
167
+ end
168
+
169
+ def test_handle_poll_should_notify_if_triggering
170
+ c = Conditions::FakePollCondition.new
171
+ c.watch = @task
172
+ c.interval = 10
173
+ c.notify = 'tom'
174
+
175
+ m = Metric.new(@task, {true => :up})
176
+ @task.directory[c] = m
177
+
178
+ c.expects(:test).returns(true)
179
+ @task.expects(:notify)
180
+ @task.handle_poll(c)
181
+ end
182
+
183
+ def test_handle_poll_should_not_notify_if_not_triggering
184
+ c = Conditions::FakePollCondition.new
185
+ c.watch = @task
186
+ c.interval = 10
187
+ c.notify = 'tom'
188
+
189
+ m = Metric.new(@task, {true => :up})
190
+ @task.directory[c] = m
191
+
192
+ c.expects(:test).returns(false)
193
+ @task.expects(:notify).never
194
+ @task.handle_poll(c)
195
+ end
196
+
197
+ def test_handle_poll_unexpected_exception_should_reschedule
198
+ c = Conditions::FakePollCondition.new
199
+ c.watch = @task
200
+ c.interval = 10
201
+
202
+ m = Metric.new(@task, {true => :up})
203
+ @task.directory[c] = m
204
+
205
+ c.expects(:test).raises(StandardError)
206
+ @task.driver.expects(:schedule)
207
+
208
+ @task.handle_poll(c)
209
+ end
210
+
211
+ # handle_event
212
+
213
+ def test_handle_event_should_move
214
+ c = Conditions::FakeEventCondition.new
215
+ c.watch = @task
216
+
217
+ m = Metric.new(@task, {true => :up})
218
+ @task.directory[c] = m
219
+
220
+ @task.expects(:move).with(:up)
221
+ @task.handle_event(c)
222
+ end
223
+
224
+ def test_handle_event_should_notify_if_triggering
225
+ c = Conditions::FakeEventCondition.new
226
+ c.watch = @task
227
+ c.notify = 'tom'
228
+
229
+ m = Metric.new(@task, {true => :up})
230
+ @task.directory[c] = m
231
+
232
+ @task.expects(:notify)
233
+ @task.handle_event(c)
234
+ end
235
+
236
+ def test_handle_event_should_not_notify_if_no_notify_set
237
+ c = Conditions::FakeEventCondition.new
238
+ c.watch = @task
239
+
240
+ m = Metric.new(@task, {true => :up})
241
+ @task.directory[c] = m
242
+
243
+ @task.expects(:notify).never
244
+ @task.handle_event(c)
245
+ end
246
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTimeline < Test::Unit::TestCase
4
+ def setup
5
+ @timeline = Timeline.new(5)
6
+ end
7
+
8
+ def test_new_should_be_empty
9
+ assert_equal 0, @timeline.size
10
+ end
11
+
12
+ def test_should_not_grow_to_more_than_size
13
+ (1..10).each do |i|
14
+ @timeline.push(i)
15
+ end
16
+
17
+ assert_equal [6, 7, 8, 9, 10], @timeline
18
+ end
19
+
20
+ def test_clear_should_clear_array
21
+ @timeline << 1
22
+ assert_equal [1], @timeline
23
+ assert_equal [], @timeline.clear
24
+ end
25
+
26
+ # def test_benchmark
27
+ # require 'benchmark'
28
+ #
29
+ # count = 1_000_000
30
+ #
31
+ # t = Timeline.new(10)
32
+ #
33
+ # Benchmark.bmbm do |x|
34
+ # x.report("go") { count.times { t.push(5) } }
35
+ # end
36
+ # end
37
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTrigger < Test::Unit::TestCase
4
+ def setup
5
+ Trigger.reset
6
+ end
7
+
8
+ # base case
9
+
10
+ def test_should_have_empty_triggers
11
+ assert_equal({}, Trigger.triggers)
12
+ end
13
+
14
+ # register
15
+
16
+ def test_register_should_add_condition_to_triggers
17
+ c = Condition.new
18
+ c.watch = stub(:name => 'foo')
19
+ Trigger.register(c)
20
+
21
+ assert_equal({'foo' => [c]}, Trigger.triggers)
22
+ end
23
+
24
+ def test_register_should_add_condition_to_triggers_twice
25
+ watch = stub(:name => 'foo')
26
+ c = Condition.new
27
+ c.watch = watch
28
+ Trigger.register(c)
29
+
30
+ c2 = Condition.new
31
+ c2.watch = watch
32
+ Trigger.register(c2)
33
+
34
+ assert_equal({'foo' => [c, c2]}, Trigger.triggers)
35
+ end
36
+
37
+ # deregister
38
+
39
+ def test_deregister_should_remove_condition_from_triggers
40
+ c = Condition.new
41
+ c.watch = stub(:name => 'foo')
42
+ Trigger.register(c)
43
+ Trigger.deregister(c)
44
+
45
+ assert_equal({}, Trigger.triggers)
46
+ end
47
+
48
+ # broadcast
49
+
50
+ def test_broadcast_should_call_process_on_each_condition
51
+ c = Condition.new
52
+ c.watch = stub(:name => 'foo')
53
+ Trigger.register(c)
54
+
55
+ c.expects(:process).with(:state_change, [:up, :start])
56
+
57
+ Trigger.broadcast(c.watch, :state_change, [:up, :start])
58
+ end
59
+ end