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,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
+ 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
@@ -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
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestDriver < Test::Unit::TestCase
4
+ def setup
5
+
6
+ end
7
+
8
+ def test_
9
+
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestEmail < Test::Unit::TestCase
4
+ def setup
5
+ God::Contacts::Email.to_email = 'dev@example.com'
6
+ God::Contacts::Email.from_email = 'god@example.com'
7
+ @email = God::Contacts::Email.new
8
+ end
9
+
10
+ def test_validity_delivery
11
+ @email.delivery_method = :brainwaves
12
+ assert_equal false, @email.valid?
13
+ end
14
+
15
+ def test_smtp_delivery_method_for_notify
16
+ @email.delivery_method = :smtp
17
+
18
+ God::Contacts::Email.any_instance.expects(:notify_sendmail).never
19
+ God::Contacts::Email.any_instance.expects(:notify_smtp).once.returns(nil)
20
+
21
+ @email.notify('msg', Time.now, 'prio', 'cat', 'host')
22
+ assert_equal "sent email to dev@example.com via smtp", @email.info
23
+ end
24
+
25
+ def test_sendmail_delivery_method_for_notify
26
+ @email.delivery_method = :sendmail
27
+
28
+ God::Contacts::Email.any_instance.expects(:notify_smtp).never
29
+ God::Contacts::Email.any_instance.expects(:notify_sendmail).once.returns(nil)
30
+
31
+ @email.notify('msg', Time.now, 'prio', 'cat', 'host')
32
+ assert_equal "sent email to dev@example.com via sendmail", @email.info
33
+ end
34
+ end
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ module God
4
+ class EventHandler
5
+
6
+ def self.actions=(value)
7
+ @@actions = value
8
+ end
9
+
10
+ def self.actions
11
+ @@actions
12
+ end
13
+
14
+ def self.handler=(value)
15
+ @@handler = value
16
+ end
17
+ end
18
+ end
19
+
20
+ class TestEventHandler < Test::Unit::TestCase
21
+ def setup
22
+ @h = God::EventHandler
23
+ end
24
+
25
+ def test_register_one_event
26
+ pid = 4445
27
+ event = :proc_exit
28
+ block = lambda {
29
+ puts "Hi"
30
+ }
31
+
32
+ mock_handler = mock()
33
+ mock_handler.expects(:register_process).with(pid, [event])
34
+ @h.handler = mock_handler
35
+
36
+ @h.register(pid, event, &block)
37
+ assert_equal @h.actions, {pid => {event => block}}
38
+ end
39
+
40
+ def test_register_multiple_events_per_process
41
+ pid = 4445
42
+ exit_block = lambda { puts "Hi" }
43
+ @h.actions = {pid => {:proc_exit => exit_block}}
44
+
45
+ mock_handler = mock()
46
+ mock_handler.expects(:register_process).with do |a, b|
47
+ a == pid &&
48
+ b.to_set == [:proc_exit, :proc_fork].to_set
49
+ end
50
+ @h.handler = mock_handler
51
+
52
+ fork_block = lambda { puts "Forking" }
53
+ @h.register(pid, :proc_fork, &fork_block)
54
+ assert_equal @h.actions, {pid => {:proc_exit => exit_block,
55
+ :proc_fork => fork_block }}
56
+ end
57
+
58
+ # JIRA PLATFORM-75
59
+ def test_call_should_check_for_pid_and_action_before_executing
60
+ exit_block = mock()
61
+ exit_block.expects(:call).times 1
62
+ @h.actions = {4445 => {:proc_exit => exit_block}}
63
+ @h.call(4446, :proc_exit) # shouldn't call, bad pid
64
+ @h.call(4445, :proc_fork) # shouldn't call, bad event
65
+ @h.call(4445, :proc_exit) # should call
66
+ end
67
+
68
+ def teardown
69
+ # Reset handler
70
+ @h.actions = {}
71
+ @h.load
72
+ end
73
+ end
74
+
75
+ class TestEventHandlerOperational < Test::Unit::TestCase
76
+ def test_operational
77
+ God::EventHandler.start
78
+ assert God::EventHandler.loaded?
79
+ end
80
+ end
data/test/test_god.rb ADDED
@@ -0,0 +1,570 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestGod < Test::Unit::TestCase
4
+ def setup
5
+ God::Socket.stubs(:new).returns(true)
6
+ God.stubs(:setup).returns(true)
7
+ God.stubs(:validater).returns(true)
8
+ Thread.any_instance.stubs(:join).returns(true)
9
+ God.reset
10
+ God.pid_file_directory = '/var/run/god'
11
+ end
12
+
13
+ def teardown
14
+ God.main && God.main.kill
15
+ if God.watches
16
+ God.watches.each do |k, w|
17
+ w.driver.thread.kill
18
+ end
19
+ end
20
+ end
21
+
22
+ # applog
23
+
24
+ def test_applog
25
+ LOG.expects(:log).with(nil, :debug, 'foo')
26
+ applog(nil, :debug, 'foo')
27
+ end
28
+
29
+ # internal_init
30
+
31
+ def test_init_should_initialize_watches_to_empty_array
32
+ God.internal_init { }
33
+ assert_equal Hash.new, God.watches
34
+ end
35
+
36
+ # init
37
+
38
+ def test_pid_file_directory_should_abort_if_called_after_watch
39
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
40
+
41
+ assert_abort do
42
+ God.pid_file_directory = 'foo'
43
+ end
44
+ end
45
+
46
+ # pid_file_directory
47
+
48
+ def test_pid_file_directory_should_return_default_if_not_set_explicitly
49
+ God.internal_init
50
+ assert_equal '/var/run/god', God.pid_file_directory
51
+ end
52
+
53
+ def test_pid_file_directory_equals_should_set
54
+ God.pid_file_directory = '/foo'
55
+ God.internal_init
56
+ assert_equal '/foo', God.pid_file_directory
57
+ end
58
+
59
+ # watch
60
+
61
+ def test_watch_should_get_stored
62
+ watch = nil
63
+ God.watch do |w|
64
+ w.name = 'foo'
65
+ w.start = 'bar'
66
+ watch = w
67
+ end
68
+
69
+ assert_equal 1, God.watches.size
70
+ assert_equal watch, God.watches.values.first
71
+
72
+ assert_equal 0, God.groups.size
73
+ end
74
+
75
+ def test_watch_should_get_stored_in_pending_watches
76
+ watch = nil
77
+ God.watch do |w|
78
+ w.name = 'foo'
79
+ w.start = 'bar'
80
+ watch = w
81
+ end
82
+
83
+ assert_equal 1, God.pending_watches.size
84
+ assert_equal watch, God.pending_watches.first
85
+ end
86
+
87
+ def test_watch_should_register_processes
88
+ assert_nil God.registry['foo']
89
+ God.watch do |w|
90
+ w.name = 'foo'
91
+ w.start = 'bar'
92
+ end
93
+ assert_kind_of God::Process, God.registry['foo']
94
+ end
95
+
96
+ def test_watch_should_get_stored_by_group
97
+ a = nil
98
+
99
+ God.watch do |w|
100
+ a = w
101
+ w.name = 'foo'
102
+ w.start = 'bar'
103
+ w.group = 'test'
104
+ end
105
+
106
+ assert_equal({'test' => [a]}, God.groups)
107
+ end
108
+
109
+ def test_watches_should_get_stored_by_group
110
+ a = nil
111
+ b = nil
112
+
113
+ God.watch do |w|
114
+ a = w
115
+ w.name = 'foo'
116
+ w.start = 'bar'
117
+ w.group = 'test'
118
+ end
119
+
120
+ God.watch do |w|
121
+ b = w
122
+ w.name = 'bar'
123
+ w.start = 'baz'
124
+ w.group = 'test'
125
+ end
126
+
127
+ assert_equal({'test' => [a, b]}, God.groups)
128
+ end
129
+
130
+ def test_watch_should_allow_multiple_watches
131
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
132
+
133
+ assert_nothing_raised do
134
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
135
+ end
136
+ end
137
+
138
+ def test_watch_should_disallow_duplicate_watch_names
139
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
140
+
141
+ assert_abort do
142
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
143
+ end
144
+ end
145
+
146
+ def test_watch_should_disallow_identical_watch_and_group_names
147
+ God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
148
+
149
+ assert_abort do
150
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
151
+ end
152
+ end
153
+
154
+ def test_watch_should_disallow_identical_watch_and_group_names_other_way
155
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
156
+
157
+ assert_abort do
158
+ God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
159
+ end
160
+ end
161
+
162
+ def test_watch_should_unwatch_new_watch_if_running_and_duplicate_watch
163
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
164
+ God.running = true
165
+
166
+ assert_nothing_raised do
167
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
168
+ end
169
+ end
170
+
171
+ # unwatch
172
+
173
+ def test_unwatch_should_unmonitor_watch
174
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
175
+ w = God.watches['bar']
176
+ w.state = :up
177
+ w.expects(:unmonitor)
178
+ God.unwatch(w)
179
+ end
180
+
181
+ def test_unwatch_should_unregister_watch
182
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
183
+ w = God.watches['bar']
184
+ w.expects(:unregister!)
185
+ God.unwatch(w)
186
+ end
187
+
188
+ def test_unwatch_should_remove_same_name_watches
189
+ God.watch { |w| w.name = 'bar'; w.start = 'bar' }
190
+ w = God.watches['bar']
191
+ God.unwatch(w)
192
+ assert_equal 0, God.watches.size
193
+ end
194
+
195
+ def test_unwatch_should_remove_from_group
196
+ God.watch do |w|
197
+ w.name = 'bar'
198
+ w.start = 'baz'
199
+ w.group = 'test'
200
+ end
201
+ w = God.watches['bar']
202
+ God.unwatch(w)
203
+ assert !God.groups[w.group].include?(w)
204
+ end
205
+
206
+ # contact
207
+
208
+ def test_contact_should_ensure_init_is_called
209
+ God.contact(:fake_contact) { |c| c.name = 'tom' }
210
+ assert God.inited
211
+ end
212
+
213
+ def test_contact_should_abort_on_invalid_contact_kind
214
+ assert_abort do
215
+ God.contact(:foo) { |c| c.name = 'tom' }
216
+ end
217
+ end
218
+
219
+ def test_contact_should_create_and_store_contact
220
+ contact = nil
221
+ God.contact(:fake_contact) { |c| c.name = 'tom'; contact = c }
222
+ assert [contact], God.contacts
223
+ end
224
+
225
+ def test_contact_should_add_to_group
226
+ God.contact(:fake_contact) { |c| c.name = 'tom'; c.group = 'devs' }
227
+ God.contact(:fake_contact) { |c| c.name = 'chris'; c.group = 'devs' }
228
+ assert 2, God.contact_groups.size
229
+ end
230
+
231
+ def test_contact_should_abort_on_no_name
232
+ assert_abort do
233
+ God.contact(:fake_contact) { |c| }
234
+ end
235
+ end
236
+
237
+ def test_contact_should_abort_on_duplicate_contact_name
238
+ God.contact(:fake_contact) { |c| c.name = 'tom' }
239
+ assert_nothing_raised do
240
+ God.contact(:fake_contact) { |c| c.name = 'tom' }
241
+ end
242
+ end
243
+
244
+ def test_contact_should_abort_on_contact_with_same_name_as_group
245
+ God.contact(:fake_contact) { |c| c.name = 'tom'; c.group = 'devs' }
246
+ assert_nothing_raised do
247
+ God.contact(:fake_contact) { |c| c.name = 'devs' }
248
+ end
249
+ end
250
+
251
+ def test_contact_should_abort_on_contact_with_same_group_as_name
252
+ God.contact(:fake_contact) { |c| c.name = 'tom' }
253
+ assert_abort do
254
+ God.contact(:fake_contact) { |c| c.name = 'chris'; c.group = 'tom' }
255
+ end
256
+ end
257
+
258
+ def test_contact_should_abort_if_contact_is_invalid
259
+ assert_abort do
260
+ God.contact(:fake_contact) do |c|
261
+ c.name = 'tom'
262
+ c.stubs(:valid?).returns(false)
263
+ end
264
+ end
265
+ end
266
+
267
+ # control
268
+
269
+ def test_control_should_monitor_on_start
270
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
271
+
272
+ w = God.watches['foo']
273
+ w.expects(:monitor)
274
+ God.control('foo', 'start')
275
+ end
276
+
277
+ def test_control_should_move_to_restart_on_restart
278
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
279
+
280
+ w = God.watches['foo']
281
+ w.expects(:move).with(:restart)
282
+ God.control('foo', 'restart')
283
+ end
284
+
285
+ def test_control_should_unmonitor_and_stop_on_stop
286
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
287
+
288
+ w = God.watches['foo']
289
+ w.state = :up
290
+ w.expects(:unmonitor).returns(w)
291
+ w.expects(:action).with(:stop)
292
+ God.control('foo', 'stop')
293
+ end
294
+
295
+ def test_control_should_unmonitor_on_unmonitor
296
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
297
+
298
+ w = God.watches['foo']
299
+ w.state = :up
300
+ w.expects(:unmonitor).returns(w)
301
+ God.control('foo', 'unmonitor')
302
+ end
303
+
304
+ def test_control_should_unwatch_on_remove
305
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
306
+
307
+ w = God.watches['foo']
308
+ w.state = :up
309
+ God.expects(:unwatch)
310
+ God.control('foo', 'remove')
311
+ end
312
+
313
+ def test_control_should_raise_on_invalid_command
314
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
315
+
316
+ assert_raise InvalidCommandError do
317
+ God.control('foo', 'invalid')
318
+ end
319
+ end
320
+
321
+ def test_control_should_operate_on_each_watch_in_group
322
+ God.watch do |w|
323
+ w.name = 'foo1'
324
+ w.start = 'go'
325
+ w.group = 'bar'
326
+ end
327
+
328
+ God.watch do |w|
329
+ w.name = 'foo2'
330
+ w.start = 'go'
331
+ w.group = 'bar'
332
+ end
333
+
334
+ God.watches['foo1'].expects(:monitor)
335
+ God.watches['foo2'].expects(:monitor)
336
+
337
+ God.control('bar', 'start')
338
+ end
339
+
340
+ # stop_all
341
+
342
+ # terminate
343
+
344
+ def test_terminate_should_exit
345
+ God.pid = nil
346
+ FileUtils.expects(:rm_f).never
347
+ God.expects(:exit!)
348
+ God.terminate
349
+ end
350
+
351
+ def test_terminate_should_delete_pid
352
+ God.pid = '/foo/bar'
353
+ FileUtils.expects(:rm_f).with("/foo/bar")
354
+ God.expects(:exit!)
355
+ God.terminate
356
+ end
357
+
358
+ # status
359
+
360
+ def test_status_should_show_state
361
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
362
+
363
+ w = God.watches['foo']
364
+ w.state = :up
365
+ assert_equal({'foo' => {:state => :up, :group => nil}}, God.status)
366
+ end
367
+
368
+ def test_status_should_show_state_with_group
369
+ God.watch { |w| w.name = 'foo'; w.start = 'bar'; w.group = 'g' }
370
+
371
+ w = God.watches['foo']
372
+ w.state = :up
373
+ assert_equal({'foo' => {:state => :up, :group => 'g'}}, God.status)
374
+ end
375
+
376
+ def test_status_should_show_unmonitored_for_nil_state
377
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
378
+
379
+ w = God.watches['foo']
380
+ assert_equal({'foo' => {:state => :unmonitored, :group => nil}}, God.status)
381
+ end
382
+
383
+ # running_log
384
+
385
+ def test_running_log_should_call_watch_log_since_on_main_log
386
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
387
+ t = Time.now
388
+ LOG.expects(:watch_log_since).with('foo', t)
389
+ God.running_log('foo', t)
390
+ end
391
+
392
+ def test_running_log_should_raise_on_unknown_watch
393
+ God.internal_init
394
+ assert_raise(NoSuchWatchError) do
395
+ God.running_log('foo', Time.now)
396
+ end
397
+ end
398
+
399
+ # running_load
400
+
401
+ def test_running_load_should_eval_code
402
+ code = <<-EOF
403
+ God.watch do |w|
404
+ w.name = 'foo'
405
+ w.start = 'go'
406
+ end
407
+ EOF
408
+
409
+ God.running_load(code, '/foo/bar.god')
410
+
411
+ assert_equal 1, God.watches.size
412
+ end
413
+
414
+ def test_running_load_should_monitor_new_watches
415
+ code = <<-EOF
416
+ God.watch do |w|
417
+ w.name = 'foo'
418
+ w.start = 'go'
419
+ end
420
+ EOF
421
+
422
+ Watch.any_instance.expects(:monitor)
423
+ God.running_load(code, '/foo/bar.god')
424
+ end
425
+
426
+ def test_running_load_should_not_monitor_new_watches_with_autostart_false
427
+ code = <<-EOF
428
+ God.watch do |w|
429
+ w.name = 'foo'
430
+ w.start = 'go'
431
+ w.autostart = false
432
+ end
433
+ EOF
434
+
435
+ Watch.any_instance.expects(:monitor).never
436
+ God.running_load(code, '/foo/bar.god')
437
+ end
438
+
439
+ def test_running_load_should_return_array_of_affected_watches
440
+ code = <<-EOF
441
+ God.watch do |w|
442
+ w.name = 'foo'
443
+ w.start = 'go'
444
+ end
445
+ EOF
446
+
447
+ w = nil
448
+ w, e = *God.running_load(code, '/foo/bar.god')
449
+ assert_equal 1, w.size
450
+ assert_equal 'foo', w.first
451
+ end
452
+
453
+ def test_running_load_should_clear_pending_watches
454
+ code = <<-EOF
455
+ God.watch do |w|
456
+ w.name = 'foo'
457
+ w.start = 'go'
458
+ end
459
+ EOF
460
+
461
+ God.running_load(code, '/foo/bar.god')
462
+ assert_equal 0, God.pending_watches.size
463
+ end
464
+
465
+ # load
466
+
467
+ def test_load_should_collect_and_load_globbed_path
468
+ Dir.expects(:[]).with('/path/to/*.thing').returns(['a', 'b'])
469
+ Kernel.expects(:load).with('a').once
470
+ Kernel.expects(:load).with('b').once
471
+ God.load('/path/to/*.thing')
472
+ end
473
+
474
+ # start
475
+
476
+ def test_start_should_kick_off_a_server_instance
477
+ God::Socket.expects(:new).returns(true)
478
+ God.start
479
+ end
480
+
481
+ def test_start_should_begin_monitoring_autostart_watches
482
+ God.watch do |w|
483
+ w.name = 'foo'
484
+ w.start = 'go'
485
+ end
486
+
487
+ Watch.any_instance.expects(:monitor).once
488
+ God.start
489
+ end
490
+
491
+ def test_start_should_not_begin_monitoring_non_autostart_watches
492
+ God.watch do |w|
493
+ w.name = 'foo'
494
+ w.start = 'go'
495
+ w.autostart = false
496
+ end
497
+
498
+ Watch.any_instance.expects(:monitor).never
499
+ God.start
500
+ end
501
+
502
+ def test_start_should_get_and_join_timer
503
+ God.watch { |w| w.name = 'foo'; w.start = 'bar' }
504
+ God.start
505
+ end
506
+
507
+ # at_exit
508
+
509
+ def test_at_exit_should_call_start
510
+ God.expects(:start).once
511
+ God.at_exit
512
+ end
513
+
514
+ # pattern_match
515
+
516
+ def test_pattern_match
517
+ list = %w{ mongrel-3000 mongrel-3001 fuzed22 fuzed fuzed2 apache mysql}
518
+
519
+ assert_equal %w{ mongrel-3000 }, God.pattern_match('m3000', list)
520
+ assert_equal %w{ mongrel-3001 }, God.pattern_match('m31', list)
521
+ assert_equal %w{ fuzed fuzed2 fuzed22}, God.pattern_match('fu', list)
522
+ assert_equal %w{ mysql }, God.pattern_match('sql', list)
523
+ end
524
+ end
525
+
526
+
527
+ # class TestGodOther < Test::Unit::TestCase
528
+ # def setup
529
+ # God::Socket.stubs(:new).returns(true)
530
+ # God.internal_init
531
+ # God.reset
532
+ # end
533
+ #
534
+ # def teardown
535
+ # God.main && God.main.kill
536
+ # end
537
+ #
538
+ # # setup
539
+ #
540
+ # def test_setup_should_create_pid_file_directory_if_it_doesnt_exist
541
+ # God.expects(:test).returns(false)
542
+ # FileUtils.expects(:mkdir_p).with(God.pid_file_directory)
543
+ # God.setup
544
+ # end
545
+ #
546
+ # def test_setup_should_raise_if_no_permissions_to_create_pid_file_directory
547
+ # God.expects(:test).returns(false)
548
+ # FileUtils.expects(:mkdir_p).raises(Errno::EACCES)
549
+ #
550
+ # assert_abort do
551
+ # God.setup
552
+ # end
553
+ # end
554
+ #
555
+ # # validate
556
+ #
557
+ # def test_validate_should_abort_if_pid_file_directory_is_unwriteable
558
+ # God.expects(:test).returns(false)
559
+ # assert_abort do
560
+ # God.validater
561
+ # end
562
+ # end
563
+ #
564
+ # def test_validate_should_not_abort_if_pid_file_directory_is_writeable
565
+ # God.expects(:test).returns(true)
566
+ # assert_nothing_raised do
567
+ # God.validater
568
+ # end
569
+ # end
570
+ # end