rack 1.4.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (81) hide show
  1. data/COPYING +1 -1
  2. data/KNOWN-ISSUES +9 -0
  3. data/README.rdoc +72 -7
  4. data/Rakefile +18 -11
  5. data/SPEC +3 -1
  6. data/contrib/rack.png +0 -0
  7. data/contrib/rack.svg +150 -0
  8. data/contrib/rdoc.css +412 -0
  9. data/lib/rack/auth/basic.rb +1 -1
  10. data/lib/rack/auth/digest/nonce.rb +1 -1
  11. data/lib/rack/backports/uri/common_18.rb +14 -28
  12. data/lib/rack/backports/uri/common_192.rb +14 -17
  13. data/lib/rack/backports/uri/common_193.rb +29 -0
  14. data/lib/rack/body_proxy.rb +10 -0
  15. data/lib/rack/builder.rb +1 -1
  16. data/lib/rack/cascade.rb +11 -0
  17. data/lib/rack/commonlogger.rb +18 -5
  18. data/lib/rack/deflater.rb +5 -1
  19. data/lib/rack/directory.rb +1 -1
  20. data/lib/rack/etag.rb +6 -3
  21. data/lib/rack/file.rb +13 -4
  22. data/lib/rack/head.rb +1 -0
  23. data/lib/rack/lint.rb +3 -1
  24. data/lib/rack/lock.rb +3 -4
  25. data/lib/rack/mime.rb +1 -1
  26. data/lib/rack/mock.rb +3 -2
  27. data/lib/rack/multipart.rb +2 -2
  28. data/lib/rack/multipart/parser.rb +6 -4
  29. data/lib/rack/reloader.rb +1 -1
  30. data/lib/rack/request.rb +2 -4
  31. data/lib/rack/response.rb +2 -1
  32. data/lib/rack/server.rb +28 -2
  33. data/lib/rack/session/abstract/id.rb +5 -0
  34. data/lib/rack/session/cookie.rb +9 -0
  35. data/lib/rack/static.rb +90 -8
  36. data/lib/rack/utils.rb +17 -10
  37. data/rack.gemspec +3 -3
  38. data/test/builder/line.ru +1 -0
  39. data/test/cgi/assets/folder/test.js +1 -0
  40. data/test/cgi/assets/fonts/font.eot +1 -0
  41. data/test/cgi/assets/images/image.png +1 -0
  42. data/test/cgi/assets/index.html +1 -0
  43. data/test/cgi/assets/javascripts/app.js +1 -0
  44. data/test/cgi/assets/stylesheets/app.css +1 -0
  45. data/test/spec_auth_basic.rb +8 -0
  46. data/test/spec_auth_digest.rb +14 -0
  47. data/test/spec_body_proxy.rb +4 -0
  48. data/test/spec_builder.rb +7 -1
  49. data/test/spec_cascade.rb +8 -0
  50. data/test/spec_chunked.rb +6 -6
  51. data/test/spec_config.rb +0 -1
  52. data/test/spec_content_length.rb +26 -13
  53. data/test/spec_content_type.rb +15 -5
  54. data/test/spec_deflater.rb +35 -17
  55. data/test/spec_directory.rb +20 -1
  56. data/test/spec_etag.rb +29 -13
  57. data/test/spec_file.rb +42 -25
  58. data/test/spec_head.rb +25 -7
  59. data/test/spec_lobster.rb +20 -5
  60. data/test/spec_lock.rb +46 -21
  61. data/test/spec_logger.rb +2 -7
  62. data/test/spec_methodoverride.rb +21 -22
  63. data/test/spec_mock.rb +12 -7
  64. data/test/spec_multipart.rb +29 -0
  65. data/test/spec_nulllogger.rb +13 -2
  66. data/test/spec_recursive.rb +12 -9
  67. data/test/spec_request.rb +2 -2
  68. data/test/spec_response.rb +30 -0
  69. data/test/spec_runtime.rb +15 -5
  70. data/test/spec_sendfile.rb +11 -8
  71. data/test/spec_server.rb +47 -0
  72. data/test/spec_session_cookie.rb +68 -1
  73. data/test/spec_session_memcache.rb +10 -8
  74. data/test/spec_session_pool.rb +13 -10
  75. data/test/spec_showexceptions.rb +9 -4
  76. data/test/spec_showstatus.rb +10 -5
  77. data/test/spec_static.rb +85 -9
  78. data/test/spec_urlmap.rb +10 -10
  79. data/test/spec_utils.rb +14 -1
  80. data/test/static/another/index.html +1 -0
  81. metadata +21 -8
