Codebase list ruby-god / 73f81c1
Imported Upstream version 0.13.6 Sébastien Delafond 8 years ago
48 changed file(s) with 591 addition(s) and 114 deletion(s). Raw diff Collapse all Expand all
0 == 0.13.6 / 2015-02-21
1 * Minor Enhancements
2 * sensu notifier (#199)
3
4 == 0.13.5 / 2015-01-09
5 * Minor Enhancements
6 * statsd notifier (#144)
7 * Slack notifier (#172)
8 * Bug fixes
9 * Add support for Ruby 2.2.0 (#206)
10 * Fix tests for Ruby 2.0 (#205)
11 * Make group assignment more like login (#159)
12 * Flush file descriptors to prevent too many processes from being started (#141)
13 * Allow SSL URLs (#168)
14 * Documentation fixes
15 * Clarify Hipchat privilege requirements (#176)
16
017 == 0.13.4 / 2014-03-05
118 * Minor Enhancements
219 * Hipchat reporter (#162)
435435 restart operations. You can define as many watches as you like. In the example
436436 above, I've got some Rails instances running in Mongrels that I need to keep
437437 alive. Every watch must have a unique `name` so that it can be identified
438 later on. The `start` and `stop` attributes specify the commands to start
439 and stop the process. If no `restart` attribute is set, restart will be
438 later on. The `start` and `stop` attributes specify the commands to start
439 and stop the process. If no `restart` attribute is set, restart will be
440440 represented by a call to stop followed by a call to start. The
441441 optional `grace` attribute sets the amount of time following a
442442 start/stop/restart command to wait before resuming normal monitoring
574574 Need to watch a script that doesn't have built in daemonization? No problem!
575575 God will daemonize and keep track of your process for you. If you don't
576576 specify a `pid_file` attribute for a watch, it will be auto-daemonized and a
577 PID file will be stored for it in `/var/run/god`.
577 PID file will be stored for it in `/var/run/god`.
578578
579579
580580 ```ruby
584584 God.watch do |w|
585585 w.name = 'mongrel'
586586 w.pid_file = w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
587
587
588588 w.start = "mongrel_rails start -P #{RAILS_ROOT}/log/mongrel.pid -d"
589
589
590590 # ...
591591 end
592592
594594 God.watch do |w|
595595 w.name = 'worker'
596596 # w.pid_file = is not set
597
597
598598 w.start = "rake resque:worker"
599
599
600600 # ...
601601 end
602602 ```
603603
604604
605 If you'd rather have the PID file stored in a different location, you can
605 If you'd rather have the PID file stored in a different location, you can
606606 set it at the top of your config:
607607
608608 ```ruby
10201020 (default: false).
10211021 from - The String representing who the message should be sent as.
10221022 ```
1023
1024 NOTE: in Hipchat you must have a token with 'admin' privileges. 'Notification' privileges will not be enough.
10231025
10241026 Email
10251027 ~~~~~
12421244 apikey - The String API key.
12431245 ```
12441246
1247 Slack
1248 ~~~~~
1249
1250 Send a message to a channel in Slack (https://slack.com/).
1251
1252 First, set up an Incoming Webhook in your Slack account.
1253
1254 Then, in your God configuration, set the defaults:
1255
1256 ```ruby
1257 God::Contacts::Slack.defaults do |d|
1258 d.account = "foo"
1259 d.token = "abc123abc123abc123"
1260 c.notify_channel = true
1261 c.format = '%{host} alert: %{message}'
1262 end
1263 ```
1264
1265 `account` is the name of your Slack account; if you view slack at
1266 "foo.slack.com", then your account is "foo". `token` is from your
1267 newly-created webhook, and will be a string of unintelligible
1268 characters.
1269
1270 The `notify_channel` and `format` settings are optional. The first
1271 controls whether the message includes `@channel` (sending notifications
1272 to everyone in the channel); the second controls how the message is
1273 formatted. Acceptable values within the format are `priority`, `host`,
1274 `message`, `category`, and `time`.
1275
1276 Once you've set the defaults, create contacts for the channels that you
1277 want to notify. You can create as many as you like, and they'll look
1278 something like this:
1279
1280 ```ruby
1281 God.contact(:slack) do |c|
1282 c.name = '#ops'
1283 c.channel = '#ops'
1284 end
1285 ```
1286
12451287 /////////////////////////////////////////////////////////////////////////////
12461288 /////////////////////////////////////////////////////////////////////////////
12471289
88 end
99 end
1010
11 have_func('rb_wait_for_single_fd')
1112 case RUBY_PLATFORM
1213 when /bsd/i, /darwin/i
1314 unless have_header('sys/event.h')
33 #include <sys/event.h>
44 #include <sys/time.h>
55 #include <errno.h>
6
7 #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
8 #include <ruby/io.h>
9 #endif
610
711 static VALUE mGod;
812 static VALUE cKQueueHandler;
6266 {
6367 int nevents, i, num_to_fetch;
6468 struct kevent *events;
69
70 #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
71 rb_wait_for_single_fd(kq, RB_WAITFD_IN, NULL);
72 #else
6573 fd_set read_set;
6674
6775 FD_ZERO(&read_set);
6977
7078 // Don't actually run this method until we've got an event
7179 rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
72
80 #endif
7381 // Grabbing num_events once for thread safety
7482 num_to_fetch = num_events;
7583 events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
00 #ifdef __linux__ /* only build on linux */
11
22 #include <ruby.h>
3
4 #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
5 #include <ruby/io.h>
6 #endif
7
8
39 #include <sys/types.h>
410 #include <unistd.h>
511 #include <sys/socket.h>
3036
3137 VALUE extra_data;
3238
39 #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
40 int ret;
41 if((ret = rb_wait_for_single_fd(nl_sock, RB_WAITFD_IN, NULL)) < 0){
42 rb_raise(rb_eStandardError, "%s", strerror(errno));
43 }
44 /* If there were no events detected, return */
45 if(!(ret & RB_WAITFD_IN)){
46 return INT2FIX(0);
47 }
48 #else
3349 fd_set fds;
3450
3551 FD_ZERO(&fds);
4359 if (! FD_ISSET(nl_sock, &fds)) {
4460 return INT2FIX(0);
4561 }
62 #endif
4663
4764 /* if there are events, make calls */
4865 if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
22 s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
33
44 s.name = 'god'
5 s.version = '0.13.4'
6 s.date = '2014-03-05'
5 s.version = '0.13.6'
6 s.date = '2015-03-21'
77
88 s.summary = "Process monitoring framework."
99 s.description = "An easy to configure, easy to extend monitoring framework written in Ruby."
2424
2525 s.add_development_dependency('json', '~> 1.6')
2626 s.add_development_dependency('rake')
27 s.add_development_dependency('minitest')
2728 s.add_development_dependency('rdoc', '~> 3.10')
2829 s.add_development_dependency('twitter', '~> 4.0')
2930 s.add_development_dependency('prowly', '~> 0.3')
3031 s.add_development_dependency('xmpp4r', '~> 0.5')
3132 s.add_development_dependency('dike', '~> 0.0.3')
32 s.add_development_dependency('rcov', '~> 0.9')
33 # s.add_development_dependency('rcov', '~> 0.9')
3334 s.add_development_dependency('daemons', '~> 1.1')
3435 s.add_development_dependency('mocha', '~> 0.10')
3536 s.add_development_dependency('gollum', '~> 1.3.1')
37 #the last version to support 1.8.7 is 0.99.6
38 s.add_development_dependency('mustache', ['~> 0.99.0', '< 0.99.7'])
3639 s.add_development_dependency('airbrake', '~> 3.1.7')
3740 s.add_development_dependency('nokogiri', '~> 1.5.0')
3841 s.add_development_dependency('activesupport', [ '>= 2.3.10', '< 4.0.0' ])
42 s.add_development_dependency('statsd-ruby')
43 s.add_development_dependency('i18n', '< 0.7.0')
3944 # = MANIFEST =
4045 s.files = %w[
4146 Announce.txt
8691 lib/god/contacts/jabber.rb
8792 lib/god/contacts/prowl.rb
8893 lib/god/contacts/scout.rb
94 lib/god/contacts/sensu.rb
95 lib/god/contacts/slack.rb
96 lib/god/contacts/statsd.rb
8997 lib/god/contacts/twitter.rb
9098 lib/god/contacts/webhook.rb
9199 lib/god/driver.rb
161169 test/test_process.rb
162170 test/test_prowl.rb
163171 test/test_registry.rb
172 test/test_sensu.rb
173 test/test_slack.rb
164174 test/test_socket.rb
175 test/test_statsd.rb
165176 test/test_sugar.rb
166177 test/test_system_portable_poller.rb
167178 test/test_system_process.rb
0 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 # Send a notice to a SENSU client socket, port 3030 on 'localhost' only.
2 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 # [mandatory]
4 # check_name - a unique check name
5 #
6 # [optional]
7 # status_code - status codes used are 0 for OK, 1 for WARNING, 2 for CRITICAL, and 3 or greater to indicate UNKNOWN or CUSTOM.
8 # handler - default handler
9 #
10
11 CONTACT_DEPS[:sensu] = ['json']
12 CONTACT_DEPS[:sensu].each do |d|
13 require d
14 end
15
16 module God
17 module Contacts
18
19 class Sensu < Contact
20 class << self
21 attr_accessor :check_name, :status_code, :handler, :host, :port
22 end
23
24 self.status_code = 2
25 self.handler = 'default'
26 self.host = 'localhost'
27 self.port = 3030
28
29 def valid?
30 valid = true
31 valid &= complain("Attribute 'check_name' must be specified", self) unless arg(:check_name)
32 valid
33 end
34
35 attr_accessor :check_name, :status_code, :handler, :host, :port
36
37 def sensu_client_socket(msg)
38 u = UDPSocket.new
39 u.send(msg + "\n", 0, arg(:host).nil? ? self.host : arg(:host), arg(:port).nil? ? self.port : arg(:port))
40 u.close
41 end
42
43 def notify(message, time, priority, category, host)
44 data = {
45 :category => category,
46 :message => message,
47 :priority => priority,
48 :host => host,
49 :time => time,
50 }
51 parcel = { 'name' => arg(:check_name), 'status' => arg(:status_code).nil? ? self.status_code : arg(:status_code), 'output' => data.to_json, 'handler' => arg(:handler).empty? ? self.handler : arg(:handler), 'executed' => Time.now.to_i }
52 sensu_client_socket parcel.to_json
53 self.info = "notified sensu: #{arg(:check_name)}"
54 end
55 end
56 end
57 end
58
0 # Send a message to a Slack channel
1 #
2 # account - The name of your Slack account (visible in URL, e.g. foo.slack.com)
3 # token - The token of the webhook created in Slack
4 # channel - The name of the channel to send the message to, prefixed with #
5 # notify_channel - Whether to send an "@channel" in the message, to alert everyone in the channel
6 # format - An optional format string to change how the alert is displayed
7
8 require 'net/http'
9 require 'uri'
10
11 CONTACT_DEPS[:slack] = ['json']
12 CONTACT_DEPS[:slack].each do |d|
13 require d
14 end
15
16 module God
17 module Contacts
18
19 class Slack < Contact
20 class << self
21 attr_accessor :account, :token, :channel, :notify_channel, :format, :username, :emoji
22 end
23
24 self.channel = "#general"
25 self.notify_channel = false
26 self.format = "%{priority} alert on %{host}: %{message} (%{category}, %{time})"
27
28 def valid?
29 valid = true
30 valid &= complain("Attribute 'account' must be specified", self) unless arg(:account)
31 valid &= complain("Attribute 'token' must be specified", self) unless arg(:token)
32 valid
33 end
34
35 attr_accessor :account, :token, :channel, :notify_channel, :format, :username, :emoji
36
37 def text(data)
38 text = ""
39 text << "<!channel> " if arg(:notify_channel)
40
41 if RUBY_VERSION =~ /^1\.8/
42 text << arg(:format).gsub(/%\{(\w+)\}/) do |match|
43 data[$1.to_sym]
44 end
45 else
46 text << arg(:format) % data
47 end
48
49 text
50 end
51
52 def notify(message, time, priority, category, host)
53 text = text({
54 :message => message,
55 :time => time,
56 :priority => priority,
57 :category => category,
58 :host => host
59 })
60
61 request(text)
62 end
63
64 def api_url
65 URI.parse("https://#{arg(:account)}.slack.com/services/hooks/incoming-webhook?token=#{arg(:token)}")
66 end
67
68 def request(text)
69 http = Net::HTTP.new(api_url.host, api_url.port)
70 http.use_ssl = true
71
72 req = Net::HTTP::Post.new(api_url.request_uri)
73 req.body = {
74 :link_names => 1,
75 :text => text,
76 :channel => arg(:channel)
77 }.tap { |payload|
78 payload[:username] = arg(:username) if arg(:username)
79 payload[:icon_emoji] = arg(:emoji) if arg(:emoji)
80 }.to_json
81
82 res = http.request(req)
83
84 case res
85 when Net::HTTPSuccess
86 self.info = "successfully notified slack on channel #{arg(:channel)}"
87 else
88 self.info = "failed to send webhook to #{arg(:url)}: #{res.error!}"
89 end
90 rescue Object => e
91 applog(nil, :info, "failed to send webhook to #{arg(:url)}: #{e.message}")
92 applog(nil, :debug, e.backtrace.join("\n"))
93 end
94
95 end
96
97 end
98 end
99
0 # Send a notice to statsd
1 #
2 # host - statsd host
3 # port - statsd port (optional)
4
5 require 'statsd-ruby'
6
7 module God
8 module Contacts
9
10 class Statsd < Contact
11 class << self
12 attr_accessor :host, :port
13 end
14
15 attr_accessor :host, :port
16
17 def valid?
18 valid = true
19 valid &= complain("Attribute 'statsd_host' must be specified", self) unless arg(:host)
20 valid
21 end
22
23 def notify(message, time, priority, category, hostname)
24 statsd = ::Statsd.new host, (port ? port.to_i : 8125) # 8125 is the default statsd port
25
26 hostname.gsub! /\./, '_'
27 app = message.gsub /([^\s]*).*/, '\1'
28
29 [
30 'cpu out of bounds',
31 'memory out of bounds',
32 'process is flapping'
33 ].each do |event_type|
34 statsd.increment "god.#{event_type.gsub(/\s/, '_')}.#{hostname}.#{app}" if message.include? event_type
35 end
36
37 self.info = 'sent statsd alert'
38 rescue => e
39 applog(nil, :info, "failed to send statsd alert: #{e.message}")
40 applog(nil, :debug, e.backtrace.join("\n"))
41 end
42 end
43
44 end
45 end
4040
4141 uri = URI.parse(arg(:url))
4242 http = Net::HTTP.new(uri.host, uri.port)
43 http.use_ssl = true if uri.scheme == "https"
4344
4445 req = nil
4546 res = nil
3131 begin
3232 uid_num = Etc.getpwnam(self.uid).uid if self.uid
3333 gid_num = Etc.getgrnam(self.gid).gid if self.gid
34 gid_num = Etc.getpwnam(self.uid).gid if self.gid.nil? && self.uid
3435
3536 ::Dir.chroot(self.chroot) if self.chroot
36 ::Process.groups = [gid_num] if self.gid
37 ::Process::Sys.setgid(gid_num) if self.gid
37 ::Process.groups = [gid_num] if gid_num
38 ::Process.initgroups(self.uid, gid_num) if self.uid && gid_num
39 ::Process::Sys.setgid(gid_num) if gid_num
3840 ::Process::Sys.setuid(uid_num) if self.uid
3941 rescue ArgumentError, Errno::EPERM, Errno::ENOENT
4042 exit(1)
4143 end
4244
43 File.writable?(file_in_chroot(file)) ? exit(0) : exit(1)
45 File.writable?(file_in_chroot(file)) ? exit!(0) : exit!(1)
4446 end
4547
4648 wpid, status = ::Process.waitpid2(pid)
245247 r.close
246248 pid = self.spawn(command)
247249 puts pid.to_s # send pid back to forker
250 exit!(0)
248251 end
249252
250253 ::Process.waitpid(opid, 0)
294297 File.umask self.umask if self.umask
295298 uid_num = Etc.getpwnam(self.uid).uid if self.uid
296299 gid_num = Etc.getgrnam(self.gid).gid if self.gid
300 gid_num = Etc.getpwnam(self.uid).gid if self.gid.nil? && self.uid
297301
298302 ::Dir.chroot(self.chroot) if self.chroot
299303 ::Process.setsid
300 ::Process.groups = [gid_num] if self.gid
301 ::Process::Sys.setgid(gid_num) if self.gid
304 ::Process.groups = [gid_num] if gid_num
305 ::Process.initgroups(self.uid, gid_num) if self.uid && gid_num
306 ::Process::Sys.setgid(gid_num) if gid_num
302307 ::Process::Sys.setuid(uid_num) if self.uid
303308 self.dir ||= '/'
304309 Dir.chdir self.dir
8989 load_contact(:jabber)
9090 load_contact(:prowl)
9191 load_contact(:scout)
92 load_contact(:statsd)
9293 load_contact(:twitter)
9394 load_contact(:webhook)
9495 load_contact(:airbrake)
96 load_contact(:slack)
97 load_contact(:sensu)
9598
9699 $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
97100
157160
158161 module God
159162 # The String version number for this package.
160 VERSION = '0.13.4'
163 VERSION = '0.13.6'
161164
162165 # The Integer number of lines of backlog to keep for the logger.
163166 LOG_BUFFER_SIZE_DEFAULT = 100
00 --- !ruby/object:Gem::Specification
11 name: god
22 version: !ruby/object:Gem::Version
3 hash: 35
3 hash: 39
44 prerelease:
55 segments:
66 - 0
77 - 13
8 - 4
9 version: 0.13.4
8 - 6
9 version: 0.13.6
1010 platform: ruby
1111 authors:
1212 - Tom Preston-Werner
1616 bindir: bin
1717 cert_chain: []
1818
19 date: 2014-03-05 00:00:00 -08:00
19 date: 2015-03-21 00:00:00 -07:00
2020 default_executable:
2121 dependencies:
2222 - !ruby/object:Gem::Dependency
5050 type: :development
5151 - !ruby/object:Gem::Dependency
5252 version_requirements: &id003 !ruby/object:Gem::Requirement
53 none: false
54 requirements:
55 - - ">="
56 - !ruby/object:Gem::Version
57 hash: 3
58 segments:
59 - 0
60 version: "0"
61 prerelease: false
62 requirement: *id003
63 name: minitest
64 type: :development
65 - !ruby/object:Gem::Dependency
66 version_requirements: &id004 !ruby/object:Gem::Requirement
5367 none: false
5468 requirements:
5569 - - ~>
6074 - 10
6175 version: "3.10"
6276 prerelease: false
63 requirement: *id003
77 requirement: *id004
6478 name: rdoc
6579 type: :development
6680 - !ruby/object:Gem::Dependency
67 version_requirements: &id004 !ruby/object:Gem::Requirement
81 version_requirements: &id005 !ruby/object:Gem::Requirement
6882 none: false
6983 requirements:
7084 - - ~>
7589 - 0
7690 version: "4.0"
7791 prerelease: false
78 requirement: *id004
92 requirement: *id005
7993 name: twitter
8094 type: :development
8195 - !ruby/object:Gem::Dependency
82 version_requirements: &id005 !ruby/object:Gem::Requirement
96 version_requirements: &id006 !ruby/object:Gem::Requirement
8397 none: false
8498 requirements:
8599 - - ~>
90104 - 3
91105 version: "0.3"
92106 prerelease: false
93 requirement: *id005
107 requirement: *id006
94108 name: prowly
95109 type: :development
96110 - !ruby/object:Gem::Dependency
97 version_requirements: &id006 !ruby/object:Gem::Requirement
111 version_requirements: &id007 !ruby/object:Gem::Requirement
98112 none: false
99113 requirements:
100114 - - ~>
105119 - 5
106120 version: "0.5"
107121 prerelease: false
108 requirement: *id006
122 requirement: *id007
109123 name: xmpp4r
110124 type: :development
111125 - !ruby/object:Gem::Dependency
112 version_requirements: &id007 !ruby/object:Gem::Requirement
126 version_requirements: &id008 !ruby/object:Gem::Requirement
113127 none: false
114128 requirements:
115129 - - ~>
121135 - 3
122136 version: 0.0.3
123137 prerelease: false
124 requirement: *id007
138 requirement: *id008
125139 name: dike
126 type: :development
127 - !ruby/object:Gem::Dependency
128 version_requirements: &id008 !ruby/object:Gem::Requirement
129 none: false
130 requirements:
131 - - ~>
132 - !ruby/object:Gem::Version
133 hash: 25
134 segments:
135 - 0
136 - 9
137 version: "0.9"
138 prerelease: false
139 requirement: *id008
140 name: rcov
141140 type: :development
142141 - !ruby/object:Gem::Dependency
143142 version_requirements: &id009 !ruby/object:Gem::Requirement
191190 requirements:
192191 - - ~>
193192 - !ruby/object:Gem::Version
193 hash: 403
194 segments:
195 - 0
196 - 99
197 - 0
198 version: 0.99.0
199 - - <
200 - !ruby/object:Gem::Version
201 hash: 413
202 segments:
203 - 0
204 - 99
205 - 7
206 version: 0.99.7
207 prerelease: false
208 requirement: *id012
209 name: mustache
210 type: :development
211 - !ruby/object:Gem::Dependency
212 version_requirements: &id013 !ruby/object:Gem::Requirement
213 none: false
214 requirements:
215 - - ~>
216 - !ruby/object:Gem::Version
194217 hash: 13
195218 segments:
196219 - 3
198221 - 7
199222 version: 3.1.7
200223 prerelease: false
201 requirement: *id012
224 requirement: *id013
202225 name: airbrake
203226 type: :development
204227 - !ruby/object:Gem::Dependency
205 version_requirements: &id013 !ruby/object:Gem::Requirement
228 version_requirements: &id014 !ruby/object:Gem::Requirement
206229 none: false
207230 requirements:
208231 - - ~>
214237 - 0
215238 version: 1.5.0
216239 prerelease: false
217 requirement: *id013
240 requirement: *id014
218241 name: nokogiri
219242 type: :development
220243 - !ruby/object:Gem::Dependency
221 version_requirements: &id014 !ruby/object:Gem::Requirement
244 version_requirements: &id015 !ruby/object:Gem::Requirement
222245 none: false
223246 requirements:
224247 - - ">="
238261 - 0
239262 version: 4.0.0
240263 prerelease: false
241 requirement: *id014
264 requirement: *id015
242265 name: activesupport
266 type: :development
267 - !ruby/object:Gem::Dependency
268 version_requirements: &id016 !ruby/object:Gem::Requirement
269 none: false
270 requirements:
271 - - ">="
272 - !ruby/object:Gem::Version
273 hash: 3
274 segments:
275 - 0
276 version: "0"
277 prerelease: false
278 requirement: *id016
279 name: statsd-ruby
280 type: :development
281 - !ruby/object:Gem::Dependency
282 version_requirements: &id017 !ruby/object:Gem::Requirement
283 none: false
284 requirements:
285 - - <
286 - !ruby/object:Gem::Version
287 hash: 3
288 segments:
289 - 0
290 - 7
291 - 0
292 version: 0.7.0
293 prerelease: false
294 requirement: *id017
295 name: i18n
243296 type: :development
244297 description: An easy to configure, easy to extend monitoring framework written in Ruby.
245298 email: god-rb@googlegroups.com
298351 - lib/god/contacts/jabber.rb
299352 - lib/god/contacts/prowl.rb
300353 - lib/god/contacts/scout.rb
354 - lib/god/contacts/sensu.rb
355 - lib/god/contacts/slack.rb
356 - lib/god/contacts/statsd.rb
301357 - lib/god/contacts/twitter.rb
302358 - lib/god/contacts/webhook.rb
303359 - lib/god/driver.rb
373429 - test/test_process.rb
374430 - test/test_prowl.rb
375431 - test/test_registry.rb
432 - test/test_sensu.rb
433 - test/test_slack.rb
376434 - test/test_socket.rb
435 - test/test_statsd.rb
377436 - test/test_sugar.rb
378437 - test/test_system_portable_poller.rb
379438 - test/test_system_process.rb
440499 - test/test_process.rb
441500 - test/test_prowl.rb
442501 - test/test_registry.rb
502 - test/test_sensu.rb
503 - test/test_slack.rb
443504 - test/test_socket.rb
505 - test/test_statsd.rb
444506 - test/test_sugar.rb
445507 - test/test_system_portable_poller.rb
446508 - test/test_system_process.rb
66 require File.join(File.dirname(__FILE__), *%w[.. lib god])
77 God::EventHandler.load
88
9 require 'test/unit'
9 require 'minitest/autorun'
10 require 'minitest/unit'
1011 require 'set'
1112
1213 include God
114115 # end
115116 # end
116117
117 module Test::Unit::Assertions
118 module Minitest::Assertions
118119 def assert_abort
119 assert_raise SystemExit do
120 assert_raises SystemExit do
120121 yield
121122 end
123 end
124
125 def assert_nothing_raised
126 yield
122127 end
123128 end
124129
00 #!/usr/bin/env ruby
11 require File.dirname(__FILE__) + '/helper'
22
3 class TestAirbrake < Test::Unit::TestCase
3 class TestAirbrake < Minitest::Test
44 def test_notify
55 airbrake = God::Contacts::Airbrake.new
66 airbrake.apikey = "put_your_apikey_here"
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestBehavior < Test::Unit::TestCase
2 class TestBehavior < Minitest::Test
33 def test_generate_should_return_an_object_corresponding_to_the_given_type
44 assert_equal Behaviors::FakeBehavior, Behavior.generate(:fake_behavior, nil).class
55 end
66
77 def test_generate_should_raise_on_invalid_type
8 assert_raise NoSuchBehaviorError do
8 assert_raises NoSuchBehaviorError do
99 Behavior.generate(:foo, nil)
1010 end
1111 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestCampfire < Test::Unit::TestCase
2 class TestCampfire < Minitest::Test
33 def setup
44 @campfire = God::Contacts::Campfire.new
55 end
22 class BadlyImplementedCondition < PollCondition
33 end
44
5 class TestCondition < Test::Unit::TestCase
5 class TestCondition < Minitest::Test
66
77 # generate
88
1111 end
1212
1313 def test_generate_should_raise_on_invalid_type
14 assert_raise NoSuchConditionError do
14 assert_raises NoSuchConditionError do
1515 Condition.generate(:foo, nil)
1616 end
1717 end
4444 def test_test_should_raise_if_not_defined_in_subclass
4545 c = BadlyImplementedCondition.new
4646
47 assert_raise AbstractMethodNotOverriddenError do
47 assert_raises AbstractMethodNotOverriddenError do
4848 c.test
4949 end
5050 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestConditionsDiskUsage < Test::Unit::TestCase
2 class TestConditionsDiskUsage < Minitest::Test
33 # valid?
44
55 def test_valid_should_return_false_if_no_above_given
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestHttpResponseCode < Test::Unit::TestCase
2 class TestHttpResponseCode < Minitest::Test
33 def valid_condition
44 c = Conditions::HttpResponseCode.new()
55 c.watch = stub(:name => 'foo')
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestConditionsProcessRunning < Test::Unit::TestCase
2 class TestConditionsProcessRunning < Minitest::Test
33 def test_missing_pid_file_returns_opposite
44 [true, false].each do |r|
55 c = Conditions::ProcessRunning.new
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestConditionsSocketResponding < Test::Unit::TestCase
2 class TestConditionsSocketResponding < Minitest::Test
33 # valid?
44
55 def test_valid_should_return_false_if_no_options_set
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestConditionsTries < Test::Unit::TestCase
2 class TestConditionsTries < Minitest::Test
33 # valid?
44
55 def test_valid_should_return_false_if_times_not_set
1010 end
1111
1212
13 class TestConditionsTries < Test::Unit::TestCase
13 class TestConditionsTries < Minitest::Test
1414 def setup
1515 @c = Conditions::Tries.new
1616 @c.times = 3
4141 end
4242
4343
44 class TestConditionsTriesWithin < Test::Unit::TestCase
44 class TestConditionsTriesWithin < Minitest::Test
4545 def setup
4646 @c = Conditions::Tries.new
4747 @c.times = 3
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestContact < Test::Unit::TestCase
2 class TestContact < Minitest::Test
33 def test_exists
44 God::Contact
55 end
77 # generate
88
99 def test_generate_should_raise_on_invalid_kind
10 assert_raise(NoSuchContactError) do
10 assert_raises(NoSuchContactError) do
1111 Contact.generate(:invalid)
1212 end
1313 end
5858
5959 def test_normalize_should_raise_on_non_string_array_hash
6060 input = 1
61 assert_raise ArgumentError do
61 assert_raises ArgumentError do
6262 Contact.normalize(input)
6363 end
6464 end
6565
6666 def test_normalize_should_raise_on_non_string_array_contacts_key
6767 input = {:contacts => 1}
68 assert_raise ArgumentError do
68 assert_raises ArgumentError do
6969 Contact.normalize(input)
7070 end
7171 end
7272
7373 def test_normalize_should_raise_on_non_string_containing_array
7474 input = [1]
75 assert_raise ArgumentError do
75 assert_raises ArgumentError do
7676 Contact.normalize(input)
7777 end
7878 end
7979
8080 def test_normalize_should_raise_on_non_string_containing_array_contacts_key
8181 input = {:contacts => [1]}
82 assert_raise ArgumentError do
82 assert_raises ArgumentError do
8383 Contact.normalize(input)
8484 end
8585 end
8686
8787 def test_normalize_should_raise_on_absent_contacts_key
8888 input = {}
89 assert_raise ArgumentError do
89 assert_raises ArgumentError do
9090 Contact.normalize(input)
9191 end
9292 end
9393
9494 def test_normalize_should_raise_on_extra_keys
9595 input = {:contacts => ['tom'], :priority => 1, :category => 'product', :extra => 'foo'}
96 assert_raise ArgumentError do
96 assert_raises ArgumentError do
9797 Contact.normalize(input)
9898 end
9999 end
101101 # notify
102102
103103 def test_notify_should_be_abstract
104 assert_raise(AbstractMethodNotOverriddenError) do
104 assert_raises(AbstractMethodNotOverriddenError) do
105105 Contact.new.notify(:a, :b, :c, :d, :e)
106106 end
107107 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestDriver < Test::Unit::TestCase
2 class TestDriver < Minitest::Test
33 def setup
44
55 end
66
77 def test_push_pop_wait
8
89 eq = God::DriverEventQueue.new
9
10 MonitorMixin::ConditionVariable.any_instance.expects(:wait).times(1)
10 cond = eq.instance_variable_get(:@resource)
11 cond.expects(:wait).times(1)
1112
1213 eq.push(God::TimedEvent.new(0))
1314 eq.push(God::TimedEvent.new(0.1))
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestEmail < Test::Unit::TestCase
2 class TestEmail < Minitest::Test
33 def setup
44 God::Contacts::Email.to_email = 'dev@example.com'
55 God::Contacts::Email.from_email = 'god@example.com'
1616 end
1717 end
1818
19 class TestEventHandler < Test::Unit::TestCase
19 class TestEventHandler < Minitest::Test
2020 def setup
2121 @h = God::EventHandler
2222 end
7373
7474 # This doesn't currently work:
7575 #
76 # class TestEventHandlerOperational < Test::Unit::TestCase
76 # class TestEventHandlerOperational < Minitest::Test
7777 # def test_operational
7878 # God::EventHandler.start
7979 # assert God::EventHandler.loaded?
00 require File.dirname(__FILE__) + '/helper'
1
2 class TestGod < Test::Unit::TestCase
1 class TestGod < MiniTest::Test
32 def setup
43 God::Socket.stubs(:new).returns(true)
54 God.stubs(:setup).returns(true)
1514 w.driver.thread.kill
1615 end
1716 end
17 God.reset
18 #Some of the tests in this file intentionally set pid_file_directory to an invalid value
19 #This can cause a later test failure since God will call abort if pid_file_directory is not writable
20 God.pid_file_directory = '~/.god/pids'
1821 end
1922
2023 # applog
3134 assert_equal Hash.new, God.watches
3235 end
3336
34 # init
37 # # init
3538
3639 def test_pid_file_directory_should_abort_if_called_after_watch
3740 God.watch { |w| w.name = 'foo'; w.start = 'bar' }
38
3941 assert_abort do
4042 God.pid_file_directory = 'foo'
4143 end
312314 def test_control_should_raise_on_invalid_command
313315 God.watch { |w| w.name = 'foo'; w.start = 'bar' }
314316
315 assert_raise InvalidCommandError do
317 assert_raises InvalidCommandError do
316318 God.control('foo', 'invalid')
317319 end
318320 end
450452
451453 def test_running_log_should_raise_on_unknown_watch
452454 God.internal_init
453 assert_raise(NoSuchWatchError) do
455 assert_raises(NoSuchWatchError) do
454456 God.running_log('foo', Time.now)
455457 end
456458 end
661663 end
662664
663665
664 # class TestGodOther < Test::Unit::TestCase
666 # class TestGodOther < Minitest::Test
665667 # def setup
666668 # God::Socket.stubs(:new).returns(true)
667669 # God.internal_init
11
22 if God::EventHandler.event_system == "kqueue"
33
4 class TestHandlersKqueueHandler < Test::Unit::TestCase
4 class TestHandlersKqueueHandler < Minitest::Test
55 def test_register_process
66 KQueueHandler.expects(:monitor_process).with(1234, 2147483648)
77 KQueueHandler.register_process(1234, [:proc_exit])
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestHipchat < Test::Unit::TestCase
2 class TestHipchat < Minitest::Test
33 def setup
44 @hipchat = God::Contacts::Hipchat.new
55 end
00 #!/usr/bin/env ruby
11 require File.dirname(__FILE__) + '/helper'
22
3 class TestJabber < Test::Unit::TestCase
3 class TestJabber < Minitest::Test
44
55 def setup
66 @jabber = God::Contacts::Jabber.new
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestLogger < Test::Unit::TestCase
2 class TestLogger < Minitest::Test
33 def setup
44 @log = God::Logger.new(StringIO.new('/dev/null'))
55 end
4040
4141 out = @log.watch_log_since('foo', t2)
4242
43 assert_no_match(/one/, out)
44 assert_no_match(/two/, out)
43 assert(/one/ !~ out)
44 assert(/two/ !~ out)
4545 assert_match(/three/, out)
4646 end
4747
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestMetric < Test::Unit::TestCase
2 class TestMetric < Minitest::Test
33 def setup
44 @metric = Metric.new(stub(:interval => 10), nil)
55 end
1111 end
1212 end
1313
14 class TestProcessChild < Test::Unit::TestCase
14 class TestProcessChild < Minitest::Test
1515 def setup
1616 God.internal_init
1717 @p = God::Process.new
4343 @p.start = 'qux'
4444 @p.log = '/tmp/foo.log'
4545 @p.uid = 'root'
46
47 ::Process.stubs(:groups=)
48 ::Process.stubs(:initgroups)
4649
4750 assert @p.valid?
4851 end
141144 #
142145 ###############################################################################
143146
144 class TestProcessDaemon < Test::Unit::TestCase
147 class TestProcessDaemon < Minitest::Test
145148 def setup
146149 God.internal_init
147150 @p = God::Process.new
148151 @p.name = 'foo'
149152 @p.pid_file = 'blah.pid'
150153 @p.stubs(:test).returns true # so we don't try to mkdir_p
154 God::System::Process.stubs(:fetch_system_poller).returns(God::System::PortablePoller)
151155 Process.stubs(:detach) # because we stub fork
152156 end
153157
242246
243247 assert @p.valid?
244248
245 assert_raise NotImplementedError do
249 assert_raises NotImplementedError do
246250 @p.call_action(:start)
247251 end
248252 end
00 #!/usr/bin/env ruby
11 require File.dirname(__FILE__) + '/helper'
22
3 class TestProwl < Test::Unit::TestCase
3 class TestProwl < Minitest::Test
44 def test_live_notify
55 prowl = God::Contacts::Prowl.new
66 prowl.name = "Prowly"
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestRegistry < Test::Unit::TestCase
2 class TestRegistry < Minitest::Test
33 def setup
44 God.registry.reset
55 end
0 require File.dirname(__FILE__) + '/helper'
1
2 class TestSensu < Minitest::Test
3 def test_sensu_notify
4 sensu = God::Contacts::Sensu.new
5 sensu.check_name = "TestSensuContact"
6
7 UDPSocket.any_instance.expects(:send)
8 sensu.notify("Test", Time.now, "Test", "Test", "")
9 end
10 end
0 require File.dirname(__FILE__) + '/helper'
1
2 class TestSlack < Minitest::Test
3 def setup
4 @slack = God::Contacts::Slack.new
5 @slack.account = "foo"
6 @slack.token = "foo"
7
8 @sample_data = {
9 :message => "a sample message",
10 :time => "2038-01-01 00:00:00",
11 :priority => "High",
12 :category => "Test",
13 :host => "example.com"
14 }
15 end
16
17 def test_api_url
18 assert_equal "https://foo.slack.com/services/hooks/incoming-webhook?token=foo", @slack.api_url.to_s
19 end
20
21 def test_notify
22 Net::HTTP.any_instance.expects(:request).returns(Net::HTTPSuccess.new('a', 'b', 'c'))
23
24 @slack.channel = "#ops"
25
26 @slack.notify('msg', Time.now, 'prio', 'cat', 'host')
27 assert_equal "successfully notified slack on channel #ops", @slack.info
28 end
29
30 def test_default_channel
31 Net::HTTP.any_instance.expects(:request).returns(Net::HTTPSuccess.new('a', 'b', 'c'))
32
33 @slack.notify('msg', Time.now, 'prio', 'cat', 'host')
34 assert_equal "successfully notified slack on channel #general", @slack.info
35 end
36
37 def test_default_formatting
38 text = @slack.text(@sample_data)
39 assert_equal "High alert on example.com: a sample message (Test, 2038-01-01 00:00:00)", text
40 end
41
42 def test_custom_formatting
43 @slack.format = "%{host}: %{message}"
44 text = @slack.text(@sample_data)
45 assert_equal "example.com: a sample message", text
46 end
47
48 def test_notify_channel
49 @slack.notify_channel = true
50 @slack.format = ""
51 text = @slack.text(@sample_data)
52 assert_equal "<!channel> ", text
53 end
54 end
55
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestSocket < Test::Unit::TestCase
2 class TestSocket < Minitest::Test
33 def setup
44 silence_warnings do
55 Object.const_set(:DRb, stub_everything)
0 require File.dirname(__FILE__) + '/helper'
1
2 class TestStatsd < Minitest::Test
3 def setup
4 @statsd = God::Contacts::Statsd.new
5 end
6
7 def test_exists
8 God::Contacts::Statsd
9 end
10
11 def test_notify
12 [
13 'cpu out of bounds',
14 'memory out of bounds',
15 'process is flapping'
16 ].each do |event_type|
17 ::Statsd.any_instance.expects(:increment).with("god.#{event_type.gsub(/\s/, '_')}.127_0_0_1.myapp-thin-1234")
18 @statsd.notify("myapp-thin-1234 [trigger] #{event_type}", Time.now, 'some priority', 'and some category', '127.0.0.1')
19 end
20 end
21 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestSugar < Test::Unit::TestCase
2 class TestSugar < Minitest::Test
33 def test_seconds
44 assert_equal 1, 1.seconds
55 assert_equal 1, 1.second
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestSystemPortablePoller < Test::Unit::TestCase
2 class TestSystemPortablePoller < Minitest::Test
33 def setup
44 pid = Process.pid
55 @process = System::PortablePoller.new(pid)
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestSystemProcess < Test::Unit::TestCase
2 class TestSystemProcess < Minitest::Test
33 def setup
44 pid = Process.pid
55 @process = System::Process.new(pid)
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestTask < Test::Unit::TestCase
2 class TestTask < Minitest::Test
33 def setup
44 God.internal_init
55 @task = Task.new
4545 end
4646
4747 def test_method_missing_should_raise_for_non_states
48 assert_raise NoMethodError do
48 assert_raises NoMethodError do
4949 @task.baz = 5
5050 end
5151 end
5252
5353 def test_method_missing_should_raise_for_non_setters
54 assert_raise NoMethodError do
54 assert_raises NoMethodError do
5555 @task.baz
5656 end
5757 end
7474
7575 def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
7676 @task.driver.stubs(:in_driver_context?).returns(true)
77 assert_raise NotImplementedError do
77 assert_raises NotImplementedError do
7878 @task.foo = 7
7979 @task.action(:foo, nil)
8080 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestTimeline < Test::Unit::TestCase
2 class TestTimeline < Minitest::Test
33 def setup
44 @timeline = Timeline.new(5)
55 end
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestTrigger < Test::Unit::TestCase
2 class TestTrigger < Minitest::Test
33 def setup
4 Trigger.reset
5 end
6
7 def teardown
48 Trigger.reset
59 end
610
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestWatch < Test::Unit::TestCase
2 class TestWatch < Minitest::Test
33 def setup
44 God.internal_init
55 @watch = Watch.new
00 require File.dirname(__FILE__) + '/helper'
11
2 class TestWebhook < Test::Unit::TestCase
2 class TestWebhook < Minitest::Test
33 def setup
44 @webhook = God::Contacts::Webhook.new
55 end