rainbows 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/FAQ +39 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -1
- data/Rakefile +39 -2
- data/lib/rainbows.rb +14 -2
- data/lib/rainbows/base.rb +8 -30
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/ev_core.rb +6 -2
- data/lib/rainbows/ev_thread_core.rb +80 -0
- data/lib/rainbows/event_machine.rb +10 -14
- data/lib/rainbows/http_response.rb +1 -1
- data/lib/rainbows/http_server.rb +10 -4
- data/lib/rainbows/rev.rb +4 -158
- data/lib/rainbows/rev/client.rb +73 -0
- data/lib/rainbows/rev/core.rb +42 -0
- data/lib/rainbows/rev/deferred_response.rb +74 -0
- data/lib/rainbows/rev/heartbeat.rb +1 -10
- data/lib/rainbows/rev_thread_spawn.rb +94 -0
- data/lib/rainbows/revactor.rb +23 -27
- data/lib/rainbows/revactor/tee_input.rb +13 -5
- data/lib/rainbows/thread_pool.rb +5 -6
- data/lib/rainbows/thread_spawn.rb +3 -6
- data/local.mk.sample +1 -1
- data/rainbows.gemspec +3 -2
- data/t/GNUmakefile +1 -0
- data/t/bin/sha1sum.rb +23 -0
- data/t/heartbeat-timeout.ru +1 -3
- data/t/sha1-random-size.ru +19 -0
- data/t/sha1.ru +6 -5
- data/t/simple-http_RevThreadSpawn.ru +9 -0
- data/t/t0003-reopen-logs.sh +11 -1
- data/t/t0004-heartbeat-timeout.sh +2 -2
- data/t/t0007-worker-follows-master-to-death.sh +50 -0
- data/t/t0008-ensure-usable-after-limit.sh +181 -0
- data/t/t0100-rack-input-hammer.sh +6 -1
- data/t/t0102-rack-input-short.sh +32 -0
- data/t/t9000-rack-app-pool.sh +1 -1
- data/t/test-lib.sh +12 -2
- data/t/worker-follows-master-to-death.ru +17 -0
- metadata +21 -4
data/lib/rainbows/revactor.rb
CHANGED
@@ -57,18 +57,8 @@ module Rainbows
|
|
57
57
|
HttpResponse.write(client, response, out)
|
58
58
|
end while alive and hp.reset.nil? and env.clear
|
59
59
|
client.close
|
60
|
-
|
61
|
-
|
62
|
-
# if the socket is already closed or broken. We'll always ensure
|
63
|
-
# the socket is closed at the end of this function
|
64
|
-
rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
65
|
-
emergency_response(client, Const::ERROR_500_RESPONSE)
|
66
|
-
rescue HttpParserError # try to tell the client they're bad
|
67
|
-
buf.empty? or emergency_response(client, Const::ERROR_400_RESPONSE)
|
68
|
-
rescue Object => e
|
69
|
-
emergency_response(client, Const::ERROR_500_RESPONSE)
|
70
|
-
logger.error "Read error: #{e.inspect}"
|
71
|
-
logger.error e.backtrace.join("\n")
|
60
|
+
rescue => e
|
61
|
+
handle_error(client, e)
|
72
62
|
end
|
73
63
|
|
74
64
|
# runs inside each forked worker, this sits around and waits
|
@@ -101,35 +91,41 @@ module Rainbows
|
|
101
91
|
end
|
102
92
|
end
|
103
93
|
|
104
|
-
m = 0
|
105
|
-
check_quit = lambda do
|
106
|
-
worker.tmp.chmod(m = 0 == m ? 1 : 0)
|
107
|
-
G.alive = false if master_pid != Process.ppid
|
108
|
-
end
|
109
|
-
|
110
94
|
begin
|
111
95
|
Actor.receive do |filter|
|
112
|
-
filter.after(1
|
96
|
+
filter.after(1) { G.tick }
|
113
97
|
filter.when(Case[:exit, Actor, Object]) do |_,actor,_|
|
114
98
|
orig = clients.size
|
115
99
|
clients.delete(actor.object_id)
|
116
100
|
orig >= limit and listeners.each { |l| l << :resume }
|
117
|
-
|
101
|
+
G.tick
|
118
102
|
end
|
119
103
|
end
|
120
104
|
end while G.alive || clients.size > 0
|
121
105
|
end
|
122
106
|
|
123
|
-
|
124
|
-
|
125
|
-
#
|
126
|
-
#
|
127
|
-
def
|
107
|
+
# if we get any error, try to write something back to the client
|
108
|
+
# assuming we haven't closed the socket, but don't get hung up
|
109
|
+
# if the socket is already closed or broken. We'll always ensure
|
110
|
+
# the socket is closed at the end of this function
|
111
|
+
def handle_error(client, e)
|
112
|
+
msg = case e
|
113
|
+
when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
114
|
+
Const::ERROR_500_RESPONSE
|
115
|
+
when HttpParserError # try to tell the client they're bad
|
116
|
+
Const::ERROR_400_RESPONSE
|
117
|
+
else
|
118
|
+
logger.error "Read error: #{e.inspect}"
|
119
|
+
logger.error e.backtrace.join("\n")
|
120
|
+
Const::ERROR_500_RESPONSE
|
121
|
+
end
|
128
122
|
client.instance_eval do
|
129
123
|
# this is Revactor implementation dependent
|
130
|
-
@_io.write_nonblock(
|
124
|
+
@_io.write_nonblock(msg)
|
125
|
+
close
|
131
126
|
end
|
132
|
-
|
127
|
+
rescue
|
128
|
+
nil
|
133
129
|
end
|
134
130
|
|
135
131
|
def revactorize_listeners!
|
@@ -21,19 +21,27 @@ module Rainbows
|
|
21
21
|
# returns nil if reading from the input returns nil
|
22
22
|
def tee(length, dst)
|
23
23
|
unless parser.body_eof?
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
if parser.filter_body(dst, buf << socket.read).nil?
|
25
|
+
@tmp.write(dst)
|
26
|
+
diff = dst.size - length
|
27
|
+
if diff > 0
|
28
|
+
dst.replace(dst[0,length])
|
29
|
+
@tmp.seek(-diff, IO::SEEK_CUR)
|
28
30
|
end
|
29
|
-
|
31
|
+
return dst
|
30
32
|
end
|
31
33
|
end
|
32
34
|
finalize_input
|
35
|
+
rescue => e
|
36
|
+
client_error(e)
|
33
37
|
end
|
34
38
|
|
35
39
|
def finalize_input
|
36
40
|
while parser.trailers(req, buf).nil?
|
41
|
+
# Don't worry about raising ClientShutdown here on EOFError, tee()
|
42
|
+
# will catch EOFError when app is processing it, otherwise in
|
43
|
+
# initialize we never get any chance to enter the app so the
|
44
|
+
# EOFError will just get trapped by Unicorn and not the Rack app
|
37
45
|
buf << socket.read
|
38
46
|
end
|
39
47
|
self.socket = nil
|
data/lib/rainbows/thread_pool.rb
CHANGED
@@ -28,16 +28,15 @@ module Rainbows
|
|
28
28
|
def worker_loop(worker)
|
29
29
|
init_worker_process(worker)
|
30
30
|
pool = (1..worker_connections).map { new_worker_thread }
|
31
|
-
m = 0
|
32
31
|
|
33
|
-
while G.alive
|
32
|
+
while G.alive
|
33
|
+
# if any worker dies, something is serious wrong, bail
|
34
34
|
pool.each do |thr|
|
35
|
-
|
36
|
-
|
37
|
-
thr.join(1) and break
|
35
|
+
G.tick
|
36
|
+
thr.join(1) and G.quit!
|
38
37
|
end
|
39
38
|
end
|
40
|
-
join_threads(pool
|
39
|
+
join_threads(pool)
|
41
40
|
end
|
42
41
|
|
43
42
|
def new_worker_thread
|
@@ -22,21 +22,18 @@ module Rainbows
|
|
22
22
|
def worker_loop(worker)
|
23
23
|
init_worker_process(worker)
|
24
24
|
threads = ThreadGroup.new
|
25
|
-
alive = worker.tmp
|
26
|
-
m = 0
|
27
25
|
limit = worker_connections
|
28
26
|
|
29
27
|
begin
|
30
|
-
G.alive && master_pid == Process.ppid or break
|
31
28
|
ret = begin
|
32
|
-
|
29
|
+
G.tick or break
|
33
30
|
IO.select(LISTENERS, nil, nil, 1) or next
|
34
31
|
rescue Errno::EINTR
|
35
32
|
retry
|
36
33
|
rescue Errno::EBADF, TypeError
|
37
34
|
break
|
38
35
|
end
|
39
|
-
|
36
|
+
G.tick
|
40
37
|
|
41
38
|
ret.first.each do |l|
|
42
39
|
# Sleep if we're busy, another less busy worker process may
|
@@ -57,7 +54,7 @@ module Rainbows
|
|
57
54
|
rescue Object => e
|
58
55
|
listen_loop_error(e)
|
59
56
|
end while true
|
60
|
-
join_threads(threads.list
|
57
|
+
join_threads(threads.list)
|
61
58
|
end
|
62
59
|
|
63
60
|
end
|
data/local.mk.sample
CHANGED
data/rainbows.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.name = %q{rainbows}
|
15
15
|
s.version = ENV["VERSION"]
|
16
16
|
|
17
|
-
s.authors = ["Rainbows!
|
17
|
+
s.authors = ["Rainbows! hackers"]
|
18
18
|
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
19
19
|
s.description = File.read("README").split(/\n\n/)[1]
|
20
20
|
s.email = %q{rainbows-talk@rubyforge.org}
|
@@ -41,7 +41,8 @@ Gem::Specification.new do |s|
|
|
41
41
|
s.test_files = test_files
|
42
42
|
|
43
43
|
# we need Unicorn for the HTTP parser and process management
|
44
|
-
|
44
|
+
# Unicorn 0.95.0 should be released on or around Nov 13/14/15, 2009
|
45
|
+
s.add_dependency(%q<unicorn>, ["~> 0.95.0"])
|
45
46
|
|
46
47
|
# Unicorn already depends on Rack
|
47
48
|
# s.add_dependency(%q<rack>)
|
data/t/GNUmakefile
CHANGED
data/t/bin/sha1sum.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
|
4
|
+
# Reads from stdin and outputs the SHA1 hex digest of the input this is
|
5
|
+
# ONLY used as a last resort, our test code will try to use sha1sum(1),
|
6
|
+
# openssl(1), or gsha1sum(1) before falling back to using this. We try
|
7
|
+
# all options first because we have a strong and healthy distrust of our
|
8
|
+
# Ruby abilities in general, and *especially* when it comes to
|
9
|
+
# understanding (and trusting the implementation of) Ruby 1.9 encoding.
|
10
|
+
|
11
|
+
require 'digest/sha1'
|
12
|
+
$stdout.sync = $stderr.sync = true
|
13
|
+
$stdout.binmode
|
14
|
+
$stdin.binmode
|
15
|
+
bs = 16384
|
16
|
+
digest = Digest::SHA1.new
|
17
|
+
if buf = $stdin.read(bs)
|
18
|
+
begin
|
19
|
+
digest.update(buf)
|
20
|
+
end while $stdin.read(bs, buf)
|
21
|
+
end
|
22
|
+
|
23
|
+
$stdout.syswrite("#{digest.hexdigest}\n")
|
data/t/heartbeat-timeout.ru
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
use Rack::ContentLength
|
2
|
-
fifo = ENV['FIFO_PATH'] or abort "FIFO_PATH not defined"
|
3
2
|
headers = { 'Content-Type' => 'text/plain' }
|
4
3
|
run lambda { |env|
|
5
4
|
case env['PATH_INFO']
|
6
5
|
when "/block-forever"
|
7
|
-
# one of these should block forever
|
8
6
|
Process.kill(:STOP, $$)
|
9
|
-
|
7
|
+
sleep # in case STOP signal is not received in time
|
10
8
|
[ 500, headers, [ "Should never get here\n" ] ]
|
11
9
|
else
|
12
10
|
[ 200, headers, [ "#$$\n" ] ]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# SHA1 checksum generator
|
2
|
+
require 'digest/sha1'
|
3
|
+
use Rack::ContentLength
|
4
|
+
cap = 16384
|
5
|
+
app = lambda do |env|
|
6
|
+
/\A100-continue\z/i =~ env['HTTP_EXPECT'] and
|
7
|
+
return [ 100, {}, [] ]
|
8
|
+
digest = Digest::SHA1.new
|
9
|
+
input = env['rack.input']
|
10
|
+
if buf = input.read(rand(cap))
|
11
|
+
begin
|
12
|
+
raise "#{buf.size} > #{cap}" if buf.size > cap
|
13
|
+
digest.update(buf)
|
14
|
+
end while input.read(rand(cap), buf)
|
15
|
+
end
|
16
|
+
|
17
|
+
[ 200, {'Content-Type' => 'text/plain'}, [ digest.hexdigest << "\n" ] ]
|
18
|
+
end
|
19
|
+
run app
|
data/t/sha1.ru
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# SHA1 checksum generator
|
2
|
-
bs = ENV['bs'] ? ENV['bs'].to_i :
|
2
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 16384
|
3
3
|
require 'digest/sha1'
|
4
4
|
use Rack::ContentLength
|
5
5
|
app = lambda do |env|
|
@@ -7,10 +7,11 @@ app = lambda do |env|
|
|
7
7
|
return [ 100, {}, [] ]
|
8
8
|
digest = Digest::SHA1.new
|
9
9
|
input = env['rack.input']
|
10
|
-
buf = input.read(bs)
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
if buf = input.read(bs)
|
11
|
+
begin
|
12
|
+
digest.update(buf)
|
13
|
+
end while input.read(bs, buf)
|
14
|
+
end
|
14
15
|
|
15
16
|
[ 200, {'Content-Type' => 'text/plain'}, [ digest.hexdigest << "\n" ] ]
|
16
17
|
end
|
data/t/t0003-reopen-logs.sh
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
nr_client=${nr_client-2}
|
4
4
|
. ./test-lib.sh
|
5
5
|
|
6
|
-
t_plan
|
6
|
+
t_plan 19 "reopen rotated logs"
|
7
7
|
|
8
8
|
t_begin "setup and startup" && {
|
9
9
|
rtmpfiles curl_out curl_err r_rot
|
@@ -44,6 +44,16 @@ t_begin "wait for rotated log to reappear" && {
|
|
44
44
|
done
|
45
45
|
}
|
46
46
|
|
47
|
+
t_begin "wait for worker to reopen logs" && {
|
48
|
+
nr=60
|
49
|
+
re="worker=.* done reopening logs"
|
50
|
+
while ! grep "$re" < $r_err >/dev/null && test $nr -ge 0
|
51
|
+
do
|
52
|
+
sleep 1
|
53
|
+
nr=$(( $nr - 1 ))
|
54
|
+
done
|
55
|
+
}
|
56
|
+
|
47
57
|
dbgcat r_rot
|
48
58
|
dbgcat r_err
|
49
59
|
|
@@ -7,7 +7,7 @@ t_begin "setup and startup" && {
|
|
7
7
|
rainbows_setup $model
|
8
8
|
echo timeout 3 >> $unicorn_config
|
9
9
|
echo preload_app true >> $unicorn_config
|
10
|
-
|
10
|
+
rainbows -D heartbeat-timeout.ru -c $unicorn_config
|
11
11
|
rainbows_wait_start
|
12
12
|
}
|
13
13
|
|
@@ -37,7 +37,7 @@ t_begin "ensure timeout took 3-6 seconds" && {
|
|
37
37
|
}
|
38
38
|
|
39
39
|
t_begin "wait for new worker to start up" && {
|
40
|
-
test
|
40
|
+
test xSTART = x"$(cat $fifo)"
|
41
41
|
}
|
42
42
|
|
43
43
|
t_begin "we get a fresh new worker process" && {
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 7 "ensure worker follows master to death"
|
4
|
+
|
5
|
+
t_begin "setup" && {
|
6
|
+
rtmpfiles curl_err curl_out
|
7
|
+
rainbows_setup
|
8
|
+
echo timeout 3 >> $unicorn_config
|
9
|
+
rainbows -D -c $unicorn_config worker-follows-master-to-death.ru
|
10
|
+
rainbows_wait_start
|
11
|
+
}
|
12
|
+
|
13
|
+
t_begin "read worker PID" && {
|
14
|
+
worker_pid=$(curl -sSf http://$listen/pid)
|
15
|
+
t_info "worker_pid=$worker_pid"
|
16
|
+
}
|
17
|
+
|
18
|
+
t_begin "start a long sleeping request" && {
|
19
|
+
curl -sSfv -T- </dev/null http://$listen/sleep/2 >$curl_out 2> $fifo &
|
20
|
+
curl_pid=$!
|
21
|
+
t_info "curl_pid=$curl_pid"
|
22
|
+
}
|
23
|
+
|
24
|
+
t_begin "nuke the master once we're connected" && {
|
25
|
+
awk -v rainbows_pid=$rainbows_pid '
|
26
|
+
{ print $0 }
|
27
|
+
/100 Continue/ {
|
28
|
+
print "awk: sending SIGKILL to", rainbows_pid
|
29
|
+
system("kill -9 "rainbows_pid)
|
30
|
+
}' < $fifo > $curl_err
|
31
|
+
wait
|
32
|
+
}
|
33
|
+
|
34
|
+
t_begin "worker is no longer running" && {
|
35
|
+
sleep 6
|
36
|
+
kill -0 $worker_pid 2> $tmp && false
|
37
|
+
test -s $tmp
|
38
|
+
}
|
39
|
+
|
40
|
+
t_begin "sleepy curl request is no longer running" && {
|
41
|
+
kill -0 $curl_pid 2> $tmp && false
|
42
|
+
test -s $tmp
|
43
|
+
}
|
44
|
+
|
45
|
+
t_begin "sleepy curl request completed gracefully" && {
|
46
|
+
test x$(cat $curl_out) = x$worker_pid
|
47
|
+
dbgcat curl_err
|
48
|
+
}
|
49
|
+
|
50
|
+
t_done
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
test -r random_blob || die "random_blob required, run with 'make $0'"
|
4
|
+
|
5
|
+
t_plan 14 "ensure we're accounting worker_connections properly"
|
6
|
+
nr=2
|
7
|
+
|
8
|
+
t_begin "setup" && {
|
9
|
+
rtmpfiles a b c d
|
10
|
+
rainbows_setup $model $nr
|
11
|
+
rainbows -D sha1.ru -c $unicorn_config
|
12
|
+
rainbows_wait_start
|
13
|
+
}
|
14
|
+
|
15
|
+
null_sha1=da39a3ee5e6b4b0d3255bfef95601890afd80709
|
16
|
+
|
17
|
+
t_begin "fire off concurrent processes" && {
|
18
|
+
|
19
|
+
req='POST / HTTP/1.1\r\n'
|
20
|
+
req="$req"'Host: example.com\r\n'
|
21
|
+
req="$req"'Transfer-Encoding: chunked\r\n\r\n'
|
22
|
+
|
23
|
+
for i in a b c d
|
24
|
+
do
|
25
|
+
rtmpfiles ${i}_fifo ${i}_tmp
|
26
|
+
eval 'i_fifo=$'${i}_fifo
|
27
|
+
eval 'i_tmp=$'${i}_tmp
|
28
|
+
eval "i=$"$i
|
29
|
+
(
|
30
|
+
(
|
31
|
+
cat $i_fifo > $i_tmp &
|
32
|
+
# need a full HTTP request to get around
|
33
|
+
# httpready
|
34
|
+
printf "$req"
|
35
|
+
sleep 5
|
36
|
+
printf '0\r\n\r\n'
|
37
|
+
wait
|
38
|
+
echo ok > $i
|
39
|
+
) | socat - TCP:$listen > $i_fifo
|
40
|
+
) &
|
41
|
+
done
|
42
|
+
wait
|
43
|
+
}
|
44
|
+
|
45
|
+
t_begin "check results" && {
|
46
|
+
for i in a b c d
|
47
|
+
do
|
48
|
+
eval 'i_tmp=$'${i}_tmp
|
49
|
+
eval "i=$"$i
|
50
|
+
test xok = x$(cat $i)
|
51
|
+
test x$null_sha1 = x$(tail -1 $i_tmp)
|
52
|
+
done
|
53
|
+
}
|
54
|
+
|
55
|
+
t_begin "repeat concurrent tests with faster clients" && {
|
56
|
+
for i in a b c d
|
57
|
+
do
|
58
|
+
eval 'i_tmp=$'${i}_tmp
|
59
|
+
eval "i=$"$i
|
60
|
+
curl -sSf -T- </dev/null http://$listen/ > $i 2> $i_tmp &
|
61
|
+
done
|
62
|
+
wait
|
63
|
+
}
|
64
|
+
|
65
|
+
t_begin "check results" && {
|
66
|
+
for i in a b c d
|
67
|
+
do
|
68
|
+
eval 'i_tmp=$'${i}_tmp
|
69
|
+
eval "i=$"$i
|
70
|
+
test ! -s $i_tmp
|
71
|
+
test x$null_sha1 = x$(cat $i)
|
72
|
+
done
|
73
|
+
}
|
74
|
+
|
75
|
+
t_begin "fire off truncated concurrent requests" && {
|
76
|
+
|
77
|
+
req='POST / HTTP/1.1\r\n'
|
78
|
+
req="$req"'Host: example.com\r\n'
|
79
|
+
req="$req"'Transfer-Encoding: chunked\r\n'
|
80
|
+
|
81
|
+
for i in a b c d
|
82
|
+
do
|
83
|
+
rtmpfiles ${i}_tmp
|
84
|
+
eval 'i_tmp=$'${i}_tmp
|
85
|
+
eval "i=$"$i
|
86
|
+
(
|
87
|
+
(
|
88
|
+
# need a full HTTP request to get around
|
89
|
+
# httpready
|
90
|
+
printf "$req"
|
91
|
+
echo ok > $i
|
92
|
+
) | socat - TCP:$listen > $i_tmp
|
93
|
+
) &
|
94
|
+
done
|
95
|
+
wait
|
96
|
+
}
|
97
|
+
|
98
|
+
t_begin "check broken results" && {
|
99
|
+
for i in a b c d
|
100
|
+
do
|
101
|
+
eval 'i_tmp=$'${i}_tmp
|
102
|
+
eval "i=$"$i
|
103
|
+
test xok = x$(cat $i)
|
104
|
+
dbgcat i_tmp
|
105
|
+
done
|
106
|
+
}
|
107
|
+
|
108
|
+
t_begin "repeat concurrent tests with faster clients" && {
|
109
|
+
for i in a b c d
|
110
|
+
do
|
111
|
+
eval 'i_tmp=$'${i}_tmp
|
112
|
+
eval "i=$"$i
|
113
|
+
curl -sSf -T- </dev/null http://$listen/ > $i 2> $i_tmp &
|
114
|
+
done
|
115
|
+
wait
|
116
|
+
}
|
117
|
+
|
118
|
+
t_begin "check results" && {
|
119
|
+
for i in a b c d
|
120
|
+
do
|
121
|
+
eval 'i_tmp=$'${i}_tmp
|
122
|
+
eval "i=$"$i
|
123
|
+
test ! -s $i_tmp
|
124
|
+
test x$null_sha1 = x$(cat $i)
|
125
|
+
done
|
126
|
+
}
|
127
|
+
|
128
|
+
t_begin "fire off garbage" && {
|
129
|
+
for i in a b c d
|
130
|
+
do
|
131
|
+
rtmpfiles ${i}_fifo ${i}_tmp
|
132
|
+
eval 'i_fifo=$'${i}_fifo
|
133
|
+
eval 'i_tmp=$'${i}_tmp
|
134
|
+
eval "i=$"$i
|
135
|
+
(
|
136
|
+
(
|
137
|
+
cat $i_fifo > $i_tmp &
|
138
|
+
dd if=random_blob bs=4096 count=1
|
139
|
+
wait
|
140
|
+
echo ok > $i
|
141
|
+
) | socat - TCP:$listen > $i_fifo
|
142
|
+
) &
|
143
|
+
done
|
144
|
+
wait
|
145
|
+
}
|
146
|
+
|
147
|
+
t_begin "check broken results" && {
|
148
|
+
for i in a b c d
|
149
|
+
do
|
150
|
+
eval 'i_tmp=$'${i}_tmp
|
151
|
+
eval "i=$"$i
|
152
|
+
test xok = x$(cat $i)
|
153
|
+
grep -F 'HTTP/1.1 400 Bad Request' $i_tmp
|
154
|
+
done
|
155
|
+
}
|
156
|
+
|
157
|
+
t_begin "repeat concurrent tests with faster clients" && {
|
158
|
+
for i in a b c d
|
159
|
+
do
|
160
|
+
eval 'i_tmp=$'${i}_tmp
|
161
|
+
eval "i=$"$i
|
162
|
+
curl -sSf -T- </dev/null http://$listen/ > $i 2> $i_tmp &
|
163
|
+
done
|
164
|
+
wait
|
165
|
+
}
|
166
|
+
|
167
|
+
t_begin "check results" && {
|
168
|
+
for i in a b c d
|
169
|
+
do
|
170
|
+
eval 'i_tmp=$'${i}_tmp
|
171
|
+
eval "i=$"$i
|
172
|
+
test ! -s $i_tmp
|
173
|
+
test x$null_sha1 = x$(cat $i)
|
174
|
+
done
|
175
|
+
}
|
176
|
+
|
177
|
+
t_begin "teardown" && {
|
178
|
+
kill $rainbows_pid
|
179
|
+
}
|
180
|
+
|
181
|
+
t_done
|