@@ -3,20 +3,24 @@ require 'rack/methodoverride'
3
3
  require 'rack/mock'
4
4
 
5
5
  describe Rack::MethodOverride do
6
+ def app
7
+ Rack::Lint.new(Rack::MethodOverride.new(lambda {|e|
8
+ [200, {"Content-Type" => "text/plain"}, []]
9
+ }))
10
+ end
11
+
6
12
  should "not affect GET requests" do
7
13
  env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET")
8
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
9
- req = app.call(env)
14
+ app.call env
10
15
 
11
- req.env["REQUEST_METHOD"].should.equal "GET"
16
+ env["REQUEST_METHOD"].should.equal "GET"
12
17
  end
13
18
 
14
19
  should "modify REQUEST_METHOD for POST requests when _method parameter is set" do
15
20
  env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=put")
16
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
17
- req = app.call(env)
21
+ app.call env
18
22
 
19
- req.env["REQUEST_METHOD"].should.equal "PUT"
23
+ env["REQUEST_METHOD"].should.equal "PUT"
20
24
  end
21
25
 
22
26
  should "modify REQUEST_METHOD for POST requests when X-HTTP-Method-Override is set" do
@@ -24,36 +28,32 @@ describe Rack::MethodOverride do
24
28
  :method => "POST",
25
29
  "HTTP_X_HTTP_METHOD_OVERRIDE" => "PATCH"
26
30
  )
27
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
28
- req = app.call(env)
31
+ app.call env
29
32
 
30
- req.env["REQUEST_METHOD"].should.equal "PATCH"
33
+ env["REQUEST_METHOD"].should.equal "PATCH"
31
34
  end
32
35
 
33
36
  should "not modify REQUEST_METHOD if the method is unknown" do
34
37
  env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=foo")
35
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
36
- req = app.call(env)
38
+ app.call env
37
39
 
38
- req.env["REQUEST_METHOD"].should.equal "POST"
40
+ env["REQUEST_METHOD"].should.equal "POST"
39
41
  end
40
42
 
41
43
  should "not modify REQUEST_METHOD when _method is nil" do
42
44
  env = Rack::MockRequest.env_for("/", :method => "POST", :input => "foo=bar")
43
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
44
- req = app.call(env)
45
+ app.call env
45
46
 
46
- req.env["REQUEST_METHOD"].should.equal "POST"
47
+ env["REQUEST_METHOD"].should.equal "POST"
47
48
  end
48
49
 
49
50
  should "store the original REQUEST_METHOD prior to overriding" do
50
51
  env = Rack::MockRequest.env_for("/",
51
52
  :method => "POST",
52
53
  :input => "_method=options")
53
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
54
- req = app.call(env)
54
+ app.call env
55
55
 
56
- req.env["rack.methodoverride.original_method"].should.equal "POST"
56
+ env["rack.methodoverride.original_method"].should.equal "POST"
57
57
  end
58
58
 
59
59
  should "not modify REQUEST_METHOD when given invalid multipart form data" do
@@ -63,11 +63,10 @@ content-disposition: form-data; name="huge"; filename="huge"\r
63
63
  EOF
64
64
  env = Rack::MockRequest.env_for("/",
65
65
  "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
66
- "CONTENT_LENGTH" => input.size,
66
+ "CONTENT_LENGTH" => input.size.to_s,
67
67
  :method => "POST", :input => input)
68
- app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
69
- req = app.call(env)
68
+ app.call env
70
69
 
71
- req.env["REQUEST_METHOD"].should.equal "POST"
70
+ env["REQUEST_METHOD"].should.equal "POST"
72
71
  end
73
72
  end
@@ -1,8 +1,9 @@
1
1
  require 'yaml'
2
+ require 'rack/lint'
2
3
  require 'rack/mock'
3
4
  require 'stringio'
4
5
 
