about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-10-24 17:10:49 -0700
committerEric Wong <normalperson@yhbt.net>2009-10-24 17:10:49 -0700
commite77369a6bde35a4e8925d450aac85f328f87d208 (patch)
treee43c5b68ac26ee625a372a710a2e302711fa59f1
parent60ff6aaee097ff1f3ddca34ab53da9b077997dde (diff)
downloadrainbows-e77369a6bde35a4e8925d450aac85f328f87d208.tar.gz
Everything passes, and "set -e" prevents us from
making any stupid mistakes...
-rw-r--r--t/GNUmakefile31
-rwxr-xr-xt/bin/unused_listen2
-rw-r--r--t/lib-async-response-no-autochunk.sh3
-rw-r--r--t/lib-async-response.sh78
-rw-r--r--t/lib-graceful.sh35
-rw-r--r--t/lib-input-trailer.sh114
-rw-r--r--t/lib-large-file-response.sh105
-rw-r--r--t/lib-parser-error.sh39
-rw-r--r--t/lib-rack-input-hammer.sh64
-rw-r--r--t/lib-reopen-logs.sh114
-rw-r--r--t/lib-simple-http.sh171
-rwxr-xr-xt/t9000-rack-app-pool.sh58
-rwxr-xr-xt/test-lib.sh58
13 files changed, 527 insertions, 345 deletions
diff --git a/t/GNUmakefile b/t/GNUmakefile
index e4e4f5a..24ce750 100644
--- a/t/GNUmakefile
+++ b/t/GNUmakefile
@@ -2,7 +2,7 @@
 
 all::
 
-RUBY = ruby
+RUBY = $(ruby)
 rainbows_lib := $(shell cd ../lib && pwd)
 -include ../local.mk
 ifeq ($(RUBY_VERSION),)
@@ -22,34 +22,19 @@ all:: $(T)
 
 # can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
 t_pfx = trash/$@-$(RUBY_VERSION)
-t_code = $(t_pfx).code
-t_log = $(t_pfx).log
+TEST_OPTS =
 # TRACER = strace -f -o $(t_pfx).strace -s 100000
 # TRACER = /usr/bin/time -o $(t_pfx).time
-t_run = $(TRACER) $(SHELL) $(SH_TEST_OPTS) $@
+run_test = $(TRACER) $(SHELL) $(SH_TEST_OPTS) $@ $(TEST_OPTS)
 
-# prefix stdout messages with ':', and stderr messages with '!'
-t_wrap = ( ( ( echo 42 > $(t_code); \
-  $(t_run); \
-  echo $$? > $(t_code) ) \
-  | sed 's/^/$(pfx):/' 1>&3 ) 2>&1 \
-  | sed 's/^/$(pfx)!/' 1>&2 ) 3>&1
-
-ifndef V
-  quiet_pre = @echo '* $@';
-  quiet_post = > $(t_log) 2>&1; exit $$(cat $(t_code))
-  pfx =
-else
+ifdef V
   ifeq ($(V),2)
-    SH_TEST_OPTS += -x
+    TEST_OPTS += --trace
+  else
+    TEST_OPTS += --verbose
   endif
-  quiet_pre = @echo '* $@';
-  quiet_post = 2>&1 | ./bin/utee $(t_log); exit $$(cat $(t_code))
-  pfx = $@
 endif
 
-run_test = $(quiet_pre) ( $(t_wrap) ) $(quiet_post)
-
 test-bin-$(RUBY_VERSION)/rainbows: ruby_bin = $(shell which $(RUBY))
 test-bin-$(RUBY_VERSION)/rainbows: ../bin/rainbows
         mkdir -p $(@D)
