zbatery 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.manifest CHANGED
@@ -27,8 +27,12 @@ t/bin/unused_listen
27
27
  t/bin/utee
28
28
  t/large-file-response.ru
29
29
  t/my-tap-lib.sh
30
+ t/sha1-random-size.ru
30
31
  t/sleep.ru
31
32
  t/t0003-reopen-logs.sh
32
33
  t/t0005-large-file-response.sh
34
+ t/t0020-large-sendfile-response.sh
35
+ t/t0103-rack-input-limit.sh
33
36
  t/test-lib.sh
37
+ t/test_isolate.rb
34
38
  zbatery.gemspec
data/ChangeLog CHANGED
@@ -1,5 +1,36 @@
1
- ChangeLog from git://git.bogomips.org/zbatery.git (v0.1.1..v0.2.1)
1
+ ChangeLog from git://git.bogomips.org/zbatery.git (v0.1.1..v0.3.0)
2
2
 
3
+ commit d4f095ed8ed0da4f190280eb957c14b3f5e9a2e9
4
+ Author: Eric Wong <normalperson@yhbt.net>
5
+ Date: Sat Jul 10 09:56:27 2010 +0000
6
+
7
+ Zbatery v0.3.0 - for newer Rainbows!
8
+
9
+ Rainbows! v0.95.0 is more awesome than v0.94.0, so we've updated
10
+ ourselves to use it and be more awesome as well!
11
+
12
+ commit 00f570d6c3363794ee4489fae17b05555b78b2cf
13
+ Author: Eric Wong <normalperson@yhbt.net>
14
+ Date: Sat Jul 10 09:55:20 2010 +0000
15
+
16
+ gemspec: small doc updates
17
+
18
+ commit 59d3b3f6318a85e4d68592e1f7b992dd54832aa0
19
+ Author: Eric Wong <normalperson@yhbt.net>
20
+ Date: Sat Jul 10 09:53:52 2010 +0000
21
+
22
+ add additional tests for newish Rainbows! features
23
+
24
+ commit bd6b2263869c271113577b88d526c7c2a6f1455d
25
+ Author: Eric Wong <normalperson@yhbt.net>
26
+ Date: Sat Jul 10 02:41:46 2010 -0700
27
+
28
+ updates for Rainbows! 0.95.0
29
+
30
+ Rainbows! 0.95.0 made some incompatible changes, so update
31
+ everything. Unfortunately we have to avoid subclassing here.
32
+ Tests use isolate now.
33
+
3
34
  commit 5764336aa3785af8a08be7ec7b40846ec139eb6c
4
35
  Author: Eric Wong <normalperson@yhbt.net>
5
36
  Date: Mon Apr 19 14:14:46 2010 -0700
data/GIT-VERSION-FILE CHANGED
@@ -1 +1 @@
1
- GIT_VERSION = 0.2.1
1
+ GIT_VERSION = 0.3.0
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.2.1.GIT
4
+ DEF_VER=v0.3.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,7 +1,9 @@
1
1
  # use GNU Make to run tests in parallel, and without depending on RubyGems
2
2
  all::
3
+ MRI = ruby
3
4
  RUBY = ruby
4
5
  RAKE = rake
6
+ RSYNC = rsync
5
7
  GIT_URL = git://git.bogomips.org/zbatery.git
6
8
 
7
9
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@@ -14,9 +16,11 @@ endif
14
16
  ifeq ($(RUBY_VERSION),)
15
17
  RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
16
18
  endif
19
+ RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
17
20
 
18
21
  base_bins := zbatery
19
22
  bins := $(addprefix bin/, $(base_bins))
23
+ man1_rdoc := $(addsuffix _1, $(base_bins))
20
24
  man1_bins := $(addsuffix .1, $(base_bins))
21
25
  man1_paths := $(addprefix man/man1/, $(man1_bins))
22
26
 
@@ -76,26 +80,52 @@ cgit_atom := http://git.bogomips.org/cgit/zbatery.git/atom/?h=master
76
80
  atom = <link rel="alternate" title="Atom feed" href="$(1)" \
77
81
  type="application/atom+xml"/>
78
82
 
79
- # using rdoc 2.4.1+
83
+ # using rdoc 2.5.x+
80
84
  doc: .document NEWS ChangeLog
81
- for i in $(man1_bins); do > $$i; done
82
- rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
85
+ for i in $(man1_rdoc); do echo > $$i; done
86
+ find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
87
+ rdoc -t "$(shell sed -ne '1s/^= //p' README)"
83
88
  install -m644 COPYING doc/COPYING
84
89
  install -m644 $(shell grep '^[A-Z]' .document) doc/
85
90
  $(MAKE) -C Documentation install-html install-man
86
91
  install -m644 $(man1_paths) doc/
