rainbows 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/GIT-VERSION-GEN +1 -1
  2. data/GNUmakefile +12 -6
  3. data/README +3 -2
  4. data/Rakefile +3 -3
  5. data/TODO +2 -9
  6. data/lib/rainbows.rb +1 -0
  7. data/lib/rainbows/app_pool.rb +10 -6
  8. data/lib/rainbows/base.rb +1 -1
  9. data/lib/rainbows/const.rb +1 -1
  10. data/lib/rainbows/ev_core.rb +88 -0
  11. data/lib/rainbows/event_machine.rb +218 -0
  12. data/lib/rainbows/http_server.rb +4 -1
  13. data/lib/rainbows/rev.rb +21 -89
  14. data/lib/rainbows/revactor.rb +4 -10
  15. data/local.mk.sample +13 -7
  16. data/rainbows.gemspec +17 -2
  17. data/t/.gitignore +1 -0
  18. data/t/GNUmakefile +63 -40
  19. data/t/README +6 -2
  20. data/t/async_sinatra.ru +13 -0
  21. data/t/bin/unused_listen +1 -1
  22. data/t/large-file-response.ru +1 -0
  23. data/t/my-tap-lib.sh +200 -0
  24. data/t/simple-http_Base.ru +3 -0
  25. data/t/simple-http_EventMachine.ru +9 -0
  26. data/t/simple-http_Rev.ru +9 -0
  27. data/t/simple-http_Revactor.ru +10 -0
  28. data/t/simple-http_ThreadPool.ru +10 -0
  29. data/t/simple-http_ThreadSpawn.ru +10 -0
  30. data/t/t0000-simple-http.sh +142 -0
  31. data/t/t0001-unix-http.sh +103 -0
  32. data/t/t0002-graceful.sh +32 -0
  33. data/t/t0002-parser-error.sh +31 -0
  34. data/t/t0003-reopen-logs.sh +97 -0
  35. data/t/t0005-large-file-response.sh +83 -0
  36. data/t/t0100-rack-input-hammer.sh +45 -0
  37. data/t/t0101-rack-input-trailer.sh +68 -0
  38. data/t/t0200-async-response.sh +66 -0
  39. data/t/t0201-async-response-no-autochunk.sh +3 -0
  40. data/t/t0300-async_sinatra.sh +65 -0
  41. data/t/t9000-rack-app-pool.sh +45 -33
  42. data/t/test-lib.sh +67 -56
  43. metadata +26 -56
  44. data/t/lib-async-response-no-autochunk.sh +0 -6
  45. data/t/lib-async-response.sh +0 -45
  46. data/t/lib-graceful.sh +0 -40
  47. data/t/lib-input-trailer.sh +0 -63
  48. data/t/lib-large-file-response.sh +0 -45
  49. data/t/lib-parser-error.sh +0 -29
  50. data/t/lib-rack-input-hammer.sh +0 -38
  51. data/t/lib-reopen-logs.sh +0 -60
  52. data/t/lib-simple-http.sh +0 -92
  53. data/t/t0000-basic.sh +0 -2
  54. data/t/t1000-thread-pool-basic.sh +0 -2
  55. data/t/t1002-thread-pool-graceful.sh +0 -2
  56. data/t/t1003-thread-pool-reopen-logs.sh +0 -2
  57. data/t/t1004-thread-pool-async-response.sh +0 -45
  58. data/t/t1005-thread-pool-large-file-response.sh +0 -45
  59. data/t/t1006-thread-pool-async-response-no-autochunk.sh +0 -6
  60. data/t/t1100-thread-pool-rack-input.sh +0 -2
  61. data/t/t1101-thread-pool-input-trailer.sh +0 -2
  62. data/t/t2000-thread-spawn-basic.sh +0 -2
  63. data/t/t2002-thread-spawn-graceful.sh +0 -2
  64. data/t/t2003-thread-spawn-reopen-logs.sh +0 -2
  65. data/t/t2004-thread-spawn-async-response.sh +0 -45
  66. data/t/t2005-thread-spawn-large-file-response.sh +0 -45
  67. data/t/t2006-thread-spawn-async-response-no-autochunk.sh +0 -6
  68. data/t/t2100-thread-spawn-rack-input.sh +0 -2
  69. data/t/t2101-thread-spawn-input-trailer.sh +0 -2
  70. data/t/t3000-revactor-basic.sh +0 -2
  71. data/t/t3002-revactor-graceful.sh +0 -2
  72. data/t/t3003-revactor-reopen-logs.sh +0 -2
  73. data/t/t3004-revactor-async-response.sh +0 -45
  74. data/t/t3005-revactor-large-file-response.sh +0 -2
  75. data/t/t3006-revactor-async-response-no-autochunk.sh +0 -6
  76. data/t/t3100-revactor-rack-input.sh +0 -2
  77. data/t/t3101-revactor-rack-input-trailer.sh +0 -2
  78. data/t/t4000-rev-basic.sh +0 -2
  79. data/t/t4002-rev-graceful.sh +0 -2
  80. data/t/t4003-rev-parser-error.sh +0 -2
  81. data/t/t4003-rev-reopen-logs.sh +0 -2
  82. data/t/t4004-rev-async-response.sh +0 -45
  83. data/t/t4005-rev-large-file-response.sh +0 -2
  84. data/t/t4006-rev-async-response-no-autochunk.sh +0 -6
  85. data/t/t4100-rev-rack-input.sh +0 -2
  86. data/t/t4101-rev-rack-input-trailer.sh +0 -2
