vendor/rails/railties/test/fcgi_dispatcher_test.rb in radiant-0.6.4 vs vendor/rails/railties/test/fcgi_dispatcher_test.rb in radiant-0.6.5

- old
+ new

@@ -1,259 +1,241 @@ require File.dirname(__FILE__) + "/abstract_unit" -begin # rescue LoadError +uses_mocha 'fcgi dispatcher tests' do -require 'mocha' -require 'stubba' - -$:.unshift File.dirname(__FILE__) + "/mocks" - -require 'stringio' - -# Stubs require 'fcgi_handler' -require 'routes' -require 'stubbed_breakpoint' -require 'stubbed_kernel' -class RailsFCGIHandler - attr_reader :exit_code - attr_reader :reloaded - attr_accessor :thread - attr_reader :gc_runs +module ActionController; module Routing; module Routes; end end end - def trap(signal, handler, &block) - handler ||= block - (@signal_handlers ||= Hash.new)[signal] = handler - end - - def exit(code=0) - @exit_code = code - (thread || Thread.current).exit - end - - def send_signal(which) - @signal_handlers[which].call(which) - end - - def breakpoint - end - - alias_method :old_run_gc!, :run_gc! - def run_gc! - @gc_runs ||= 0 - @gc_runs += 1 - old_run_gc! - end -end - class RailsFCGIHandlerTest < Test::Unit::TestCase def setup @log = StringIO.new @handler = RailsFCGIHandler.new(@log) - FCGI.time_to_sleep = nil - FCGI.raise_exception = nil - Dispatcher.time_to_sleep = nil - Dispatcher.raise_exception = nil end def test_process_restart - @handler.stubs(:when_ready).returns(:restart) - - @handler.expects(:close_connection) + cgi = mock + FCGI.stubs(:each_cgi).yields(cgi) + + @handler.expects(:process_request).once + @handler.expects(:dispatcher_error).never + + @handler.expects(:when_ready).returns(:restart) + @handler.expects(:close_connection).with(cgi) + @handler.expects(:reload!).never @handler.expects(:restart!) + @handler.process! end - + def test_process_exit - @handler.stubs(:when_ready).returns(:exit) - - @handler.expects(:close_connection) + cgi = mock + FCGI.stubs(:each_cgi).yields(cgi) + + @handler.expects(:process_request).once + @handler.expects(:dispatcher_error).never + + @handler.expects(:when_ready).returns(:exit) + @handler.expects(:close_connection).with(cgi) + @handler.expects(:reload!).never + @handler.expects(:restart!).never + @handler.process! end - - def test_process_breakpoint - @handler.stubs(:when_ready).returns(:breakpoint) - - @handler.expects(:close_connection) - @handler.expects(:breakpoint!) - @handler.process! - end - + def test_process_with_system_exit_exception - @handler.stubs(:process_request).raises(SystemExit) - - @handler.expects(:dispatcher_log).with(:info, "terminated by explicit exit") + cgi = mock + FCGI.stubs(:each_cgi).yields(cgi) + + @handler.expects(:process_request).once.raises(SystemExit) + @handler.stubs(:dispatcher_log) + @handler.expects(:dispatcher_log).with(:info, regexp_matches(/^stopping/)) + @handler.expects(:dispatcher_error).never + + @handler.expects(:when_ready).never + @handler.expects(:close_connection).never + @handler.expects(:reload!).never + @handler.expects(:restart!).never + @handler.process! end - + def test_restart_handler @handler.expects(:dispatcher_log).with(:info, "asked to restart ASAP") - + @handler.send(:restart_handler, nil) assert_equal :restart, @handler.when_ready end - - def test_breakpoint_handler - @handler.expects(:dispatcher_log).with(:info, "asked to breakpoint ASAP") - @handler.send(:breakpoint_handler, nil) - assert_equal :breakpoint, @handler.when_ready - end - def test_install_signal_handler_should_log_on_bad_signal @handler.stubs(:trap).raises(ArgumentError) @handler.expects(:dispatcher_log).with(:warn, "Ignoring unsupported signal CHEESECAKE.") @handler.send(:install_signal_handler, "CHEESECAKE", nil) end - + def test_reload @handler.expects(:restore!) @handler.expects(:dispatcher_log).with(:info, "reloaded") @handler.send(:reload!) assert_nil @handler.when_ready end - - + + def test_reload_runs_gc_when_gc_request_period_set @handler.expects(:run_gc!) @handler.expects(:restore!) @handler.expects(:dispatcher_log).with(:info, "reloaded") @handler.gc_request_period = 10 @handler.send(:reload!) end - + def test_reload_doesnt_run_gc_if_gc_request_period_isnt_set @handler.expects(:run_gc!).never @handler.expects(:restore!) @handler.expects(:dispatcher_log).with(:info, "reloaded") @handler.send(:reload!) end - + def test_restart! @handler.expects(:dispatcher_log).with(:info, "restarted") - assert_equal true, @handler.send(:restart!), "Exec wasn't run" + @handler.expects(:exec).returns('restarted') + assert_equal 'restarted', @handler.send(:restart!) end - + def test_restore! $".expects(:replace) Dispatcher.expects(:reset_application!) ActionController::Routing::Routes.expects(:reload) @handler.send(:restore!) end - def test_breakpoint! - @handler.expects(:require).with('breakpoint') - Breakpoint.expects(:activate_drb) - @handler.expects(:breakpoint) - @handler.expects(:dispatcher_log).with(:info, "breakpointing") - @handler.send(:breakpoint!) - assert_nil @handler.when_ready - end - def test_uninterrupted_processing + cgi = mock + FCGI.expects(:each_cgi).yields(cgi) + @handler.expects(:process_request).with(cgi) + @handler.process! - assert_nil @handler.exit_code + assert_nil @handler.when_ready end +end + +class RailsFCGIHandlerSignalsTest < Test::Unit::TestCase + def setup + @log = StringIO.new + @handler = RailsFCGIHandler.new(@log) + end + def test_interrupted_via_HUP_when_not_in_request - @handler.expects(:reload!) - FCGI.time_to_sleep = 1 - @handler.thread = Thread.new { @handler.process! } - sleep 0.1 # let the thread get started - @handler.send_signal("HUP") - @handler.thread.join - assert_nil @handler.exit_code + cgi = mock + FCGI.expects(:each_cgi).once.yields(cgi) + @handler.expects(:gc_countdown).returns { Process.kill 'HUP', $$ } + + @handler.expects(:reload!).once + @handler.expects(:close_connection).never + @handler.expects(:exit).never + + @handler.process! assert_equal :reload, @handler.when_ready end def test_interrupted_via_HUP_when_in_request - @handler.expects(:reload!) - - Dispatcher.time_to_sleep = 1 - @handler.thread = Thread.new { @handler.process! } - sleep 0.1 # let the thread get started - @handler.send_signal("HUP") - @handler.thread.join - assert_nil @handler.exit_code + cgi = mock + FCGI.expects(:each_cgi).once.yields(cgi) + Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'HUP', $$ } + + @handler.expects(:reload!).once + @handler.expects(:close_connection).never + @handler.expects(:exit).never + + @handler.process! assert_equal :reload, @handler.when_ready end def test_interrupted_via_USR1_when_not_in_request - FCGI.time_to_sleep = 1 - @handler.thread = Thread.new { @handler.process! } - sleep 0.1 # let the thread get started - @handler.send_signal("USR1") - @handler.thread.join - assert_nil @handler.exit_code - assert_equal :exit, @handler.when_ready + cgi = mock + FCGI.expects(:each_cgi).once.yields(cgi) + @handler.expects(:gc_countdown).returns { Process.kill 'USR1', $$ } + @handler.expects(:exit_handler).never + + @handler.expects(:reload!).never + @handler.expects(:close_connection).with(cgi).once + @handler.expects(:exit).never + + @handler.process! + assert_nil @handler.when_ready end def test_interrupted_via_USR1_when_in_request - Dispatcher.time_to_sleep = 1 - @handler.thread = Thread.new { @handler.process! } - sleep 0.1 # let the thread get started - @handler.send_signal("USR1") - @handler.thread.join - assert_nil @handler.exit_code + cgi = mock + FCGI.expects(:each_cgi).once.yields(cgi) + Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'USR1', $$ } + + @handler.expects(:reload!).never + @handler.expects(:close_connection).with(cgi).once + @handler.expects(:exit).never + + @handler.process! assert_equal :exit, @handler.when_ready end - + def test_interrupted_via_TERM - Dispatcher.time_to_sleep = 1 - @handler.thread = Thread.new { @handler.process! } - sleep 0.1 # let the thread get started - @handler.send_signal("TERM") - @handler.thread.join - assert_equal 0, @handler.exit_code + cgi = mock + FCGI.expects(:each_cgi).once.yields(cgi) + Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'TERM', $$ } + + @handler.expects(:reload!).never + @handler.expects(:close_connection).never + + @handler.process! assert_nil @handler.when_ready end - %w(RuntimeError SignalException).each do |exception| - define_method("test_#{exception}_in_fcgi") do - FCGI.raise_exception = Object.const_get(exception) - @handler.process! - assert_match %r{Dispatcher failed to catch}, @log.string - case exception - when "RuntimeError" - assert_match %r{almost killed}, @log.string - when "SignalException" - assert_match %r{^killed}, @log.string - end - end + def test_runtime_exception_in_fcgi + error = RuntimeError.new('foo') + FCGI.expects(:each_cgi).times(2).raises(error) + @handler.expects(:dispatcher_error).with(error, regexp_matches(/^retrying/)) + @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/)) + @handler.process! + end - define_method("test_#{exception}_in_dispatcher") do - Dispatcher.raise_exception = Object.const_get(exception) - @handler.process! - assert_match %r{Dispatcher failed to catch}, @log.string - case exception - when "RuntimeError" - assert_no_match %r{killed}, @log.string - when "SignalException" - assert_match %r{^killed}, @log.string - end - end + def test_runtime_error_in_dispatcher + cgi = mock + error = RuntimeError.new('foo') + FCGI.expects(:each_cgi).once.yields(cgi) + Dispatcher.expects(:dispatch).once.with(cgi).raises(error) + @handler.expects(:dispatcher_error).with(error, regexp_matches(/^unhandled/)) + @handler.process! end + + def test_signal_exception_in_fcgi + error = SignalException.new('USR2') + FCGI.expects(:each_cgi).once.raises(error) + @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/)) + @handler.process! + end + + def test_signal_exception_in_dispatcher + cgi = mock + error = SignalException.new('USR2') + FCGI.expects(:each_cgi).once.yields(cgi) + Dispatcher.expects(:dispatch).once.with(cgi).raises(error) + @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/)) + @handler.process! + end end + class RailsFCGIHandlerPeriodicGCTest < Test::Unit::TestCase def setup @log = StringIO.new - FCGI.time_to_sleep = nil - FCGI.raise_exception = nil - FCGI.each_cgi_count = nil - Dispatcher.time_to_sleep = nil - Dispatcher.raise_exception = nil - Dispatcher.dispatch_hook = nil end def teardown - FCGI.each_cgi_count = nil - Dispatcher.dispatch_hook = nil GC.enable end def test_normal_gc @handler = RailsFCGIHandler.new(@log) @@ -262,33 +244,22 @@ # When GC is enabled, GC.disable disables and returns false. assert_equal false, GC.disable end def test_periodic_gc - Dispatcher.dispatch_hook = lambda do |cgi| - # When GC is disabled, GC.enable enables and returns true. - assert_equal true, GC.enable - GC.disable - end - @handler = RailsFCGIHandler.new(@log, 10) assert_equal 10, @handler.gc_request_period - FCGI.each_cgi_count = 1 - @handler.process! - assert_equal 1, @handler.gc_runs - FCGI.each_cgi_count = 10 - @handler.process! - assert_equal 3, @handler.gc_runs + cgi = mock + FCGI.expects(:each_cgi).times(10).yields(cgi) + Dispatcher.expects(:dispatch).times(10).with(cgi) - FCGI.each_cgi_count = 25 + @handler.expects(:run_gc!).never + 9.times { @handler.process! } + @handler.expects(:run_gc!).once @handler.process! - assert_equal 6, @handler.gc_runs - assert_nil @handler.exit_code assert_nil @handler.when_ready end end -rescue LoadError - $stderr.puts "Skipping dispatcher tests. `gem install mocha` and try again." -end \ No newline at end of file +end # uses_mocha