87
92
  cd doc && for i in $(base_bins); do \
93
+ $(RM) 1.html $${i}.1.html; \
88
94
  sed -e '/"documentation">/r man1/'$$i'.1.html' \
89
- < $${i}_1.html > tmp && mv tmp $${i}_1.html; done
90
- $(RUBY) -i -p -e \
95
+ < $${i}_1.html > tmp && mv tmp $${i}_1.html; \
96
+ ln $${i}_1.html $${i}.1.html; \
97
+ done
98
+ $(MRI) -i -p -e \
91
99
  '$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
92
100
  doc/ChangeLog.html
93
- $(RUBY) -i -p -e \
101
+ $(MRI) -i -p -e \
94
102
  '$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
95
103
  doc/NEWS.html doc/README.html
96
104
  $(RAKE) -s news_atom > doc/NEWS.atom.xml
97
105
  cd doc && ln README.html tmp && mv tmp index.html
98
- $(RM) $(man1_bins)
106
+ $(RM) $(man1_rdoc)
107
+
108
+ # publishes docs to http://zbatery.bogomip.org/
109
+ publish_doc:
110
+ -git set-file-times
111
+ $(RM) -r doc ChangeLog NEWS
112
+ $(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
113
+ awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
114
+ < NEWS > doc/LATEST
115
+ find doc/images doc/js -type f | \
116
+ TZ=UTC xargs touch -d '1970-01-01 00:00:01' doc/rdoc.css
117
+ $(MAKE) doc_gz
118
+ chmod 644 $$(find doc -type f)
119
+ $(RSYNC) -av doc/ zbatery.bogomip.org:/srv/zbatery/
120
+ git ls-files | xargs touch
121
+
122
+ # Create gzip variants of the same timestamp as the original so nginx
123
+ # "gzip_static on" can serve the gzipped versions directly.
124
+ doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
125
+ doc_gz:
126
+ touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
127
+ for i in $(docs); do \
128
+ gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
99
129
 
100
130
  ifneq ($(VERSION),)
101
131
  rfproject := rainbows
@@ -152,11 +182,13 @@ release: verify package $(release_notes) $(release_changes)
152
182
  # make tgz release on RubyForge
153
183
  rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
154
184
  $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
155
- # push gem to Gemcutter
185
+ # push gem to RubyGems.org
156
186
  gem push $(pkggem)
157
187
  # in case of gem downloads from RubyForge releases page
158
188
  -rubyforge add_file \
159
189
  $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
190
+ $(RAKE) raa_update VERSION=$(VERSION)
191
+ $(RAKE) fm_update VERSION=$(VERSION)
160
192
  else
161
193
  gem install-gem: GIT-VERSION-FILE
162
194
  $(MAKE) $@ VERSION=$(GIT_VERSION)
data/NEWS CHANGED
@@ -1,3 +1,8 @@
1
+ === 0.3.0 / 2010-07-10 09:58 UTC
2
+
3
+ Rainbows! v0.95.0 is more awesome than v0.94.0, so we've updated
4
+ ourselves to use it and be more awesome as well!
5
+
1
6
  === 0.2.1 / 2010-04-19 21:16 UTC
2
7
 
3
8
  This release fixes a denial-of-service vector for deployments
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
+ autoload :Gem, 'rubygems'
2
3
 
3
4
  # most tasks are in the GNUmakefile which offers better parallelism
4
5
 
@@ -89,8 +90,6 @@ end
89
90
 
90
91
  desc "print release notes for Rubyforge"
91
92
  task :release_notes do
92
- require 'rubygems'
93
-
94
93
  spec = Gem::Specification.load('zbatery.gemspec')
95
94
  puts spec.description.strip
96
95
  puts ""
@@ -121,7 +120,6 @@ end
121
120
 
122
121
  desc "post to RAA"
123
122
  task :raa_update do
124
- require 'rubygems'
125
123
  require 'net/http'
126
124
  require 'net/netrc'
127
125
  rc = Net::Netrc.locate('zbatery-raa') or abort "~/.netrc not found"
@@ -156,3 +154,32 @@ task :raa_update do
156
154
  p res
157
155
  puts res.body
158
156
  end
157
+
158
+ desc "post to FM"
159
+ task :fm_update do
160
+ require 'tempfile'
161
+ require 'net/http'
162
+ require 'net/netrc'
163
+ require 'json'
164
+ version = ENV['VERSION'] or abort "VERSION= needed"
165
+ uri = URI.parse('http://freshmeat.net/projects/zbatery/releases.json')
166
+ rc = Net::Netrc.locate('zbatery-fm') or abort "~/.netrc not found"
167
+ api_token = rc.password
168
+ changelog = tags.find { |t| t[:tag] == "v#{version}" }[:body]
169
+ tmp = Tempfile.new('fm-changelog')
170
+ tmp.syswrite(changelog)
171
+ system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
172
+ changelog = File.read(tmp.path).strip
173
+
174
+ req = {
175
+ "auth_code" => api_token,
176
+ "release" => {
177
+ "tag_list" => "Stable",
178
+ "version" => version,
179
+ "changelog" => changelog,
180
+ },
181
+ }.to_json
182
+ Net::HTTP.start(uri.host, uri.port) do |http|
183
+ p http.post(uri.path, req, {'Content-Type'=>'application/json'})
184
+ end
185
+ end
data/lib/zbatery.rb CHANGED
@@ -1,17 +1,18 @@
1
1
  # -*- encoding: binary -*-
2
+ # :enddoc:
2
3
  require 'rainbows'
3
4
 
4
5
  module Zbatery
5
6
 
6
7
  # current version of Zbatery
7
- VERSION = "0.2.1"
8
+ VERSION = "0.3.0"
8
9
 
9
10
  class << self
10
11
 
11
12
  # runs the Zbatery HttpServer with +app+ and +options+ and does
12
13
  # not return until the server has exited.
13
14
  def run(app, options = {})
14
- HttpServer.new(app, options).start.join
15
+ Rainbows::HttpServer.new(app, options).start.join
15
16
  end
16
17
  end
17
18
 
@@ -32,7 +33,37 @@ module Zbatery
32
33
  # config files...
33
34
  FORK_HOOK = lambda { |_,_| }
34
35
 
35
- class HttpServer < Rainbows::HttpServer
36
+ end
37
+
38
+ # :stopdoc:
39
+ # override stuff we don't need or can't use portably
40
+ module Rainbows
41
+
42
+ module Base
43
+ # master == worker in our case
44
+ def init_worker_process(worker)
45
+ after_fork.call(self, worker)
46
+ worker.user(*user) if user.kind_of?(Array) && ! worker.switched
47
+ build_app! unless preload_app
48
+ Rainbows::Response.setup(self.class)
49
+ Rainbows::MaxBody.setup
50
+
51
+ # avoid spurious wakeups and blocking-accept() with 1.8 green threads
52
+ if RUBY_VERSION.to_f < 1.9
53
+ require "io/nonblock"
54
+ HttpServer::LISTENERS.each { |l| l.nonblock = true }
55
+ end
56
+
57
+ logger.info "Zbatery #@use worker_connections=#@worker_connections"
58
+ end
59
+ end
60
+
61
+ # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
62
+ def G.tick
63
+ alive
64
+ end
65
+
66
+ class HttpServer
36
67
 
37
68
  # this class is only used to avoid breaking Unicorn user switching
38
69
  class DeadIO
@@ -115,47 +146,20 @@ module Zbatery
115
146
 
116
147
  def before_fork
117
148
  hook = super
118
- hook == FORK_HOOK or
149
+ hook == Zbatery::FORK_HOOK or
119
150
  logger.warn "calling before_fork without forking"
120
151
  hook
121
152
  end
122
153
 
123
154
  def after_fork
124
155
  hook = super
125
- hook == FORK_HOOK or
156
+ hook == Zbatery::FORK_HOOK or
126
157
  logger.warn "calling after_fork without having forked"
127
158
  hook
128
159
  end
129
160
  end
130
161
  end
131
162
 
132
- # :stopdoc:
133
- # override stuff we don't need or can't use portably
134
- module Rainbows
135
-
136
- module Base
137
- # master == worker in our case
138
- def init_worker_process(worker)
139
- after_fork.call(self, worker)
140
- worker.user(*user) if user.kind_of?(Array) && ! worker.switched
141
- build_app! unless preload_app
142
-
143
- # avoid spurious wakeups and blocking-accept() with 1.8 green threads
144
- if RUBY_VERSION.to_f < 1.9
145
- require "io/nonblock"
146
- HttpServer::LISTENERS.each { |l| l.nonblock = true }
147
- end
148
-
149
- logger.info "Zbatery #@use worker_connections=#@worker_connections"
150
- end
151
- end
152
-
153
- # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
154
- def G.tick
155
- alive
156
- end
157
- end
158
-
159
163
  module Unicorn
160
164
 
161
165
  class Configurator
data/t/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
1
  /test-results-*
2
- /test-bin-*
2
+ /bin-*
3
3
  /random_blob
4
4
  /.dep+*
5
+ /trash
6
+ /tmp
data/t/GNUmakefile CHANGED
@@ -4,6 +4,7 @@ all::
4
4
 
5
5
  pid := $(shell echo $$PPID)
6
6
 
7
+ MRI = ruby
7
8
  RUBY = ruby
8
9
  zbatery_lib := $(shell cd ../lib && pwd)
9
10
  -include ../local.mk
@@ -15,13 +16,11 @@ ifeq ($(RUBY_VERSION),)
15
16
  $(error unable to detect RUBY_VERSION)
16
17
  endif
17
18
 
18
- ifeq ($(RUBYLIB),)
19
- RUBYLIB := $(zbatery_lib)
20
- else
21
- RUBYLIB := $(zbatery_lib):$(RUBYLIB)
22
- endif
23
- export RUBYLIB RUBY_VERSION
19
+ RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
20
+ export RUBY_VERSION RUBY_ENGINE
24
21
 
22
+ models += WriterThreadPool
23
+ models += WriterThreadSpawn
25
24
  models += ThreadPool
26
25
  models += ThreadSpawn
27
26
  models += Rev
@@ -30,13 +29,19 @@ models += NeverBlock
30
29
  models += RevThreadSpawn
31
30
  models += RevThreadPool
32
31
 
33
- rp := )
34
- ONENINE := $(shell case $(RUBY_VERSION) in 1.9.*$(rp) echo true;;esac)
35
- ifeq ($(ONENINE),true)
36
- models += Revactor
37
- models += FiberSpawn
38
- models += RevFiberSpawn
39
- models += FiberPool
32
+ ifeq ($(RUBY_ENGINE),ruby)
33
+ rp := )
34
+ ONENINE := $(shell case $(RUBY_VERSION) in 1.9.*$(rp) echo true;;esac)
35
+ ifeq ($(ONENINE),true)
36
+ models += Revactor
37
+ models += FiberSpawn
38
+ models += RevFiberSpawn
39
+ models += FiberPool
40
+ endif
41
+ endif
42
+
43
+ ifeq ($(RUBY_ENGINE),rbx)
44
+ models += ActorSpawn
40
45
  endif
