diff options
-rw-r--r-- | t/.gitignore | 4 | ||||
-rw-r--r-- | t/GNUmakefile | 117 | ||||
-rwxr-xr-x | t/bin/content-md5-put | 36 | ||||
-rwxr-xr-x | t/bin/sha1sum.rb | 23 | ||||
-rwxr-xr-x | t/bin/unused_listen | 40 | ||||
-rwxr-xr-x | t/bin/utee | 12 | ||||
-rw-r--r-- | t/large-file-response.ru | 14 | ||||
-rw-r--r-- | t/my-tap-lib.sh | 200 | ||||
-rw-r--r-- | t/sleep.ru | 13 | ||||
-rwxr-xr-x | t/t0003-reopen-logs.sh | 107 | ||||
-rwxr-xr-x | t/t0005-large-file-response.sh | 83 | ||||
-rw-r--r-- | t/test-lib.sh | 155 |
12 files changed, 804 insertions, 0 deletions
diff --git a/t/.gitignore b/t/.gitignore new file mode 100644 index 0000000..bee30c6 --- /dev/null +++ b/t/.gitignore @@ -0,0 +1,4 @@ +/test-results-* +/test-bin-* +/random_blob +/.dep+* diff --git a/t/GNUmakefile b/t/GNUmakefile new file mode 100644 index 0000000..dbd78c4 --- /dev/null +++ b/t/GNUmakefile @@ -0,0 +1,117 @@ +# we can run tests in parallel with GNU make + +all:: + +pid := $(shell echo $$PPID) + +RUBY = ruby +zbatery_lib := $(shell cd ../lib && pwd) +-include ../local.mk +ifeq ($(RUBY_VERSION),) + RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION') +endif + +ifeq ($(RUBY_VERSION),) + $(error unable to detect RUBY_VERSION) +endif + +ifeq ($(RUBYLIB),) + RUBYLIB := $(zbatery_lib) +else + RUBYLIB := $(zbatery_lib):$(RUBYLIB) +endif +export RUBYLIB RUBY_VERSION + +models += ThreadPool +models += ThreadSpawn +models += Rev +models += EventMachine +models += NeverBlock +models += RevThreadSpawn +models += RevThreadPool + +rp := ) +ONENINE := $(shell case $(RUBY_VERSION) in 1.9.*$(rp) echo true;;esac) +ifeq ($(ONENINE),true) + models += Revactor + models += FiberSpawn + models += RevFiberSpawn + models += FiberPool +endif +all_models := $(models) Base + +T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) + +MODEL_T := $(foreach m,$(all_models),$(addprefix $(m).,$(T))) +$(T): MODELS = $(models) + +# some tests can be run with all models +t0000-simple-http.sh: MODELS = $(all_models) +t0001-unix-http.sh: MODELS = $(all_models) +t0002-graceful.sh: MODELS = $(all_models) +t0002-parser-error.sh: MODELS = $(all_models) +t0003-reopen-logs.sh: MODELS = $(all_models) + +# recursively run per-model tests +# haven't figured out a good way to make make non-recursive here, yet... +$(T): + $(MAKE) $(foreach m,$(MODELS),$(addprefix $(m).,$@)) + +$(all_models): + $(MAKE) $(filter $@.%,$(MODEL_T)) + +all:: $(T) + +# can't rely on "set -o pipefail" since we don't require bash or ksh93 :< +t_pfx = trash/$@-$(RUBY_VERSION) +TEST_OPTS = +# TRACER = strace -f -o $(t_pfx).strace -s 100000 +# TRACER = /usr/bin/time -o $(t_pfx).time + +ifdef V + ifeq ($(V),2) + TEST_OPTS += --trace + else + TEST_OPTS += --verbose + endif +endif + +test-bin-$(RUBY_VERSION)/zbatery: ruby_bin = $(shell which $(RUBY)) +test-bin-$(RUBY_VERSION)/zbatery: ../bin/zbatery + mkdir -p $(@D) + install -m 755 $^ $@.$(pid) + $(RUBY) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@.$(pid) + mv $@.$(pid) $@ + +random_blob: + dd if=/dev/urandom bs=1M count=30 of=$@.$(pid) + mv $@.$(pid) $@ + +$(T): random_blob + +dependencies := socat curl +deps := $(addprefix .dep+,$(dependencies)) +$(deps): dep_bin = $(lastword $(subst +, ,$@)) +$(deps): + @which $(dep_bin) > $@.$(pid) 2>/dev/null || : + @test -s $@.$(pid) || \ + { echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; } + @mv $@.$(pid) $@ +dep: $(deps) + +$(MODEL_T): export model = $(firstword $(subst ., ,$@)) +$(MODEL_T): script = $(subst $(model).,,$@) +$(MODEL_T): trash/.gitignore +$(MODEL_T): export RUBY := $(RUBY) +$(MODEL_T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH) +$(MODEL_T): test-bin-$(RUBY_VERSION)/zbatery dep + $(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS) + +trash/.gitignore: + mkdir -p $(@D) + echo '*' > $@ + +clean: + $(RM) -r trash/*.log trash/*.code test-bin-$(RUBY_VERSION) + +.PHONY: $(T) clean diff --git a/t/bin/content-md5-put b/t/bin/content-md5-put new file mode 100755 index 0000000..01da0bb --- /dev/null +++ b/t/bin/content-md5-put @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +# -*- encoding: binary -*- +# simple chunked HTTP PUT request generator (and just that), +# it reads stdin and writes to stdout so socat can write to a +# UNIX or TCP socket (or to another filter or file) along with +# a Content-MD5 trailer. +require 'digest/md5' +$stdout.sync = $stderr.sync = true +$stdout.binmode +$stdin.binmode + +bs = ENV['bs'] ? ENV['bs'].to_i : 4096 + +if ARGV.grep("--no-headers").empty? + $stdout.write( + "PUT / HTTP/1.1\r\n" \ + "Host: example.com\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "Trailer: Content-MD5\r\n" \ + "\r\n" + ) +end + +digest = Digest::MD5.new +if buf = $stdin.readpartial(bs) + begin + digest.update(buf) + $stdout.write("%x\r\n" % [ buf.size ]) + $stdout.write(buf) + $stdout.write("\r\n") + end while $stdin.read(bs, buf) +end + +digest = [ digest.digest ].pack('m').strip +$stdout.write("0\r\n") +$stdout.write("Content-MD5: #{digest}\r\n\r\n") diff --git a/t/bin/sha1sum.rb b/t/bin/sha1sum.rb new file mode 100755 index 0000000..b602e79 --- /dev/null +++ b/t/bin/sha1sum.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# -*- encoding: binary -*- + +# Reads from stdin and outputs the SHA1 hex digest of the input this is +# ONLY used as a last resort, our test code will try to use sha1sum(1), +# openssl(1), or gsha1sum(1) before falling back to using this. We try +# all options first because we have a strong and healthy distrust of our +# Ruby abilities in general, and *especially* when it comes to +# understanding (and trusting the implementation of) Ruby 1.9 encoding. + +require 'digest/sha1' +$stdout.sync = $stderr.sync = true +$stdout.binmode +$stdin.binmode +bs = 16384 +digest = Digest::SHA1.new +if buf = $stdin.read(bs) + begin + digest.update(buf) + end while $stdin.read(bs, buf) +end + +$stdout.syswrite("#{digest.hexdigest}\n") diff --git a/t/bin/unused_listen b/t/bin/unused_listen new file mode 100755 index 0000000..b638f54 --- /dev/null +++ b/t/bin/unused_listen @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby +# -*- encoding: binary -*- +# this is to remain compatible with the unused_port function in the +# Unicorn test/test_helper.rb file +require 'socket' +require 'tmpdir' + +default_port = 8080 +addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1' +retries = 100 +base = 5000 +port = sock = lock_path = nil + +begin + begin + port = base + rand(32768 - base) + while port == default_port + port = base + rand(32768 - base) + end + + sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) + sock.bind(Socket.pack_sockaddr_in(port, addr)) + sock.listen(5) + rescue Errno::EADDRINUSE, Errno::EACCES + sock.close rescue nil + retry if (retries -= 1) >= 0 + end + + # since we'll end up closing the random port we just got, there's a race + # condition could allow the random port we just chose to reselect itself + # when running tests in parallel with gmake. Create a lock file while + # we have the port here to ensure that does not happen. + lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock" + lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600) +rescue Errno::EEXIST + sock.close rescue nil + retry +end +sock.close rescue nil +puts %Q(listen=#{addr}:#{port} T_RM_LIST="$T_RM_LIST #{lock_path}") diff --git a/t/bin/utee b/t/bin/utee new file mode 100755 index 0000000..7b61fea --- /dev/null +++ b/t/bin/utee @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# -*- encoding: binary -*- +# tee(1) as distributed on most(all?) systems is buffered in luserspace +# this only does unbuffered writes (with line-buffered input) to make +# test output appear in real-time +$stdin.binmode +$stdout.binmode +fp = File.open(ARGV.shift, "wb") +$stdin.each_line do |line| + fp.syswrite line + $stdout.syswrite line +end diff --git a/t/large-file-response.ru b/t/large-file-response.ru new file mode 100644 index 0000000..84163c1 --- /dev/null +++ b/t/large-file-response.ru @@ -0,0 +1,14 @@ +# lib-large-file-response will stop running if we're not on Linux here +use Rack::ContentLength +use Rack::ContentType +map "/rss" do + run lambda { |env| + # on Linux, this is in kilobytes + GC.start if GC.respond_to?(:start) + ::File.read("/proc/self/status") =~ /^VmRSS:\s+(\d+)/ + [ 200, {}, [ ($1.to_i * 1024).to_s ] ] + } +end +map "/" do + run Rack::File.new(Dir.pwd) +end diff --git a/t/my-tap-lib.sh b/t/my-tap-lib.sh new file mode 100644 index 0000000..ada77ac --- /dev/null +++ b/t/my-tap-lib.sh @@ -0,0 +1,200 @@ +#!/bin/sh +# Copyright (c) 2009 Eric Wong <normalperson@yhbt.net> +# +# TAP-producing shell library for POSIX-compliant Bourne shells We do +# not _rely_ on Bourne Again features, though we will use "set -o +# pipefail" from ksh93 or bash 3 if available +# +# Only generic, non-project/non-language-specific stuff goes here. We +# only have POSIX dependencies for the core tests (without --verbose), +# though we'll enable useful non-POSIX things if they're available. +# +# This test library is intentionally unforgiving, it does not support +# skipping tests nor continuing after any failure. Any failures +# immediately halt execution as do any references to undefined +# variables. +# +# When --verbose is specified, we always prefix stdout/stderr +# output with "#" to avoid confusing TAP consumers. Otherwise +# the normal stdout/stderr streams are redirected to /dev/null + +# dup normal stdout(fd=1) and stderr (fd=2) to fd=3 and fd=4 respectively +# normal TAP output goes to fd=3, nothing should go to fd=4 +exec 3>&1 4>&2 + +# ensure a sane environment +TZ=UTC LC_ALL=C LANG=C +export LANG LC_ALL TZ +unset CDPATH + +# pipefail is non-POSIX, but very useful in ksh93/bash +( set -o pipefail 2>/dev/null ) && set -o pipefail + +SED=${SED-sed} + +# Unlike other test frameworks, we are unforgiving and bail immediately +# on any failures. We do this because we're lazy about error handling +# and also because we believe anything broken should not be allowed to +# propagate throughout the rest of the test +set -e +set -u + +# name of our test +T=${0##*/} + +t_expect_nr=-1 +t_nr=0 +t_current= +t_complete=false + +# list of files to remove unconditionally on exit +T_RM_LIST= + +# list of files to remove only on successful exit +T_OK_RM_LIST= + +# emit output to stdout, it'll be parsed by the TAP consumer +# so it must be TAP-compliant output +t_echo () { + echo >&3 "$@" +} + +# emits non-parsed information to stdout, it will be prefixed with a '#' +# to not throw off TAP consumers +t_info () { + t_echo '#' "$@" +} + +# exit with an error and print a diagnostic +die () { + echo >&2 "$@" + exit 1 +} + +# our at_exit handler, it'll fire for all exits except SIGKILL (unavoidable) +t_at_exit () { + code=$? + set +e + if test $code -eq 0 + then + $t_complete || { + t_info "t_done not called" + code=1 + } + elif test -n "$t_current" + then + t_echo "not ok $t_nr - $t_current" + fi + if test $t_expect_nr -ne -1 + then + test $t_expect_nr -eq $t_nr || { + t_info "planned $t_expect_nr tests but ran $t_nr" + test $code -ne 0 || code=1 + } + fi + $t_complete || { + t_info "unexpected test failure" + test $code -ne 0 || code=1 + } + rm -f $T_RM_LIST + test $code -eq 0 && rm -f $T_OK_RM_LIST + set +x + exec >&3 2>&4 + t_close_fds + exit $code +} + +# close test-specific extra file descriptors +t_close_fds () { + exec 3>&- 4>&- +} + +# call this at the start of your test to specify the number of tests +# you plan to run +t_plan () { + test "$1" -ge 1 || die "must plan at least one test" + test $t_expect_nr -eq -1 || die "tried to plan twice in one test" + t_expect_nr=$1 + shift + t_echo 1..$t_expect_nr "#" "$@" + trap t_at_exit EXIT +} + +_t_checkup () { + test $t_expect_nr -le 0 && die "no tests planned" + test -n "$t_current" && t_echo "ok $t_nr - $t_current" + true +} + +# finalizes any previously test and starts a new one +t_begin () { + _t_checkup + t_nr=$(( $t_nr + 1 )) + t_current="$1" + + # just in case somebody wanted to cheat us: + set -e +} + +# finalizes the current test without starting a new one +t_end () { + _t_checkup + t_current= +} + +# run this to signify the end of your test +t_done () { + _t_checkup + t_current= + t_complete=true + test $t_expect_nr -eq $t_nr || exit 1 + exit 0 +} + +# create and assign named-pipes to variable _names_ passed to this function +t_fifos () { + for _id in "$@" + do + _name=$_id + _tmp=$(mktemp -t $T.$$.$_id.XXXXXXXX) + eval "$_id=$_tmp" + rm -f $_tmp + mkfifo $_tmp + T_RM_LIST="$T_RM_LIST $_tmp" + done +} + +t_verbose=false t_trace=false + +while test "$#" -ne 0 +do + arg="$1" + shift + case $arg in + -v|--verbose) t_verbose=true ;; + --trace) t_trace=true t_verbose=true ;; + *) die "Unknown option: $arg" ;; + esac +done + +# we always only setup stdout, nothing should end up in the "real" stderr +if $t_verbose +then + if test x"$(which mktemp 2>/dev/null)" = x + then + die "mktemp(1) not available for --verbose" + fi + t_fifos t_stdout t_stderr + + ( + # use a subshell so seds are not waitable + $SED -e 's/^/#: /' $t_stdout & + $SED -e 's/^/#! /' $t_stderr & + ) & + exec > $t_stdout 2> $t_stderr +else + exec > /dev/null 2> /dev/null +fi + +$t_trace && set -x +true diff --git a/t/sleep.ru b/t/sleep.ru new file mode 100644 index 0000000..b57efc3 --- /dev/null +++ b/t/sleep.ru @@ -0,0 +1,13 @@ +use Rack::ContentLength + +run lambda { |env| + /\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [ 100, {}, [] ] + + env['rack.input'].read + nr = 1 + env["PATH_INFO"] =~ %r{/([\d\.]+)\z} and nr = $1.to_f + + Rainbows.sleep(nr) + + [ 200, {'Content-Type' => 'text/plain'}, [ "Hello\n" ] ] +} diff --git a/t/t0003-reopen-logs.sh b/t/t0003-reopen-logs.sh new file mode 100755 index 0000000..91c3dc4 --- /dev/null +++ b/t/t0003-reopen-logs.sh @@ -0,0 +1,107 @@ +#!/bin/sh +# don't set nr_client for Rev, only _one_ app running at once :x +nr_client=${nr_client-2} +. ./test-lib.sh + +t_plan 19 "reopen rotated logs" + +t_begin "setup and startup" && { + rtmpfiles curl_out curl_err r_rot + zbatery_setup $model + zbatery -D sleep.ru -c $unicorn_config + zbatery_wait_start +} + +t_begin "ensure server is responsive" && { + curl -sSf http://$listen/ >/dev/null +} + +t_begin "start $nr_client concurrent requests" && { + start=$(date +%s) + for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null) + do + ( curl -sSf http://$listen/2 >> $curl_out 2>> $curl_err ) & + done +} + +t_begin "ensure stderr log is clean" && check_stderr + +t_begin "external log rotation" && { + rm -f $r_rot + mv $r_err $r_rot +} + +t_begin "send reopen log signal (USR1)" && { + kill -USR1 $zbatery_pid +} + +t_begin "wait for rotated log to reappear" && { + nr=60 + while ! test -f $r_err && test $nr -ge 0 + do + sleep 1 + nr=$(( $nr - 1 )) + done +} + +t_begin "wait for worker to reopen logs" && { + nr=60 + re="worker=.* done reopening logs" + while ! grep "$re" < $r_err >/dev/null && test $nr -ge 0 + do + sleep 1 + nr=$(( $nr - 1 )) + done +} + +dbgcat r_rot +dbgcat r_err + +t_begin "wait curl requests to finish" && { + wait + t_info elapsed=$(( $(date +%s) - $start )) +} + +t_begin "ensure no errors from curl" && { + test ! -s $curl_err +} + +t_begin "curl got $nr_client responses" && { + test "$(wc -l < $curl_out)" -eq $nr_client +} + +t_begin "all responses were identical" && { + nr=$(sort < $curl_out | uniq | wc -l) + test "$nr" -eq 1 +} + +t_begin 'response was "Hello"' && { + test x$(sort < $curl_out | uniq) = xHello +} + +t_begin "current server stderr is clean" && check_stderr + +t_begin "rotated stderr is clean" && { + check_stderr $r_rot +} + +t_begin "server is now writing logs to new stderr" && { + before_rot=$(wc -c < $r_rot) + before_err=$(wc -c < $r_err) + curl -sSfv http://$listen/ + after_rot=$(wc -c < $r_rot) + after_err=$(wc -c < $r_err) + test $after_rot -eq $before_rot + test $after_err -gt $before_err +} + +t_begin "stop server" && { + kill $zbatery_pid +} + +dbgcat r_err + +t_begin "current server stderr is clean" && check_stderr +t_begin "rotated stderr is clean" && check_stderr $r_rot + +t_done diff --git a/t/t0005-large-file-response.sh b/t/t0005-large-file-response.sh new file mode 100755 index 0000000..2deba61 --- /dev/null +++ b/t/t0005-large-file-response.sh @@ -0,0 +1,83 @@ +#!/bin/sh +. ./test-lib.sh +test -r random_blob || die "random_blob required, run with 'make $0'" + +if ! grep -v ^VmRSS: /proc/self/status >/dev/null 2>&1 +then + t_info "skipping, can't read RSS from /proc/self/status" + exit 0 +fi + +t_plan 10 "large file response slurp avoidance for $model" + +t_begin "setup and startup" && { + rtmpfiles curl_out + zbatery_setup $model + # can't load Rack::Lint here since it'll cause Rev to slurp + zbatery -E none -D large-file-response.ru -c $unicorn_config + zbatery_wait_start +} + +t_begin "read random blob size" && { + random_blob_size=$(wc -c < random_blob) +} + +t_begin "read current RSS" && { + curl -v http://$listen/rss + dbgcat r_err + rss_before=$(curl -sSfv http://$listen/rss) + t_info "rss_before=$rss_before" +} + +t_begin "send a series HTTP/1.1 requests sequentially" && { + for i in a b c + do + size=$( (curl -sSfv http://$listen/random_blob && + echo ok >$ok) |wc -c) + test $size -eq $random_blob_size + test xok = x$(cat $ok) + done +} + +# this was a problem during development +t_begin "HTTP/1.0 test" && { + size=$( (curl -0 -sSfv http://$listen/random_blob && + echo ok >$ok) |wc -c) + test $size -eq $random_blob_size + test xok = x$(cat $ok) +} + +t_begin "HTTP/0.9 test" && { + ( + printf 'GET /random_blob\r\n' + cat $fifo > $tmp & + wait + echo ok > $ok + ) | socat - TCP:$listen > $fifo + cmp $tmp random_blob + test xok = x$(cat $ok) +} + +dbgcat r_err + +t_begin "read RSS again" && { + curl -v http://$listen/rss + rss_after=$(curl -sSfv http://$listen/rss) + t_info "rss_after=$rss_after" +} + +t_begin "shutdown server" && { + kill -QUIT $zbatery_pid +} + +t_begin "compare RSS before and after" && { + diff=$(( $rss_after - $rss_before )) + t_info "test diff=$diff < orig=$random_blob_size" + test $diff -le $random_blob_size +} + +dbgcat r_err + +t_begin "check stderr" && check_stderr + +t_done diff --git a/t/test-lib.sh b/t/test-lib.sh new file mode 100644 index 0000000..7ea07e7 --- /dev/null +++ b/t/test-lib.sh @@ -0,0 +1,155 @@ +#!/bin/sh +# Copyright (c) 2009 Rainbows! developers +. ./my-tap-lib.sh + +set +u +if test -z "$model" +then + # defaulting to Base would unfortunately fail some concurrency tests + model=ThreadSpawn + t_info "model undefined, defaulting to $model" +fi + +set -e +RUBY="${RUBY-ruby}" +RUBY_VERSION=${RUBY_VERSION-$($RUBY -e 'puts RUBY_VERSION')} +t_pfx=$PWD/trash/$model.$T-$RUBY_VERSION +set -u + +PATH=$PWD/bin:$PATH +export PATH + +test -x $PWD/bin/unused_listen || die "must be run in 't' directory" + +wait_for_pid () { + path="$1" + nr=30 + while ! test -s "$path" && test $nr -gt 0 + do + nr=$(($nr - 1)) + sleep 1 + done +} + +# requires $1 and prints out the value of $2 +require_check () { + lib=$1 + const=$2 + if ! $RUBY -r$lib -e "puts $const" >/dev/null 2>&1 + then + t_info "skipping $T since we don't have $lib" + exit 0 + fi +} + +# given a list of variable names, create temporary files and assign +# the pathnames to those variables +rtmpfiles () { + for id in "$@" + do + name=$id + _tmp=$t_pfx.$id + eval "$id=$_tmp" + + case $name in + *fifo) + rm -f $_tmp + mkfifo $_tmp + T_RM_LIST="$T_RM_LIST $_tmp" + ;; + *socket) + rm -f $_tmp + T_RM_LIST="$T_RM_LIST $_tmp" + ;; + *) + > $_tmp + T_OK_RM_LIST="$T_OK_RM_LIST $_tmp" + ;; + esac + done +} + +dbgcat () { + id=$1 + eval '_file=$'$id + echo "==> $id <==" + sed -e "s/^/$id:/" < $_file +} + +check_stderr () { + set +u + _r_err=${1-${r_err}} + set -u + if grep -i Error $_r_err + then + die "Errors found in $_r_err" + elif grep SIGKILL $_r_err + then + die "SIGKILL found in $_r_err" + fi +} + +# zbatery_setup [ MODEL [ WORKER_CONNECTIONS ] ] +zbatery_setup () { + eval $(unused_listen) + rtmpfiles unicorn_config pid r_err r_out fifo tmp ok + cat > $unicorn_config <<EOF +listen "$listen" +pid "$pid" +stderr_path "$r_err" +stdout_path "$r_out" + +after_fork do |server, worker| + # test script will block while reading from $fifo, + # so notify the script on the first worker we spawn + # by opening the FIFO + if worker.nr == 0 + File.open("$fifo", "wb") { |fp| fp.syswrite "START" } + end +end +EOF + { + # set a higher default for tests since we run heavily-loaded + # boxes and sometimes sleep 1s in tests + kato=5 + echo 'Rainbows! do' + if test $# -ge 1 + then + echo " use :$1" + test $# -eq 2 && echo " worker_connections $2" + if test $# -eq 3 + then + echo " keepalive_timeout $3" + else + echo " keepalive_timeout $kato" + fi + else + echo " use :$model" + echo " keepalive_timeout $kato" + fi + echo end + } >> $unicorn_config +} + +zbatery_wait_start () { + # "cat $fifo" will block until the before_fork hook is called in + # the Unicorn config file + test xSTART = x"$(cat $fifo)" + zbatery_pid=$(cat $pid) +} + +rsha1 () { + _cmd="$(which sha1sum 2>/dev/null || :)" + test -n "$_cmd" || _cmd="$(which openssl 2>/dev/null || :) sha1" + test "$_cmd" != " sha1" || _cmd="$(which gsha1sum 2>/dev/null || :)" + + # last resort, see comments in sha1sum.rb for reasoning + test -n "$_cmd" || _cmd=sha1sum.rb + expr "$($_cmd < random_blob)" : '\([a-f0-9]\{40\}\)' +} + +case $model in +Rev) require_check rev Rev::VERSION ;; +Revactor) require_check revactor Revactor::VERSION ;; +EventMachine) require_check eventmachine EventMachine::VERSION ;; +esac |