@@ -0,0 +1,32 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 4 "graceful exit test for $model"
5
+
6
+ t_begin "setup and startup" && {
7
+ rtmpfiles curl_out
8
+ rainbows_setup $model
9
+ rainbows -D sleep.ru -c $unicorn_config
10
+ rainbows_wait_start
11
+ }
12
+
13
+ t_begin "send a request and SIGQUIT while request is processing" && {
14
+ curl -sSfv -T- </dev/null http://$listen/5 > $curl_out 2> $fifo &
15
+ awk -v rainbows_pid=$rainbows_pid '
16
+ { print $0 }
17
+ /100 Continue/ {
18
+ print "awk: sending SIGQUIT to", rainbows_pid
19
+ system("kill -QUIT "rainbows_pid)
20
+ }' $fifo
21
+ wait
22
+ }
23
+
24
+ dbgcat r_err
25
+
26
+ t_begin 'response returned "Hello"' && {
27
+ test x$(cat $curl_out) = xHello
28
+ }
29
+
30
+ t_begin 'stderr has no errors' && check_stderr
31
+
32
+ t_done
@@ -0,0 +1,31 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 5 "parser error test for $model"
4
+
5
+ t_begin "setup and startup" && {
6
+ rainbows_setup $model
7
+ rainbows -D env.ru -c $unicorn_config
8
+ rainbows_wait_start
9
+ }
10
+
11
+ t_begin "send request" && {
12
+ (
13
+ printf 'GET / HTTP/1/1\r\nHost: example.com\r\n\r\n'
14
+ cat $fifo > $tmp &
15
+ wait
16
+ echo ok > $ok
17
+ ) | socat - TCP:$listen > $fifo
18
+ test xok = x$(cat $ok)
19
+ }
20
+
21
+ dbgcat tmp
22
+
23
+ t_begin "response should be a 400" && {
24
+ grep -F 'HTTP/1.1 400 Bad Request' $tmp
25
+ }
26
+
27
+ t_begin "server stderr should be clean" && check_stderr
28
+
29
+ t_begin "term signal sent" && kill $rainbows_pid
30
+
31
+ t_done
@@ -0,0 +1,97 @@
1
+ #!/bin/sh
2
+ # don't set nr_client for Rev, only _one_ app running at once :x
3
+ nr_client=${nr_client-2}
4
+ . ./test-lib.sh
5
+
6
+ t_plan 18 "reopen rotated logs"
7
+
8
+ t_begin "setup and startup" && {
9
+ rtmpfiles curl_out curl_err r_rot
10
+ rainbows_setup $model
11
+ rainbows -D sleep.ru -c $unicorn_config
12
+ rainbows_wait_start
13
+ }
14
+
15
+ t_begin "ensure server is responsive" && {
16
+ curl -sSf http://$listen/ >/dev/null
17
+ }
18
+
19
+ t_begin "start $nr_client concurrent requests" && {
20
+ start=$(date +%s)
21
+ for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
22
+ do
23
+ ( curl -sSf http://$listen/2 >> $curl_out 2>> $curl_err ) &
24
+ done
25
+ }
26
+
27
+ t_begin "ensure stderr log is clean" && check_stderr
28
+
29
+ t_begin "external log rotation" && {
30
+ rm -f $r_rot
31
+ mv $r_err $r_rot
32
+ }
33
+
34
+ t_begin "send reopen log signal (USR1)" && {
35
+ kill -USR1 $rainbows_pid
36
+ }
37
+
38
+ t_begin "wait for rotated log to reappear" && {
39
+ nr=60
40
+ while ! test -f $r_err && test $nr -ge 0
41
+ do
42
+ sleep 1
43
+ nr=$(( $nr - 1 ))
44
+ done
45
+ }
46
+
47
+ dbgcat r_rot
48
+ dbgcat r_err
49
+
50
+ t_begin "wait curl requests to finish" && {
51
+ wait
52
+ t_info elapsed=$(( $(date +%s) - $start ))
53
+ }
54
+
55
+ t_begin "ensure no errors from curl" && {
56
+ test ! -s $curl_err
57
+ }
58
+
59
+ t_begin "curl got $nr_client responses" && {
60
+ test "$(wc -l < $curl_out)" -eq $nr_client
61
+ }
62
+
63
+ t_begin "all responses were identical" && {
64
+ nr=$(sort < $curl_out | uniq | wc -l)
65
+ test "$nr" -eq 1
66
+ }
67
+
68
+ t_begin 'response was "Hello"' && {
69
+ test x$(sort < $curl_out | uniq) = xHello
70
+ }
71
+
72
+ t_begin "current server stderr is clean" && check_stderr
73
+
74
+ t_begin "rotated stderr is clean" && {
75
+ check_stderr $r_rot
76
+ }
77
+
78
+ t_begin "server is now writing logs to new stderr" && {
79
+ before_rot=$(wc -c < $r_rot)
80
+ before_err=$(wc -c < $r_err)
81
+ curl -sSfv http://$listen/
82
+ after_rot=$(wc -c < $r_rot)
83
+ after_err=$(wc -c < $r_err)
84
+ test $after_rot -eq $before_rot
85
+ test $after_err -gt $before_err
86
+ }
87
+
88
+ t_begin "stop server" && {
89
+ kill $rainbows_pid
90
+ }
91
+
92
+ dbgcat r_err
93
+
94
+ t_begin "current server stderr is clean" && check_stderr
95
+ t_begin "rotated stderr is clean" && check_stderr $r_rot
96
+
97
+ t_done
@@ -0,0 +1,83 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ test -r random_blob || die "random_blob required, run with 'make $0'"
4
+
5
+ if ! grep -v ^VmRSS: /proc/self/status >/dev/null 2>&1
6
+ then
7
+ t_info "skipping, can't read RSS from /proc/self/status"
8
+ exit 0
9
+ fi
10
+
11
+ t_plan 10 "large file response slurp avoidance for $model"
12
+
13
+ t_begin "setup and startup" && {
14
+ rtmpfiles curl_out
15
+ rainbows_setup $model
16
+ # can't load Rack::Lint here since it'll cause Rev to slurp
17
+ rainbows -E none -D large-file-response.ru -c $unicorn_config
18
+ rainbows_wait_start
19
+ }
20
+
21
+ t_begin "read random blob size" && {
22
+ random_blob_size=$(wc -c < random_blob)
23
+ }
24
+
25
+ t_begin "read current RSS" && {
26
+ curl -v http://$listen/rss
27
+ dbgcat r_err
28
+ rss_before=$(curl -sSfv http://$listen/rss)
29
+ t_info "rss_before=$rss_before"
30
+ }
31
+
32
+ t_begin "send a series HTTP/1.1 requests sequentially" && {
33
+ for i in a b c
34
+ do
35
+ size=$( (curl -sSfv http://$listen/random_blob &&
36
+ echo ok >$ok) |wc -c)
37
+ test $size -eq $random_blob_size
38
+ test xok = x$(cat $ok)
39
+ done
40
+ }
41
+
42
+ # this was a problem during development
43
+ t_begin "HTTP/1.0 test" && {
44
+ size=$( (curl -0 -sSfv http://$listen/random_blob &&
45
+ echo ok >$ok) |wc -c)
46
+ test $size -eq $random_blob_size
47
+ test xok = x$(cat $ok)
48
+ }
49
+
50
+ t_begin "HTTP/0.9 test" && {
51
+ (
52
+ printf 'GET /random_blob\r\n'
53
+ cat $fifo > $tmp &
54
+ wait
55
+ echo ok > $ok
56
+ ) | socat - TCP:$listen > $fifo
57
+ cmp $tmp random_blob
58
+ test xok = x$(cat $ok)
59
+ }
60
+
61
+ dbgcat r_err
62
+
63
+ t_begin "read RSS again" && {
64
+ curl -v http://$listen/rss
65
+ rss_after=$(curl -sSfv http://$listen/rss)
66
+ t_info "rss_after=$rss_after"
67
+ }
68
+
69
+ t_begin "shutdown server" && {
70
+ kill -QUIT $rainbows_pid
71
+ }
72
+
73
+ t_begin "compare RSS before and after" && {
74
+ diff=$(( $rss_after - $rss_before ))
75
+ t_info "test diff=$diff < orig=$random_blob_size"
76
+ test $diff -le $random_blob_size
77
+ }
78
+
79
+ dbgcat r_err
80
+
81
+ t_begin "check stderr" && check_stderr
82
+
83
+ t_done
@@ -0,0 +1,45 @@
1
+ nr_client=${nr_client-4}
2
+ . ./test-lib.sh
3
+ test -r random_blob || die "random_blob required, run with 'make $0'"
4
+
5
+ t_plan 7 "concurrent rack.input hammer stress test"
6
+
7
+ t_begin "setup and startup" && {
8
+ rtmpfiles curl_out curl_err
9
+ rainbows_setup $model
10
+ rainbows -D sha1.ru -c $unicorn_config
11
+ rainbows_wait_start
12
+ }
13
+
14
+ t_begin "send $nr_client concurrent requests" && {
15
+ start=$(date +%s)
16
+ for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
17
+ do
18
+ (
19
+ curl -sSf -T- http://$listen/$i \
20
+ < random_blob >> $curl_out 2>> $curl_err
21
+ ) &
22
+ done
23
+ wait
24
+ t_info elapsed=$(( $(date +%s) - $start ))
25
+ }
26
+
27
+ t_begin "kill server" && kill $rainbows_pid
28
+
29
+ t_begin "got $nr_client responses" && {
30
+ test $nr_client -eq $(wc -l < $curl_out)
31
+ }
32
+
33
+ t_begin "all responses identical" && {
34
+ test 1 -eq $(sort < $curl_out | uniq | wc -l)
35
+ }
36
+
37
+ t_begin "sha1 matches on-disk sha1" && {
38
+ blob_sha1=$( expr "$(sha1sum < random_blob)" : '\([a-f0-9]\+\)')
39
+ t_info blob_sha1=$blob_sha1
40
+ test x"$blob_sha1" = x"$(sort < $curl_out | uniq)"
41
+ }
42
+
43
+ t_begin "no errors in stderr log" && check_stderr
44
+
45
+ t_done
@@ -0,0 +1,68 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ test -r random_blob || die "random_blob required, run with 'make $0'"
4
+
5
+ t_plan 11 "input trailer test $model"
6
+
7
+ t_begin "setup and startup" && {
8
+ rtmpfiles curl_out
9
+ rainbows_setup $model
10
+ rainbows -D content-md5.ru -c $unicorn_config
11
+ rainbows_wait_start
12
+ }
13
+
14
+ t_begin "upload small blob" && {
15
+ (
16
+ cat $fifo > $tmp &
17
+ echo hello world | content-md5-put
18
+ wait
19
+ echo ok > $ok
20
+ ) | socat - TCP:$listen > $fifo
21
+ test xok = x"$(cat $ok)"
22
+ }
23
+
24
+ t_begin "HTTP response is OK" && fgrep 'HTTP/1.1 200 OK' $tmp
25
+ t_begin "no errors in stderr log" && check_stderr
26
+
27
+ t_begin "big blob request" && {
28
+ (
29
+ cat $fifo > $tmp &
30
+ content-md5-put < random_blob
31
+ wait
32
+ echo ok > $ok
33
+ ) | socat - TCP:$listen > $fifo
34
+ test xok = x"$(cat $ok)"
35
+ }
36
+
37
+ t_begin "HTTP response is OK" && fgrep 'HTTP/1.1 200 OK' $tmp
38
+ t_begin "no errors in stderr log" && check_stderr
39
+
40
+ t_begin "staggered blob upload" && {
41
+ (
42
+ cat $fifo > $tmp &
43
+ (
44
+ dd bs=164 count=1 < random_blob
45
+ sleep 2
46
+ dd bs=4545 count=1 < random_blob
47
+ sleep 2
48
+ dd bs=1234 count=1 < random_blob
49
+ echo subok > $ok
50
+ ) 2>/dev/null | content-md5-put
51
+ test xsubok = x"$(cat $ok)"
52
+ wait
53
+ echo ok > $ok
54
+ ) | socat - TCP:$listen > $fifo
55
+ test xok = x"$(cat $ok)"
56
+ }
57
+
58
+ t_begin "HTTP response is OK" && {
59
+ fgrep 'HTTP/1.1 200 OK' $tmp
60
+ }
61
+
62
+ t_begin "no errors in stderr log" && check_stderr
63
+
64
+ t_begin "kill server" && {
65
+ kill $rainbows_pid
66
+ }
67
+
68
+ t_done
@@ -0,0 +1,66 @@
1
+ #!/bin/sh
2
+ CONFIG_RU=${CONFIG_RU-'async-response.ru'}
3
+ . ./test-lib.sh
4
+
5
+ case $CONFIG_RU in
6
+ *no-autochunk.ru)
7
+ t_plan 7 "async response w/o autochunk for $model"
8
+ skip_autochunk=true
9
+ ;;
10
+ *)
11
+ t_plan 6 "async response for $model"
12
+ skip_autochunk=false
13
+ ;;
14
+ esac
15
+
16
+ t_begin "setup and start" && {
17
+ rainbows_setup
18
+ rtmpfiles a b c curl_err
19
+ # can't load Rack::Lint here since it'll cause Rev to slurp
20
+ rainbows -E none -D $CONFIG_RU -c $unicorn_config
21
+ rainbows_wait_start
22
+ }
23
+
24
+ t_begin "send async requests off in parallel" && {
25
+ t0=$(date +%s)
26
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $a) &
27
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $b) &
28
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $c) &
29
+ wait
30
+ t1=$(date +%s)
31
+ }
32
+
33
+ t_begin "ensure elapsed requests were processed in parallel" && {
34
+ elapsed=$(( $t1 - $t0 ))
35
+ echo "elapsed=$elapsed < 30"
36
+ test $elapsed -lt 30
37
+ }
38
+
39
+ t_begin "termination signal sent" && {
40
+ kill $rainbows_pid
41
+ }
42
+
43
+ dbgcat a
44
+ dbgcat b
45
+ dbgcat c
46
+ dbgcat r_err
47
+ dbgcat curl_err
48
+
49
+ t_begin "no errors from curl" && {
50
+ test ! -s $curl_err
51
+ }
52
+
53
+ t_begin "no errors in stderr" && check_stderr
54
+
55
+ dbgcat r_err
56
+
57
+ if $skip_autochunk
58
+ then
59
+ t_begin "no responses are chunked" && {
60
+ test x"$(cat $a)" = x0123456789
61
+ test x"$(cat $b)" = x0123456789
62
+ test x"$(cat $c)" = x0123456789
63
+ }
64
+ fi
65
+
66
+ t_done
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ CONFIG_RU=async-response-no-autochunk.ru
3
+ . ./t0200-async-response.sh
@@ -0,0 +1,65 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ # n - number of seconds to sleep
5
+ n=10
6
+ CONFIG_RU=async_sinatra.ru
7
+ case $model in
8
+ EventMachine) ;;
9
+ *)
10
+ t_info "skipping $T since it's not compatible with $model"
11
+ exit 0
12
+ ;;
13
+ esac
14
+
15
+ t_plan 7 "async_sinatra test for EM"
16
+
17
+ t_begin "setup and start" && {
18
+ rainbows_setup
19
+ rtmpfiles a b c curl_err
20
+
21
+ # Async Sinatra does not support Rack::Lint
22
+ rainbows -E none -D $CONFIG_RU -c $unicorn_config
23
+ rainbows_wait_start
24
+ }
25
+
26
+ t_begin "send async requests off in parallel" && {
27
+ t0=$(date +%s)
28
+ ( curl --no-buffer -sSf http://$listen/$n 2>> $curl_err | utee $a) &
29
+ ( curl --no-buffer -sSf http://$listen/$n 2>> $curl_err | utee $b) &
30
+ ( curl --no-buffer -sSf http://$listen/$n 2>> $curl_err | utee $c) &
31
+ }
32
+
33
+ t_begin "ensure elapsed requests were processed in parallel" && {
34
+ wait
35
+ t1=$(date +%s)
36
+ elapsed=$(( $t1 - $t0 ))
37
+ echo "elapsed=$elapsed < 30"
38
+ test $elapsed -lt 30
39
+ }
40
+
41
+ t_begin "termination signal sent" && {
42
+ kill $rainbows_pid
43
+ }
44
+
45
+ dbgcat a
46
+ dbgcat b
47
+ dbgcat c
48
+ dbgcat r_err
49
+ dbgcat curl_err
50
+
51
+ t_begin "no errors from curl" && {
52
+ test ! -s $curl_err
53
+ }
54
+
55
+ t_begin "no errors in stderr" && check_stderr
56
+
57
+ dbgcat r_err
58
+
59
+ t_begin "no responses are chunked" && {
60
+ test x"$(cat $a)" = x"delayed for $n seconds"
61
+ test x"$(cat $b)" = x"delayed for $n seconds"
62
+ test x"$(cat $c)" = x"delayed for $n seconds"
63
+ }
64
+
65
+ t_done