41
46
  all_models := $(models) Base
42
47
 
@@ -63,7 +68,7 @@ $(all_models):
63
68
  all:: $(T)
64
69
 
65
70
  # can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
66
- t_pfx = trash/$@-$(RUBY_VERSION)
71
+ t_pfx = trash/$@-$(RUBY_ENGINE)-$(RUBY_VERSION)
67
72
  TEST_OPTS =
68
73
  # TRACER = strace -f -o $(t_pfx).strace -s 100000
69
74
  # TRACER = /usr/bin/time -o $(t_pfx).time
@@ -76,11 +81,13 @@ ifdef V
76
81
  endif
77
82
  endif
78
83
 
79
- test-bin-$(RUBY_VERSION)/zbatery: ruby_bin = $(shell which $(RUBY))
80
- test-bin-$(RUBY_VERSION)/zbatery: ../bin/zbatery
84
+ bindir := $(CURDIR)/bin-$(RUBY_ENGINE)-$(RUBY_VERSION)
85
+ bin_zbatery := $(bindir)/zbatery
86
+ $(bin_zbatery): ruby_bin = $(shell which $(RUBY))
87
+ $(bin_zbatery): ../bin/zbatery
81
88
  mkdir -p $(@D)
82
89
  install -m 755 $^ $@.$(pid)
