god 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ if $0 == __FILE__
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. lib god])
3
+ end
4
+
5
+ RAILS_ROOT = "/Users/tom/dev/git/helloworld"
6
+
7
+ God.meddle do |god|
8
+ god.watch do |w|
9
+ w.name = "local-3000"
10
+ w.interval = 5 # seconds
11
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
12
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
13
+ w.grace = 5
14
+
15
+ pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
16
+
17
+ # clean pid files before start if necessary
18
+ w.behavior(:clean_pid_file) do |b|
19
+ b.pid_file = pid_file
20
+ end
21
+
22
+ # start if process is not running
23
+ w.start_if do |start|
24
+ # start.condition(:process_exits) do |c|
25
+ # c.pid_file = pid_file
26
+ # end
27
+
28
+ start.condition(:process_not_running) do |c|
29
+ c.pid_file = pid_file
30
+ end
31
+ end
32
+
33
+ # restart if memory or cpu is too high
34
+ w.restart_if do |restart|
35
+ restart.condition(:memory_usage) do |c|
36
+ c.interval = 20
37
+ c.pid_file = pid_file
38
+ c.above = (50 * 1024) # 50mb
39
+ c.times = [3, 5]
40
+ end
41
+
42
+ restart.condition(:cpu_usage) do |c|
43
+ c.interval = 10
44
+ c.pid_file = pid_file
45
+ c.above = 10 # percent
46
+ c.times = [3, 5]
47
+ end
48
+ end
49
+ end
50
+
51
+ # clear old session files
52
+ # god.watch do |w|
53
+ # w.name = "local-session-cleanup"
54
+ # w.start = lambda do
55
+ # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f|
56
+ # File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
57
+ # end.each { |f| File.delete(f) }
58
+ # end
59
+ #
60
+ # w.start_if do |start|
61
+ # start.condition(:always)
62
+ # end
63
+ # end
64
+ end
@@ -0,0 +1,93 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. lib god])
2
+
3
+ require 'test/unit'
4
+
5
+ begin
6
+ require 'mocha'
7
+ rescue LoadError
8
+ unless gems ||= false
9
+ require 'rubygems'
10
+ gems = true
11
+ retry
12
+ else
13
+ abort "=> You need the Mocha gem to run these tests."
14
+ end
15
+ end
16
+
17
+ include God
18
+
19
+ module God
20
+ class AbortCalledError < StandardError
21
+ end
22
+
23
+ class Base
24
+ def abort(msg)
25
+ raise AbortCalledError.new("abort called")
26
+ end
27
+
28
+ def self.abort(msg)
29
+ raise AbortCalledError.new("abort called")
30
+ end
31
+ end
32
+
33
+ module Conditions
34
+ class FakeCondition < Condition
35
+ def test
36
+ true
37
+ end
38
+ end
39
+
40
+ class FakePollCondition < PollCondition
41
+ def test
42
+ true
43
+ end
44
+ end
45
+
46
+ class FakeEventCondition < EventCondition
47
+ def test
48
+ true
49
+ end
50
+ end
51
+ end
52
+
53
+ module Behaviors
54
+ class FakeBehavior < Behavior
55
+ end
56
+ end
57
+ end
58
+
59
+ def silence_warnings
60
+ old_verbose, $VERBOSE = $VERBOSE, nil
61
+ yield
62
+ ensure
63
+ $VERBOSE = old_verbose
64
+ end
65
+
66
+ # This allows you to be a good OOP citizen and honor encapsulation, but
67
+ # still make calls to private methods (for testing) by doing
68
+ #
69
+ # obj.bypass.private_thingie(arg1, arg2)
70
+ #
71
+ # Which is easier on the eye than
72
+ #
73
+ # obj.send(:private_thingie, arg1, arg2)
74
+ #
75
+ class Object
76
+ class Bypass
77
+ instance_methods.each do |m|
78
+ undef_method m unless m =~ /^__/
79
+ end
80
+
81
+ def initialize(ref)
82
+ @ref = ref
83
+ end
84
+
85
+ def method_missing(sym, *args)
86
+ @ref.__send__(sym, *args)
87
+ end
88
+ end
89
+
90
+ def bypass
91
+ Bypass.new(self)
92
+ end
93
+ end
@@ -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,13 @@
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).class
6
+ end
7
+
8
+ def test_generate_should_raise_on_invalid_type
9
+ assert_raise NoSuchBehaviorError do
10
+ Behavior.generate(:foo)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestCondition < Test::Unit::TestCase
4
+ def test_generate_should_return_an_object_corresponding_to_the_given_type
5
+ assert_equal Conditions::ProcessNotRunning, Condition.generate(:process_not_running).class
6
+ end
7
+
8
+ def test_generate_should_raise_on_invalid_type
9
+ assert_raise NoSuchConditionError do
10
+ Condition.generate(:foo)
11
+ end
12
+ end
13
+
14
+ def test_generate_should_return_a_good_error_message_for_invalid_types
15
+ emsg = "No Condition found with the class name God::Conditions::FooBar"
16
+ rmsg = nil
17
+
18
+ begin
19
+ Condition.generate(:foo_bar)
20
+ rescue => e
21
+ rmsg = e.message
22
+ end
23
+
24
+ assert_equal emsg, rmsg
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestGod < Test::Unit::TestCase
4
+ def test_should_create_new_meddle
5
+ Meddle.expects(:new).with(:port => 1).returns(mock(:monitor => true, :timer => stub(:join => nil)))
6
+
7
+ God.meddle(:port => 1) {}
8
+ end
9
+
10
+ def test_should_start_monitoring
11
+ Meddle.any_instance.expects(:monitor)
12
+ Meddle.any_instance.expects(:timer).returns(stub(:join => nil))
13
+ God.meddle {}
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestMeddle < Test::Unit::TestCase
4
+ def setup
5
+ Server.stubs(:new).returns(true)
6
+ @meddle = Meddle.new
7
+ end
8
+
9
+ def test_should_initialize_watches_to_empty_array
10
+ assert_equal [], @meddle.watches
11
+ end
12
+
13
+ def test_watches_should_get_stored
14
+ watch = nil
15
+ @meddle.watch { |w| watch = w }
16
+
17
+ assert_equal 1, @meddle.watches.size
18
+ assert_equal watch, @meddle.watches.first
19
+ end
20
+
21
+ def test_should_kick_off_a_server_instance
22
+ Server.expects(:new).returns(true)
23
+ Meddle.new
24
+ end
25
+
26
+ def test_should_take_an_options_hash
27
+ Server.expects(:new)
28
+ Meddle.new(:port => 5555)
29
+ end
30
+
31
+ def test_should_allow_multiple_watches
32
+ @meddle.watch { |w| w.name = 'foo' }
33
+
34
+ assert_nothing_raised do
35
+ @meddle.watch { |w| w.name = 'bar' }
36
+ end
37
+ end
38
+
39
+ def test_should_disallow_duplicate_watch_names
40
+ @meddle.watch { |w| w.name = 'foo' }
41
+
42
+ assert_raise AbortCalledError do
43
+ @meddle.watch { |w| w.name = 'foo' }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestReporter < Test::Unit::TestCase
4
+
5
+ def test_should_create_a_drb_object
6
+ DRb.expects(:start_service)
7
+ DRbObject.expects(:new).with(nil, "druby://host:port").returns(stub(:anything => true))
8
+
9
+ Reporter.new('host', 'port').anything
10
+ end
11
+
12
+ def test_should_forward_unknown_methods_to_drb_object
13
+ Reporter.any_instance.expects(:service).returns(mock(:something_fake => true))
14
+
15
+ reporter = Reporter.new('host', 'port')
16
+ reporter.something_fake
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestServer < 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
+ Server.new
13
+ end
14
+
15
+ def test_should_use_supplied_port_and_host
16
+ DRb.expects(:start_service).with { |uri, object| uri == "druby://host:port" && object.is_a?(Server) }
17
+ server = Server.new(nil, 'host', 'port')
18
+ end
19
+
20
+ def test_should_forward_foreign_method_calls_to_meddle
21
+ server = Server.new(mock(:something_random => true))
22
+ server.something_random
23
+ end
24
+ end
@@ -0,0 +1,42 @@
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(0).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
+
30
+ def test_cpu_time
31
+ assert_kind_of Integer, @process.cpu_time
32
+ end
33
+
34
+ def test_time_string_to_seconds
35
+ assert_equal 0, @process.bypass.time_string_to_seconds('0:00:00')
36
+ assert_equal 0, @process.bypass.time_string_to_seconds('0:00:55')
37
+ assert_equal 27, @process.bypass.time_string_to_seconds('0:27:32')
38
+ assert_equal 75, @process.bypass.time_string_to_seconds('1:15:13')
39
+ assert_equal 735, @process.bypass.time_string_to_seconds('12:15:13')
40
+ end
41
+ end
42
+
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTimeline < Test::Unit::TestCase
4
+ def setup
5
+ @timeline = Conditions::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 [10, 9, 8, 7, 6], @timeline
18
+ end
19
+
20
+ def test_clear_should_clear_array
21
+ @timeline.push(1)
22
+ assert_equal [], @timeline.clear
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTimer < Test::Unit::TestCase
4
+ def setup
5
+ @t = Timer.new
6
+ end
7
+
8
+ def test_new_timer_should_have_no_events
9
+ assert_equal 0, @t.events.size
10
+ end
11
+
12
+ def test_register_should_queue_event
13
+ Time.stubs(:now).returns(0)
14
+
15
+ w = Watch.new(nil)
16
+ @t.register(w, stub(:interval => 20), nil)
17
+
18
+ assert_equal 1, @t.events.size
19
+ assert_equal w, @t.events.first.watch
20
+ end
21
+
22
+ def test_timer_should_remove_expired_events
23
+ @t.register(nil, stub(:interval => 0), nil)
24
+ sleep(0.3)
25
+ assert_equal 0, @t.events.size
26
+ end
27
+
28
+ def test_timer_should_remove_only_expired_events
29
+ @t.register(nil, stub(:interval => 0), nil)
30
+ @t.register(nil, stub(:interval => 1000), nil)
31
+ sleep(0.3)
32
+ assert_equal 1, @t.events.size
33
+ end
34
+
35
+ def test_timer_should_sort_timer_events
36
+ @t.register(nil, stub(:interval => 1000), nil)
37
+ @t.register(nil, stub(:interval => 800), nil)
38
+ @t.register(nil, stub(:interval => 900), nil)
39
+ @t.register(nil, stub(:interval => 100), nil)
40
+ sleep(0.3)
41
+ assert_equal [100, 800, 900, 1000], @t.events.map { |x| x.condition.interval }
42
+ end
43
+ end
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestWatch < Test::Unit::TestCase
4
+ def setup
5
+ @watch = Watch.new(nil)
6
+ end
7
+
8
+ def test_should_have_empty_start_conditions
9
+ assert_equal [], @watch.conditions[:start]
10
+ end
11
+
12
+ def test_should_have_empty_restart_conditions
13
+ assert_equal [], @watch.conditions[:restart]
14
+ end
15
+
16
+ def test_should_have_standard_attributes
17
+ assert_nothing_raised do
18
+ @watch.name = 'foo'
19
+ @watch.start = 'start'
20
+ @watch.stop = 'stop'
21
+ @watch.restart = 'restart'
22
+ @watch.interval = 30
23
+ @watch.grace = 5
24
+ end
25
+ end
26
+
27
+ # _if methods
28
+
29
+ def test_start_if_should_modify_action_within_scope
30
+ assert_equal nil, @watch.instance_variable_get(:@action)
31
+ @watch.start_if do |w|
32
+ assert_equal :start, @watch.instance_variable_get(:@action)
33
+ end
34
+ assert_equal nil, @watch.instance_variable_get(:@action)
35
+ end
36
+
37
+ def test_restart_if_should_modify_action_within_scope
38
+ assert_equal nil, @watch.instance_variable_get(:@action)
39
+ @watch.restart_if do |w|
40
+ assert_equal :restart, @watch.instance_variable_get(:@action)
41
+ end
42
+ assert_equal nil, @watch.instance_variable_get(:@action)
43
+ end
44
+
45
+ # condition
46
+
47
+ def test_start_condition_should_record_condition_in_correct_list
48
+ cond = nil
49
+ @watch.interval = 0
50
+ @watch.start_if do |w|
51
+ w.condition(:fake_poll_condition) { |c| cond = c }
52
+ end
53
+ assert_equal 1, @watch.conditions[:start].size
54
+ assert_equal cond, @watch.conditions[:start].first
55
+ end
56
+
57
+ def test_restart_condition_should_record_condition_in_correct_list
58
+ cond = nil
59
+ @watch.interval = 0
60
+ @watch.restart_if do |w|
61
+ w.condition(:fake_poll_condition) { |c| cond = c }
62
+ end
63
+ assert_equal 1, @watch.conditions[:restart].size
64
+ assert_equal cond, @watch.conditions[:restart].first
65
+ end
66
+
67
+ def test_condition_called_from_outside_if_block_should_raise
68
+ assert_raise AbortCalledError do
69
+ @watch.condition(:fake_poll_condition) { |c| cond = c }
70
+ end
71
+ end
72
+
73
+ def test_condition_should_be_block_optional
74
+ @watch.interval = 0
75
+ @watch.start_if do |w|
76
+ w.condition(:always)
77
+ end
78
+ assert_equal 1, @watch.conditions[:start].size
79
+ end
80
+
81
+ def test_poll_condition_should_inherit_interval_from_watch_if_not_specified
82
+ @watch.interval = 27
83
+ @watch.start_if do |w|
84
+ w.condition(:fake_poll_condition)
85
+ end
86
+ assert_equal 27, @watch.conditions[:start].first.interval
87
+ end
88
+
89
+ def test_poll_condition_should_abort_if_no_interval_and_no_watch_interval
90
+ assert_raise AbortCalledError do
91
+ @watch.start_if do |w|
92
+ w.condition(:fake_poll_condition)
93
+ end
94
+ end
95
+ end
96
+
97
+ def test_condition_should_allow_generation_of_subclasses_of_poll_or_event
98
+ @watch.interval = 27
99
+ assert_nothing_raised do
100
+ @watch.start_if do |w|
101
+ w.condition(:fake_poll_condition)
102
+ w.condition(:fake_event_condition)
103
+ end
104
+ end
105
+ end
106
+
107
+ def test_condition_should_abort_if_not_subclass_of_poll_or_event
108
+ assert_raise AbortCalledError do
109
+ @watch.start_if do |w|
110
+ w.condition(:fake_condition) { |c| }
111
+ end
112
+ end
113
+ end
114
+
115
+ # behavior
116
+
117
+ def test_behavior_should_record_behavior
118
+ beh = nil
119
+ @watch.behavior(:fake_behavior) { |b| beh = b }
120
+ assert_equal 1, @watch.behaviors.size
121
+ assert_equal beh, @watch.behaviors.first
122
+ end
123
+ end