about summary refs log tree commit homepage
path: root/t
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-10-04 16:38:08 -0700
committerEric Wong <normalperson@yhbt.net>2009-10-04 18:38:32 -0700
commit903766ba0d278cb55d08e072c4c96c1d7f0dee8d (patch)
tree3f29a3aab6452c304043816c7c1c3c76f3009d8a /t
parent756c060f2992d35e30249688f1cfab8de9b4dfc1 (diff)
downloadrainbows-903766ba0d278cb55d08e072c4c96c1d7f0dee8d.tar.gz
I'd rather write shell scripts in shell than shell scripts in
Ruby like was done with Unicorn.  We're a *nix-only project so
we'll embrace *nix tools to their fullest extent and as a
pleasant side-effect these test cases are immune to internal API
changes.
Diffstat (limited to 't')
-rw-r--r--t/.gitignore4
-rw-r--r--t/GNUmakefile64
-rwxr-xr-xt/bin/unused_listen39
-rwxr-xr-xt/t0000-basic.sh18
-rwxr-xr-xt/t1000-thread-pool-basic.sh53
-rwxr-xr-xt/t3000-revactor-basic.sh52
-rw-r--r--t/test-lib.sh41
7 files changed, 271 insertions, 0 deletions
diff --git a/t/.gitignore b/t/.gitignore
new file mode 100644
index 0000000..7cb5e32
--- /dev/null
+++ b/t/.gitignore
@@ -0,0 +1,4 @@
+/test-results-*
+/test-bin-*
+/*.code
+/*.log
diff --git a/t/GNUmakefile b/t/GNUmakefile
new file mode 100644
index 0000000..1a95992
--- /dev/null
+++ b/t/GNUmakefile
@@ -0,0 +1,64 @@
+# we can run tests in parallel with GNU make
+
+all::
+
+ruby = ruby
+rainbows_lib := $(shell cd ../lib && pwd)
+-include ../local.mk
+ifeq ($(RUBY_VERSION),)
+  RUBY_VERSION := $(shell $(ruby) -e 'puts RUBY_VERSION')
+endif
+
+ifeq ($(RUBYLIB),)
+  RUBYLIB := $(rainbows_lib)
+else
+  RUBYLIB := $(rainbows_lib):$(RUBYLIB)
+endif
+export RUBYLIB
+
+T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
+
+all:: $(T)
+
+# can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
+t_code = $@-$(RUBY_VERSION).code
+t_log = $@-$(RUBY_VERSION).log
+t_run = $(TRACER) $(SHELL) $(TEST_OPTS) $@
+
+# prefix stdout messages with ':', and stderr messages with '!'
+t_wrap = ( ( ( $(RM) $(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
+  quiet_pre = @echo '* $@';
+  quiet_post = 2>&1 | tee $(t_log); exit $$(cat $(t_code))
+  pfx = $@
+endif
+
+# TRACER='strace -f -o $@.strace -s 100000'
+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)
+        install -m 755 $^ $@+
+        $(ruby) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@+
+        cmp $@+ $@ || mv $@+ $@
+        $(RM) $@+
+
+$(T): export ruby := $(ruby)
+$(T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
+$(T): test-bin-$(RUBY_VERSION)/rainbows
+        $(run_test)
+
+clean:
+        $(RM) -r *.log *.code test-bin-$(RUBY_VERSION)
+
+.PHONY: $(T) clean
diff --git a/t/bin/unused_listen b/t/bin/unused_listen
new file mode 100755
index 0000000..c13f97d
--- /dev/null
+++ b/t/bin/unused_listen
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+# 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 "listen=#{addr}:#{port} lock_path=#{lock_path}"
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
new file mode 100755
index 0000000..7c5c754
--- /dev/null
+++ b/t/t0000-basic.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+. ./test-lib.sh
+
+eval $(unused_listen)
+config_ru=$(mktemp -t rainbows.$$.XXXXXXXX.config.ru)
+pid=$(mktemp -t rainbows.$$.XXXXXXXX.pid)
+TEST_RM_LIST="$TEST_RM_LIST $config_ru $lock_path"
+
+cat > $config_ru <<\EOF
+use Rack::ContentLength
+use Rack::ContentType
+run lambda { |env| [ 200, {}, [ env.inspect << "\n" ] ] }
+EOF
+
+rainbows $config_ru -l $listen --pid $pid &
+wait_for_pid $pid
+curl -sSfv http://$listen/
+kill $(cat $pid)
diff --git a/t/t1000-thread-pool-basic.sh b/t/t1000-thread-pool-basic.sh
new file mode 100755
index 0000000..109f5ae
--- /dev/null
+++ b/t/t1000-thread-pool-basic.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+. ./test-lib.sh
+
+eval $(unused_listen)
+config_ru=$(mktemp -t rainbows.$$.XXXXXXXX.config.ru)
+unicorn_config=$(mktemp -t rainbows.$$.XXXXXXXX.unicorn.rb)
+curl_out=$(mktemp -t rainbows.$$.XXXXXXXX.curl.out)
+curl_err=$(mktemp -t rainbows.$$.XXXXXXXX.curl.err)
+pid=$(mktemp -t rainbows.$$.XXXXXXXX.pid)
+TEST_RM_LIST="$TEST_RM_LIST $config_ru $unicorn_config $lock_path"
+TEST_RM_LIST="$TEST_RM_LIST $curl_out $curl_err"
+
+cat > $config_ru <<\EOF
+use Rack::ContentLength
+use Rack::ContentType
+run lambda { |env|
+  sleep 1
+  [ 200, {}, [ Thread.current.inspect << "\n" ] ]
+}
+EOF
+
+nr_client=30
+nr_thread=10
+
+cat > $unicorn_config <<EOF
+listen "$listen"
+pid "$pid"
+Rainbows! do
+  use :ThreadPool
+  worker_connections $nr_thread
+end
+EOF
+
+rainbows -D $config_ru -c $unicorn_config
+wait_for_pid $pid
+
+start=$(date +%s)
+for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
+do
+        ( curl -sSf http://$listen/$i >> $curl_out 2>> $curl_err ) &
+done
+wait
+echo elapsed=$(( $(date +%s) - $start ))
+
+kill $(cat $pid)
+
+! test -s $curl_err
+test x"$(wc -l < $curl_out)" = x$nr_client
+
+nr=$(sort < $curl_out | uniq | wc -l)
+
+test "$nr" -le $nr_thread
+test "$nr" -gt 1
diff --git a/t/t3000-revactor-basic.sh b/t/t3000-revactor-basic.sh
new file mode 100755
index 0000000..163e0db
--- /dev/null
+++ b/t/t3000-revactor-basic.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+. ./test-lib.sh
+require_revactor
+
+eval $(unused_listen)
+config_ru=$(mktemp -t rainbows.$$.XXXXXXXX.config.ru)
+unicorn_config=$(mktemp -t rainbows.$$.XXXXXXXX.unicorn.rb)
+curl_out=$(mktemp -t rainbows.$$.XXXXXXXX.curl.out)
+curl_err=$(mktemp -t rainbows.$$.XXXXXXXX.curl.err)
+pid=$(mktemp -t rainbows.$$.XXXXXXXX.pid)
+TEST_RM_LIST="$TEST_RM_LIST $config_ru $unicorn_config $lock_path"
+TEST_RM_LIST="$TEST_RM_LIST $curl_out $curl_err"
+
+cat > $config_ru <<\EOF
+use Rack::ContentLength
+use Rack::ContentType
+run lambda { |env|
+  Actor.sleep 1
+  [ 200, {}, [ Thread.current.inspect << "\n" ] ]
+}
+EOF
+
+nr_client=30
+nr_actor=10
+
+cat > $unicorn_config <<EOF
+listen "$listen"
+pid "$pid"
+Rainbows! do
+  use :Revactor
+  worker_connections $nr_actor
+end
+EOF
+
+rainbows -D $config_ru -c $unicorn_config
+wait_for_pid $pid
+
+start=$(date +%s)
+for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
+do
+        ( curl -sSf http://$listen/$i >> $curl_out 2>> $curl_err ) &
+done
+wait
+echo elapsed=$(( $(date +%s) - $start ))
+
+kill $(cat $pid)
+
+! test -s $curl_err
+test x"$(wc -l < $curl_out)" = x$nr_client
+nr=$(sort < $curl_out | uniq | wc -l)
+
+test "$nr" -eq 1
diff --git a/t/test-lib.sh b/t/test-lib.sh
new file mode 100644
index 0000000..9e286bc
--- /dev/null
+++ b/t/test-lib.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Copyright (c) 2009 Eric Wong
+set -e
+set -u
+T=$(basename $0)
+ruby="${ruby-ruby}"
+
+# ensure a sane environment
+TZ=UTC LC_ALL=C LANG=C
+export LANG LC_ALL TZ
+unset CDPATH
+
+die () {
+        echo >&2 "$@"
+        exit 1
+}
+
+TEST_RM_LIST=""
+trap 'rm -f $TEST_RM_LIST' 0
+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
+}
+
+require_revactor () {
+        if ! $ruby -rrevactor -e "puts Revactor::VERSION" >/dev/null 2>&1
+        then
+                echo >&2 "skipping $T since we don't have Revactor"
+                exit 0
+        fi
+}