83
- $(RUBY) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@.$(pid)
90
+ $(MRI) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@.$(pid)
84
91
  mv $@.$(pid) $@
85
92
 
86
93
  random_blob:
@@ -97,21 +104,28 @@ $(deps):
97
104
  @test -s $@.$(pid) || \
98
105
  { echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
99
106
  @mv $@.$(pid) $@
100
- dep: $(deps)
107
+
108
+ libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/.libs
109
+ $(libs): test_isolate.rb
110
+ mkdir -p $(@D)
111
+ $(RUBY) $< > $@+
112
+ mv $@+ $@
113
+ t_deps := $(libs) $(deps) $(bin_zbatery) trash/.gitignore
114
+ $(T): $(t_deps)
101
115
 
102
116
  $(MODEL_T): export model = $(firstword $(subst ., ,$@))
103
117
  $(MODEL_T): script = $(subst $(model).,,$@)
104
- $(MODEL_T): trash/.gitignore
105
118
  $(MODEL_T): export RUBY := $(RUBY)
106
- $(MODEL_T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
107
- $(MODEL_T): test-bin-$(RUBY_VERSION)/zbatery dep
108
- $(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
119
+ $(MODEL_T): export PATH := $(bindir):$(PATH)
120
+ $(MODEL_T): $(t_deps)
121
+ RUBYLIB=$(zbatery_lib):$$(cat $(libs)) \
122
+ $(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
109
123
 
110
124
  trash/.gitignore:
111
125
  mkdir -p $(@D)
112
126
  echo '*' > $@
113
127
 
114
128
  clean:
115
- $(RM) -r trash/*.log trash/*.code test-bin-$(RUBY_VERSION)
129
+ $(RM) -r trash/*.log trash/*.code $(bindir)
116
130
 
117
131
  .PHONY: $(T) clean
data/t/my-tap-lib.sh CHANGED
@@ -188,9 +188,10 @@ then
188
188
 
189
189
  (
190
190
  # use a subshell so seds are not waitable
191
- $SED -e 's/^/#: /' $t_stdout &
192
- $SED -e 's/^/#! /' $t_stderr &
191
+ $SED -e 's/^/#: /' < $t_stdout &
192
+ $SED -e 's/^/#! /' < $t_stderr &
193
193
  ) &
194
+ wait
194
195
  exec > $t_stdout 2> $t_stderr
195
196
  else
196
197
  exec > /dev/null 2> /dev/null
@@ -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
@@ -12,13 +12,14 @@ t_plan 10 "large file response slurp avoidance for $model"
12
12
 
13
13
  t_begin "setup and startup" && {
14
14
  rtmpfiles curl_out
15
- zbatery_setup $model
15
+ zbatery_setup $model 1
16
16
  # can't load Rack::Lint here since it'll cause Rev to slurp
17
17
  zbatery -E none -D large-file-response.ru -c $unicorn_config
18
18
  zbatery_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,29 +33,29 @@ 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
- size=$( (curl -sSfv http://$listen/random_blob &&
36
- echo ok >$ok) |wc -c)
37
- test $size -eq $random_blob_size
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
- size=$( (curl -0 -sSfv http://$listen/random_blob &&
45
- echo ok >$ok) |wc -c)
46
- test $size -eq $random_blob_size
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
 
50
51
  t_begin "HTTP/0.9 test" && {
51
52
  (
52
53
  printf 'GET /random_blob\r\n'
53
- cat $fifo > $tmp &
54
+ rsha1 < $fifo > $tmp &
54
55
  wait
55
56
  echo ok > $ok
56
57
  ) | socat - TCP:$listen > $fifo
57
- cmp $tmp random_blob
58
+ test $(cat $tmp) = $random_blob_sha1
58
59
  test xok = x$(cat $ok)
59
60
  }
60
61
 
@@ -72,8 +73,12 @@ t_begin "shutdown server" && {
72
73
 
73
74
  t_begin "compare RSS before and after" && {
74
75
  diff=$(( $rss_after - $rss_before ))
76
+
77
+ # default GC malloc limit in MRI:
78
+ fudge=$(( 8 * 1024 * 1024 ))
79
+
75
80
  t_info "test diff=$diff < orig=$random_blob_size"
76
- test $diff -le $random_blob_size
81
+ test $diff -le $(( $random_blob_size + $fudge ))
77
82
  }
78
83
 
79
84
  dbgcat r_err
@@ -0,0 +1,141 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ test -r random_blob || die "random_blob required, run with 'make $0'"
4
+ case $RUBY_ENGINE in
5
+ ruby) ;;
6
+ *)
7
+ t_info "skipping $T since it can't load the sendfile gem, yet"
8
+ exit 0
9
+ ;;
10
+ esac
11
+
12
+ t_plan 12 "large sendfile response for $model"
13
+
14
+ t_begin "setup and startup" && {
15
+ rtmpfiles curl_out a b c slow_a slow_b
16
+ zbatery_setup $model
17
+ echo 'require "sendfile"' >> $unicorn_config
18
+ echo 'def (::IO).copy_stream(*x); abort "NO"; end' >> $unicorn_config
19
+
20
+ # can't load Rack::Lint here since it clobbers body#to_path
21
+ zbatery -E none -D large-file-response.ru -c $unicorn_config
22
+ zbatery_wait_start
23
+ }
24
+
25
+ t_begin "read random blob sha1" && {
26
+ random_blob_sha1=$(rsha1 < random_blob)
27
+ three_sha1=$(cat random_blob random_blob random_blob | rsha1)
28
+ }
29
+
30
+ t_begin "send keepalive HTTP/1.1 requests in parallel" && {
31
+ for i in $a $b $c $slow_a $slow_b
32
+ do
33
+ curl -sSf http://$listen/random_blob \
34
+ http://$listen/random_blob \
35
+ http://$listen/random_blob | rsha1 > $i &
36
+ done
37
+ wait
38
+ for i in $a $b $c $slow_a $slow_b
39
+ do
40
+ test x$(cat $i) = x$three_sha1
41
+ done
42
+ }
43
+
44
+ t_begin "send a batch of abortive HTTP/1.1 requests in parallel" && {
45
+ for i in $a $b $c $slow_a $slow_b
46
+ do
47
+ rm -f $i
48
+ (
49
+ curl -sSf --max-time 5 --limit-rate 1K \
50
+ http://$listen/random_blob >/dev/null || echo ok > $i
51
+ ) &
52
+ done
53
+ wait
54
+ }
55
+
56
+ t_begin "all requests timed out" && {
57
+ for i in $a $b $c $slow_a $slow_b
58
+ do
59
+ test x$(cat $i) = xok
60
+ done
61
+ }
62
+
63
+ s='$NF ~ /worker_connections=[0-9]+/{gsub(/[^0-9]/,"",$3); print $3; exit}'
64
+ t_begin "check proc to ensure file is closed properly (Linux only)" && {
65
+ worker_pid=$(awk "$s" < $r_err)
66
+ test -n "$worker_pid"
67
+ if test -d /proc/$worker_pid/fd
68
+ then
69
+ if ls -l /proc/$worker_pid/fd | grep random_blob
70
+ then
71
+ t_info "random_blob file is open ($model)"
72
+ fi
73
+ else
74
+ t_info "/proc/$worker_pid/fd not found"
75
+ fi
76
+ }
77
+
78
+ t_begin "send a bunch of HTTP/1.1 requests in parallel" && {
79
+ (
80
+ curl -sSf --limit-rate 1M http://$listen/random_blob | \
81
+ rsha1 > $slow_a
82
+ ) &
83
+ (
84
+ curl -sSf --limit-rate 750K http://$listen/random_blob | \
85
+ rsha1 > $slow_b
86
+ ) &
87
+ for i in $a $b $c
88
+ do
89
+ (
90
+ curl -sSf http://$listen/random_blob | rsha1 > $i
91
+ ) &
92
+ done
93
+ wait
94
+ for i in $a $b $c $slow_a $slow_b
95
+ do
96
+ test x$(cat $i) = x$random_blob_sha1
97
+ done
98
+ }
99
+
100
+ # this was a problem during development
101
+ t_begin "HTTP/1.0 test" && {
102
+ sha1=$( (curl -0 -sSf http://$listen/random_blob &&
103
+ echo ok >$ok) | rsha1)
104
+ test $sha1 = $random_blob_sha1
105
+ test xok = x$(cat $ok)
106
+ }
107
+
108
+ t_begin "HTTP/0.9 test" && {
109
+ (
110
+ printf 'GET /random_blob\r\n'
111
+ rsha1 < $fifo > $tmp &
112
+ wait
113
+ echo ok > $ok
114
+ ) | socat - TCP:$listen > $fifo
115
+ test $(cat $tmp) = $random_blob_sha1
116
+ test xok = x$(cat $ok)
117
+ }
118
+
119
+ t_begin "check proc to ensure file is closed properly (Linux only)" && {
120
+ worker_pid=$(awk "$s" < $r_err)
121
+ test -n "$worker_pid"
122
+ if test -d /proc/$worker_pid/fd
123
+ then
124
+ if ls -l /proc/$worker_pid/fd | grep random_blob
125
+ then
126
+ t_info "random_blob file is open ($model)"
127
+ fi
128
+ else
129
+ t_info "/proc/$worker_pid/fd not found"
130
+ fi
131
+ }
132
+
133
+ t_begin "shutdown server" && {
134
+ kill -QUIT $zbatery_pid
135
+ }
136
+
137
+ dbgcat r_err
138
+
139
+ t_begin "check stderr" && check_stderr
140
+
141
+ t_done
@@ -0,0 +1,61 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ test -r random_blob || die "random_blob required, run with 'make $0'"
4
+ req_curl_chunked_upload_err_check
5
+
6
+ t_plan 6 "rack.input client_max_body_size default"
7
+
8
+ t_begin "setup and startup" && {
9
+ rtmpfiles curl_out curl_err cmbs_config
10
+ zbatery_setup $model
11
+ grep -v client_max_body_size < $unicorn_config > $cmbs_config
12
+ zbatery -D sha1-random-size.ru -c $cmbs_config
13
+ zbatery_wait_start
14
+ }
15
+
16
+ t_begin "regular request" && {
17
+ rm -f $ok
18
+ curl -vsSf -T random_blob -H Expect: \
19
+ http://$listen/ > $curl_out 2> $curl_err || > $ok
20
+ dbgcat curl_err
21
+ dbgcat curl_out
22
+ test -e $ok
23
+ }
24
+
25
+ t_begin "chunked request" && {
26
+ rm -f $ok
27
+ curl -vsSf -T- < random_blob -H Expect: \
28
+ http://$listen/ > $curl_out 2> $curl_err || > $ok
29
+ dbgcat curl_err
30
+ dbgcat curl_out
31
+ test -e $ok
32
+ }
33
+
34
+ t_begin "default size sha1 chunked" && {
35
+ blob_sha1=3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
36
+ rm -f $ok
37
+ > $r_err
38
+ dd if=/dev/zero bs=1048576 count=1 | \
39
+ curl -vsSf -T- -H Expect: \
40
+ http://$listen/ > $curl_out 2> $curl_err
41
+ test "$(cat $curl_out)" = $blob_sha1
42
+ dbgcat curl_err
43
+ dbgcat curl_out
44
+ }
45
+
46
+ t_begin "default size sha1 content-length" && {
47
+ blob_sha1=3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
48
+ rm -f $ok
49
+ dd if=/dev/zero bs=1048576 count=1 of=$tmp
50
+ curl -vsSf -T $tmp -H Expect: \
51
+ http://$listen/ > $curl_out 2> $curl_err
52
+ test "$(cat $curl_out)" = $blob_sha1
53
+ dbgcat curl_err
54
+ dbgcat curl_out
55
+ }
56
+
57
+ t_begin "shutdown" && {
58
+ kill $zbatery_pid
59
+ }
60
+
61
+ t_done
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
@@ -13,7 +19,7 @@ fi
13
19
  set -e
14
20
  RUBY="${RUBY-ruby}"
15
21
  RUBY_VERSION=${RUBY_VERSION-$($RUBY -e 'puts RUBY_VERSION')}
16
- t_pfx=$PWD/trash/$model.$T-$RUBY_VERSION
22
+ t_pfx=$PWD/trash/$model.$T-$RUBY_ENGINE-$RUBY_VERSION
17
23
  set -u
18
24
 
19
25
  PATH=$PWD/bin:$PATH
@@ -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
@@ -42,6 +38,19 @@ require_check () {
42
38
  fi
43
39
  }
44
40
 
41
+ skip_models () {
42
+ for i in "$@"
43
+ do
44
+ if test x"$model" != x"$i"
45
+ then
46
+ continue
47
+ fi
48
+ t_info "skipping $T since it is not compatible with $model"
49
+ exit 0
50
+ done
51
+ }
52
+
53
+
45
54
  # given a list of variable names, create temporary files and assign
46
55
  # the pathnames to those variables
47
56
  rtmpfiles () {
@@ -113,6 +122,7 @@ EOF
113
122
  # boxes and sometimes sleep 1s in tests
114
123
  kato=5
115
124
  echo 'Rainbows! do'
125
+ echo " client_max_body_size nil"
116
126
  if test $# -ge 1
117
127
  then
118
128
  echo " use :$1"
@@ -145,7 +155,22 @@ rsha1 () {
145
155
 
146
156
  # last resort, see comments in sha1sum.rb for reasoning
147
157
  test -n "$_cmd" || _cmd=sha1sum.rb
148
- expr "$($_cmd < random_blob)" : '\([a-f0-9]\{40\}\)'
158
+ expr "$($_cmd)" : '\([a-f0-9]\{40\}\)'
159
+ }
160
+
161
+ req_curl_chunked_upload_err_check () {
162
+ set +e
163
+ curl --version 2>/dev/null | awk '$1 == "curl" {
164
+ split($2, v, /\./)
165
+ if ((v[1] < 7) || (v[1] == 7 && v[2] < 18))
166
+ code = 1
167
+ }
168
+ END { exit(code) }'
169
+ if test $? -ne 0
170
+ then
171
+ t_info "curl >= 7.18.0 required for $T"
172
+ exit 0
173
+ fi
149
174
  }
150
175
 
151
176
  case $model in
data/t/test_isolate.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'isolate'
3
+ engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
4
+
5
+ path = "tmp/isolate/#{engine}-#{RUBY_VERSION}"
6
+ opts = {
7
+ :system => false,
8
+ # we want "ruby-1.8.7" and not "ruby-1.8", so disable multiruby
9
+ :multiruby => false,
10
+ :path => path,
11
+ }
12
+
13
+ old_out = $stdout.dup
14
+ $stdout.reopen($stderr)
15
+
16
+ Isolate.now!(opts) do
17
+ gem 'rack', '1.1.0'
18
+ gem 'unicorn', '1.1.0'
19
+ gem 'rainbows', '0.95.0'
20
+
21
+ if engine == "ruby"
22
+ gem 'sendfile', '1.0.0' # next Rubinius should support this
23
+
24
+ gem 'iobuffer', '0.1.3'
25
+ gem 'rev', '0.3.2'
26
+
27
+ gem 'eventmachine', '0.12.10'
28
+ gem 'sinatra', '1.0.0'
29
+ gem 'async_sinatra', '0.2.1'
30
+
31
+ gem 'neverblock', '0.1.6.2'
32
+ gem 'cramp', '0.11'
33
+ end
34
+
35
+ if defined?(::Fiber) && engine == "ruby"
36
+ gem 'case', '0.5'
37
+ gem 'revactor', '0.1.5'
38
+ gem 'rack-fiber_pool', '0.9.0'
39
+ end
40
+ end
41
+
42
+ $stdout.reopen(old_out)
43
+ puts Dir["#{path}/gems/*-*/lib"].map { |x| File.expand_path(x) }.join(':')
data/zbatery.gemspec CHANGED
@@ -34,13 +34,13 @@ Gem::Specification.new do |s|
34
34
  s.files = manifest
35
35
  s.homepage = %q{http://zbatery.bogomip.org/}
36
36
  s.summary = %q{Rack HTTP server without a fork stuck in it}
37
- s.rdoc_options = [ "-Na", "-t", "Zbatery - #{s.summary}" ]
37
+ s.rdoc_options = [ "-t", "Zbatery - #{s.summary}" ]
38
38
  s.require_paths = %w(lib)
39
39
  s.rubyforge_project = %q{rainbows}
40
40
 
41
41
  s.test_files = test_files
42
42
 
43
- # rainbows has a boatload of dependencies
43
+ # rainbows has a boatload of optional dependencies
44
44
  # required:
45
45
  # unicorn + rack
46
46
  # optional:
@@ -54,7 +54,8 @@ Gem::Specification.new do |s|
54
54
  # Unicorn were vulnerable to a remote DoS when exposed directly to
55
55
  # untrusted clients (a configuration only supported by Zbatery and Rainbows!,
56
56
  # Unicorn has never and will never be supported without trusted LAN clients.
57
- s.add_dependency(%q<rainbows>, [">= 0.91.1", "<= 1.0.0"])
57
+ s.add_dependency(%q<rainbows>, [">= 0.95.0", "<= 1.0.0"])
58
+ s.add_development_dependency(%q<isolate>, "~> 2.1.0")
58
59
 
59
60
  # s.licenses = %w(GPLv2 Ruby) # accessor not compatible with older RubyGems
60
61
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zbatery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Zbatery hackers
@@ -9,22 +15,49 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-04-19 00:00:00 +00:00
18
+ date: 2010-07-10 00:00:00 +00:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: rainbows
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
23
- version: 0.91.1
29
+ hash: 355
30
+ segments:
31
+ - 0
32
+ - 95
33
+ - 0
34
+ version: 0.95.0
24
35
  - - <=
25
36
  - !ruby/object:Gem::Version
37
+ hash: 23
38
+ segments:
39
+ - 1
40
+ - 0
41
+ - 0
26
42
  version: 1.0.0
27
- version:
43
+ type: :runtime
44
+ version_requirements: *id001
45
+ - !ruby/object:Gem::Dependency
46
+ name: isolate
47
+ prerelease: false
48
+ requirement: &id002 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ hash: 11
54
+ segments:
55
+ - 2
56
+ - 1
57
+ - 0
58
+ version: 2.1.0
59
+ type: :development
60
+ version_requirements: *id002
28
61
  description: |-
29
62
  Zbatery is an HTTP server for Rack applications on systems that either
30
63
  do not support fork(), or have no memory (nor need) to run the
@@ -75,10 +108,14 @@ files:
75
108
  - t/bin/utee
76
109
  - t/large-file-response.ru
77
110
  - t/my-tap-lib.sh
111
+ - t/sha1-random-size.ru
78
112
  - t/sleep.ru
79
113
  - t/t0003-reopen-logs.sh
80
114
  - t/t0005-large-file-response.sh
115
+ - t/t0020-large-sendfile-response.sh
116
+ - t/t0103-rack-input-limit.sh
81
117
  - t/test-lib.sh
118
+ - t/test_isolate.rb
82
119
  - zbatery.gemspec
83
120
  has_rdoc: true
84
121
  homepage: http://zbatery.bogomip.org/
@@ -86,27 +123,32 @@ licenses: []
86
123
 
87
124
  post_install_message:
88
125
  rdoc_options:
89
- - -Na
90
126
  - -t
91
127
  - Zbatery - Rack HTTP server without a fork stuck in it
92
128
  require_paths:
93
129
  - lib
94
130
  required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
95
132
  requirements:
96
133
  - - ">="
97
134
  - !ruby/object:Gem::Version
135
+ hash: 3
136
+ segments:
137
+ - 0
98
138
  version: "0"
99
- version:
100
139
  required_rubygems_version: !ruby/object:Gem::Requirement
140
+ none: false
101
141
  requirements:
102
142
  - - ">="
103
143
  - !ruby/object:Gem::Version
144
+ hash: 3
145
+ segments:
146
+ - 0
104
147
  version: "0"
105
- version:
106
148
  requirements: []
107
149
 
108
150
  rubyforge_project: rainbows
109
- rubygems_version: 1.3.5
151
+ rubygems_version: 1.3.7
110
152
  signing_key:
111
153
  specification_version: 3
112
154
  summary: Rack HTTP server without a fork stuck in it