@@ -68,7 +53,7 @@ $(T): trash/.gitignore
 $(T): export RUBY := $(RUBY)
 $(T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
 $(T): test-bin-$(RUBY_VERSION)/rainbows
-        $(run_test)
+        @$(run_test)
 
 trash/.gitignore:
         mkdir -p $(@D)
diff --git a/t/bin/unused_listen b/t/bin/unused_listen
index d0ab24a..95f3249 100755
--- a/t/bin/unused_listen
+++ b/t/bin/unused_listen
@@ -36,4 +36,4 @@ rescue Errno::EEXIST
   retry
 end
 sock.close rescue nil
-puts %Q(listen=#{addr}:#{port} _TEST_RM_LIST="$_TEST_RM_LIST #{lock_path}")
+puts %Q(listen=#{addr}:#{port} T_RM_LIST="$T_RM_LIST #{lock_path}")
diff --git a/t/lib-async-response-no-autochunk.sh b/t/lib-async-response-no-autochunk.sh
index 66be85e..c94907a 100644
--- a/t/lib-async-response-no-autochunk.sh
+++ b/t/lib-async-response-no-autochunk.sh
@@ -1,6 +1,3 @@
 #!/bin/sh
 CONFIG_RU=async-response-no-autochunk.ru
 . ./lib-async-response.sh
-test x"$(cat $a)" = x0123456789
-test x"$(cat $b)" = x0123456789
-test x"$(cat $c)" = x0123456789
diff --git a/t/lib-async-response.sh b/t/lib-async-response.sh
index 65c6056..368792b 100644
--- a/t/lib-async-response.sh
+++ b/t/lib-async-response.sh
@@ -1,35 +1,65 @@
 CONFIG_RU=${CONFIG_RU-'async-response.ru'}
 . ./test-lib.sh
-echo "async response for model=$model"
-rtmpfiles a b c curl_err
-rainbows_setup
-# can't load Rack::Lint here since it'll cause Rev to slurp
-rainbows -E none -D $CONFIG_RU -c $unicorn_config
-rainbows_wait_start
-
-t0=$(date +%s)
-( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $a) &
-( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $b) &
-( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $c) &
-wait
-t1=$(date +%s)
-
-kill -QUIT $rainbows_pid
-elapsed=$(( $t1 - $t0 ))
-echo "elapsed=$elapsed < 30"
-test $elapsed -lt 30
+
+case $CONFIG_RU in
+*no-autochunk.ru)
+        t_plan 7 "async response w/o autochunk for $model"
+        skip_autochunk=true
+        ;;
+*)
+        t_plan 6 "async response for $model"
+        skip_autochunk=false
+        ;;
+esac
+
+t_begin "setup and start" && {
+        rainbows_setup
+        rtmpfiles a b c curl_err
+        # can't load Rack::Lint here since it'll cause Rev to slurp
+        rainbows -E none -D $CONFIG_RU -c $unicorn_config
+        rainbows_wait_start
+}
+
+t_begin "send async requests off in parallel" && {
+        t0=$(date +%s)
+        ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $a) &
+        ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $b) &
+        ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $c) &
+        wait
+        t1=$(date +%s)
+}
+
+t_begin "ensure elapsed requests were processed in parallel" && {
+        elapsed=$(( $t1 - $t0 ))
+        echo "elapsed=$elapsed < 30"
+        test $elapsed -lt 30
+}
+
+t_begin "termination signal sent" && {
+        kill $rainbows_pid
+}
 
 dbgcat a
 dbgcat b
 dbgcat c
 dbgcat r_err
 dbgcat curl_err
-test ! -s $curl_err
-check_stderr
 
-while kill -0 $rainbows_pid >/dev/null 2>&1
-do
-        sleep 1
-done
+t_begin "no errors from curl" && {
+        test ! -s $curl_err
+}
+
+t_begin "no errors in stderr" && check_stderr
 
 dbgcat r_err
+
+if $skip_autochunk
+then
+        t_begin "no responses are chunked" && {
+                test x"$(cat $a)" = x0123456789
+                test x"$(cat $b)" = x0123456789
+                test x"$(cat $c)" = x0123456789
+        }
+fi
+
+t_done
diff --git a/t/lib-graceful.sh b/t/lib-graceful.sh
index 3bc3590..45008a5 100644
--- a/t/lib-graceful.sh
+++ b/t/lib-graceful.sh
@@ -1,30 +1,31 @@
 . ./test-lib.sh
