thin 0.6.2-x86-mswin32-60 → 0.6.3-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of thin might be problematic. Click here for more details.
- data/CHANGELOG +34 -1
- data/bin/thin +2 -164
- data/example/config.ru +4 -1
- data/example/ramaze.ru +12 -0
- data/example/thin.god +70 -66
- data/lib/rack/adapter/rails.rb +0 -3
- data/lib/rack/handler/thin.rb +6 -1
- data/lib/thin.rb +13 -4
- data/lib/thin/command.rb +9 -5
- data/lib/thin/connection.rb +5 -14
- data/lib/thin/connectors/connector.rb +61 -0
- data/lib/thin/connectors/tcp_server.rb +29 -0
- data/lib/thin/connectors/unix_server.rb +48 -0
- data/lib/thin/controllers/cluster.rb +115 -0
- data/lib/thin/controllers/controller.rb +85 -0
- data/lib/thin/controllers/service.rb +73 -0
- data/lib/thin/controllers/service.sh.erb +39 -0
- data/lib/thin/daemonizing.rb +9 -4
- data/lib/thin/headers.rb +2 -2
- data/lib/thin/runner.rb +166 -0
- data/lib/thin/server.rb +109 -89
- data/lib/thin/stats.html.erb +216 -0
- data/lib/thin/stats.rb +1 -249
- data/lib/thin/version.rb +10 -3
- data/lib/thin_parser.so +0 -0
- data/spec/command_spec.rb +0 -1
- data/spec/configs/cluster.yml +9 -0
- data/spec/configs/single.yml +9 -0
- data/spec/{cluster_spec.rb → controllers/cluster_spec.rb} +22 -10
- data/spec/controllers/controller_spec.rb +85 -0
- data/spec/controllers/service_spec.rb +51 -0
- data/spec/daemonizing_spec.rb +73 -9
- data/spec/request/mongrel_spec.rb +39 -0
- data/spec/{request_spec.rb → request/parser_spec.rb} +11 -143
- data/spec/request/perf_spec.rb +50 -0
- data/spec/request/processing_spec.rb +46 -0
- data/spec/runner_spec.rb +135 -0
- data/spec/server/builder_spec.rb +38 -0
- data/spec/server/stopping_spec.rb +45 -0
- data/spec/server/tcp_spec.rb +54 -0
- data/spec/server/unix_socket_spec.rb +30 -0
- data/spec/spec_helper.rb +49 -16
- data/tasks/announce.rake +7 -3
- data/tasks/email.erb +8 -18
- data/tasks/stats.rake +21 -8
- metadata +33 -7
- data/lib/thin/cluster.rb +0 -123
- data/spec/server_spec.rb +0 -200
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
describe Request, 'legacy Mongrel tests' do
|
5
|
+
it 'should raise error on large header names' do
|
6
|
+
proc { R("GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(1024))}: Test\r\n\r\n") }.
|
7
|
+
should raise_error(InvalidRequest)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should raise error on large mangled field values' do
|
11
|
+
proc { R("GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 100*1024+(1024), false)}\r\n\r\n") }.
|
12
|
+
should raise_error(InvalidRequest)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should raise error on big fat ugly headers' do
|
16
|
+
get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
|
17
|
+
get << "X-Test: test\r\n" * (80 * 1024)
|
18
|
+
proc { R(get) }.should raise_error(InvalidRequest)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should raise error on random garbage' do
|
22
|
+
proc { R("GET #{rand_data(1024, 1024+(1024), false)} #{rand_data(1024, 1024+(1024), false)}\r\n\r\n") }.
|
23
|
+
should raise_error(InvalidRequest)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def rand_data(min, max, readable=true)
|
28
|
+
count = min + ((rand(max)+1) *10).to_i
|
29
|
+
res = count.to_s + "/"
|
30
|
+
|
31
|
+
if readable
|
32
|
+
res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
|
33
|
+
else
|
34
|
+
res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
|
35
|
+
end
|
36
|
+
|
37
|
+
return res
|
38
|
+
end
|
39
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
|
-
require File.dirname(__FILE__) + '
|
2
|
-
require 'digest/sha1'
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
2
|
|
4
|
-
describe Request do
|
3
|
+
describe Request, 'parser' do
|
5
4
|
it 'should include basic headers' do
|
6
5
|
request = R("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
|
7
6
|
request.env['SERVER_PROTOCOL'].should == 'HTTP/1.1'
|
@@ -50,27 +49,6 @@ describe Request do
|
|
50
49
|
request.should validate_with_lint
|
51
50
|
end
|
52
51
|
|
53
|
-
it 'should raise error on large header names' do
|
54
|
-
proc { R("GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(1024))}: Test\r\n\r\n") }.
|
55
|
-
should raise_error(InvalidRequest)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'should raise error on large mangled field values' do
|
59
|
-
proc { R("GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 100*1024+(1024), false)}\r\n\r\n") }.
|
60
|
-
should raise_error(InvalidRequest)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'should raise error on big fat ugly headers' do
|
64
|
-
get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
|
65
|
-
get << "X-Test: test\r\n" * (80 * 1024)
|
66
|
-
proc { R(get) }.should raise_error(InvalidRequest)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'should raise error on random garbage' do
|
70
|
-
proc { R("GET #{rand_data(1024, 1024+(1024), false)} #{rand_data(1024, 1024+(1024), false)}\r\n\r\n") }.
|
71
|
-
should raise_error(InvalidRequest)
|
72
|
-
end
|
73
|
-
|
74
52
|
it 'should parse headers from GET request' do
|
75
53
|
request = R(<<-EOS, true)
|
76
54
|
GET / HTTP/1.1
|
@@ -89,10 +67,10 @@ EOS
|
|
89
67
|
request.env['SERVER_NAME'].should == 'localhost'
|
90
68
|
request.env['SERVER_PORT'].should == '3000'
|
91
69
|
request.env['HTTP_COOKIE'].should == 'mium=7'
|
92
|
-
|
70
|
+
|
93
71
|
request.should validate_with_lint
|
94
72
|
end
|
95
|
-
|
73
|
+
|
96
74
|
it 'should parse POST request with data' do
|
97
75
|
request = R(<<-EOS.chomp, true)
|
98
76
|
POST /postit HTTP/1.1
|
@@ -120,10 +98,10 @@ EOS
|
|
120
98
|
request.body.rewind
|
121
99
|
request.body.read.should == 'name=marc&email=macournoyer@gmail.com'
|
122
100
|
request.body.class.should == StringIO
|
123
|
-
|
101
|
+
|
124
102
|
request.should validate_with_lint
|
125
103
|
end
|
126
|
-
|
104
|
+
|
127
105
|
it 'should not fuck up on stupid fucked IE6 headers' do
|
128
106
|
body = <<-EOS
|
129
107
|
POST /codes/58-tracking-file-downloads-automatically-in-google-analytics-with-prototype/refactors HTTP/1.0
|
@@ -145,10 +123,10 @@ a
|
|
145
123
|
EOS
|
146
124
|
request = R(body, true)
|
147
125
|
request.env['HTTP_COOKIE2'].should == '$Version="1"'
|
148
|
-
|
126
|
+
|
149
127
|
request.should validate_with_lint
|
150
128
|
end
|
151
|
-
|
129
|
+
|
152
130
|
it 'shoud accept long query string' do
|
153
131
|
body = <<-EOS
|
154
132
|
GET /session?open_id_complete=1&nonce=ytPOcwni&nonce=ytPOcwni&openid.assoc_handle=%7BHMAC-SHA1%7D%7B473e38fe%7D%7BJTjJxA%3D%3D%7D&openid.identity=http%3A%2F%2Fmacournoyer.myopenid.com%2F&openid.mode=id_res&openid.op_endpoint=http%3A%2F%2Fwww.myopenid.com%2Fserver&openid.response_nonce=2007-11-29T01%3A19%3A35ZGA5FUU&openid.return_to=http%3A%2F%2Flocalhost%3A3000%2Fsession%3Fopen_id_complete%3D1%26nonce%3DytPOcwni%26nonce%3DytPOcwni&openid.sig=lPIRgwpfR6JAdGGnb0ZjcY%2FWjr8%3D&openid.signed=assoc_handle%2Cidentity%2Cmode%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned%2Csreg.email%2Csreg.nickname&openid.sreg.email=macournoyer%40yahoo.ca&openid.sreg.nickname=macournoyer HTTP/1.1
|
@@ -156,9 +134,9 @@ Host: localhost:3000
|
|
156
134
|
|
157
135
|
EOS
|
158
136
|
request = R(body, true)
|
159
|
-
|
137
|
+
|
160
138
|
request.env['QUERY_STRING'].should == 'open_id_complete=1&nonce=ytPOcwni&nonce=ytPOcwni&openid.assoc_handle=%7BHMAC-SHA1%7D%7B473e38fe%7D%7BJTjJxA%3D%3D%7D&openid.identity=http%3A%2F%2Fmacournoyer.myopenid.com%2F&openid.mode=id_res&openid.op_endpoint=http%3A%2F%2Fwww.myopenid.com%2Fserver&openid.response_nonce=2007-11-29T01%3A19%3A35ZGA5FUU&openid.return_to=http%3A%2F%2Flocalhost%3A3000%2Fsession%3Fopen_id_complete%3D1%26nonce%3DytPOcwni%26nonce%3DytPOcwni&openid.sig=lPIRgwpfR6JAdGGnb0ZjcY%2FWjr8%3D&openid.signed=assoc_handle%2Cidentity%2Cmode%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned%2Csreg.email%2Csreg.nickname&openid.sreg.email=macournoyer%40yahoo.ca&openid.sreg.nickname=macournoyer'
|
161
|
-
|
139
|
+
|
162
140
|
request.should validate_with_lint
|
163
141
|
end
|
164
142
|
|
@@ -171,119 +149,9 @@ Content-Length: 300
|
|
171
149
|
aye
|
172
150
|
EOS
|
173
151
|
request = R(body, true)
|
174
|
-
|
152
|
+
|
175
153
|
request.body.rewind
|
176
154
|
request.body.read.should == 'aye'
|
177
155
|
end
|
178
156
|
|
179
|
-
it 'should parse in chunks' do
|
180
|
-
request = Request.new
|
181
|
-
request.parse("POST / HTTP/1.1\r\n").should be_false
|
182
|
-
request.parse("Host: localhost\r\n").should be_false
|
183
|
-
request.parse("Content-Length: 9\r\n").should be_false
|
184
|
-
request.parse("\r\nvery ").should be_false
|
185
|
-
request.parse("cool").should be_true
|
186
|
-
|
187
|
-
request.env['CONTENT_LENGTH'].should == '9'
|
188
|
-
request.body.read.should == 'very cool'
|
189
|
-
request.should validate_with_lint
|
190
|
-
end
|
191
|
-
|
192
|
-
it "should move body to tempfile when too big" do
|
193
|
-
request = Request.new
|
194
|
-
request.parse("POST /postit HTTP/1.1\r\nContent-Length: #{Request::MAX_BODY*2}\r\n\r\n#{'X' * Request::MAX_BODY}")
|
195
|
-
request.parse('X' * Request::MAX_BODY)
|
196
|
-
|
197
|
-
request.body.size.should == Request::MAX_BODY * 2
|
198
|
-
request.should be_finished
|
199
|
-
request.body.class.should == Tempfile
|
200
|
-
end
|
201
|
-
|
202
|
-
it "should delete body tempfile when closing" do
|
203
|
-
body = 'X' * (Request::MAX_BODY + 1)
|
204
|
-
|
205
|
-
request = R(<<-EOS.chomp, true)
|
206
|
-
POST /postit HTTP/1.1
|
207
|
-
Content-Length: #{body.size}
|
208
|
-
|
209
|
-
#{body}
|
210
|
-
EOS
|
211
|
-
|
212
|
-
request.body.path.should_not be_nil
|
213
|
-
request.close
|
214
|
-
request.body.path.should be_nil
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should raise error when header is too big" do
|
218
|
-
big_headers = "X-Test: X\r\n" * (1024 * (80 + 32))
|
219
|
-
proc { R("GET / HTTP/1.1\r\n#{big_headers}\r\n") }.should raise_error(InvalidRequest)
|
220
|
-
end
|
221
|
-
|
222
|
-
it "should be faster then #{max_parsing_time = 0.0002} RubySeconds" do
|
223
|
-
body = <<-EOS.chomp.gsub("\n", "\r\n")
|
224
|
-
POST /postit HTTP/1.1
|
225
|
-
Host: localhost:3000
|
226
|
-
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
|
227
|
-
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
228
|
-
Accept-Language: en-us,en;q=0.5
|
229
|
-
Accept-Encoding: gzip,deflate
|
230
|
-
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
|
231
|
-
Keep-Alive: 300
|
232
|
-
Connection: keep-alive
|
233
|
-
Content-Type: text/html
|
234
|
-
Content-Length: 37
|
235
|
-
|
236
|
-
hi=there&name=marc&email=macournoyer@gmail.com
|
237
|
-
EOS
|
238
|
-
|
239
|
-
proc { R(body) }.should be_faster_then(max_parsing_time)
|
240
|
-
end
|
241
|
-
|
242
|
-
it 'should be comparable to Mongrel parser' do
|
243
|
-
require 'http11'
|
244
|
-
|
245
|
-
body = <<-EOS.chomp.gsub("\n", "\r\n")
|
246
|
-
POST /postit HTTP/1.1
|
247
|
-
Host: localhost:3000
|
248
|
-
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
|
249
|
-
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
250
|
-
Accept-Language: en-us,en;q=0.5
|
251
|
-
Accept-Encoding: gzip,deflate
|
252
|
-
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
|
253
|
-
Keep-Alive: 300
|
254
|
-
Connection: keep-alive
|
255
|
-
Content-Type: text/html
|
256
|
-
Content-Length: 37
|
257
|
-
|
258
|
-
hi=there&name=marc&email=macournoyer@gmail.com
|
259
|
-
EOS
|
260
|
-
|
261
|
-
tests = 10_000
|
262
|
-
puts
|
263
|
-
Benchmark.bmbm(10) do |results|
|
264
|
-
results.report("mongrel:") { tests.times { Mongrel::HttpParser.new.execute({}, body.dup, 0) } }
|
265
|
-
results.report("thin:") { tests.times { Thin::HttpParser.new.execute({'rack.input' => StringIO.new}, body.dup, 0) } }
|
266
|
-
end
|
267
|
-
end if ENV['BM']
|
268
|
-
|
269
|
-
private
|
270
|
-
def rand_data(min, max, readable=true)
|
271
|
-
count = min + ((rand(max)+1) *10).to_i
|
272
|
-
res = count.to_s + "/"
|
273
|
-
|
274
|
-
if readable
|
275
|
-
res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
|
276
|
-
else
|
277
|
-
res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
|
278
|
-
end
|
279
|
-
|
280
|
-
return res
|
281
|
-
end
|
282
|
-
|
283
|
-
def R(raw, convert_line_feed=false)
|
284
|
-
raw.gsub!("\n", "\r\n") if convert_line_feed
|
285
|
-
request = Thin::Request.new
|
286
|
-
request.parse(raw)
|
287
|
-
request
|
288
|
-
end
|
289
157
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Request, 'performance' do
|
4
|
+
it "should be faster then #{max_parsing_time = 0.0002} RubySeconds" do
|
5
|
+
body = <<-EOS.chomp.gsub("\n", "\r\n")
|
6
|
+
POST /postit HTTP/1.1
|
7
|
+
Host: localhost:3000
|
8
|
+
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
|
9
|
+
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
10
|
+
Accept-Language: en-us,en;q=0.5
|
11
|
+
Accept-Encoding: gzip,deflate
|
12
|
+
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
|
13
|
+
Keep-Alive: 300
|
14
|
+
Connection: keep-alive
|
15
|
+
Content-Type: text/html
|
16
|
+
Content-Length: 37
|
17
|
+
|
18
|
+
hi=there&name=marc&email=macournoyer@gmail.com
|
19
|
+
EOS
|
20
|
+
|
21
|
+
proc { R(body) }.should be_faster_then(max_parsing_time)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should be comparable to Mongrel parser' do
|
25
|
+
require 'http11'
|
26
|
+
|
27
|
+
body = <<-EOS.chomp.gsub("\n", "\r\n")
|
28
|
+
POST /postit HTTP/1.1
|
29
|
+
Host: localhost:3000
|
30
|
+
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
|
31
|
+
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
32
|
+
Accept-Language: en-us,en;q=0.5
|
33
|
+
Accept-Encoding: gzip,deflate
|
34
|
+
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
|
35
|
+
Keep-Alive: 300
|
36
|
+
Connection: keep-alive
|
37
|
+
Content-Type: text/html
|
38
|
+
Content-Length: 37
|
39
|
+
|
40
|
+
hi=there&name=marc&email=macournoyer@gmail.com
|
41
|
+
EOS
|
42
|
+
|
43
|
+
tests = 10_000
|
44
|
+
puts
|
45
|
+
Benchmark.bmbm(10) do |results|
|
46
|
+
results.report("mongrel:") { tests.times { Mongrel::HttpParser.new.execute({}, body.dup, 0) } }
|
47
|
+
results.report("thin:") { tests.times { Thin::HttpParser.new.execute({'rack.input' => StringIO.new}, body.dup, 0) } }
|
48
|
+
end
|
49
|
+
end if ENV['BM']
|
50
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Request, 'processing' do
|
4
|
+
it 'should parse in chunks' do
|
5
|
+
request = Request.new
|
6
|
+
request.parse("POST / HTTP/1.1\r\n").should be_false
|
7
|
+
request.parse("Host: localhost\r\n").should be_false
|
8
|
+
request.parse("Content-Length: 9\r\n").should be_false
|
9
|
+
request.parse("\r\nvery ").should be_false
|
10
|
+
request.parse("cool").should be_true
|
11
|
+
|
12
|
+
request.env['CONTENT_LENGTH'].should == '9'
|
13
|
+
request.body.read.should == 'very cool'
|
14
|
+
request.should validate_with_lint
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should move body to tempfile when too big" do
|
18
|
+
request = Request.new
|
19
|
+
request.parse("POST /postit HTTP/1.1\r\nContent-Length: #{Request::MAX_BODY*2}\r\n\r\n#{'X' * Request::MAX_BODY}")
|
20
|
+
request.parse('X' * Request::MAX_BODY)
|
21
|
+
|
22
|
+
request.body.size.should == Request::MAX_BODY * 2
|
23
|
+
request.should be_finished
|
24
|
+
request.body.class.should == Tempfile
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should delete body tempfile when closing" do
|
28
|
+
body = 'X' * (Request::MAX_BODY + 1)
|
29
|
+
|
30
|
+
request = R(<<-EOS.chomp, true)
|
31
|
+
POST /postit HTTP/1.1
|
32
|
+
Content-Length: #{body.size}
|
33
|
+
|
34
|
+
#{body}
|
35
|
+
EOS
|
36
|
+
|
37
|
+
request.body.path.should_not be_nil
|
38
|
+
request.close
|
39
|
+
request.body.path.should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should raise error when header is too big" do
|
43
|
+
big_headers = "X-Test: X\r\n" * (1024 * (80 + 32))
|
44
|
+
proc { R("GET / HTTP/1.1\r\n#{big_headers}\r\n") }.should raise_error(InvalidRequest)
|
45
|
+
end
|
46
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Runner do
|
4
|
+
it "should parse options" do
|
5
|
+
runner = Runner.new(%w(start --pid test.pid --port 5000))
|
6
|
+
|
7
|
+
runner.options[:pid].should == 'test.pid'
|
8
|
+
runner.options[:port].should == 5000
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should parse specified command" do
|
12
|
+
Runner.new(%w(start)).command.should == 'start'
|
13
|
+
Runner.new(%w(stop)).command.should == 'stop'
|
14
|
+
Runner.new(%w(restart)).command.should == 'restart'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should abort on unknow command" do
|
18
|
+
runner = Runner.new(%w(poop))
|
19
|
+
|
20
|
+
runner.should_receive(:abort)
|
21
|
+
runner.run!
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should exit on empty command" do
|
25
|
+
runner = Runner.new([])
|
26
|
+
|
27
|
+
runner.should_receive(:exit).with(1)
|
28
|
+
|
29
|
+
silence_stream(STDOUT) do
|
30
|
+
runner.run!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should use Controller when controlling a single server" do
|
35
|
+
runner = Runner.new(%w(start))
|
36
|
+
|
37
|
+
controller = mock('controller')
|
38
|
+
controller.should_receive(:start)
|
39
|
+
Controller.should_receive(:new).and_return(controller)
|
40
|
+
|
41
|
+
runner.run!
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should use Cluster controller when controlling multiple servers" do
|
45
|
+
runner = Runner.new(%w(start --servers 3))
|
46
|
+
|
47
|
+
controller = mock('cluster')
|
48
|
+
controller.should_receive(:start)
|
49
|
+
Cluster.should_receive(:new).and_return(controller)
|
50
|
+
|
51
|
+
runner.run!
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should default to single server controller" do
|
55
|
+
Runner.new(%w(start)).should_not be_a_cluster
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should consider as a cluster with :servers option" do
|
59
|
+
Runner.new(%w(start --servers 3)).should be_a_cluster
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should consider as a cluster with :only option" do
|
63
|
+
Runner.new(%w(start --only 3000)).should be_a_cluster
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe Runner, 'with config file' do
|
68
|
+
before do
|
69
|
+
@runner = Runner.new(%w(start --config spec/configs/cluster.yml))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should load options from file with :config option" do
|
73
|
+
@runner.send :load_options_from_config_file!
|
74
|
+
|
75
|
+
@runner.options[:environment].should == 'production'
|
76
|
+
@runner.options[:chdir].should == 'spec/rails_app'
|
77
|
+
@runner.options[:port].should == 5000
|
78
|
+
@runner.options[:servers].should == 3
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should change directory after loading config" do
|
82
|
+
@orig_dir = Dir.pwd
|
83
|
+
|
84
|
+
controller = mock('controller')
|
85
|
+
controller.should_receive(:respond_to?).with('start').and_return(true)
|
86
|
+
controller.should_receive(:start)
|
87
|
+
Cluster.should_receive(:new).and_return(controller)
|
88
|
+
expected_dir = File.expand_path('spec/rails_app')
|
89
|
+
|
90
|
+
begin
|
91
|
+
silence_stream(STDERR) do
|
92
|
+
@runner.run!
|
93
|
+
end
|
94
|
+
|
95
|
+
Dir.pwd.should == expected_dir
|
96
|
+
|
97
|
+
ensure
|
98
|
+
# any other spec using relative paths should work as expected
|
99
|
+
Dir.chdir(@orig_dir)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe Runner, "service" do
|
105
|
+
before do
|
106
|
+
Thin.stub!(:linux?).and_return(true)
|
107
|
+
|
108
|
+
@controller = mock('service')
|
109
|
+
Service.stub!(:new).and_return(@controller)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should use Service controller when controlling all servers" do
|
113
|
+
runner = Runner.new(%w(start --all))
|
114
|
+
|
115
|
+
@controller.should_receive(:start)
|
116
|
+
|
117
|
+
runner.run!
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should call install with arguments" do
|
121
|
+
runner = Runner.new(%w(install /etc/cool))
|
122
|
+
|
123
|
+
@controller.should_receive(:install).with('/etc/cool')
|
124
|
+
|
125
|
+
runner.run!
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should call install without arguments" do
|
129
|
+
runner = Runner.new(%w(install))
|
130
|
+
|
131
|
+
@controller.should_receive(:install).with()
|
132
|
+
|
133
|
+
runner.run!
|
134
|
+
end
|
135
|
+
end
|