god 0.1.0
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.
- data/History.txt +5 -0
- data/Manifest.txt +37 -0
- data/README.txt +42 -0
- data/Rakefile +28 -0
- data/bin/god +26 -0
- data/examples/gravatar.god +41 -0
- data/examples/local.god +60 -0
- data/lib/god.rb +35 -0
- data/lib/god/base.rb +13 -0
- data/lib/god/behavior.rb +67 -0
- data/lib/god/behaviors/clean_pid_file.rb +23 -0
- data/lib/god/condition.rb +48 -0
- data/lib/god/conditions/always.rb +11 -0
- data/lib/god/conditions/cpu_usage.rb +44 -0
- data/lib/god/conditions/memory_usage.rb +44 -0
- data/lib/god/conditions/process_not_running.rb +22 -0
- data/lib/god/conditions/timeline.rb +17 -0
- data/lib/god/errors.rb +12 -0
- data/lib/god/meddle.rb +54 -0
- data/lib/god/reporter.rb +25 -0
- data/lib/god/server.rb +28 -0
- data/lib/god/system/process.rb +56 -0
- data/lib/god/timer.rb +78 -0
- data/lib/god/watch.rb +151 -0
- data/test/configs/real.rb +64 -0
- data/test/helper.rb +93 -0
- data/test/suite.rb +6 -0
- data/test/test_behavior.rb +13 -0
- data/test/test_condition.rb +26 -0
- data/test/test_god.rb +15 -0
- data/test/test_meddle.rb +46 -0
- data/test/test_reporter.rb +18 -0
- data/test/test_server.rb +24 -0
- data/test/test_system_process.rb +42 -0
- data/test/test_timeline.rb +24 -0
- data/test/test_timer.rb +43 -0
- data/test/test_watch.rb +123 -0
- metadata +111 -0
@@ -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
|
data/test/helper.rb
ADDED
@@ -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
|
data/test/suite.rb
ADDED
@@ -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
|
data/test/test_god.rb
ADDED
@@ -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
|
data/test/test_meddle.rb
ADDED
@@ -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
|
data/test/test_server.rb
ADDED
@@ -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
|
data/test/test_timer.rb
ADDED
@@ -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
|
data/test/test_watch.rb
ADDED
@@ -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
|