-echo "graceful test for model=$model"
 
-rtmpfiles curl_out
-rainbows_setup
-rainbows -D sleep.ru -c $unicorn_config
-rainbows_wait_start
+t_plan 4 "graceful exit test for $model"
 
-curl -sSfv -T- </dev/null http://$listen/5 > $curl_out 2> $fifo &
+t_begin "setup and startup" && {
+        rtmpfiles curl_out
+        rainbows_setup $model
+        rainbows -D sleep.ru -c $unicorn_config
+        rainbows_wait_start
+}
 
-awk -v rainbows_pid=$rainbows_pid '
+t_begin "send a request and SIGQUIT while request is processing" && {
+        curl -sSfv -T- </dev/null http://$listen/5 > $curl_out 2> $fifo &
+        awk -v rainbows_pid=$rainbows_pid '
 { print $0 }
 /100 Continue/ {
         print "awk: sending SIGQUIT to", rainbows_pid
         system("kill -QUIT "rainbows_pid)
 }' $fifo
-wait
+        wait
+}
 
 dbgcat r_err
 
-test x"$(wc -l < $curl_out)" = x1
-nr=$(sort < $curl_out | uniq | wc -l)
+t_begin 'response returned "Hello"' && {
+        test x$(cat $curl_out) = xHello
+}
 
-test "$nr" -eq 1
-test x$(sort < $curl_out | uniq) = xHello
-check_stderr
-while kill -0 $rainbows_pid >/dev/null 2>&1
-do
-        sleep 1
-done
+t_begin 'stderr has no errors' && check_stderr
+
+t_done
diff --git a/t/lib-input-trailer.sh b/t/lib-input-trailer.sh
index 08331b1..9dce292 100644
--- a/t/lib-input-trailer.sh
+++ b/t/lib-input-trailer.sh
@@ -1,53 +1,67 @@
 . ./test-lib.sh
 test -r random_blob || die "random_blob required, run with 'make $0'"