5
- app = lambda { |env|
6
+ app = Rack::Lint.new(lambda { |env|
6
7
  req = Rack::Request.new(env)
7
8
 
8
9
  env["mock.postdata"] = env["rack.input"].read
@@ -11,10 +12,11 @@ app = lambda { |env|
11
12
  env["rack.errors"].flush
12
13
  end
13
14
 
14
- Rack::Response.new(env.to_yaml,
15
+ body = req.head? ? "" : env.to_yaml
16
+ Rack::Response.new(body,
15
17
  req.GET["status"] || 200,
16
18
  "Content-Type" => "text/yaml").finish
17
- }
19
+ })
18
20
 
19
21
  describe Rack::MockRequest do
20
22
  should "return a MockResponse" do
@@ -55,13 +57,16 @@ describe Rack::MockRequest do
55
57
  env = YAML.load(res.body)
56
58
  env["REQUEST_METHOD"].should.equal "PUT"
57
59
 
58
- res = Rack::MockRequest.new(app).delete("", :input => "foo")
60
+ res = Rack::MockRequest.new(app).patch("", :input => "foo")
59
61
  env = YAML.load(res.body)
60
- env["REQUEST_METHOD"].should.equal "DELETE"
62
+ env["REQUEST_METHOD"].should.equal "PATCH"
61
63
 
62
- res = Rack::MockRequest.new(app).head("", :input => "foo")
64
+ res = Rack::MockRequest.new(app).delete("", :input => "foo")
63
65
  env = YAML.load(res.body)
64
- env["REQUEST_METHOD"].should.equal "HEAD"
66
+ env["REQUEST_METHOD"].should.equal "DELETE"
67
+
68
+ Rack::MockRequest.env_for("/", :method => "HEAD")["REQUEST_METHOD"].
69
+ should.equal "HEAD"
65
70
 
66
71
  Rack::MockRequest.env_for("/", :method => "OPTIONS")["REQUEST_METHOD"].
67
72
  should.equal "OPTIONS"
@@ -360,4 +360,33 @@ EOF
360
360
  params.should.equal({"description"=>"Very very blue"})
361
361
  end
362
362
 
363
+ should "parse multipart upload with no content-length header" do
364
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
365
+ env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
366
+ env.delete 'CONTENT_LENGTH'
367
+ params = Rack::Multipart.parse_multipart(env)
368
+ params['profile']['bio'].should.include 'hello'
369
+ end
370
+
371
+ should "parse very long unquoted multipart file names" do
372
+ data = <<-EOF
373
+ --AaB03x\r
374
+ Content-Type: text/plain\r
375
+ Content-Disposition: attachment; name=file; filename=#{'long' * 100}\r
376
+ \r
377
+ contents\r
378
+ --AaB03x--\r
379
+ EOF
380
+
381
+ options = {
382
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
383
+ "CONTENT_LENGTH" => data.length.to_s,
384
+ :input => StringIO.new(data)
385
+ }
386
+ env = Rack::MockRequest.env_for("/", options)
387
+ params = Rack::Utils::Multipart.parse_multipart(env)
388
+
389
+ params["file"][:filename].should.equal('long' * 100)
390
+ end
391
+
363
392
  end
@@ -1,12 +1,23 @@
1
+ require 'enumerator'
2
+ require 'rack/lint'
3
+ require 'rack/mock'
1
4
  require 'rack/nulllogger'
2
5
 
3
6
  describe Rack::NullLogger do
7
+ ::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
8
+
4
9
  should "act as a noop logger" do
5
10
  app = lambda { |env|
6
11
  env['rack.logger'].warn "b00m"
7
12
  [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
8
13
  }
9
- logger = Rack::NullLogger.new(app)
10
- lambda{ logger.call({}) }.should.not.raise
14
+
15
+ logger = Rack::Lint.new(Rack::NullLogger.new(app))
16
+
17
+ res = logger.call(Rack::MockRequest.env_for)
18
+ res[0..1].should.equal [
19
+ 200, {'Content-Type' => 'text/plain'}
20
+ ]
21
+ Enumerator.new(res[2]).to_a.should.equal ["Hello, World!"]
11
22
  end
12
23
  end
@@ -1,3 +1,4 @@
1
+ require 'rack/lint'
1
2
  require 'rack/recursive'
2
3
  require 'rack/mock'
3
4
 
@@ -28,11 +29,14 @@ describe Rack::Recursive do
28
29
  @app4 = lambda { |env|
29
30
  raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
30
31
  }
32
+
33
+ def recursive(map)
34
+ Rack::Lint.new Rack::Recursive.new(Rack::URLMap.new(map))
35
+ end
31
36
 
32
37
  should "allow for subrequests" do
33
- res = Rack::MockRequest.new(Rack::Recursive.new(
34
- Rack::URLMap.new("/app1" => @app1,
35
- "/app2" => @app2))).
38
+ res = Rack::MockRequest.new(recursive("/app1" => @app1,
39
+ "/app2" => @app2)).
36
40
  get("/app2")
37
41
 
38
42
  res.should.be.ok
@@ -41,9 +45,8 @@ describe Rack::Recursive do
41
45
 
42
46
  should "raise error on requests not below the app" do
43
47
  app = Rack::URLMap.new("/app1" => @app1,
44
- "/app" => Rack::Recursive.new(
45
- Rack::URLMap.new("/1" => @app1,
46
- "/2" => @app2)))
48
+ "/app" => recursive("/1" => @app1,
49
+ "/2" => @app2))
47
50
 
48
51
  lambda {
49
52
  Rack::MockRequest.new(app).get("/app/2")
@@ -52,9 +55,9 @@ describe Rack::Recursive do
52
55
  end
53
56
 
54
57
  should "support forwarding" do
55
- app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
56
- "/app3" => @app3,
57
- "/app4" => @app4))
58
+ app = recursive("/app1" => @app1,
59
+ "/app3" => @app3,
60
+ "/app4" => @app4)
58
61
 
59
62
  res = Rack::MockRequest.new(app).get("/app3")
60
63
  res.should.be.ok
@@ -411,9 +411,9 @@ describe Rack::Request do
411
411
  req.cookies.should.equal 'foo' => 'bar'
412
412
  end
413
413
 
414
- should "raise any errors on every request" do
414
+ should "pass through non-uri escaped cookies as-is" do
415
415
  req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
416
- 2.times { proc { req.cookies }.should.raise(ArgumentError) }
416
+ req.cookies["foo"].should == "%"
417
417
  end
418
418
 
419
419
  should "parse cookies according to RFC 2109" do
@@ -280,4 +280,34 @@ describe Rack::Response do
280
280
  res.close
281
281
  res.body.should.be.closed
282
282
  end
283
+
284
+ it "calls close on #body when 204, 205, or 304" do
285
+ res = Rack::Response.new
286
+ res.body = StringIO.new
287
+ res.finish
288
+ res.body.should.not.be.closed
289
+
290
+ res.status = 204
291
+ _, _, b = res.finish
292
+ res.body.should.be.closed
293
+ b.should.not == res.body
294
+
295
+ res.body = StringIO.new
296
+ res.status = 205
297
+ _, _, b = res.finish
298
+ res.body.should.be.closed
299
+ b.should.not == res.body
300
+
301
+ res.body = StringIO.new
302
+ res.status = 304
303
+ _, _, b = res.finish
304
+ res.body.should.be.closed
305
+ b.should.not == res.body
306
+ end
307
+
308
+ it "wraps the body from #to_ary to prevent infinite loops" do
309
+ res = Rack::Response.new
310
+ res.finish.last.should.not.respond_to?(:to_ary)
311
+ lambda { res.finish.last.to_ary }.should.raise(NoMethodError)
312
+ end
283
313
  end
@@ -1,27 +1,37 @@
1
+ require 'rack/lint'
2
+ require 'rack/mock'
1
3
  require 'rack/runtime'
2
4
 
3
5
  describe Rack::Runtime do
6
+ def runtime_app(app, *args)
7
+ Rack::Lint.new Rack::Runtime.new(app, *args)
8
+ end
9
+
10
+ def request
11
+ Rack::MockRequest.env_for
12
+ end
13
+
4
14
  it "sets X-Runtime is none is set" do
5
15
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
6
- response = Rack::Runtime.new(app).call({})
16
+ response = runtime_app(app).call(request)
7
17
  response[1]['X-Runtime'].should =~ /[\d\.]+/
8
18
  end
9
19
 
10
20
  it "doesn't set the X-Runtime if it is already set" do
11
21
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
12
- response = Rack::Runtime.new(app).call({})
22
+ response = runtime_app(app).call(request)
13
23
  response[1]['X-Runtime'].should == "foobar"
14
24
  end
15
25
 
16
26
  should "allow a suffix to be set" do
17
27
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
18
- response = Rack::Runtime.new(app, "Test").call({})
28
+ response = runtime_app(app, "Test").call(request)
19
29
  response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
20
30
  end
21
31
 
22
32
  should "allow multiple timers to be set" do
23
33
  app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
24
- runtime = Rack::Runtime.new(app, "App")
34
+ runtime = runtime_app(app, "App")
25
35
 
26
36
  # wrap many times to guarantee a measurable difference
27
37
  100.times do |i|
@@ -29,7 +39,7 @@ describe Rack::Runtime do
29
39
  end
30
40
  runtime = Rack::Runtime.new(runtime, "All")
31
41
 
32
- response = runtime.call({})
42
+ response = runtime.call(request)
33
43
 
34
44
  response[1]['X-Runtime-App'].should =~ /[\d\.]+/
35
45
  response[1]['X-Runtime-All'].should =~ /[\d\.]+/
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+ require 'rack/lint'
1
3
  require 'rack/sendfile'
2
4
  require 'rack/mock'
3
5
 
@@ -9,8 +11,9 @@ end
9
11
 
10
12
  describe Rack::Sendfile do
11
13
  def sendfile_body
14
+ FileUtils.touch "/tmp/rack_sendfile"
12
15
  res = ['Hello World']
13
- def res.to_path ; "/tmp/hello.txt" ; end
16
+ def res.to_path ; "/tmp/rack_sendfile" ; end
14
17
  res
15
18
  end
16
19
 
@@ -19,7 +22,7 @@ describe Rack::Sendfile do
19
22
  end
20
23
 
21
24
  def sendfile_app(body=sendfile_body)
22
- Rack::Sendfile.new(simple_app(body))
25
+ Rack::Lint.new Rack::Sendfile.new(simple_app(body))
23
26
  end
24
27
 
25
28
  @request = Rack::MockRequest.new(sendfile_app)
@@ -40,8 +43,8 @@ describe Rack::Sendfile do
40
43
  request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
41
44
  response.should.be.ok
42
45
  response.body.should.be.empty
43
- response.headers['Content-Length'].should == '0'
44
- response.headers['X-Sendfile'].should.equal '/tmp/hello.txt'
46
+ response.headers['Content-Length'].should.equal '0'
47
+ response.headers['X-Sendfile'].should.equal '/tmp/rack_sendfile'
45
48
  end
46
49
  end
47
50
 
@@ -49,8 +52,8 @@ describe Rack::Sendfile do
49
52
  request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
50
53
  response.should.be.ok
51
54
  response.body.should.be.empty
52
- response.headers['Content-Length'].should == '0'
53
- response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt'
55
+ response.headers['Content-Length'].should.equal '0'
56
+ response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/rack_sendfile'
54
57
  end
55
58
  end
56
59
 
@@ -62,8 +65,8 @@ describe Rack::Sendfile do
62
65
  request headers do |response|
63
66
  response.should.be.ok
64
67
  response.body.should.be.empty
65
- response.headers['Content-Length'].should == '0'
66
- response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt'
68
+ response.headers['Content-Length'].should.equal '0'
69
+ response.headers['X-Accel-Redirect'].should.equal '/foo/bar/rack_sendfile'
67
70
  end
68
71
  end
69
72
 
@@ -10,6 +10,13 @@ describe Rack::Server do
10
10
  lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
11
11
  end
12
12
 
13
+ def with_stderr
14
+ old, $stderr = $stderr, StringIO.new
15
+ yield $stderr
16
+ ensure
17
+ $stderr = old
18
+ end
19
+
13
20
  it "overrides :config if :app is passed in" do
14
21
  server = Rack::Server.new(:app => "FOO")
15
22
  server.app.should == "FOO"
@@ -71,4 +78,44 @@ describe Rack::Server do
71
78
  open(pidfile) { |f| f.read.should.eql $$.to_s }
72
79
  end
73
80
 
81
+ should "check pid file presence and running process" do
82
+ pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
83
+ server = Rack::Server.new(:pid => pidfile)
84
+ server.send(:pidfile_process_status).should.eql :running
85
+ end
86
+
87
+ should "check pid file presence and dead process" do
88
+ dead_pid = `echo $$`.to_i
89
+ pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
90
+ server = Rack::Server.new(:pid => pidfile)
91
+ server.send(:pidfile_process_status).should.eql :dead
92
+ end
93
+
94
+ should "check pid file presence and exited process" do
95
+ pidfile = Tempfile.open('pidfile') { |f| break f }.path
96
+ ::File.delete(pidfile)
97
+ server = Rack::Server.new(:pid => pidfile)
98
+ server.send(:pidfile_process_status).should.eql :exited
99
+ end
100
+
101
+ should "check pid file presence and not owned process" do
102
+ pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
103
+ server = Rack::Server.new(:pid => pidfile)
104
+ server.send(:pidfile_process_status).should.eql :not_owned
105
+ end
106
+
107
+ should "inform the user about existing pidfiles with running processes" do
108
+ pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
109
+ server = Rack::Server.new(:pid => pidfile)
110
+ with_stderr do |err|
111
+ should.raise(SystemExit) do
112
+ server.start
113
+ end
114
+ err.rewind
115
+ output = err.read
116
+ output.should.match(/already running/)
117
+ output.should.include? pidfile
118
+ end
119
+ end
120
+
74
121
  end