zbatery 0.2.1 → 0.3.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/.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