From e77369a6bde35a4e8925d450aac85f328f87d208 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 24 Oct 2009 17:10:49 -0700 Subject: [PATCH] tests: port all existing tests to TAP library Everything passes, and "set -e" prevents us from making any stupid mistakes... --- t/GNUmakefile | 31 ++--- t/bin/unused_listen | 2 +- t/lib-async-response-no-autochunk.sh | 3 - t/lib-async-response.sh | 100 ++++++++++------ t/lib-graceful.sh | 61 +++++----- t/lib-input-trailer.sh | 120 ++++++++++--------- t/lib-large-file-response.sh | 133 +++++++++++++-------- t/lib-parser-error.sh | 49 +++++--- t/lib-rack-input-hammer.sh | 72 +++++++----- t/lib-reopen-logs.sh | 150 +++++++++++++++--------- t/lib-simple-http.sh | 221 ++++++++++++++++++++++------------- t/t9000-rack-app-pool.sh | 64 ++++++---- t/test-lib.sh | 58 +++------ 13 files changed, 623 insertions(+), 441 deletions(-) rewrite t/lib-async-response.sh (82%) rewrite t/lib-graceful.sh (74%) rewrite t/lib-input-trailer.sh (90%) rewrite t/lib-large-file-response.sh (82%) rewrite t/lib-parser-error.sh (91%) rewrite t/lib-rack-input-hammer.sh (83%) rewrite t/lib-reopen-logs.sh (85%) rewrite t/lib-simple-http.sh (92%) rewrite t/t9000-rack-app-pool.sh (94%) 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 dissimilarity index 82% 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 - -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 - -dbgcat r_err +CONFIG_RU=${CONFIG_RU-'async-response.ru'} +. ./test-lib.sh + +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 + +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 dissimilarity index 74% 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 - -curl -sSfv -T- $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 - -dbgcat r_err - -test x"$(wc -l < $curl_out)" = x1 -nr=$(sort < $curl_out | uniq | wc -l) - -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 +. ./test-lib.sh + +t_plan 4 "graceful exit test for $model" + +t_begin "setup and startup" && { + rtmpfiles curl_out + rainbows_setup $model + rainbows -D sleep.ru -c $unicorn_config + rainbows_wait_start +} + +t_begin "send a request and SIGQUIT while request is processing" && { + curl -sSfv -T- $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 +} + +dbgcat r_err + +t_begin 'response returned "Hello"' && { + test x$(cat $curl_out) = xHello +} + +t_begin 'stderr has no errors' && check_stderr + +t_done diff --git a/t/lib-input-trailer.sh b/t/lib-input-trailer.sh dissimilarity index 90% 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 & - ( - 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) +. ./test-lib.sh +test -r random_blob || die "random_blob required, run with 'make $0'" + +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" && { + ( + 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 dissimilarity index 82% 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" - 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 - -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" - -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 - -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) - -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 -dbgcat r_err +. ./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 + 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" +} + +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 $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 dissimilarity index 91% 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" - -rainbows_setup -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) - -dbgcat tmp -grep -F 'HTTP/1.1 400 Bad Request' $tmp -check_stderr +. ./test-lib.sh +t_plan 5 "parser error test for $model" + +t_begin "setup and startup" && { + rainbows_setup $model + rainbows -D env.ru -c $unicorn_config + rainbows_wait_start +} + +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 + +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 dissimilarity index 83% index 5bc3a58..3e543b3 100644 --- a/t/lib-rack-input-hammer.sh +++ b/t/lib-rack-input-hammer.sh @@ -1,27 +1,45 @@ -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}" > $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 +nr_client=${nr_client-4} +. ./test-lib.sh +test -r random_blob || die "random_blob required, run with 'make $0'" + +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}" > $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 dissimilarity index 85% index d295ba9..822de8b 100644 --- a/t/lib-reopen-logs.sh +++ b/t/lib-reopen-logs.sh @@ -1,53 +1,97 @@ -#!/bin/sh -# don't set nr_client for Rev, only _one_ app running at once :x -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 - -# ensure our server is started and responding before signaling -curl -sSf http://$listen/ >/dev/null - -start=$(date +%s) -for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" > $curl_out 2>> $curl_err ) & -done -check_stderr - -rm -f $r_rot -mv $r_err $r_rot - -kill -USR1 $(cat $pid) -wait_for_pid $r_err - -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) - -test "$nr" -eq 1 -test x$(sort < $curl_out | uniq) = xHello -check_stderr -check_stderr $r_rot - -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 && echo "before_rot -eq after_rot" -test $after_err -gt $before_err && echo "before_err -gt after_err" - -kill $(cat $pid) -dbgcat r_err -check_stderr -check_stderr $r_rot +#!/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 18 "reopen rotated logs" + +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 +} + +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}" > $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 $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 + +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 $rainbows_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/lib-simple-http.sh b/t/lib-simple-http.sh dissimilarity index 92% 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 - -echo "simple HTTP connection keepalive/pipelining tests for $model" - -tbase=$(expr "$T" : '^\(t....\)-').ru -test -f "$tbase" || die "$tbase missing for $T" - -rainbows_setup -rainbows -D $tbase -c $unicorn_config -rainbows_wait_start - -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 -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 - -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 - - -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 - -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 - -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 - -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) +#!/bin/sh +. ./test-lib.sh +t_plan 24 "simple HTTP connection keepalive/pipelining tests for $model" + +t_begin "checking for config.ru for $model" && { + tbase=$(expr "$T" : '^\(t....\)-').ru + test -f "$tbase" +} + +t_begin "setup and 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/ +} + +dbgcat r_err + +t_begin "two requests with keepalive" && { + curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1 +} + +dbgcat r_err +dbgcat tmp + +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 + +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 +} + + +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 + +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 +} + +t_begin "stderr log has no errors" && { + check_stderr +} + +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 + +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 dissimilarity index 94% 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 -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}" > $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 +#!/bin/sh +. ./test-lib.sh +nr_client=30 APP_POOL_SIZE=4 + +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}" > $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 -- 2.11.4.GIT