rainbows 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +6 -5
- data/DEPLOY +13 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -1
- data/README +32 -6
- data/SIGNALS +11 -7
- data/TODO +2 -3
- data/lib/rainbows.rb +10 -3
- data/lib/rainbows/app_pool.rb +90 -0
- data/lib/rainbows/base.rb +41 -4
- data/lib/rainbows/const.rb +1 -6
- data/lib/rainbows/http_server.rb +1 -1
- data/lib/rainbows/rev.rb +174 -0
- data/lib/rainbows/revactor.rb +40 -37
- data/lib/rainbows/thread_pool.rb +31 -57
- data/lib/rainbows/thread_spawn.rb +32 -45
- data/local.mk.sample +4 -3
- data/t/.gitignore +1 -2
- data/t/GNUmakefile +21 -7
- data/t/README +42 -0
- data/t/bin/content-md5-put +36 -0
- data/t/bin/unused_listen +1 -1
- data/t/content-md5.ru +23 -0
- data/t/sleep.ru +11 -0
- data/t/t0000-basic.sh +29 -3
- data/t/t1000-thread-pool-basic.sh +5 -6
- data/t/t1000.ru +5 -1
- data/t/t1002-thread-pool-graceful.sh +37 -0
- data/t/t2000-thread-spawn-basic.sh +4 -6
- data/t/t2000.ru +5 -1
- data/t/t2002-thread-spawn-graceful.sh +37 -0
- data/t/t3000-revactor-basic.sh +4 -6
- data/t/t3000.ru +5 -1
- data/t/t3001-revactor-pipeline.sh +46 -0
- data/t/t3002-revactor-graceful.sh +38 -0
- data/t/t3003-revactor-reopen-logs.sh +54 -0
- data/t/t3100-revactor-tee-input.sh +8 -13
- data/t/t4000-rev-basic.sh +51 -0
- data/t/t4000.ru +9 -0
- data/t/t4002-rev-graceful.sh +52 -0
- data/t/t4003-rev-parser-error.sh +34 -0
- data/t/t4100-rev-rack-input.sh +44 -0
- data/t/t4101-rev-rack-input-trailer.sh +51 -0
- data/t/t9000-rack-app-pool.sh +37 -0
- data/t/t9000.ru +14 -0
- data/t/test-lib.sh +29 -2
- data/vs_Unicorn +50 -1
- metadata +28 -6
data/t/README
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= Rainbows! test suite
|
2
|
+
|
3
|
+
These are all integration tests that start the server on random, unused
|
4
|
+
TCP ports or Unix domain sockets. They're all designed to run
|
5
|
+
concurrently with other tests to minimize test time, but tests may be
|
6
|
+
run independently as well.
|
7
|
+
|
8
|
+
We write our tests in Bourne shell because that's what we're
|
9
|
+
comfortable writing integration tests with.
|
10
|
+
|
11
|
+
== Requirements
|
12
|
+
|
13
|
+
* {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
|
14
|
+
* {GNU make}[http://www.gnu.org/software/make/]
|
15
|
+
* {socat}[http://www.dest-unreach.org/socat/]
|
16
|
+
* {curl}[http://curl.haxx.se/]
|
17
|
+
* standard UNIX shell utilities (Bourne sh, awk, sed, grep, tee, ...)
|
18
|
+
|
19
|
+
We do not use bashisms or any non-portable, non-POSIX constructs
|
20
|
+
in our shell code. We use the "pipefail" option if available and
|
21
|
+
mainly test with {ksh}[http://kornshell.com/], but occasionally
|
22
|
+
with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
|
23
|
+
{bash}[http://www.gnu.org/software/bash/], too.
|
24
|
+
|
25
|
+
== Running Tests
|
26
|
+
|
27
|
+
To run the entire test suite with 8 tests running at once:
|
28
|
+
|
29
|
+
make -j8
|
30
|
+
|
31
|
+
To run one individual test:
|
32
|
+
|
33
|
+
make t0000-basic.sh
|
34
|
+
|
35
|
+
You may also increase verbosity by setting the "V" variable for
|
36
|
+
GNU make. To disable trapping of stdout/stderr:
|
37
|
+
|
38
|
+
make V=1
|
39
|
+
|
40
|
+
To enable the "set -x" option in shell scripts to trace execution
|
41
|
+
|
42
|
+
make V=2
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# simple chunked HTTP PUT request generator (and just that),
|
3
|
+
# it reads stdin and writes to stdout so socat can write to a
|
4
|
+
# UNIX or TCP socket (or to another filter or file) along with
|
5
|
+
# a Content-MD5 trailer.
|
6
|
+
# -*- encoding: binary -*-
|
7
|
+
require 'digest/md5'
|
8
|
+
$stdout.sync = $stderr.sync = true
|
9
|
+
$stdout.binmode
|
10
|
+
$stdin.binmode
|
11
|
+
|
12
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 4096
|
13
|
+
|
14
|
+
if ARGV.grep("--no-headers").empty?
|
15
|
+
$stdout.write(
|
16
|
+
"PUT / HTTP/1.1\r\n" \
|
17
|
+
"Host: example.com\r\n" \
|
18
|
+
"Transfer-Encoding: chunked\r\n" \
|
19
|
+
"Trailer: Content-MD5\r\n" \
|
20
|
+
"\r\n"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
digest = Digest::MD5.new
|
25
|
+
if buf = $stdin.read(bs)
|
26
|
+
begin
|
27
|
+
digest.update(buf)
|
28
|
+
$stdout.write("%x\r\n" % [ buf.size ])
|
29
|
+
$stdout.write(buf)
|
30
|
+
$stdout.write("\r\n")
|
31
|
+
end while $stdin.read(bs, buf)
|
32
|
+
end
|
33
|
+
|
34
|
+
digest = [ digest.digest ].pack('m').strip
|
35
|
+
$stdout.write("0\r\n")
|
36
|
+
$stdout.write("Content-MD5: #{digest}\r\n\r\n")
|
data/t/bin/unused_listen
CHANGED
data/t/content-md5.ru
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# SHA1 checksum generator
|
2
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 4096
|
3
|
+
require 'digest/md5'
|
4
|
+
use Rack::ContentLength
|
5
|
+
app = lambda do |env|
|
6
|
+
/\A100-continue\z/i =~ env['HTTP_EXPECT'] and
|
7
|
+
return [ 100, {}, [] ]
|
8
|
+
digest = Digest::MD5.new
|
9
|
+
input = env['rack.input']
|
10
|
+
if buf = input.read(bs)
|
11
|
+
begin
|
12
|
+
digest.update(buf)
|
13
|
+
end while input.read(bs, buf)
|
14
|
+
end
|
15
|
+
|
16
|
+
expect = env['HTTP_CONTENT_MD5']
|
17
|
+
readed = [ digest.digest ].pack('m').strip
|
18
|
+
body = "expect=#{expect}\nreaded=#{readed}\n"
|
19
|
+
status = expect == readed ? 200 : 500
|
20
|
+
|
21
|
+
[ status, {'Content-Type' => 'text/plain'}, [ body ] ]
|
22
|
+
end
|
23
|
+
run app
|
data/t/sleep.ru
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
use Rack::ContentLength
|
2
|
+
use Rack::ContentType
|
3
|
+
sleep_class = ENV['SLEEP_CLASS']
|
4
|
+
sleep_class = sleep_class ? Object.const_get(sleep_class) : Kernel
|
5
|
+
$stderr.puts "sleep_class=#{sleep_class.inspect}"
|
6
|
+
run lambda { |env|
|
7
|
+
nr = 1
|
8
|
+
env["PATH_INFO"] =~ %r{/([\d\.]+)\z} and nr = $1.to_f
|
9
|
+
sleep_class.sleep(nr)
|
10
|
+
[ 200, {}, [ "Hello\n" ] ]
|
11
|
+
}
|
data/t/t0000-basic.sh
CHANGED
@@ -2,10 +2,36 @@
|
|
2
2
|
. ./test-lib.sh
|
3
3
|
|
4
4
|
eval $(unused_listen)
|
5
|
-
pid
|
6
|
-
TEST_RM_LIST="$TEST_RM_LIST $lock_path $pid"
|
5
|
+
rtmpfiles pid tmp ok fifo
|
7
6
|
|
8
|
-
|
7
|
+
rm -f $fifo
|
8
|
+
mkfifo $fifo
|
9
|
+
|
10
|
+
rainbows -D t0000.ru -l $listen --pid $pid &
|
9
11
|
wait_for_pid $pid
|
12
|
+
|
13
|
+
echo "single request"
|
10
14
|
curl -sSfv http://$listen/
|
15
|
+
|
16
|
+
echo "two requests with keepalive"
|
17
|
+
curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
|
18
|
+
grep 'Re-using existing connection' < $tmp
|
19
|
+
|
20
|
+
echo "pipelining partial requests"
|
21
|
+
req='GET / HTTP/1.1\r\nHost: foo\r\n'
|
22
|
+
(
|
23
|
+
printf "$req"'\r\n'"$req"
|
24
|
+
cat $fifo > $tmp &
|
25
|
+
sleep 1
|
26
|
+
printf 'Connection: close\r\n\r\n'
|
27
|
+
echo ok > $ok
|
28
|
+
) | socat - TCP:$listen > $fifo
|
29
|
+
|
11
30
|
kill $(cat $pid)
|
31
|
+
|
32
|
+
# sed -ne 's/^/------/p' < $tmp
|
33
|
+
test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
|
34
|
+
test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
|
35
|
+
test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
|
36
|
+
test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
|
37
|
+
test x"$(cat $ok)" = xok
|
@@ -2,17 +2,14 @@
|
|
2
2
|
. ./test-lib.sh
|
3
3
|
|
4
4
|
eval $(unused_listen)
|
5
|
-
unicorn_config
|
6
|
-
curl_out=$(mktemp -t rainbows.$$.curl.out.XXXXXXXX)
|
7
|
-
curl_err=$(mktemp -t rainbows.$$.curl.err.XXXXXXXX)
|
8
|
-
pid=$(mktemp -t rainbows.$$.pid.XXXXXXXX)
|
9
|
-
TEST_RM_LIST="$TEST_RM_LIST $unicorn_config $lock_path $pid"
|
10
|
-
TEST_RM_LIST="$TEST_RM_LIST $curl_out $curl_err"
|
5
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
11
6
|
|
12
7
|
nr_client=30
|
13
8
|
nr_thread=10
|
14
9
|
|
15
10
|
cat > $unicorn_config <<EOF
|
11
|
+
stderr_path "$r_err"
|
12
|
+
stdout_path "$r_out"
|
16
13
|
listen "$listen"
|
17
14
|
pid "$pid"
|
18
15
|
Rainbows! do
|
@@ -41,3 +38,5 @@ nr=$(sort < $curl_out | uniq | wc -l)
|
|
41
38
|
|
42
39
|
test "$nr" -le $nr_thread
|
43
40
|
test "$nr" -gt 1
|
41
|
+
|
42
|
+
! grep Error $r_err
|
data/t/t1000.ru
CHANGED
@@ -2,5 +2,9 @@ use Rack::ContentLength
|
|
2
2
|
use Rack::ContentType
|
3
3
|
run lambda { |env|
|
4
4
|
sleep 1
|
5
|
-
[
|
5
|
+
if env['rack.multithread'] && env['rainbows.model'] == :ThreadPool
|
6
|
+
[ 200, {}, [ Thread.current.inspect << "\n" ] ]
|
7
|
+
else
|
8
|
+
raise "rack.multithread is not true"
|
9
|
+
end
|
6
10
|
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
eval $(unused_listen)
|
5
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
6
|
+
nr_thread=10
|
7
|
+
nr_client=10
|
8
|
+
cat > $unicorn_config <<EOF
|
9
|
+
listen "$listen"
|
10
|
+
stderr_path "$r_err"
|
11
|
+
stdout_path "$r_out"
|
12
|
+
pid "$pid"
|
13
|
+
Rainbows! do
|
14
|
+
use :ThreadPool
|
15
|
+
worker_connections $nr_thread
|
16
|
+
end
|
17
|
+
EOF
|
18
|
+
|
19
|
+
rainbows -D sleep.ru -c $unicorn_config
|
20
|
+
wait_for_pid $pid
|
21
|
+
|
22
|
+
for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
|
23
|
+
do
|
24
|
+
curl -sSf http://$listen/5 >> $curl_out 2>> $curl_err &
|
25
|
+
done
|
26
|
+
sleep 2
|
27
|
+
kill -QUIT $(cat $pid)
|
28
|
+
wait
|
29
|
+
|
30
|
+
dbgcat r_err
|
31
|
+
! test -s $curl_err
|
32
|
+
test x"$(wc -l < $curl_out)" = x$nr_client
|
33
|
+
nr=$(sort < $curl_out | uniq | wc -l)
|
34
|
+
|
35
|
+
test "$nr" -eq 1
|
36
|
+
test x$(sort < $curl_out | uniq) = xHello
|
37
|
+
! grep Error $r_err
|
@@ -2,17 +2,14 @@
|
|
2
2
|
. ./test-lib.sh
|
3
3
|
|
4
4
|
eval $(unused_listen)
|
5
|
-
unicorn_config
|
6
|
-
curl_out=$(mktemp -t rainbows.$$.curl.out.XXXXXXXX)
|
7
|
-
curl_err=$(mktemp -t rainbows.$$.curl.err.XXXXXXXX)
|
8
|
-
pid=$(mktemp -t rainbows.$$.pid.XXXXXXXX)
|
9
|
-
TEST_RM_LIST="$TEST_RM_LIST $unicorn_config $lock_path $pid"
|
10
|
-
TEST_RM_LIST="$TEST_RM_LIST $curl_out $curl_err"
|
5
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
11
6
|
|
12
7
|
nr_client=30
|
13
8
|
nr_thread=10
|
14
9
|
|
15
10
|
cat > $unicorn_config <<EOF
|
11
|
+
stderr_path "$r_err"
|
12
|
+
stdout_path "$r_out"
|
16
13
|
listen "$listen"
|
17
14
|
pid "$pid"
|
18
15
|
Rainbows! do
|
@@ -38,3 +35,4 @@ kill $(cat $pid)
|
|
38
35
|
test x"$(wc -l < $curl_out)" = x$nr_client
|
39
36
|
nr=$(sort < $curl_out | uniq | wc -l)
|
40
37
|
test "$nr" -eq $nr_client
|
38
|
+
! grep Error $r_err
|
data/t/t2000.ru
CHANGED
@@ -2,5 +2,9 @@ use Rack::ContentLength
|
|
2
2
|
use Rack::ContentType
|
3
3
|
run lambda { |env|
|
4
4
|
sleep 1
|
5
|
-
[
|
5
|
+
if env['rack.multithread'] && env['rainbows.model'] == :ThreadSpawn
|
6
|
+
[ 200, {}, [ Thread.current.inspect << "\n" ] ]
|
7
|
+
else
|
8
|
+
raise "rack.multithread is not true"
|
9
|
+
end
|
6
10
|
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
eval $(unused_listen)
|
5
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
6
|
+
nr_thread=10
|
7
|
+
nr_client=10
|
8
|
+
cat > $unicorn_config <<EOF
|
9
|
+
listen "$listen"
|
10
|
+
stderr_path "$r_err"
|
11
|
+
stdout_path "$r_out"
|
12
|
+
pid "$pid"
|
13
|
+
Rainbows! do
|
14
|
+
use :ThreadSpawn
|
15
|
+
worker_connections $nr_thread
|
16
|
+
end
|
17
|
+
EOF
|
18
|
+
|
19
|
+
rainbows -D sleep.ru -c $unicorn_config
|
20
|
+
wait_for_pid $pid
|
21
|
+
|
22
|
+
for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
|
23
|
+
do
|
24
|
+
curl -sSf http://$listen/5 >> $curl_out 2>> $curl_err &
|
25
|
+
done
|
26
|
+
sleep 2
|
27
|
+
kill -QUIT $(cat $pid)
|
28
|
+
wait
|
29
|
+
|
30
|
+
dbgcat r_err
|
31
|
+
! test -s $curl_err
|
32
|
+
test x"$(wc -l < $curl_out)" = x$nr_client
|
33
|
+
nr=$(sort < $curl_out | uniq | wc -l)
|
34
|
+
|
35
|
+
test "$nr" -eq 1
|
36
|
+
test x$(sort < $curl_out | uniq) = xHello
|
37
|
+
! grep Error $r_err
|
data/t/t3000-revactor-basic.sh
CHANGED
@@ -3,12 +3,7 @@
|
|
3
3
|
require_revactor
|
4
4
|
|
5
5
|
eval $(unused_listen)
|
6
|
-
unicorn_config
|
7
|
-
curl_out=$(mktemp -t rainbows.$$.curl.out.XXXXXXXX)
|
8
|
-
curl_err=$(mktemp -t rainbows.$$.curl.err.XXXXXXXX)
|
9
|
-
pid=$(mktemp -t rainbows.$$.pid.XXXXXXXX)
|
10
|
-
TEST_RM_LIST="$TEST_RM_LIST $pid $unicorn_config $lock_path"
|
11
|
-
TEST_RM_LIST="$TEST_RM_LIST $curl_out $curl_err"
|
6
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
12
7
|
|
13
8
|
nr_client=30
|
14
9
|
nr_actor=10
|
@@ -16,6 +11,8 @@ nr_actor=10
|
|
16
11
|
cat > $unicorn_config <<EOF
|
17
12
|
listen "$listen"
|
18
13
|
pid "$pid"
|
14
|
+
stderr_path "$r_err"
|
15
|
+
stdout_path "$r_out"
|
19
16
|
Rainbows! do
|
20
17
|
use :Revactor
|
21
18
|
worker_connections $nr_actor
|
@@ -40,3 +37,4 @@ test x"$(wc -l < $curl_out)" = x$nr_client
|
|
40
37
|
nr=$(sort < $curl_out | uniq | wc -l)
|
41
38
|
|
42
39
|
test "$nr" -eq 1
|
40
|
+
! grep Error $r_err
|
data/t/t3000.ru
CHANGED
@@ -2,5 +2,9 @@ use Rack::ContentLength
|
|
2
2
|
use Rack::ContentType
|
3
3
|
run lambda { |env|
|
4
4
|
Actor.sleep 1
|
5
|
-
[
|
5
|
+
if env['rack.multithread'] == false && env['rainbows.model'] == :Revactor
|
6
|
+
[ 200, {}, [ Thread.current.inspect << "\n" ] ]
|
7
|
+
else
|
8
|
+
raise "rack.multithread is true"
|
9
|
+
end
|
6
10
|
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
require_revactor
|
4
|
+
|
5
|
+
eval $(unused_listen)
|
6
|
+
rtmpfiles unicorn_config curl_out curl_err pid fifo tmp ok r_err r_out
|
7
|
+
|
8
|
+
rm -f $fifo
|
9
|
+
mkfifo $fifo
|
10
|
+
|
11
|
+
cat > $unicorn_config <<EOF
|
12
|
+
stderr_path "$r_err"
|
13
|
+
stdout_path "$r_out"
|
14
|
+
listen "$listen"
|
15
|
+
pid "$pid"
|
16
|
+
Rainbows! do
|
17
|
+
use :Revactor
|
18
|
+
end
|
19
|
+
EOF
|
20
|
+
|
21
|
+
rainbows -D t0000.ru -c $unicorn_config
|
22
|
+
wait_for_pid $pid
|
23
|
+
|
24
|
+
echo "two requests with keepalive"
|
25
|
+
curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
|
26
|
+
grep 'Re-using existing connection' < $tmp
|
27
|
+
|
28
|
+
echo "pipelining partial requests"
|
29
|
+
req='GET / HTTP/1.1\r\nHost: foo\r\n'
|
30
|
+
(
|
31
|
+
printf "$req"'\r\n'"$req"
|
32
|
+
cat $fifo > $tmp &
|
33
|
+
sleep 1
|
34
|
+
printf 'Connection: close\r\n\r\n'
|
35
|
+
echo ok > $ok
|
36
|
+
) | socat - TCP:$listen > $fifo
|
37
|
+
|
38
|
+
kill $(cat $pid)
|
39
|
+
|
40
|
+
dbgcat tmp
|
41
|
+
test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
|
42
|
+
test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
|
43
|
+
test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
|
44
|
+
test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
|
45
|
+
test x"$(cat $ok)" = xok
|
46
|
+
! grep Error $r_err
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
require_revactor
|
4
|
+
|
5
|
+
eval $(unused_listen)
|
6
|
+
rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
|
7
|
+
nr_actor=10
|
8
|
+
nr_client=10
|
9
|
+
cat > $unicorn_config <<EOF
|
10
|
+
listen "$listen"
|
11
|
+
stderr_path "$r_err"
|
12
|
+
stdout_path "$r_out"
|
13
|
+
pid "$pid"
|
14
|
+
Rainbows! do
|
15
|
+
use :Revactor
|
16
|
+
worker_connections $nr_actor
|
17
|
+
end
|
18
|
+
EOF
|
19
|
+
|
20
|
+
SLEEP_CLASS=Actor rainbows -D sleep.ru -c $unicorn_config
|
21
|
+
wait_for_pid $pid
|
22
|
+
|
23
|
+
for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
|
24
|
+
do
|
25
|
+
curl -sSf http://$listen/5 >> $curl_out 2>> $curl_err &
|
26
|
+
done
|
27
|
+
sleep 2
|
28
|
+
kill -QUIT $(cat $pid)
|
29
|
+
wait
|
30
|
+
|
31
|
+
dbgcat r_err
|
32
|
+
! test -s $curl_err
|
33
|
+
test x"$(wc -l < $curl_out)" = x$nr_client
|
34
|
+
nr=$(sort < $curl_out | uniq | wc -l)
|
35
|
+
|
36
|
+
test "$nr" -eq 1
|
37
|
+
test x$(sort < $curl_out | uniq) = xHello
|
38
|
+
! grep Error $r_err
|