rainbows 0.93.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +1 -0
- data/.gitignore +0 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +16 -7
- data/Rakefile +0 -21
- data/Test_Suite +63 -0
- data/lib/rainbows.rb +1 -0
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/sendfile.rb +100 -0
- data/lib/rainbows/writer_thread_pool.rb +3 -8
- data/lib/rainbows/writer_thread_spawn.rb +2 -6
- data/local.mk.sample +20 -52
- data/rainbows.gemspec +1 -0
- data/t/.gitignore +1 -0
- data/t/GNUmakefile +12 -10
- data/t/README +21 -4
- data/t/t0005-large-file-response.sh +9 -8
- data/t/t0300-async_sinatra.sh +6 -0
- data/t/t9001-sendfile-to-path.sh +45 -0
- data/t/t9001.ru +11 -0
- data/t/test-lib.sh +6 -10
- data/t/test_isolate.rb +39 -0
- metadata +19 -4
- data/config/.gitignore +0 -1
- data/config/isolate.rb +0 -25
data/.document
CHANGED
data/.gitignore
CHANGED
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
all::
|
3
3
|
RUBY = ruby
|
4
4
|
RAKE = rake
|
5
|
+
RSYNC = rsync
|
5
6
|
GIT_URL = git://git.bogomips.org/rainbows.git
|
6
|
-
ISOLATE_CONFIG = config/isolate.rb
|
7
7
|
|
8
8
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
9
9
|
@./GIT-VERSION-GEN
|
@@ -16,12 +16,6 @@ ifeq ($(RUBY_VERSION),)
|
|
16
16
|
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
17
17
|
endif
|
18
18
|
|
19
|
-
# rake takes forever to start
|
20
|
-
isolate: tmp/isolate/ruby-$(RUBY_VERSION)/.isolate
|
21
|
-
tmp/isolate/ruby-$(RUBY_VERSION)/.isolate: $(ISOLATE_CONFIG)
|
22
|
-
ISOLATE_CONFIG=$(ISOLATE_CONFIG) $(RAKE) isolate
|
23
|
-
> $@
|
24
|
-
|
25
19
|
base_bins := rainbows
|
26
20
|
bins := $(addprefix bin/, $(base_bins))
|
27
21
|
man1_rdoc := $(addsuffix _1, $(base_bins))
|
@@ -112,6 +106,19 @@ doc: .document NEWS ChangeLog
|
|
112
106
|
cat Documentation/comparison.css >> doc/rdoc.css
|
113
107
|
$(RM) $(man1_rdoc)
|
114
108
|
|
109
|
+
# publishes docs to http://rainbows.rubyforge.org
|
110
|
+
publish_doc: NEWS
|
111
|
+
-git set-file-times
|
112
|
+
$(RM) -r doc ChangeLog NEWS
|
113
|
+
$(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
|
114
|
+
awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
|
115
|
+
< NEWS > doc/LATEST
|
116
|
+
-find doc/images doc/js -type f | \
|
117
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:01' doc/rdoc.css
|
118
|
+
chmod 644 $$(find doc -type f)
|
119
|
+
$(RSYNC) -av doc/ rubyforge.org:/var/www/gforge-projects/rainbows/
|
120
|
+
git ls-files | xargs touch
|
121
|
+
|
115
122
|
ifneq ($(VERSION),)
|
116
123
|
rfproject := rainbows
|
117
124
|
rfpackage := rainbows
|
@@ -172,6 +179,8 @@ release: verify package $(release_notes) $(release_changes)
|
|
172
179
|
# in case of gem downloads from RubyForge releases page
|
173
180
|
-rubyforge add_file \
|
174
181
|
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
182
|
+
$(RAKE) raa_update VERSION=$(VERSION)
|
183
|
+
$(RAKE) fm_update VERSION=$(VERSION)
|
175
184
|
else
|
176
185
|
gem install-gem: GIT-VERSION-FILE
|
177
186
|
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
data/Rakefile
CHANGED
@@ -183,24 +183,3 @@ task :fm_update do
|
|
183
183
|
p http.post(uri.path, req, {'Content-Type'=>'application/json'})
|
184
184
|
end
|
185
185
|
end
|
186
|
-
|
187
|
-
desc 'isolate gems for development'
|
188
|
-
task :isolate do
|
189
|
-
require 'isolate'
|
190
|
-
require 'rbconfig'
|
191
|
-
|
192
|
-
Isolate.now! :file => ENV['ISOLATE_CONFIG'], :system => false
|
193
|
-
|
194
|
-
# for Ruby 1.8 isolate uses "1.8" instead of "1.8.7" for paths,
|
195
|
-
# but we'll still try to support 1.8.6 for now even though isolate
|
196
|
-
# does not.
|
197
|
-
if Gem.ruby_engine == "ruby" &&
|
198
|
-
RbConfig::CONFIG["ruby_version"] != RUBY_VERSION
|
199
|
-
require 'fileutils'
|
200
|
-
Dir.chdir('tmp/isolate') do
|
201
|
-
FileUtils.rm_rf("ruby-#{RUBY_VERSION}")
|
202
|
-
File.symlink "ruby-#{RbConfig::CONFIG["ruby_version"]}",
|
203
|
-
"ruby-#{RUBY_VERSION}"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
data/Test_Suite
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= \Rainbows! test suite - YES OUR TEST SUITE IS CONCURRENT!
|
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 primarily in Bourne shell because that's what we're
|
9
|
+
comfortable writing integration tests with. This test suite is also
|
10
|
+
easily portable to non-Ruby web servers.
|
11
|
+
|
12
|
+
== Requirements
|
13
|
+
|
14
|
+
* {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
|
15
|
+
* {isolate ~> 2.0.2}[http://github.com/jbarnette/isolate] - for dependencies
|
16
|
+
* {GNU make}[http://www.gnu.org/software/make/]
|
17
|
+
* {socat}[http://www.dest-unreach.org/socat/]
|
18
|
+
* {curl >= 7.18.0}[http://curl.haxx.se/]
|
19
|
+
* standard UNIX shell utilities (Bourne sh, awk, sed, grep, ...)
|
20
|
+
|
21
|
+
We do not use bashisms or any non-portable, non-POSIX constructs
|
22
|
+
in our shell code. We use the "pipefail" option if available and
|
23
|
+
mainly test with {ksh}[http://kornshell.com/], but occasionally
|
24
|
+
with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
|
25
|
+
{bash}[http://www.gnu.org/software/bash/], too.
|
26
|
+
|
27
|
+
== Running Tests
|
28
|
+
|
29
|
+
*BSD users: use "gmake" instead of "make"
|
30
|
+
|
31
|
+
To run the entire test suite with 8 tests running at once:
|
32
|
+
|
33
|
+
make -j8
|
34
|
+
|
35
|
+
To run one individual test for all concurrency models:
|
36
|
+
|
37
|
+
make t0000-simple-http.sh
|
38
|
+
|
39
|
+
To run one individual test for one concurrency model:
|
40
|
+
|
41
|
+
make Revactor.t0000-simple-http.sh
|
42
|
+
|
43
|
+
To run all tests for one concurrency model:
|
44
|
+
|
45
|
+
make EventMachine
|
46
|
+
|
47
|
+
You may also increase verbosity by setting the "V" variable for
|
48
|
+
GNU make. To disable trapping of stdout/stderr:
|
49
|
+
|
50
|
+
make V=1
|
51
|
+
|
52
|
+
To enable the "set -x" option in shell scripts to trace execution
|
53
|
+
|
54
|
+
make V=2
|
55
|
+
|
56
|
+
== Performance
|
57
|
+
|
58
|
+
Some of the tests are rather I/O intensive due to the rewindability
|
59
|
+
requirement of "rack.input" in the Rack specification and the somewhat
|
60
|
+
complicated (but awesome!) nature of the TeeInput class leading us to
|
61
|
+
test it very heavily. If you have lots of RAM and a large tmpfs
|
62
|
+
partition, it is advisable to set your TMPDIR and also make the t/trash/
|
63
|
+
directory a symlink to a directory inside in your TMPDIR.
|
data/lib/rainbows.rb
CHANGED
@@ -32,6 +32,7 @@ module Rainbows
|
|
32
32
|
require 'rainbows/http_response'
|
33
33
|
require 'rainbows/base'
|
34
34
|
require 'rainbows/tee_input'
|
35
|
+
autoload :Sendfile, 'rainbows/sendfile'
|
35
36
|
autoload :AppPool, 'rainbows/app_pool'
|
36
37
|
autoload :DevFdResponse, 'rainbows/dev_fd_response'
|
37
38
|
autoload :MaxBody, 'rainbows/max_body'
|
data/lib/rainbows/const.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
module Rainbows
|
3
|
+
|
4
|
+
# This middleware handles X-\Sendfile headers generated by applications
|
5
|
+
# or middlewares down the stack. It should be placed at the top
|
6
|
+
# (outermost layer) of the middleware stack to avoid having its
|
7
|
+
# +to_path+ method clobbered by another middleware.
|
8
|
+
#
|
9
|
+
# This converts X-\Sendfile responses to bodies which respond to the
|
10
|
+
# +to_path+ method which allows certain concurrency models to serve
|
11
|
+
# efficiently using sendfile() or similar. With multithreaded models
|
12
|
+
# under Ruby 1.9, IO.copy_stream will be used.
|
13
|
+
#
|
14
|
+
# This middleware is the opposite of Rack::Contrib::Sendfile as it
|
15
|
+
# reverses the effect of Rack::Contrib::Sendfile. Unlike many Ruby
|
16
|
+
# web servers, some configurations of \Rainbows! are capable of
|
17
|
+
# serving static files efficiently.
|
18
|
+
#
|
19
|
+
# === Compatibility (via IO.copy_stream in Ruby 1.9):
|
20
|
+
# * ThreadSpawn
|
21
|
+
# * ThreadPool
|
22
|
+
# * WriterThreadPool
|
23
|
+
# * WriterThreadSpawn
|
24
|
+
#
|
25
|
+
# === Compatibility (Ruby 1.8 and 1.9)
|
26
|
+
# * EventMachine
|
27
|
+
# * NeverBlock (using EventMachine)
|
28
|
+
#
|
29
|
+
# DO NOT use this middleware if you're proxying to \Rainbows! with a
|
30
|
+
# server that understands X-\Sendfile (e.g. Apache, Lighttpd) natively.
|
31
|
+
#
|
32
|
+
# This does NOT understand X-Accel-Redirect headers intended for nginx.
|
33
|
+
# X-Accel-Redirect requires the application to be highly coupled with
|
34
|
+
# the corresponding nginx configuration, and is thus too complicated to
|
35
|
+
# be worth supporting.
|
36
|
+
#
|
37
|
+
# Example config.ru:
|
38
|
+
#
|
39
|
+
# use Rainbows::Sendfile
|
40
|
+
# run lambda { |env|
|
41
|
+
# path = "#{Dir.pwd}/random_blob"
|
42
|
+
# [ 200,
|
43
|
+
# {
|
44
|
+
# 'X-Sendfile' => path,
|
45
|
+
# 'Content-Type' => 'application/octet-stream'
|
46
|
+
# },
|
47
|
+
# []
|
48
|
+
# ]
|
49
|
+
# }
|
50
|
+
|
51
|
+
class Sendfile < Struct.new(:app)
|
52
|
+
|
53
|
+
# :stopdoc:
|
54
|
+
HH = Rack::Utils::HeaderHash
|
55
|
+
# :startdoc:
|
56
|
+
|
57
|
+
# Body wrapper, this allows us to fall back gracefully to
|
58
|
+
# +each+ in case a given concurrency model does not optimize
|
59
|
+
# +to_path+ calls.
|
60
|
+
class Body < Struct.new(:to_io)
|
61
|
+
|
62
|
+
def initialize(path, headers)
|
63
|
+
# Rainbows! will try #to_io if #to_path exists to avoid unnecessary
|
64
|
+
# open() calls.
|
65
|
+
self.to_io = File.open(path, 'rb')
|
66
|
+
|
67
|
+
unless headers['Content-Length']
|
68
|
+
stat = to_io.stat
|
69
|
+
headers['Content-Length'] = stat.size.to_s if stat.file?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_path
|
74
|
+
to_io.path
|
75
|
+
end
|
76
|
+
|
77
|
+
# fallback in case our +to_path+ doesn't get handled for whatever reason
|
78
|
+
def each(&block)
|
79
|
+
buf = ''
|
80
|
+
while to_io.read(0x4000, buf)
|
81
|
+
yield buf
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def close
|
86
|
+
to_io.close
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def call(env)
|
91
|
+
status, headers, body = app.call(env)
|
92
|
+
headers = HH.new(headers)
|
93
|
+
if path = headers.delete('X-Sendfile')
|
94
|
+
body = Body.new(path, headers) unless body.respond_to?(:to_path)
|
95
|
+
end
|
96
|
+
[ status, headers, body ]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -46,13 +46,8 @@ module Rainbows
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
undef_method :write_body
|
52
|
-
|
53
|
-
def write_body(qclient, body)
|
54
|
-
qclient.q << [ qclient.to_io, :body, body ]
|
55
|
-
end
|
49
|
+
def write_body(qclient, body)
|
50
|
+
qclient.q << [ qclient.to_io, :body, body ]
|
56
51
|
end
|
57
52
|
|
58
53
|
@@nr = 0
|
@@ -71,7 +66,7 @@ module Rainbows
|
|
71
66
|
begin
|
72
67
|
io, arg1, arg2 = response
|
73
68
|
case arg1
|
74
|
-
when :body then
|
69
|
+
when :body then Base.write_body(io, arg2)
|
75
70
|
when :close then io.close unless io.closed?
|
76
71
|
else
|
77
72
|
io.write(arg1)
|
@@ -88,12 +88,8 @@ module Rainbows
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
def write_body(my_sock, body)
|
95
|
-
my_sock.write_body(body)
|
96
|
-
end
|
91
|
+
def write_body(my_sock, body)
|
92
|
+
my_sock.write_body(body)
|
97
93
|
end
|
98
94
|
|
99
95
|
def process_client(client)
|
data/local.mk.sample
CHANGED
@@ -4,37 +4,32 @@
|
|
4
4
|
#
|
5
5
|
# This is depends on a bunch of GNU-isms from bash, sed, touch.
|
6
6
|
|
7
|
-
RSYNC = rsync
|
8
7
|
DLEXT := so
|
9
8
|
|
9
|
+
# if you have a decent amount of RAM, setting TMPDIR to be on tmpfs
|
10
|
+
# can significantly improve performance because uploads take a lot
|
11
|
+
# of disk I/O due to the rewindability requirement in Rack.
|
12
|
+
# TMPDIR := /dev/shm
|
13
|
+
# export TMPDIR
|
14
|
+
|
10
15
|
# Avoid loading rubygems to speed up tests because gmake is
|
11
16
|
# fork+exec heavy with Ruby.
|
12
17
|
prefix = $(HOME)
|
13
18
|
|
14
|
-
ifeq ($(
|
15
|
-
|
19
|
+
ifeq ($(r192),)
|
20
|
+
ifeq ($(r19),)
|
21
|
+
RUBY := $(prefix)/bin/ruby
|
22
|
+
else
|
23
|
+
prefix := $(prefix)/ruby-1.9
|
24
|
+
export PATH := $(prefix)/bin:$(PATH)
|
25
|
+
RUBY := $(prefix)/bin/ruby --disable-gems
|
26
|
+
endif
|
16
27
|
else
|
17
|
-
prefix := $(prefix)/ruby-1.9
|
28
|
+
prefix := $(prefix)/ruby-1.9.2
|
18
29
|
export PATH := $(prefix)/bin:$(PATH)
|
19
30
|
RUBY := $(prefix)/bin/ruby --disable-gems
|
20
31
|
endif
|
21
32
|
|
22
|
-
ifndef NO_ISOLATE
|
23
|
-
x := $(shell test -d t/ && \
|
24
|
-
PATH=$(PATH) NO_ISOLATE=T $(MAKE) -s isolate RUBY:="$(RUBY)")
|
25
|
-
endif
|
26
|
-
|
27
|
-
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
28
|
-
|
29
|
-
updir := $(shell git rev-parse --show-cdup)
|
30
|
-
gem_paths := $(wildcard $(updir)tmp/isolate/ruby-$(RUBY_VERSION)/gems/*-*)
|
31
|
-
|
32
|
-
ifdef gem_paths
|
33
|
-
sp :=
|
34
|
-
sp +=
|
35
|
-
export RUBYLIB := $(subst $(sp),:,$(addsuffix /lib,$(gem_paths)))
|
36
|
-
endif
|
37
|
-
|
38
33
|
# pipefail is THE reason to use bash (v3+) or never revisions of ksh93
|
39
34
|
# SHELL := /bin/bash -e -o pipefail
|
40
35
|
SHELL := /bin/ksh93 -e -o pipefail
|
@@ -43,37 +38,10 @@ SHELL := /bin/ksh93 -e -o pipefail
|
|
43
38
|
# TRACER = strace -f -o $(t_pfx).strace -s 100000
|
44
39
|
TRACER = /usr/bin/time -v -o $(t_pfx).time
|
45
40
|
|
46
|
-
full-test: test-18 test-
|
41
|
+
full-test: test-18 test-191 test-192
|
47
42
|
test-18:
|
48
43
|
$(MAKE) test 2>&1 | sed -e 's!^!1.8 !'
|
49
|
-
test-
|
50
|
-
$(MAKE) test r19=T 2>&1 | sed -e 's!^!1.9 !'
|
51
|
-
|
52
|
-
|
53
|
-
@awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' < $<
|
54
|
-
|
55
|
-
# publishes docs to http://rainbows.rubyforge.org
|
56
|
-
publish_doc:
|
57
|
-
-git set-file-times
|
58
|
-
$(RM) -r doc ChangeLog NEWS
|
59
|
-
$(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
|
60
|
-
$(MAKE) -s latest > doc/LATEST
|
61
|
-
find doc/images doc/js -type f | \
|
62
|
-
TZ=UTC xargs touch -d '1970-01-01 00:00:00' doc/rdoc.css
|
63
|
-
$(MAKE) doc_gz
|
64
|
-
chmod 644 $$(find doc -type f)
|
65
|
-
$(RSYNC) -av doc/ rubyforge.org:/var/www/gforge-projects/rainbows/
|
66
|
-
$(RSYNC) -av doc/ dcvr:/srv/rainbows/
|
67
|
-
git ls-files | xargs touch
|
68
|
-
|
69
|
-
# Create gzip variants of the same timestamp as the original so nginx
|
70
|
-
# "gzip_static on" can serve the gzipped versions directly.
|
71
|
-
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
72
|
-
doc_gz:
|
73
|
-
touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
|
74
|
-
for i in $(docs); do \
|
75
|
-
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
76
|
-
|
77
|
-
# launches any of the following shells with RUBYLIB set
|
78
|
-
irb sh bash ksh:
|
79
|
-
$@
|
44
|
+
test-191:
|
45
|
+
$(MAKE) test r19=T 2>&1 | sed -e 's!^!1.9.1 !'
|
46
|
+
test-192:
|
47
|
+
$(MAKE) test r192=T 2>&1 | sed -e 's!^!1.9.2 !'
|
data/rainbows.gemspec
CHANGED
@@ -44,6 +44,7 @@ Gem::Specification.new do |s|
|
|
44
44
|
# The HTTP parser in Unicorn <= 0.97.0 was vulnerable to a remote DoS
|
45
45
|
# when exposed directly to untrusted clients.
|
46
46
|
s.add_dependency(%q<unicorn>, [">= 0.97.1", "< 2.0.0"])
|
47
|
+
s.add_development_dependency(%q<isolate>, "~> 2.0.2")
|
47
48
|
|
48
49
|
# Unicorn already depends on Rack
|
49
50
|
# s.add_dependency(%q<rack>)
|
data/t/.gitignore
CHANGED
data/t/GNUmakefile
CHANGED
@@ -15,12 +15,7 @@ ifeq ($(RUBY_VERSION),)
|
|
15
15
|
$(error unable to detect RUBY_VERSION)
|
16
16
|
endif
|
17
17
|
|
18
|
-
|
19
|
-
RUBYLIB := $(rainbows_lib)
|
20
|
-
else
|
21
|
-
RUBYLIB := $(rainbows_lib):$(RUBYLIB)
|
22
|
-
endif
|
23
|
-
export RUBYLIB RUBY_VERSION
|
18
|
+
export RUBY_VERSION
|
24
19
|
|
25
20
|
models += WriterThreadPool
|
26
21
|
models += WriterThreadSpawn
|
@@ -99,15 +94,22 @@ $(deps):
|
|
99
94
|
@test -s $@.$(pid) || \
|
100
95
|
{ echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
|
101
96
|
@mv $@.$(pid) $@
|
102
|
-
|
97
|
+
|
98
|
+
libs := tmp/isolate/ruby-$(RUBY_VERSION)/.libs
|
99
|
+
$(libs): test_isolate.rb
|
100
|
+
mkdir -p $(@D)
|
101
|
+
$(RUBY) $< > $@+
|
102
|
+
mv $@+ $@
|
103
|
+
t_deps := $(libs) $(deps) test-bin-$(RUBY_VERSION)/rainbows trash/.gitignore
|
104
|
+
$(T): $(t_deps)
|
103
105
|
|
104
106
|
$(MODEL_T): export model = $(firstword $(subst ., ,$@))
|
105
107
|
$(MODEL_T): script = $(subst $(model).,,$@)
|
106
|
-
$(MODEL_T): trash/.gitignore
|
107
108
|
$(MODEL_T): export RUBY := $(RUBY)
|
108
109
|
$(MODEL_T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
|
109
|
-
$(MODEL_T):
|
110
|
-
|
110
|
+
$(MODEL_T): $(t_deps)
|
111
|
+
RUBYLIB=$(rainbows_lib):$$(cat $(libs)) \
|
112
|
+
$(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
|
111
113
|
|
112
114
|
trash/.gitignore:
|
113
115
|
mkdir -p $(@D)
|
data/t/README
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
= Rainbows! test suite
|
1
|
+
= \Rainbows! test suite - YES OUR TEST SUITE IS CONCURRENT!
|
2
2
|
|
3
3
|
These are all integration tests that start the server on random, unused
|
4
4
|
TCP ports or Unix domain sockets. They're all designed to run
|
5
5
|
concurrently with other tests to minimize test time, but tests may be
|
6
6
|
run independently as well.
|
7
7
|
|
8
|
-
We write our tests in Bourne shell because that's what we're
|
9
|
-
comfortable writing integration tests with.
|
8
|
+
We write our tests primarily in Bourne shell because that's what we're
|
9
|
+
comfortable writing integration tests with. This test suite is also
|
10
|
+
easily portable to non-Ruby web servers.
|
10
11
|
|
11
12
|
== Requirements
|
12
13
|
|
13
14
|
* {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
|
15
|
+
* {isolate ~> 2.0.2}[http://github.com/jbarnette/isolate] - for dependencies
|
14
16
|
* {GNU make}[http://www.gnu.org/software/make/]
|
15
17
|
* {socat}[http://www.dest-unreach.org/socat/]
|
16
|
-
* {curl}[http://curl.haxx.se/]
|
18
|
+
* {curl >= 7.18.0}[http://curl.haxx.se/]
|
17
19
|
* standard UNIX shell utilities (Bourne sh, awk, sed, grep, ...)
|
18
20
|
|
19
21
|
We do not use bashisms or any non-portable, non-POSIX constructs
|
@@ -24,6 +26,8 @@ with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
|
|
24
26
|
|
25
27
|
== Running Tests
|
26
28
|
|
29
|
+
*BSD users: use "gmake" instead of "make"
|
30
|
+
|
27
31
|
To run the entire test suite with 8 tests running at once:
|
28
32
|
|
29
33
|
make -j8
|
@@ -36,6 +40,10 @@ To run one individual test for one concurrency model:
|
|
36
40
|
|
37
41
|
make Revactor.t0000-simple-http.sh
|
38
42
|
|
43
|
+
To run all tests for one concurrency model:
|
44
|
+
|
45
|
+
make EventMachine
|
46
|
+
|
39
47
|
You may also increase verbosity by setting the "V" variable for
|
40
48
|
GNU make. To disable trapping of stdout/stderr:
|
41
49
|
|
@@ -44,3 +52,12 @@ GNU make. To disable trapping of stdout/stderr:
|
|
44
52
|
To enable the "set -x" option in shell scripts to trace execution
|
45
53
|
|
46
54
|
make V=2
|
55
|
+
|
56
|
+
== Performance
|
57
|
+
|
58
|
+
Some of the tests are rather I/O intensive due to the rewindability
|
59
|
+
requirement of "rack.input" in the Rack specification and the somewhat
|
60
|
+
complicated (but awesome!) nature of the TeeInput class leading us to
|
61
|
+
test it very heavily. If you have lots of RAM and a large tmpfs
|
62
|
+
partition, it is advisable to set your TMPDIR and also make the t/trash/
|
63
|
+
directory a symlink to a directory inside in your TMPDIR.
|
@@ -18,7 +18,8 @@ t_begin "setup and startup" && {
|
|
18
18
|
rainbows_wait_start
|
19
19
|
}
|
20
20
|
|
21
|
-
t_begin "read random blob size" && {
|
21
|
+
t_begin "read random blob sha1 and size" && {
|
22
|
+
random_blob_sha1=$(rsha1 < random_blob)
|
22
23
|
random_blob_size=$(wc -c < random_blob)
|
23
24
|
}
|
24
25
|
|
@@ -32,18 +33,18 @@ t_begin "read current RSS" && {
|
|
32
33
|
t_begin "send a series HTTP/1.1 requests sequentially" && {
|
33
34
|
for i in a b c
|
34
35
|
do
|
35
|
-
|
36
|
-
echo ok >$ok) |
|
37
|
-
test $
|
36
|
+
sha1=$( (curl -sSfv http://$listen/random_blob &&
|
37
|
+
echo ok >$ok) | rsha1)
|
38
|
+
test $sha1 = $random_blob_sha1
|
38
39
|
test xok = x$(cat $ok)
|
39
40
|
done
|
40
41
|
}
|
41
42
|
|
42
43
|
# this was a problem during development
|
43
44
|
t_begin "HTTP/1.0 test" && {
|
44
|
-
|
45
|
-
echo ok >$ok) |
|
46
|
-
test $
|
45
|
+
sha1=$( (curl -0 -sSfv http://$listen/random_blob &&
|
46
|
+
echo ok >$ok) | rsha1)
|
47
|
+
test $sha1 = $random_blob_sha1
|
47
48
|
test xok = x$(cat $ok)
|
48
49
|
}
|
49
50
|
|
@@ -54,7 +55,7 @@ t_begin "HTTP/0.9 test" && {
|
|
54
55
|
wait
|
55
56
|
echo ok > $ok
|
56
57
|
) | socat - TCP:$listen > $fifo
|
57
|
-
test $(cat $tmp) = $
|
58
|
+
test $(cat $tmp) = $random_blob_sha1
|
58
59
|
test xok = x$(cat $ok)
|
59
60
|
}
|
60
61
|
|
data/t/t0300-async_sinatra.sh
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
t_plan 7 "Sendfile middleware test for $model"
|
5
|
+
|
6
|
+
t_begin "configure and start" && {
|
7
|
+
rtmpfiles curl_out curl_err
|
8
|
+
rainbows_setup
|
9
|
+
|
10
|
+
# do not allow default middleware to be loaded since it may
|
11
|
+
# kill body#to_path
|
12
|
+
rainbows -E none -D t9001.ru -c $unicorn_config
|
13
|
+
rainbows_wait_start
|
14
|
+
}
|
15
|
+
|
16
|
+
t_begin "hit with curl" && {
|
17
|
+
curl -sSfv http://$listen/ > $curl_out 2> $curl_err
|
18
|
+
}
|
19
|
+
|
20
|
+
t_begin "kill server" && {
|
21
|
+
kill $rainbows_pid
|
22
|
+
}
|
23
|
+
|
24
|
+
t_begin "file matches source" && {
|
25
|
+
cmp $curl_out random_blob
|
26
|
+
}
|
27
|
+
|
28
|
+
t_begin "no errors in Rainbows! stderr" && {
|
29
|
+
check_stderr
|
30
|
+
}
|
31
|
+
|
32
|
+
t_begin "X-Sendfile does not show up in headers" && {
|
33
|
+
dbgcat curl_err
|
34
|
+
if grep -i x-sendfile $curl_err
|
35
|
+
then
|
36
|
+
die "X-Sendfile did show up!"
|
37
|
+
fi
|
38
|
+
}
|
39
|
+
|
40
|
+
t_begin "Content-Length is set correctly in headers" && {
|
41
|
+
expect=$(wc -c < random_blob)
|
42
|
+
grep "^< Content-Length: $expect" $curl_err
|
43
|
+
}
|
44
|
+
|
45
|
+
t_done
|
data/t/t9001.ru
ADDED
data/t/test-lib.sh
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
. ./my-tap-lib.sh
|
4
4
|
|
5
5
|
set +u
|
6
|
+
|
7
|
+
# sometimes we rely on http_proxy to avoid wasting bandwidth with Isolate
|
8
|
+
# and multiple Ruby versions
|
9
|
+
NO_PROXY=${UNICORN_TEST_ADDR-127.0.0.1}
|
10
|
+
export NO_PROXY
|
11
|
+
|
6
12
|
if test -z "$model"
|
7
13
|
then
|
8
14
|
# defaulting to Base would unfortunately fail some concurrency tests
|
@@ -21,16 +27,6 @@ export PATH
|
|
21
27
|
|
22
28
|
test -x $PWD/bin/unused_listen || die "must be run in 't' directory"
|
23
29
|
|
24
|
-
wait_for_pid () {
|
25
|
-
path="$1"
|
26
|
-
nr=30
|
27
|
-
while ! test -s "$path" && test $nr -gt 0
|
28
|
-
do
|
29
|
-
nr=$(($nr - 1))
|
30
|
-
sleep 1
|
31
|
-
done
|
32
|
-
}
|
33
|
-
|
34
30
|
# requires $1 and prints out the value of $2
|
35
31
|
require_check () {
|
36
32
|
lib=$1
|
data/t/test_isolate.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'isolate'
|
3
|
+
|
4
|
+
path = "tmp/isolate/ruby-#{RUBY_VERSION}"
|
5
|
+
opts = {
|
6
|
+
:system => false,
|
7
|
+
# we want "ruby-1.8.7" and not "ruby-1.8", so disable multiruby
|
8
|
+
:multiruby => false,
|
9
|
+
:path => path,
|
10
|
+
}
|
11
|
+
|
12
|
+
old_out = $stdout.dup
|
13
|
+
$stdout.reopen($stderr)
|
14
|
+
|
15
|
+
Isolate.now!(opts) do
|
16
|
+
gem 'rack', '1.1.0'
|
17
|
+
gem 'unicorn', '0.99.0'
|
18
|
+
|
19
|
+
gem 'iobuffer', '0.1.3'
|
20
|
+
gem 'rev', '0.3.2'
|
21
|
+
|
22
|
+
gem 'eventmachine', '0.12.10'
|
23
|
+
|
24
|
+
gem 'sinatra', '0.9.4'
|
25
|
+
gem 'async_sinatra', '0.1.5'
|
26
|
+
|
27
|
+
gem 'neverblock', '0.1.6.2'
|
28
|
+
|
29
|
+
if defined?(::Fiber)
|
30
|
+
gem 'case', '0.5'
|
31
|
+
gem 'revactor', '0.1.5'
|
32
|
+
gem 'rack-fiber_pool', '0.9.0'
|
33
|
+
end
|
34
|
+
|
35
|
+
gem 'cramp', '0.11'
|
36
|
+
end
|
37
|
+
|
38
|
+
$stdout.reopen(old_out)
|
39
|
+
puts Dir["#{path}/gems/*-*/lib"].map { |x| File.expand_path(x) }.join(':')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rainbows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.94.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rainbows! hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-06-04 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +25,16 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.0.0
|
27
27
|
version:
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: isolate
|
30
|
+
type: :development
|
31
|
+
version_requirement:
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ~>
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 2.0.2
|
37
|
+
version:
|
28
38
|
description: |-
|
29
39
|
\Rainbows! is an HTTP server for sleepy Rack applications. It is based on
|
30
40
|
Unicorn, but designed to handle applications that expect long
|
@@ -73,6 +83,7 @@ extra_rdoc_files:
|
|
73
83
|
- lib/rainbows/rev_thread_pool.rb
|
74
84
|
- lib/rainbows/rev_thread_spawn.rb
|
75
85
|
- lib/rainbows/revactor.rb
|
86
|
+
- lib/rainbows/sendfile.rb
|
76
87
|
- lib/rainbows/tee_input.rb
|
77
88
|
- lib/rainbows/thread_pool.rb
|
78
89
|
- lib/rainbows/thread_spawn.rb
|
@@ -86,6 +97,7 @@ extra_rdoc_files:
|
|
86
97
|
- TUNING
|
87
98
|
- vs_Unicorn
|
88
99
|
- Summary
|
100
|
+
- Test_Suite
|
89
101
|
files:
|
90
102
|
- .document
|
91
103
|
- .gitignore
|
@@ -110,9 +122,8 @@ files:
|
|
110
122
|
- Summary
|
111
123
|
- TODO
|
112
124
|
- TUNING
|
125
|
+
- Test_Suite
|
113
126
|
- bin/rainbows
|
114
|
-
- config/.gitignore
|
115
|
-
- config/isolate.rb
|
116
127
|
- lib/rainbows.rb
|
117
128
|
- lib/rainbows/actor_spawn.rb
|
118
129
|
- lib/rainbows/app_pool.rb
|
@@ -146,6 +157,7 @@ files:
|
|
146
157
|
- lib/rainbows/rev_thread_pool.rb
|
147
158
|
- lib/rainbows/rev_thread_spawn.rb
|
148
159
|
- lib/rainbows/revactor.rb
|
160
|
+
- lib/rainbows/sendfile.rb
|
149
161
|
- lib/rainbows/tee_input.rb
|
150
162
|
- lib/rainbows/thread_pool.rb
|
151
163
|
- lib/rainbows/thread_spawn.rb
|
@@ -231,7 +243,10 @@ files:
|
|
231
243
|
- t/t0700-app-deferred.sh
|
232
244
|
- t/t9000-rack-app-pool.sh
|
233
245
|
- t/t9000.ru
|
246
|
+
- t/t9001-sendfile-to-path.sh
|
247
|
+
- t/t9001.ru
|
234
248
|
- t/test-lib.sh
|
249
|
+
- t/test_isolate.rb
|
235
250
|
- t/worker-follows-master-to-death.ru
|
236
251
|
- vs_Unicorn
|
237
252
|
has_rdoc: true
|
data/config/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
/isolate_*.rb
|
data/config/isolate.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# this the default config file used by John Barnette's isolate gem
|
2
|
-
# you can create a config/isolate_local.rb file to override this
|
3
|
-
# See the corresponding tasks in Rakefile and GNUmakefile
|
4
|
-
# `rake isolate' or (faster in the unmodified case, `make isolate')
|
5
|
-
|
6
|
-
gem 'rack', '1.1.0'
|
7
|
-
gem 'unicorn', '0.99.0'
|
8
|
-
|
9
|
-
gem 'iobuffer', '0.1.3'
|
10
|
-
gem 'rev', '0.3.2'
|
11
|
-
|
12
|
-
gem 'eventmachine', '0.12.10'
|
13
|
-
|
14
|
-
gem 'sinatra', '0.9.4'
|
15
|
-
gem 'async_sinatra', '0.1.5'
|
16
|
-
|
17
|
-
gem 'neverblock', '0.1.6.2'
|
18
|
-
|
19
|
-
if defined?(::Fiber)
|
20
|
-
gem 'case', '0.5'
|
21
|
-
gem 'revactor', '0.1.5'
|
22
|
-
gem 'rack-fiber_pool', '0.9.0'
|
23
|
-
end
|
24
|
-
|
25
|
-
gem 'cramp', '0.11'
|