From 71c8ce651166b49178676f1c37723aa34c4ef9e5 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 31 Mar 2009 19:15:50 -0700 Subject: test: factor out exec helpers into common code for Rails tests --- test/test_helper.rb | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) (limited to 'test/test_helper.rb') diff --git a/test/test_helper.rb b/test/test_helper.rb index 4243606..37625ec 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,9 +4,16 @@ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html # for more information. +STDIN.sync = STDOUT.sync = STDERR.sync = true # buffering makes debugging hard + +# Some tests watch a log file or a pid file to spring up to check state +# Can't rely on inotify on non-Linux and logging to a pipe makes things +# more complicated +DEFAULT_TRIES = 1000 +DEFAULT_RES = 0.2 HERE = File.dirname(__FILE__) unless defined?(HERE) -%w(lib ext bin test).each do |dir| +%w(lib ext).each do |dir| $LOAD_PATH.unshift "#{HERE}/../#{dir}" end @@ -15,8 +22,10 @@ require 'net/http' require 'digest/sha1' require 'uri' require 'stringio' +require 'pathname' +require 'tempfile' +require 'fileutils' require 'unicorn' -require 'tmpdir' if ENV['DEBUG'] require 'ruby-debug' @@ -112,3 +121,141 @@ def unused_port(addr = '127.0.0.1') sock.close rescue nil port end + +def try_require(lib) + begin + require lib + true + rescue LoadError + false + end +end + +# sometimes the server may not come up right away +def retry_hit(uris = []) + tries = DEFAULT_TRIES + begin + hit(uris) + rescue Errno::ECONNREFUSED => err + if (tries -= 1) > 0 + sleep DEFAULT_RES + retry + end + raise err + end +end + +def assert_shutdown(pid) + wait_master_ready("test_stderr.#{pid}.log") + assert_nothing_raised { Process.kill(:QUIT, pid) } + status = nil + assert_nothing_raised { pid, status = Process.waitpid2(pid) } + assert status.success?, "exited successfully" +end + +def wait_workers_ready(path, nr_workers) + tries = DEFAULT_TRIES + lines = [] + while (tries -= 1) > 0 + begin + lines = File.readlines(path).grep(/worker=\d+ ready/) + lines.size == nr_workers and return + rescue Errno::ENOENT + end + sleep DEFAULT_RES + end + raise "#{nr_workers} workers never became ready:" \ + "\n\t#{lines.join("\n\t")}\n" +end + +def wait_master_ready(master_log) + tries = DEFAULT_TRIES + while (tries -= 1) > 0 + begin + File.readlines(master_log).grep(/master process ready/)[0] and return + rescue Errno::ENOENT + end + sleep DEFAULT_RES + end + raise "master process never became ready" +end + +def reexec_usr2_quit_test(pid, pid_file) + assert File.exist?(pid_file), "pid file OK" + assert ! File.exist?("#{pid_file}.oldbin"), "oldbin pid file" + assert_nothing_raised { Process.kill(:USR2, pid) } + assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) } + wait_for_file("#{pid_file}.oldbin") + wait_for_file(pid_file) + + old_pid = File.read("#{pid_file}.oldbin").to_i + new_pid = File.read(pid_file).to_i + + # kill old master process + assert_not_equal pid, new_pid + assert_equal pid, old_pid + assert_nothing_raised { Process.kill(:QUIT, old_pid) } + assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) } + wait_for_death(old_pid) + assert_equal new_pid, File.read(pid_file).to_i + assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) } + assert_nothing_raised { Process.kill(:QUIT, new_pid) } +end + +def reexec_basic_test(pid, pid_file) + results = retry_hit(["http://#{@addr}:#{@port}/"]) + assert_equal String, results[0].class + assert_nothing_raised { Process.kill(0, pid) } + master_log = "#{@tmpdir}/test_stderr.#{pid}.log" + wait_master_ready(master_log) + File.truncate(master_log, 0) + nr = 50 + kill_point = 2 + assert_nothing_raised do + nr.times do |i| + hit(["http://#{@addr}:#{@port}/#{i}"]) + i == kill_point and Process.kill(:HUP, pid) + end + end + wait_master_ready(master_log) + assert File.exist?(pid_file), "pid=#{pid_file} exists" + new_pid = File.read(pid_file).to_i + assert_not_equal pid, new_pid + assert_nothing_raised { Process.kill(0, new_pid) } + assert_nothing_raised { Process.kill(:QUIT, new_pid) } +end + +def wait_for_file(path) + tries = DEFAULT_TRIES + while (tries -= 1) > 0 && ! File.exist?(path) + sleep DEFAULT_RES + end + assert File.exist?(path), "path=#{path} exists #{caller.inspect}" +end + +def xfork(&block) + fork do + ObjectSpace.each_object(Tempfile) do |tmp| + ObjectSpace.undefine_finalizer(tmp) + end + yield + end +end + +# can't waitpid on detached processes +def wait_for_death(pid) + tries = DEFAULT_TRIES + while (tries -= 1) > 0 + begin + Process.kill(0, pid) + begin + Process.waitpid(pid, Process::WNOHANG) + rescue Errno::ECHILD + end + sleep(DEFAULT_RES) + rescue Errno::ESRCH + return + end + end + raise "PID:#{pid} never died!" +end -- cgit v1.2.3-24-ge0c7