-echo "input trailer test model=$model"
-
-rainbows_setup
-rainbows -D content-md5.ru -c $unicorn_config
-rainbows_wait_start
-
-echo "small blob"
-(
-        cat $fifo > $tmp &
-        echo hello world | content-md5-put
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
-
-fgrep 'HTTP/1.1 200 OK' $tmp
-test xok = x"$(cat $ok)"
-check_stderr
-
-echo "big blob"
-(
-        cat $fifo > $tmp &
-        content-md5-put < random_blob
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
-
-fgrep 'HTTP/1.1 200 OK' $tmp
-test xok = x"$(cat $ok)"
-check_stderr
-
-echo "staggered blob"
-(
-        cat $fifo > $tmp &
+
+t_plan 11 "input trailer test $model"
+
+t_begin "setup and startup" && {
+        rtmpfiles curl_out
+        rainbows_setup $model
+        rainbows -D content-md5.ru -c $unicorn_config
+        rainbows_wait_start
+}
+
+t_begin "upload small blob" && {
         (
-                dd bs=164 count=1 < random_blob
-                sleep 2
-                dd bs=4545 count=1 < random_blob
-                sleep 2
-                dd bs=1234 count=1 < random_blob
-                echo subok > $ok
-        ) 2>/dev/null | content-md5-put
-        test xsubok = x"$(cat $ok)"
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
-
-fgrep 'HTTP/1.1 200 OK' $tmp
-test xok = x"$(cat $ok)"
-check_stderr
-
-kill $(cat $pid)
+                cat $fifo > $tmp &
+                echo hello world | content-md5-put
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+        test xok = x"$(cat $ok)"
+}
+
+t_begin "HTTP response is OK" && fgrep 'HTTP/1.1 200 OK' $tmp
+t_begin "no errors in stderr log" && check_stderr
+
+t_begin "big blob request" && {
+        (
+                cat $fifo > $tmp &
+                content-md5-put < random_blob
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+        test xok = x"$(cat $ok)"
+}
+
+t_begin "HTTP response is OK" && fgrep 'HTTP/1.1 200 OK' $tmp
+t_begin "no errors in stderr log" && check_stderr
+
+t_begin "staggered blob upload" && {
+        (
+                cat $fifo > $tmp &
+                (
+                        dd bs=164 count=1 < random_blob
+                        sleep 2
+                        dd bs=4545 count=1 < random_blob
+                        sleep 2
+                        dd bs=1234 count=1 < random_blob
+                        echo subok > $ok
+                ) 2>/dev/null | content-md5-put
+                test xsubok = x"$(cat $ok)"
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+        test xok = x"$(cat $ok)"
+}
+
+t_begin "HTTP response is OK" && {
+        fgrep 'HTTP/1.1 200 OK' $tmp
+}
+
+t_begin "no errors in stderr log" && check_stderr
+
+t_begin "kill server" && {
+        kill $rainbows_pid
+}
+
+t_done
diff --git a/t/lib-large-file-response.sh b/t/lib-large-file-response.sh
index 4e387e0..9bbd767 100644
--- a/t/lib-large-file-response.sh
+++ b/t/lib-large-file-response.sh
@@ -1,51 +1,82 @@
 . ./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
-        echo >&2 "skipping, can't read RSS from /proc/self/status"
+        t_info "skipping, can't read RSS from /proc/self/status"
         exit 0
 fi
-echo "large file response slurp avoidance for model=$model"
 
-rainbows_setup
-# can't load Rack::Lint here since it'll cause Rev to slurp
-rainbows -E none -D large-file-response.ru -c $unicorn_config
-rainbows_wait_start
+t_plan 10 "large file response slurp avoidance for $model"
 
-random_blob_size=$(wc -c < random_blob)
-curl -v http://$listen/rss
-dbgcat r_err
-rss_before=$(curl -sSfv http://$listen/rss)
-echo "rss_before=$rss_before"
+t_begin "setup and startup" && {
+        rtmpfiles curl_out
+        rainbows_setup $model
+        # can't load Rack::Lint here since it'll cause Rev to slurp
+        rainbows -E none -D large-file-response.ru -c $unicorn_config
+        rainbows_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"
+}
 
-for i in a b c
-do
-        size=$( (curl -sSfv http://$listen/random_blob && echo ok >$ok) |wc -c)
+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)
-done
-
-echo "HTTP/1.0 test" # this was a problem during development
-size=$( (curl -0 -sSfv http://$listen/random_blob && echo ok >$ok) |wc -c)
-test $size -eq $random_blob_size
-test xok = x$(cat $ok)
-
-echo "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)
+}
+
+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
-curl -v http://$listen/rss
-rss_after=$(curl -sSfv http://$listen/rss)
-echo "rss_after=$rss_after"
-diff=$(( $rss_after - $rss_before ))
-echo "test diff=$diff < orig=$random_blob_size"
-kill -QUIT $(cat $pid)
-test $diff -le $random_blob_size
+
+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 $rainbows_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/lib-parser-error.sh b/t/lib-parser-error.sh
index 4d4f63e..2b35b17 100644
--- a/t/lib-parser-error.sh
+++ b/t/lib-parser-error.sh
@@ -1,19 +1,30 @@
 . ./test-lib.sh
-echo "parser error test for model=$model"
+t_plan 5 "parser error test for $model"
 
-rainbows_setup
-rainbows -D env.ru -c $unicorn_config
-rainbows_wait_start
+t_begin "setup and startup" && {
+        rainbows_setup $model
+        rainbows -D env.ru -c $unicorn_config
+        rainbows_wait_start
+}
 
-(
-        printf 'GET / HTTP/1/1\r\nHost: example.com\r\n\r\n'
-        cat $fifo > $tmp &
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
-
-kill $(cat $pid)
+t_begin "send request" && {
+        (
+                printf 'GET / HTTP/1/1\r\nHost: example.com\r\n\r\n'
+                cat $fifo > $tmp &
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+        test xok = x$(cat $ok)
+}
 
 dbgcat tmp
-grep -F 'HTTP/1.1 400 Bad Request' $tmp
-check_stderr
+
+t_begin "response should be a 400" && {
+        grep -F 'HTTP/1.1 400 Bad Request' $tmp
+}
+
+t_begin "server stderr should be clean" && check_stderr
+
+t_begin "term signal sent" && kill $rainbows_pid
+
+t_done
diff --git a/t/lib-rack-input-hammer.sh b/t/lib-rack-input-hammer.sh
index 5bc3a58..3e543b3 100644
--- a/t/lib-rack-input-hammer.sh
+++ b/t/lib-rack-input-hammer.sh
@@ -2,26 +2,44 @@ nr_client=${nr_client-4}
 . ./test-lib.sh
 test -r random_blob || die "random_blob required, run with 'make $0'"
 
-rainbows_setup
-rtmpfiles curl_out curl_err
-rainbows -D sha1.ru -c $unicorn_config
-rainbows_wait_start
-
-start=$(date +%s)
-for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
-do
-        (
-                curl -sSf -T- http://$listen/$i \
-                  < random_blob >> $curl_out 2>> $curl_err
-        ) &
-done
-wait
-echo elapsed=$(( $(date +%s) - $start ))
-
-kill $(cat $pid)
-test $nr_client -eq $(wc -l < $curl_out)
-test 1 -eq $(sort < $curl_out | uniq | wc -l)
-blob_sha1=$( expr "$(sha1sum < random_blob)" : '\([a-f0-9]\+\)')
-echo blob_sha1=$blob_sha1
-test x"$blob_sha1" = x"$(sort < $curl_out | uniq)"
-check_stderr
+t_plan 7 "concurrent rack.input hammer stress test"
+
+t_begin "setup and startup" && {
+        rtmpfiles curl_out curl_err
+        rainbows_setup $model
+        rainbows -D sha1.ru -c $unicorn_config
+        rainbows_wait_start
+}
+
+t_begin "send $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 -T- http://$listen/$i \
+                          < random_blob >> $curl_out 2>> $curl_err
+                ) &
+        done
+        wait
+        t_info elapsed=$(( $(date +%s) - $start ))
+}
+
+t_begin "kill server" && kill $rainbows_pid
+
+t_begin "got $nr_client responses" && {
+        test $nr_client -eq $(wc -l < $curl_out)
+}
+
+t_begin "all responses identical" && {
+        test 1 -eq $(sort < $curl_out | uniq | wc -l)
+}
+
+t_begin "sha1 matches on-disk sha1" && {
+        blob_sha1=$( expr "$(sha1sum < random_blob)" : '\([a-f0-9]\+\)')
+        t_info blob_sha1=$blob_sha1
+        test x"$blob_sha1" = x"$(sort < $curl_out | uniq)"
+}
+
+t_begin "no errors in stderr log" && check_stderr
+
+t_done
diff --git a/t/lib-reopen-logs.sh b/t/lib-reopen-logs.sh
index d295ba9..822de8b 100644
--- a/t/lib-reopen-logs.sh
+++ b/t/lib-reopen-logs.sh
@@ -3,51 +3,95 @@
 nr_client=${nr_client-2}
 . ./test-lib.sh
 
-rtmpfiles curl_out curl_err r_rot
-rainbows_setup
-rainbows -D sleep.ru -c $unicorn_config
-rainbows_wait_start
+t_plan 18 "reopen rotated logs"
 
-# ensure our server is started and responding before signaling
-curl -sSf http://$listen/ >/dev/null
+t_begin "setup and startup" && {
+        rtmpfiles curl_out curl_err r_rot
+        rainbows_setup $model
+        rainbows -D sleep.ru -c $unicorn_config
+        rainbows_wait_start
+}
 
-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
-check_stderr
+t_begin "ensure server is responsive" && {
+        curl -sSf http://$listen/ >/dev/null
+}
 
-rm -f $r_rot
-mv $r_err $r_rot
+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
+}
 
-kill -USR1 $(cat $pid)
-wait_for_pid $r_err
+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 $rainbows_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
+}
 
 dbgcat r_rot
 dbgcat r_err
 
-wait
-echo elapsed=$(( $(date +%s) - $start ))
-test ! -s $curl_err
-test x"$(wc -l < $curl_out)" = x$nr_client
-nr=$(sort < $curl_out | uniq | wc -l)
+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
+}
 
-test "$nr" -eq 1
-test x$(sort < $curl_out | uniq) = xHello
-check_stderr
-check_stderr $r_rot
+t_begin "all responses were identical" && {
+        nr=$(sort < $curl_out | uniq | wc -l)
+        test "$nr" -eq 1
+}
 
-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)
+t_begin 'response was "Hello"' && {
+        test x$(sort < $curl_out | uniq) = xHello
+}
 
-test $after_rot -eq $before_rot && echo "before_rot -eq after_rot"
-test $after_err -gt $before_err && echo "before_err -gt after_err"
+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 $rainbows_pid
+}
 
-kill $(cat $pid)
 dbgcat r_err
-check_stderr
-check_stderr $r_rot
+
+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/lib-simple-http.sh b/t/lib-simple-http.sh
index 235f4e3..cb0b28f 100644
--- a/t/lib-simple-http.sh
+++ b/t/lib-simple-http.sh
@@ -1,79 +1,142 @@
 #!/bin/sh
 . ./test-lib.sh
+t_plan 24 "simple HTTP connection keepalive/pipelining tests for $model"
 
-echo "simple HTTP connection keepalive/pipelining tests for $model"
+t_begin "checking for config.ru for $model" && {
+        tbase=$(expr "$T" : '^\(t....\)-').ru
+        test -f "$tbase"
+}
 
-tbase=$(expr "$T" : '^\(t....\)-').ru
-test -f "$tbase" || die "$tbase missing for $T"
+t_begin "setup and start" && {
+        rainbows_setup
+        rainbows -D $tbase -c $unicorn_config
+        rainbows_wait_start
+}
 
-rainbows_setup
-rainbows -D $tbase -c $unicorn_config
-rainbows_wait_start
+t_begin "pid file exists" && {
+        test -f $pid
+}
+
+t_begin "single request" && {
+        curl -sSfv http://$listen/
+}
 
-echo "single request"
-curl -sSfv http://$listen/
 dbgcat r_err
 
-echo "two requests with keepalive"
-curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
+t_begin "two requests with keepalive" && {
+        curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
+}
+
 dbgcat r_err
 dbgcat tmp
-grep 'Re-using existing connection' < $tmp
-
-echo "pipelining partial requests"
-req='GET / HTTP/1.1\r\nHost: example.com\r\n'
-(
-        printf "$req"'\r\n'"$req"
-        cat $fifo > $tmp &
-        sleep 1
-        printf 'Connection: close\r\n\r\n'
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
 
+t_begin "reused existing connection" && {
+        grep 'Re-using existing connection' < $tmp
+}
+
+t_begin "pipelining partial requests" && {
+        req='GET / HTTP/1.1\r\nHost: example.com\r\n'
+        (
+                cat $fifo > $tmp &
+                printf "$req"'\r\n'"$req"
+                sleep 1
+                printf 'Connection: close\r\n\r\n'
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+}
 dbgcat tmp
 
-test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
-test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
-test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
-test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
-test x"$(cat $ok)" = xok
-check_stderr
+t_begin "two HTTP/1.1 responses" && {
+        test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
+}
+
+t_begin "two HTTP/1.1 200 OK responses" && {
+        test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
+}
+
+t_begin 'one "Connection: keep-alive" response' && {
+        test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
+}
+
+t_begin 'one "Connection: close" response' && {
+        test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
+}
+
+t_begin 'check subshell success' && {
+        test x"$(cat $ok)" = xok
+}
 
 
-echo "burst pipelining"
-req='GET / HTTP/1.1\r\nHost: example.com\r\n'
-(
-        printf "$req"'\r\n'"$req"'Connection: close\r\n\r\n'
-        cat $fifo > $tmp &
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
+t_begin "check stderr" && {
+        check_stderr
+}
+
+t_begin "burst pipelining requests" && {
+        req='GET / HTTP/1.1\r\nHost: example.com\r\n'
+        (
+                cat $fifo > $tmp &
+                printf "$req"'\r\n'"$req"'Connection: close\r\n\r\n'
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+}
 
 dbgcat tmp
 dbgcat r_err
 
-test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
-test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
-test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
-test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
-test x"$(cat $ok)" = xok
+t_begin "got 2 HTTP/1.1 responses from pipelining" && {
+        test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
+}
+
+t_begin "got 2 HTTP/1.1 200 OK responses" && {
+        test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
+}
+
+t_begin "one keepalive connection" && {
+        test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
+}
+
+t_begin "second request closes connection" && {
+        test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
+}
+
+t_begin "subshell exited correctly" && {
+        test x"$(cat $ok)" = xok
+}
 
-check_stderr
+t_begin "stderr log has no errors" && {
+        check_stderr
+}
 
-echo "HTTP/0.9 request should not return headers"
-(
-        printf 'GET /\r\n'
-        cat $fifo > $tmp &
-        wait
-        echo ok > $ok
-) | socat - TCP:$listen > $fifo
+t_begin "HTTP/0.9 request should not return headers" && {
+        (
+                printf 'GET /\r\n'
+                cat $fifo > $tmp &
+                wait
+                echo ok > $ok
+        ) | socat - TCP:$listen > $fifo
+}
 
 dbgcat tmp
 dbgcat r_err
-echo "env.inspect should've put everything on one line"
-test 1 -eq $(wc -l < $tmp)
-! grep ^Connection: $tmp
-! grep ^HTTP/ $tmp
 
-kill $(cat $pid)
+t_begin "env.inspect should've put everything on one line" && {
+        test 1 -eq $(wc -l < $tmp)
+}
+
+t_begin "no headers in output" && {
+        if grep ^Connection: $tmp
+        then
+                die "Connection header found in $tmp"
+        elif grep ^HTTP/ $tmp
+        then
+                die "HTTP/ found in $tmp"
+        fi
+}
+
+t_begin "killing succeeds" && {
+        kill $rainbows_pid
+}
+
+t_done
diff --git a/t/t9000-rack-app-pool.sh b/t/t9000-rack-app-pool.sh
index 6c82ff8..b04564b 100755
--- a/t/t9000-rack-app-pool.sh
+++ b/t/t9000-rack-app-pool.sh
@@ -1,23 +1,41 @@
 #!/bin/sh
 . ./test-lib.sh
+nr_client=30 APP_POOL_SIZE=4
 
-nr_client=30
-rtmpfiles curl_out curl_err
-rainbows_setup ThreadSpawn 50
-APP_POOL_SIZE=4
-APP_POOL_SIZE=$APP_POOL_SIZE rainbows -D t9000.ru -c $unicorn_config
-rainbows_wait_start
-
-start=$(date +%s)
-for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
-do
-        ( curl -sSf http://$listen/ >> $curl_out 2>> $curl_err ) &
-done
-wait
-echo elapsed=$(( $(date +%s) - $start ))
-kill $(cat $pid)
-
-test $APP_POOL_SIZE -eq $(sort < $curl_out | uniq | wc -l)
-test ! -s $curl_err
-
-check_stderr
+t_plan 6 "AppPool Rack middleware test"
+
+t_begin "configure and start" && {
+        rtmpfiles curl_out curl_err
+        rainbows_setup ThreadSpawn 50
+        APP_POOL_SIZE=$APP_POOL_SIZE rainbows -D t9000.ru -c $unicorn_config
+        rainbows_wait_start
+}
+
+t_begin "launch $nr_client requests" && {
+        start=$(date +%s)
+        seq="$(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)"
+        for i in $seq
+        do
+                curl -sSf http://$listen/ >> $curl_out 2>> $curl_err &
+        done
+        wait
+        t_info elapsed=$(( $(date +%s) - $start ))
+}
+
+t_begin "kill server" && {
+        kill $rainbows_pid
+}
+
+t_begin "$APP_POOL_SIZE instances of app were used" && {
+        test $APP_POOL_SIZE -eq $(sort < $curl_out | uniq | wc -l)
+}
+
+t_begin "no errors in curl stderr" && {
+        test ! -s $curl_err
+}
+
+t_begin "no errors in Rainbows! stderr" && {
+        check_stderr
+}
+
+t_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index d3815c4..5e279a1 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1,21 +1,8 @@
 #!/bin/sh
 # Copyright (c) 2009 Rainbows! developers
+. ./my-tap-lib.sh
 
-# pipefail is non-POSIX, but useful in ksh/bash
-(
-        set +e
-        set -o pipefail 2>/dev/null
-)
-if test $? -eq 0
-then
-        set -o pipefail
-else
-        echo >&2 "WARNING: your shell does not understand pipefail"
-fi
-
-set -e
-
-T=$(basename $0)
+set +u
 if test -z "$model"
 then
         case $T in
@@ -27,37 +14,12 @@ then
         esac
 fi
 
+set -e
 RUBY="${RUBY-ruby}"
 RUBY_VERSION=${RUBY_VERSION-$($RUBY -e 'puts RUBY_VERSION')}
 t_pfx=$PWD/trash/$T-$RUBY_VERSION
 set -u
 
-# ensure a sane environment
-TZ=UTC LC_ALL=C LANG=C
-export LANG LC_ALL TZ
-unset CDPATH
-
-die () {
-        echo >&2 "$@"
-        exit 1
-}
-
-_test_on_exit () {
-        code=$?
-        case $code in
-        0)
-                echo "ok $T"
-                rm -f $_TEST_OK_RM_LIST
-        ;;
-        *) echo "not ok $T" ;;
-        esac
-        rm -f $_TEST_RM_LIST
-        exit $code
-}
-
-_TEST_RM_LIST=
-_TEST_OK_RM_LIST=
-trap _test_on_exit EXIT
 PATH=$PWD/bin:$PATH
 export PATH
 
@@ -73,12 +35,13 @@ wait_for_pid () {
         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
-                echo >&2 "skipping $T since we don't have $lib"
+                t_info "skipping $T since we don't have $lib"
                 exit 0
         fi
 }
@@ -96,11 +59,11 @@ rtmpfiles () {
                 *fifo)
                         rm -f $_tmp
                         mkfifo $_tmp
-                        _TEST_RM_LIST="$_TEST_RM_LIST $_tmp"
+                        T_RM_LIST="$T_RM_LIST $_tmp"
                         ;;
                 *)
                         > $_tmp
-                        _TEST_OK_RM_LIST="$_TEST_OK_RM_LIST $_tmp"
+                        T_OK_RM_LIST="$T_OK_RM_LIST $_tmp"
                         ;;
                 esac
         done
@@ -126,6 +89,7 @@ check_stderr () {
         fi
 }
 
+# rainbows_setup [ MODEL [ WORKER_CONNECTIONS ] ]
 rainbows_setup () {
         eval $(unused_listen)
         rtmpfiles unicorn_config pid r_err r_out fifo tmp ok
@@ -135,6 +99,12 @@ pid "$pid"
 stderr_path "$r_err"
 stdout_path "$r_out"
 
+# close my-tap-lib.sh FDs
+unless ENV['UNICORN_FD']
+  IO.for_fd(3).close rescue nil
+  IO.for_fd(4).close rescue nil
+end
+
 before_fork do |server, worker|
   # test script will block while reading from $fifo,
   # so notify the script on the first worker we spawn