From 05148793fb16911306c2591f0390ed6f5d237ce0 Mon Sep 17 00:00:00 2001 From: Tom Werner Date: Wed, 8 Aug 2007 15:22:24 -0700 Subject: [PATCH] Simplified config file (removing meddle construct) --- History.txt | 3 + Manifest.txt | 8 +- bin/god | 57 ++++++++------ examples/events.god | 115 ++++++++++++--------------- examples/gravatar.god | 89 ++++++++++----------- lib/god.rb | 106 ++++++++++++++++++++++--- lib/god/base.rb | 13 --- lib/god/behavior.rb | 2 +- lib/god/errors.rb | 3 + lib/god/meddle.rb | 53 ------------- lib/god/metric.rb | 4 +- lib/god/process.rb | 2 +- lib/god/server.rb | 7 +- lib/god/timer.rb | 4 +- lib/god/watch.rb | 10 +-- test/configs/pid.rb | 13 +++ test/configs/real.rb | 120 ++++++++++++++-------------- test/configs/test.rb | 149 +++++++++++++++-------------------- test/helper.rb | 30 ++++--- test/test_behavior.rb | 4 +- test/test_condition.rb | 6 +- test/{test_meddle.rb => test_god.rb} | 49 ++++++------ test/test_process.rb | 5 +- test/test_server.rb | 5 +- test/test_timer.rb | 2 +- test/test_watch.rb | 2 +- 26 files changed, 438 insertions(+), 423 deletions(-) rewrite examples/events.god (86%) rewrite examples/gravatar.god (83%) delete mode 100644 lib/god/base.rb delete mode 100644 lib/god/meddle.rb create mode 100644 test/configs/pid.rb rewrite test/configs/real.rb (89%) rewrite test/configs/test.rb (87%) rename test/{test_meddle.rb => test_god.rb} (51%) diff --git a/History.txt b/History.txt index 762d408..831e07e 100644 --- a/History.txt +++ b/History.txt @@ -11,6 +11,9 @@ * Daemonize and handle PID files for non-daemonizing scripts [kevinclark] * Fix simple mode lifecycle gap * Remove necessity to specify pid_file for every condition +* Change config file to use God.init and God.watch directly instead of God.meddle block +* Moved god binary command logic to main library +* Enhanced god binary with better reporting == 0.2.1 / diff --git a/Manifest.txt b/Manifest.txt index 9893aff..9e22a3f 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -9,7 +9,6 @@ ext/god/extconf.rb ext/god/kqueue_handler.c ext/god/netlink_handler.c lib/god.rb -lib/god/base.rb lib/god/behavior.rb lib/god/behaviors/clean_pid_file.rb lib/god/condition.rb @@ -25,13 +24,15 @@ lib/god/event_handlers/dummy_handler.rb lib/god/event_handlers/kqueue_handler.rb lib/god/event_handlers/netlink_handler.rb lib/god/hub.rb -lib/god/meddle.rb lib/god/metric.rb +lib/god/process.rb +lib/god/registry.rb lib/god/reporter.rb lib/god/server.rb lib/god/system/process.rb lib/god/timer.rb lib/god/watch.rb +test/configs/pid.rb test/configs/real.rb test/configs/test.rb test/helper.rb @@ -40,8 +41,9 @@ test/test_behavior.rb test/test_condition.rb test/test_event_handler.rb test/test_god.rb -test/test_meddle.rb test/test_metric.rb +test/test_process.rb +test/test_registry.rb test/test_reporter.rb test/test_server.rb test/test_system_process.rb diff --git a/bin/god b/bin/god index e4faa1a..defb97e 100755 --- a/bin/god +++ b/bin/god @@ -9,17 +9,6 @@ require 'drb' require 'daemons' require 'god' -unless God::EventHandler.loaded? - puts - puts "***********************************************************************" - puts "*" - puts "* Event conditions are not available for your installation of god." - puts "* You may still use and write custom conditions using the poll system" - puts "*" - puts "***********************************************************************" - puts -end - options = {:daemonize => true, :port => 17165} OptionParser.new do |opts| @@ -53,11 +42,18 @@ EOF end.parse! if options[:version] + # disable at_exit + module God; def self.at_exit; end; end + + # print version puts "Version #{God::VERSION}" exit elsif command = ARGV[0] # a command was specified + # disable at_exit + module God; def self.at_exit; end; end + # get the name of the watch/group name = ARGV[1] @@ -65,25 +61,34 @@ elsif command = ARGV[0] DRb.start_service server = DRbObject.new nil, "druby://localhost:#{options[:port]}" - # get the list of watches - watches = Array(server.watches[name] || server.groups[name]) - - # do the command - case command - when "start", "monitor" - watches.each { |w| w.monitor } - when "restart" - watches.each { |w| w.move(:restart) } - when "stop" - watches.each { |w| w.unmonitor.action(:stop) } - when "unmonitor" - watches.each { |w| w.unmonitor } - else - abort "Command '#{command}' is not valid. Run 'god --help' for usage" + begin + puts "Sending '#{command}' command" + + # send command + watches = server.control(name, command) + + # output response + puts 'The following watches were affected:' + watches.each do |w| + puts ' ' + w.name + end + rescue God::InvalidCommandError + abort "Command '#{command}' is not valid. Run 'god --help' for usage" end else # start god + unless God::EventHandler.loaded? + puts + puts "***********************************************************************" + puts "*" + puts "* Event conditions are not available for your installation of god." + puts "* You may still use and write custom conditions using the poll system" + puts "*" + puts "***********************************************************************" + puts + end + options[:config] = File.expand_path(options[:config]) if options[:config] Daemons.daemonize if options[:daemonize] diff --git a/examples/events.god b/examples/events.god dissimilarity index 86% index c89775d..eb6b712 100644 --- a/examples/events.god +++ b/examples/events.god @@ -1,63 +1,52 @@ -# This example shows how you might keep a local development Rails server up -# and running on your Mac. - -# Run with: -# god -c /path/to/events.god - -RAILS_ROOT = "/Users/tom/dev/helloworld" - -God.meddle do |god| - god.watch do |w| - w.name = "local-3000" - w.interval = 5 # seconds - w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d" - w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" - - pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") - - # clean pid files before start if necessary - w.behavior(:clean_pid_file) do |b| - b.pid_file = pid_file - end - - # determine the state on startup - w.transition(:init, { true => :up, false => :start }) do |on| - on.condition(:process_running) do |c| - c.running = true - c.pid_file = pid_file - end - end - - # determine when process has finished starting - w.transition([:start, :restart], :up) do |on| - on.condition(:process_running) do |c| - c.running = true - c.pid_file = pid_file - end - end - - # start if process is not running - w.transition(:up, :start) do |on| - on.condition(:process_exits) do |c| - c.pid_file = pid_file - end - end - - # restart if memory or cpu is too high - w.transition(:up, :restart) do |on| - on.condition(:memory_usage) do |c| - c.interval = 20 - c.pid_file = pid_file - c.above = (50 * 1024) # 50mb - c.times = [3, 5] - end - - on.condition(:cpu_usage) do |c| - c.interval = 10 - c.pid_file = pid_file - c.above = 10 # percent - c.times = [3, 5] - end - end - end -end \ No newline at end of file +# This example shows how you might keep a local development Rails server up +# and running on your Mac. + +# Run with: +# god -c /path/to/events.god + +RAILS_ROOT = "/Users/tom/dev/helloworld" + +God.watch do |w| + w.name = "local-3000" + w.interval = 5 # seconds + w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d" + w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" + w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") + + # clean pid files before start if necessary + w.behavior(:clean_pid_file) + + # determine the state on startup + w.transition(:init, { true => :up, false => :start }) do |on| + on.condition(:process_running) do |c| + c.running = true + end + end + + # determine when process has finished starting + w.transition([:start, :restart], :up) do |on| + on.condition(:process_running) do |c| + c.running = true + end + end + + # start if process is not running + w.transition(:up, :start) do |on| + on.condition(:process_exits) + end + + # restart if memory or cpu is too high + w.transition(:up, :restart) do |on| + on.condition(:memory_usage) do |c| + c.interval = 20 + c.above = (50 * 1024) # 50mb + c.times = [3, 5] + end + + on.condition(:cpu_usage) do |c| + c.interval = 10 + c.above = 10 # percent + c.times = [3, 5] + end + end +end \ No newline at end of file diff --git a/examples/gravatar.god b/examples/gravatar.god dissimilarity index 83% index b2da97a..331da6a 100644 --- a/examples/gravatar.god +++ b/examples/gravatar.god @@ -1,48 +1,41 @@ -# run with: god -c /path/to/gravatar.god -# -# This is the actual config file used to keep the mongrels of -# gravatar.com running. - -RAILS_ROOT = "/var/www/gravatar2/current" - -God.meddle do |god| - %w{8200 8201 8202}.each do |port| - god.watch do |w| - w.name = "gravatar2-mongrel-#{port}" - w.interval = 30 # seconds - w.start = "mongrel_rails cluster::start --only #{port} \ - -C #{RAILS_ROOT}/config/mongrel_cluster.yml" - w.stop = "mongrel_rails cluster::stop --only #{port} \ - -C #{RAILS_ROOT}/config/mongrel_cluster.yml" - w.grace = 10 # seconds - - pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") - - w.behavior(:clean_pid_file) do |b| - b.pid_file = pid_file - end - - w.start_if do |start| - start.condition(:process_running) do |c| - c.interval = 5 # seconds - c.running = false - c.pid_file = pid_file - end - end - - w.restart_if do |restart| - restart.condition(:memory_usage) do |c| - c.pid_file = pid_file - c.above = (150 * 1024) # 150mb - c.times = [3, 5] # 3 out of 5 intervals - end - - restart.condition(:cpu_usage) do |c| - c.pid_file = pid_file - c.above = 50 # percent - c.times = 5 - end - end - end - end -end \ No newline at end of file +# run with: god -c /path/to/gravatar.god +# +# This is the actual config file used to keep the mongrels of +# gravatar.com running. + +RAILS_ROOT = "/var/www/gravatar2/current" + +%w{8200 8201 8202}.each do |port| + God.watch do |w| + w.name = "gravatar2-mongrel-#{port}" + w.interval = 30 # seconds + w.start = "mongrel_rails cluster::start --only #{port} \ + -C #{RAILS_ROOT}/config/mongrel_cluster.yml" + w.stop = "mongrel_rails cluster::stop --only #{port} \ + -C #{RAILS_ROOT}/config/mongrel_cluster.yml" + w.grace = 10 # seconds + + pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") + + w.behavior(:clean_pid_file) + + w.start_if do |start| + start.condition(:process_running) do |c| + c.interval = 5 # seconds + c.running = false + end + end + + w.restart_if do |restart| + restart.condition(:memory_usage) do |c| + c.above = (150 * 1024) # 150mb + c.times = [3, 5] # 3 out of 5 intervals + end + + restart.condition(:cpu_usage) do |c| + c.above = 50 # percent + c.times = 5 + end + end + end +end \ No newline at end of file diff --git a/lib/god.rb b/lib/god.rb index d4e6df5..de39556 100644 --- a/lib/god.rb +++ b/lib/god.rb @@ -3,7 +3,6 @@ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed require 'syslog' # internal requires -require 'god/base' require 'god/errors' require 'god/system/process' @@ -25,9 +24,7 @@ require 'god/timer' require 'god/hub' require 'god/metric' - require 'god/watch' -require 'god/meddle' require 'god/event_handler' require 'god/registry' @@ -46,6 +43,34 @@ God::EventHandler.load module God VERSION = '0.3.0' + class << self + attr_accessor :inited, :host, :port + + # drb + attr_accessor :server + + # api + attr_accessor :watches, :groups + end + + def self.init + # only do this once + return if self.inited + + # variable init + self.watches = {} + self.groups = {} + + # yield to the config file + yield self if block_given? + + # instantiate server + self.server = Server.new(self.host, self.port) + + # init has been executed + self.inited = true + end + # Where pid files created by god will go by default def self.pid_file_directory @pid_file_directory ||= '/var/run/god' @@ -55,11 +80,64 @@ module God @pid_file_directory = value end - def self.meddle(options = {}) - m = Meddle.new(options) + # Instantiate a new, empty Watch object and pass it to the mandatory + # block. The attributes of the watch will be set by the configuration + # file. + def self.watch + self.init + + w = Watch.new + yield(w) + + # ensure the new watch has a unique name + if self.watches[w.name] || self.groups[w.name] + abort "Watch name '#{w.name}' already used for a Watch or Group" + end + + # add to list of watches + self.watches[w.name] = w + + # add to group if specified + if w.group + # ensure group name hasn't been used for a watch already + if self.watches[w.group] + abort "Group name '#{w.group}' already used for a Watch" + end + + self.groups[w.group] ||= [] + self.groups[w.group] << w.name + end + + # register watch + w.register! + end + + def self.control(name, command) + # get the list of watches + watches = Array(server.watches[name] || server.groups[name]) + + # do the command + case command + when "start", "monitor" + watches.each { |w| w.monitor } + when "restart" + watches.each { |w| w.move(:restart) } + when "stop" + watches.each { |w| w.unmonitor.action(:stop) } + when "unmonitor" + watches.each { |w| w.unmonitor } + else + raise InvalidCommandError.new + end - # yeild to the config file - yield m + watches + end + + def self.start + # make sure there's something to do + if self.watches.nil? || self.watches.empty? + abort "You must specify at least one watch!" + end # start event handler system EventHandler.start if EventHandler.loaded? @@ -67,10 +145,18 @@ module God # start the timer system Timer.get - # start monitoring - m.monitor + # start monitoring any watches set to autostart + self.watches.values.each { |w| w.monitor if w.autostart? } # join the timer thread so we don't exit Timer.get.join - end + end + + def self.at_exit + self.start + end end + +at_exit do + God.at_exit +end \ No newline at end of file diff --git a/lib/god/base.rb b/lib/god/base.rb deleted file mode 100644 index 6bc42b2..0000000 --- a/lib/god/base.rb +++ /dev/null @@ -1,13 +0,0 @@ -module God - - class Base - def abort(msg) - Kernel.abort(msg) - end - - def self.abort(msg) - Kernel.abort(msg) - end - end - -end \ No newline at end of file diff --git a/lib/god/behavior.rb b/lib/god/behavior.rb index 7c767ab..277560e 100644 --- a/lib/god/behavior.rb +++ b/lib/god/behavior.rb @@ -1,6 +1,6 @@ module God - class Behavior < Base + class Behavior attr_accessor :watch # Generate a Behavior of the given kind. The proper class if found by camel casing the diff --git a/lib/god/errors.rb b/lib/god/errors.rb index 58ea9b1..5caccfc 100644 --- a/lib/god/errors.rb +++ b/lib/god/errors.rb @@ -9,4 +9,7 @@ module God class NoSuchBehaviorError < StandardError end + class InvalidCommandError < StandardError + end + end \ No newline at end of file diff --git a/lib/god/meddle.rb b/lib/god/meddle.rb deleted file mode 100644 index 73e38a0..0000000 --- a/lib/god/meddle.rb +++ /dev/null @@ -1,53 +0,0 @@ -module God - - class Meddle < Base - # drb - attr_accessor :server - - # api - attr_accessor :watches, :groups - - # Create a new instance that is ready for use by a configuration file - def initialize(options = {}) - self.watches = {} - self.groups = {} - self.server = Server.new(self, options[:host], options[:port]) - end - - # Instantiate a new, empty Watch object and pass it to the mandatory - # block. The attributes of the watch will be set by the configuration - # file. - def watch - w = Watch.new(self) - yield(w) - - # ensure the new watch has a unique name - if @watches[w.name] || @groups[w.name] - abort "Watch name '#{w.name}' already used for a Watch or Group" - end - - # add to list of watches - @watches[w.name] = w - - # add to group if specified - if w.group - # ensure group name hasn't been used for a watch already - if @watches[w.group] - abort "Group name '#{w.group}' already used for a Watch" - end - - @groups[w.group] ||= [] - @groups[w.group] << w.name - end - - # register watch - w.register! - end - - # Start monitoring any watches set to autostart - def monitor - @watches.values.each { |w| w.monitor if w.autostart? } - end - end - -end diff --git a/lib/god/metric.rb b/lib/god/metric.rb index d5d749d..07c7d3e 100644 --- a/lib/god/metric.rb +++ b/lib/god/metric.rb @@ -1,6 +1,6 @@ module God - class Metric < Base + class Metric attr_accessor :watch, :destination, :conditions def initialize(watch, destination) @@ -31,7 +31,7 @@ module God abort "Exiting on invalid condition" end - # inherit interval from meddle if no poll condition specific interval was set + # inherit interval from watch if no poll condition specific interval was set if c.kind_of?(PollCondition) && !c.interval if self.watch.interval c.interval = self.watch.interval diff --git a/lib/god/process.rb b/lib/god/process.rb index 8696639..d2d845b 100644 --- a/lib/god/process.rb +++ b/lib/god/process.rb @@ -73,7 +73,7 @@ module God ::Process.detach pid - if @tracking_pid or (self.pid_file.nil? and WRITES_PID.include?(action)) + if @tracking_pid or (@pid_file.nil? and WRITES_PID.include?(action)) File.open(default_pid_file, 'w') do |f| f.write pid end diff --git a/lib/god/server.rb b/lib/god/server.rb index 62a2a69..e418cdc 100644 --- a/lib/god/server.rb +++ b/lib/god/server.rb @@ -5,17 +5,16 @@ require 'drb' module God class Server - attr_reader :meddle, :host, :port + attr_reader :host, :port - def initialize(meddle = nil, host = nil, port = nil) - @meddle = meddle + def initialize(host = nil, port = nil) @host = host @port = port || 17165 start end def method_missing(*args, &block) - @meddle.send(*args, &block) + God.send(*args, &block) end def ping diff --git a/lib/god/timer.rb b/lib/god/timer.rb index f981772..1ff32a4 100644 --- a/lib/god/timer.rb +++ b/lib/god/timer.rb @@ -9,10 +9,10 @@ module God end end - class Timer < Base + class Timer INTERVAL = 0.25 - attr_reader :events + attr_reader :events, :timer @@timer = nil diff --git a/lib/god/watch.rb b/lib/god/watch.rb index be582a4..3596a63 100644 --- a/lib/god/watch.rb +++ b/lib/god/watch.rb @@ -3,7 +3,7 @@ require 'forwardable' module God - class Watch < Base + class Watch VALID_STATES = [:init, :up, :start, :restart] # config @@ -26,11 +26,9 @@ module God attr_accessor :mutex # - def initialize(meddle) + def initialize @autostart ||= true @process = God::Process.new - - @meddle = meddle # no grace period by default self.grace = self.start_grace = self.stop_grace = self.restart_grace = 0 @@ -51,7 +49,7 @@ module God def behavior(kind) # create the behavior begin - b = Behavior.generate(kind) + b = Behavior.generate(kind, self) rescue NoSuchBehaviorError => e abort e.message end @@ -136,7 +134,7 @@ module God # Move from one state to another def move(to_state) - msg = "move '#{self.state}' to '#{to_state}'" + msg = "#{self.name} move '#{self.state}' to '#{to_state}'" Syslog.debug(msg) puts msg diff --git a/test/configs/pid.rb b/test/configs/pid.rb new file mode 100644 index 0000000..885c0e8 --- /dev/null +++ b/test/configs/pid.rb @@ -0,0 +1,13 @@ +God.watch do |w| + w.name = 'simple_server' + w.start = '/Users/tom/Desktop/simple_server.rb' + w.stop = '' + w.interval = 5 + w.grace = 2 + + w.start_if do |start| + start.condition(:process_running) do |c| + c.running = false + end + end +end \ No newline at end of file diff --git a/test/configs/real.rb b/test/configs/real.rb dissimilarity index 89% index 78dc813..344f9bb 100644 --- a/test/configs/real.rb +++ b/test/configs/real.rb @@ -1,61 +1,59 @@ -if $0 == __FILE__ - require File.join(File.dirname(__FILE__), *%w[.. .. lib god]) -end - -RAILS_ROOT = "/Users/tom/dev/git/helloworld" - -God.meddle do |god| - god.watch do |w| - w.name = "local-3000" - w.interval = 5 # seconds - w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d" - w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" - w.grace = 5 - - pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") - - # clean pid files before start if necessary - w.behavior(:clean_pid_file) do |b| - b.pid_file = pid_file - end - - # start if process is not running - w.start_if do |start| - start.condition(:process_running) do |c| - c.running = false - c.pid_file = pid_file - end - end - - # restart if memory or cpu is too high - w.restart_if do |restart| - restart.condition(:memory_usage) do |c| - c.interval = 20 - c.pid_file = pid_file - c.above = (50 * 1024) # 50mb - c.times = [3, 5] - end - - restart.condition(:cpu_usage) do |c| - c.interval = 10 - c.pid_file = pid_file - c.above = 10 # percent - c.times = [3, 5] - end - end - end - - # clear old session files - # god.watch do |w| - # w.name = "local-session-cleanup" - # w.start = lambda do - # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f| - # File.mtime(f) < Time.now - (7 * 24 * 60 * 60) - # end.each { |f| File.delete(f) } - # end - # - # w.start_if do |start| - # start.condition(:always) - # end - # end -end \ No newline at end of file +if $0 == __FILE__ + require File.join(File.dirname(__FILE__), *%w[.. .. lib god]) +end + +RAILS_ROOT = "/Users/tom/dev/git/helloworld" + +God.watch do |w| + w.name = "local-3000" + w.interval = 5 # seconds + w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d" + w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" + w.grace = 5 + + pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") + + # clean pid files before start if necessary + w.behavior(:clean_pid_file) do |b| + b.pid_file = pid_file + end + + # start if process is not running + w.start_if do |start| + start.condition(:process_running) do |c| + c.running = false + c.pid_file = pid_file + end + end + + # restart if memory or cpu is too high + w.restart_if do |restart| + restart.condition(:memory_usage) do |c| + c.interval = 20 + c.pid_file = pid_file + c.above = (50 * 1024) # 50mb + c.times = [3, 5] + end + + restart.condition(:cpu_usage) do |c| + c.interval = 10 + c.pid_file = pid_file + c.above = 10 # percent + c.times = [3, 5] + end + end +end + +# clear old session files +# god.watch do |w| +# w.name = "local-session-cleanup" +# w.start = lambda do +# Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f| +# File.mtime(f) < Time.now - (7 * 24 * 60 * 60) +# end.each { |f| File.delete(f) } +# end +# +# w.start_if do |start| +# start.condition(:always) +# end +# end \ No newline at end of file diff --git a/test/configs/test.rb b/test/configs/test.rb dissimilarity index 87% index 3b5ec8d..160b81a 100644 --- a/test/configs/test.rb +++ b/test/configs/test.rb @@ -1,84 +1,65 @@ -if $0 == __FILE__ - require File.join(File.dirname(__FILE__), *%w[.. .. lib god]) -end - -ENV['GOD_TEST_RAILS_ROOT'] || abort("Set a rails root for testing in an environment variable called GOD_TEST_RAILS_ROOT") - -RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT'] - -God.meddle do |god| - god.watch do |w| - w.name = "local-3000" - w.interval = 5 # seconds - w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p 3001 -d" - w.restart = "mongrel_rails restart -P ./log/mongrel.pid -c #{RAILS_ROOT}" - w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" - w.restart_grace = 5 # seconds - w.stop_grace = 5 # seconds - w.autostart = true - w.group = 'mongrels' - # w.user = "kev" - # w.group = "kev" - - w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") - - # clean pid files before start if necessary - w.behavior(:clean_pid_file) do |b| - b.pid_file = w.pid_file - end - - # determine the state on startup - w.transition(:init, { true => :up, false => :start }) do |on| - on.condition(:process_running) do |c| - c.running = true - c.pid_file = w.pid_file - end - end - - # determine when process has finished starting - w.transition([:start, :restart], :up) do |on| - on.condition(:process_running) do |c| - c.running = true - c.pid_file = w.pid_file - end - end - - # start if process is not running - w.transition(:up, :start) do |on| - on.condition(:process_exits) do |c| - c.pid_file = w.pid_file - end - end - - # restart if memory or cpu is too high - w.transition(:up, :restart) do |on| - on.condition(:memory_usage) do |c| - c.interval = 20 - c.pid_file = w.pid_file - c.above = (50 * 1024) # 50mb - c.times = [3, 5] - end - - on.condition(:cpu_usage) do |c| - c.interval = 10 - c.pid_file = w.pid_file - c.above = 10 # percent - c.times = [3, 5] - end - end - end - - # clear old session files - # god.watch do |w| - # w.name = "local-session-cleanup" - # w.start = lambda do - # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f| - # File.mtime(f) < Time.now - (7 * 24 * 60 * 60) - # end.each { |f| File.delete(f) } - # end - # - # w.start_if do |start| - # start.condition(:always) - # end - # end -end \ No newline at end of file +if $0 == __FILE__ + require File.join(File.dirname(__FILE__), *%w[.. .. lib god]) +end + +ENV['GOD_TEST_RAILS_ROOT'] || abort("Set a rails root for testing in an environment variable called GOD_TEST_RAILS_ROOT") + +RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT'] + +God.init do |g| + # g.host = + # g.port = 7777 + # g.pid_file_directory = +end + +God.watch do |w| + w.name = "local-3000" + w.interval = 5 # seconds + w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p 3001 -d" + w.restart = "mongrel_rails restart -P ./log/mongrel.pid -c #{RAILS_ROOT}" + w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}" + w.restart_grace = 5 # seconds + w.stop_grace = 5 # seconds + w.autostart = true + w.uid = 'tom' + w.gid = 'tom' + w.group = 'mongrels' + w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid") + + # clean pid files before start if necessary + w.behavior(:clean_pid_file) + + # determine the state on startup + w.transition(:init, { true => :up, false => :start }) do |on| + on.condition(:process_running) do |c| + c.running = true + end + end + + # determine when process has finished starting + w.transition([:start, :restart], :up) do |on| + on.condition(:process_running) do |c| + c.running = true + end + end + + # start if process is not running + w.transition(:up, :start) do |on| + on.condition(:process_exits) + end + + # restart if memory or cpu is too high + w.transition(:up, :restart) do |on| + on.condition(:memory_usage) do |c| + c.interval = 20 + c.above = (50 * 1024) # 50mb + c.times = [3, 5] + end + + on.condition(:cpu_usage) do |c| + c.interval = 10 + c.above = 10 # percent + c.times = [3, 5] + end + end +end \ No newline at end of file diff --git a/test/helper.rb b/test/helper.rb index 7ebe925..9608b33 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -21,16 +21,6 @@ module God class AbortCalledError < StandardError end - class Base - def abort(msg) - raise AbortCalledError.new("abort called") - end - - def self.abort(msg) - raise AbortCalledError.new("abort called") - end - end - module Conditions class FakeCondition < Condition def test @@ -55,6 +45,26 @@ module God class FakeBehavior < Behavior end end + + def self.at_exit + # disable at_exit + end + + def self.reset + self.watches = nil + self.groups = nil + self.server = nil + self.inited = nil + self.host = nil + self.port = nil + self.registry.reset + end +end + +module Kernel + def abort(msg) + raise God::AbortCalledError.new(msg) + end end def silence_warnings diff --git a/test/test_behavior.rb b/test/test_behavior.rb index 47580bb..f3b93eb 100644 --- a/test/test_behavior.rb +++ b/test/test_behavior.rb @@ -2,12 +2,12 @@ require File.dirname(__FILE__) + '/helper' class TestBehavior < Test::Unit::TestCase def test_generate_should_return_an_object_corresponding_to_the_given_type - assert_equal Behaviors::FakeBehavior, Behavior.generate(:fake_behavior).class + assert_equal Behaviors::FakeBehavior, Behavior.generate(:fake_behavior, nil).class end def test_generate_should_raise_on_invalid_type assert_raise NoSuchBehaviorError do - Behavior.generate(:foo) + Behavior.generate(:foo, nil) end end end \ No newline at end of file diff --git a/test/test_condition.rb b/test/test_condition.rb index 60e67a8..c029bbe 100644 --- a/test/test_condition.rb +++ b/test/test_condition.rb @@ -2,12 +2,12 @@ require File.dirname(__FILE__) + '/helper' class TestCondition < Test::Unit::TestCase def test_generate_should_return_an_object_corresponding_to_the_given_type - assert_equal Conditions::ProcessRunning, Condition.generate(:process_running).class + assert_equal Conditions::ProcessRunning, Condition.generate(:process_running, nil).class end def test_generate_should_raise_on_invalid_type assert_raise NoSuchConditionError do - Condition.generate(:foo) + Condition.generate(:foo, nil) end end @@ -16,7 +16,7 @@ class TestCondition < Test::Unit::TestCase rmsg = nil begin - Condition.generate(:foo_bar) + Condition.generate(:foo_bar, nil) rescue => e rmsg = e.message end diff --git a/test/test_meddle.rb b/test/test_god.rb similarity index 51% rename from test/test_meddle.rb rename to test/test_god.rb index d1ea6e5..8f7edab 100644 --- a/test/test_meddle.rb +++ b/test/test_god.rb @@ -1,78 +1,77 @@ require File.dirname(__FILE__) + '/helper' -class TestMeddle < Test::Unit::TestCase +class TestGod < Test::Unit::TestCase def setup Server.stubs(:new).returns(true) - @meddle = Meddle.new - God.registry.reset + God.reset end - def test_should_initialize_watches_to_empty_array - assert_equal Hash.new, @meddle.watches + def teardown + Timer.get.timer.kill + end + + def test_init_should_initialize_watches_to_empty_array + God.init { } + assert_equal Hash.new, God.watches end def test_watches_should_get_stored watch = nil - @meddle.watch { |w| watch = w } + God.watch { |w| watch = w } - assert_equal 1, @meddle.watches.size - assert_equal watch, @meddle.watches.values.first + assert_equal 1, God.watches.size + assert_equal watch, God.watches.values.first - assert_equal 0, @meddle.groups.size + assert_equal 0, God.groups.size end def test_watches_should_register_processes assert_nil God.registry['foo'] - @meddle.watch { |w| w.name = 'foo' } + God.watch { |w| w.name = 'foo' } assert_kind_of God::Process, God.registry['foo'] end def test_watches_should_get_stored_by_group - @meddle.watch do |w| + God.watch do |w| w.name = 'foo' w.group = 'test' end - assert_equal({'test' => ['foo']}, @meddle.groups) + assert_equal({'test' => ['foo']}, God.groups) end def test_multiple_watches_should_get_stored_by_group - @meddle.watch do |w| + God.watch do |w| w.name = 'foo' w.group = 'test' end - @meddle.watch do |w| + God.watch do |w| w.name = 'bar' w.group = 'test' end - assert_equal({'test' => ['foo', 'bar']}, @meddle.groups) + assert_equal({'test' => ['foo', 'bar']}, God.groups) end def test_should_kick_off_a_server_instance Server.expects(:new).returns(true) - Meddle.new - end - - def test_should_take_an_options_hash - Server.expects(:new) - Meddle.new(:port => 5555) + God.init end def test_should_allow_multiple_watches - @meddle.watch { |w| w.name = 'foo' } + God.watch { |w| w.name = 'foo' } assert_nothing_raised do - @meddle.watch { |w| w.name = 'bar' } + God.watch { |w| w.name = 'bar' } end end def test_should_disallow_duplicate_watch_names - @meddle.watch { |w| w.name = 'foo' } + God.watch { |w| w.name = 'foo' } assert_raise AbortCalledError do - @meddle.watch { |w| w.name = 'foo' } + God.watch { |w| w.name = 'foo' } end end end diff --git a/test/test_process.rb b/test/test_process.rb index a6b45ae..cc0b664 100644 --- a/test/test_process.rb +++ b/test/test_process.rb @@ -16,6 +16,7 @@ class TestProcess < Test::Unit::TestCase def setup @p = God::Process.new(:name => 'foo', :pid_file => 'blah.pid') @p.stubs(:test).returns true # so we don't try to mkdir_p + Process.stubs(:detach) # because we stub fork end # These actually excercise call_action in the back at this point - Kev @@ -56,10 +57,10 @@ class TestProcess < Test::Unit::TestCase @p.call_action(:stop) end - def test_call_action_should_mkdir_p_if_test_fails + def test_call_action_should_mkdir_p_if_pid_file_dir_existence_test_fails @p.pid_file = nil @p.expects(:fork) - @p.stubs(:test).returns false + @p.expects(:test).returns(false, true) FileUtils.expects(:mkdir_p).with(God.pid_file_directory) File.expects(:open) @p.start = "starting" diff --git a/test/test_server.rb b/test/test_server.rb index fb3bae5..d2d7a39 100644 --- a/test/test_server.rb +++ b/test/test_server.rb @@ -14,11 +14,12 @@ class TestServer < Test::Unit::TestCase def test_should_use_supplied_port_and_host DRb.expects(:start_service).with { |uri, object| uri == "druby://host:port" && object.is_a?(Server) } - server = Server.new(nil, 'host', 'port') + server = Server.new('host', 'port') end def test_should_forward_foreign_method_calls_to_meddle - server = Server.new(mock(:something_random => true)) + server = Server.new + God.expects(:send).with(:something_random) server.something_random end end diff --git a/test/test_timer.rb b/test/test_timer.rb index b82ee72..102d7d0 100644 --- a/test/test_timer.rb +++ b/test/test_timer.rb @@ -13,7 +13,7 @@ class TestTimer < Test::Unit::TestCase def test_schedule_should_queue_event Time.stubs(:now).returns(0) - w = Watch.new(nil) + w = Watch.new @t.schedule(stub(:interval => 20)) assert_equal 1, @t.events.size diff --git a/test/test_watch.rb b/test/test_watch.rb index 545a006..efff704 100644 --- a/test/test_watch.rb +++ b/test/test_watch.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/helper' class TestWatch < Test::Unit::TestCase def setup - @watch = Watch.new(nil) + @watch = Watch.new end # new -- 2.11.4.GIT