summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2020-01-29 13:19:36 -0800
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2020-01-30 12:26:19 +1300
commit67c19ac90c5165ca596165dc926dc055d6ac5d9f (patch)
tree2cf0fe278306a07fab75daf5d5db956746a679c2
parentc982d1a6f63b785a2921dd91ba908e0b1a706591 (diff)
downloadrack-67c19ac90c5165ca596165dc926dc055d6ac5d9f.tar.gz
Add remaining covering tests
3378 / 3378 LOC (100.0%) covered
-rw-r--r--lib/rack/files.rb4
-rw-r--r--lib/rack/lobster.rb2
-rw-r--r--test/spec_auth_digest.rb14
-rw-r--r--test/spec_builder.rb13
-rw-r--r--test/spec_cascade.rb7
-rw-r--r--test/spec_chunked.rb13
-rw-r--r--test/spec_directory.rb26
-rw-r--r--test/spec_files.rb5
-rw-r--r--test/spec_multipart.rb29
-rw-r--r--test/spec_response.rb10
-rw-r--r--test/spec_rewindable_input.rb21
-rw-r--r--test/spec_show_exceptions.rb21
-rw-r--r--test/spec_show_status.rb18
-rw-r--r--test/spec_static.rb3
-rw-r--r--test/spec_urlmap.rb6
-rw-r--r--test/spec_utils.rb6
16 files changed, 192 insertions, 6 deletions
diff --git a/lib/rack/files.rb b/lib/rack/files.rb
index c50f2937..542db693 100644
--- a/lib/rack/files.rb
+++ b/lib/rack/files.rb
@@ -45,7 +45,11 @@ module Rack
available = begin
::File.file?(path) && ::File.readable?(path)
rescue SystemCallError
+ # Not sure in what conditions this exception can occur, but this
+ # is a safe way to handle such an error.
+ # :nocov:
false
+ # :nocov:
end
if available
diff --git a/lib/rack/lobster.rb b/lib/rack/lobster.rb
index 67345cec..b86a625d 100644
--- a/lib/rack/lobster.rb
+++ b/lib/rack/lobster.rb
@@ -61,8 +61,10 @@ module Rack
end
if $0 == __FILE__
+ # :nocov:
require_relative '../rack'
Rack::Server.start(
app: Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), Port: 9292
)
+ # :nocov:
end
diff --git a/test/spec_auth_digest.rb b/test/spec_auth_digest.rb
index f0fec5fc..6e32152f 100644
--- a/test/spec_auth_digest.rb
+++ b/test/spec_auth_digest.rb
@@ -256,4 +256,18 @@ describe Rack::Auth::Digest::MD5 do
app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
realm.must_equal app.realm
end
+
+ it 'Request#respond_to? and method_missing work as expected' do
+ req = Rack::Auth::Digest::Request.new({ 'HTTP_AUTHORIZATION' => 'a=b' })
+ req.respond_to?(:banana).must_equal false
+ req.respond_to?(:nonce).must_equal true
+ req.respond_to?(:a).must_equal true
+ req.a.must_equal 'b'
+ lambda { req.a(2) }.must_raise ArgumentError
+ end
+
+ it 'Nonce#fresh? should be the opposite of stale?' do
+ Rack::Auth::Digest::Nonce.new.fresh?.must_equal true
+ Rack::Auth::Digest::Nonce.new.stale?.must_equal false
+ end
end
diff --git a/test/spec_builder.rb b/test/spec_builder.rb
index 9fc492bd..424e3314 100644
--- a/test/spec_builder.rb
+++ b/test/spec_builder.rb
@@ -38,6 +38,19 @@ describe Rack::Builder do
Rack::MockRequest.new(app).get("/sub").body.to_s.must_equal 'sub'
end
+ it "supports use when mapping" do
+ app = builder_to_app do
+ map '/sub' do
+ use Rack::ContentLength
+ run lambda { |inner_env| [200, { "Content-Type" => "text/plain" }, ['sub']] }
+ end
+ use Rack::ContentLength
+ run lambda { |inner_env| [200, { "Content-Type" => "text/plain" }, ['root']] }
+ end
+ Rack::MockRequest.new(app).get("/").headers['Content-Length'].must_equal '4'
+ Rack::MockRequest.new(app).get("/sub").headers['Content-Length'].must_equal '3'
+ end
+
it "doesn't dupe env even when mapping" do
app = builder_to_app do
use NothingMiddleware, noop: :noop
diff --git a/test/spec_cascade.rb b/test/spec_cascade.rb
index eb14ece0..299aaad2 100644
--- a/test/spec_cascade.rb
+++ b/test/spec_cascade.rb
@@ -31,6 +31,13 @@ describe Rack::Cascade do
Rack::MockRequest.new(cascade).get("/cgi/../bla").must_be :not_found?
end
+ it "include? returns whether app is included" do
+ cascade = Rack::Cascade.new([app1, app2])
+ cascade.include?(app1).must_equal true
+ cascade.include?(app2).must_equal true
+ cascade.include?(app3).must_equal false
+ end
+
it "return 404 if empty" do
Rack::MockRequest.new(cascade([])).get('/').must_be :not_found?
end
diff --git a/test/spec_chunked.rb b/test/spec_chunked.rb
index b43803db..ceb7bdfb 100644
--- a/test/spec_chunked.rb
+++ b/test/spec_chunked.rb
@@ -54,6 +54,19 @@ describe Rack::Chunked do
response.body.must_equal "0\r\n\r\n"
end
+ it 'closes body' do
+ obj = Object.new
+ closed = false
+ def obj.each; yield 's' end
+ obj.define_singleton_method(:close) { closed = true }
+ app = lambda { |env| [200, { "Content-Type" => "text/plain" }, obj] }
+ response = Rack::MockRequest.new(Rack::Chunked.new(app)).get('/', @env)
+ response.headers.wont_include 'Content-Length'
+ response.headers['Transfer-Encoding'].must_equal 'chunked'
+ response.body.must_equal "1\r\ns\r\n0\r\n\r\n"
+ closed.must_equal true
+ end
+
it 'chunks encoded bodies properly' do
body = ["\uFFFEHello", " ", "World"].map {|t| t.encode("UTF-16LE") }
app = lambda { |env| [200, { "Content-Type" => "text/plain" }, body] }
diff --git a/test/spec_directory.rb b/test/spec_directory.rb
index e61a2a7c..9b913c85 100644
--- a/test/spec_directory.rb
+++ b/test/spec_directory.rb
@@ -40,6 +40,32 @@ describe Rack::Directory do
assert_match(res, /<html><head>/)
end
+ it "serve directory indices with bad symlinks" do
+ begin
+ File.symlink('foo', 'test/cgi/foo')
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
+ get("/cgi/")
+
+ res.must_be :ok?
+ assert_match(res, /<html><head>/)
+ ensure
+ File.delete('test/cgi/foo')
+ end
+ end
+
+ it "return 404 for unreadable directories" do
+ begin
+ File.write('test/cgi/unreadable', '')
+ File.chmod(0, 'test/cgi/unreadable')
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
+ get("/cgi/unreadable")
+
+ res.status.must_equal 404
+ ensure
+ File.delete('test/cgi/unreadable')
+ end
+ end
+
it "pass to app if file found" do
res = Rack::MockRequest.new(Rack::Lint.new(app)).
get("/cgi/test")
diff --git a/test/spec_files.rb b/test/spec_files.rb
index 8ee3c2c9..106019fe 100644
--- a/test/spec_files.rb
+++ b/test/spec_files.rb
@@ -45,6 +45,11 @@ describe Rack::Files do
assert_match(res, /ruby/)
end
+ it "does not serve directories" do
+ res = Rack::MockRequest.new(files(DOCROOT)).get("/cgi/assets")
+ res.status.must_equal 404
+ end
+
it "set Last-Modified header" do
res = Rack::MockRequest.new(files(DOCROOT)).get("/cgi/test")
diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb
index 8cd3664f..717e0dc8 100644
--- a/test/spec_multipart.rb
+++ b/test/spec_multipart.rb
@@ -32,6 +32,17 @@ describe Rack::Multipart do
params["text/plain; charset=US-ASCII"].must_equal ["contents"]
end
+ it "parse multipart content when content type present but disposition is not when using IO" do
+ read, write = IO.pipe
+ env = multipart_fixture(:content_type_and_no_disposition)
+ write.write(env[:input].read)
+ write.close
+ env[:input] = read
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_disposition))
+ params = Rack::Multipart.parse_multipart(env)
+ params["text/plain; charset=US-ASCII"].must_equal ["contents"]
+ end
+
it "parse multipart content when content type present but filename is not" do
env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
params = Rack::Multipart.parse_multipart(env)
@@ -521,7 +532,7 @@ Content-Type: image/jpeg\r
params["files"][:tempfile].read.must_equal "contents"
end
- it "builds nested multipart body" do
+ it "builds nested multipart body using array" do
files = Rack::Multipart::UploadedFile.new(multipart_file("file1.txt"))
data = Rack::Multipart.build_multipart("people" => [{ "submit-name" => "Larry", "files" => files }])
@@ -537,6 +548,22 @@ Content-Type: image/jpeg\r
params["people"][0]["files"][:tempfile].read.must_equal "contents"
end
+ it "builds nested multipart body using hash" do
+ files = Rack::Multipart::UploadedFile.new(multipart_file("file1.txt"))
+ data = Rack::Multipart.build_multipart("people" => { "foo" => { "submit-name" => "Larry", "files" => files } })
+
+ options = {
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
+ "CONTENT_LENGTH" => data.length.to_s,
+ :input => StringIO.new(data)
+ }
+ env = Rack::MockRequest.env_for("/", options)
+ params = Rack::Multipart.parse_multipart(env)
+ params["people"]["foo"]["submit-name"].must_equal "Larry"
+ params["people"]["foo"]["files"][:filename].must_equal "file1.txt"
+ params["people"]["foo"]["files"][:tempfile].read.must_equal "contents"
+ end
+
it "builds multipart body from StringIO" do
files = Rack::Multipart::UploadedFile.new(io: StringIO.new('foo'), filename: 'bar.txt')
data = Rack::Multipart.build_multipart("submit-name" => "Larry", "files" => files)
diff --git a/test/spec_response.rb b/test/spec_response.rb
index 999f4828..c27112fb 100644
--- a/test/spec_response.rb
+++ b/test/spec_response.rb
@@ -512,12 +512,14 @@ describe Rack::Response do
it "provide access to the HTTP headers" do
res = Rack::Response.new
- res["Content-Type"] = "text/yaml"
+ res["Content-Type"] = "text/yaml; charset=UTF-8"
res.must_include "Content-Type"
- res.headers["Content-Type"].must_equal "text/yaml"
- res["Content-Type"].must_equal "text/yaml"
- res.content_type.must_equal "text/yaml"
+ res.headers["Content-Type"].must_equal "text/yaml; charset=UTF-8"
+ res["Content-Type"].must_equal "text/yaml; charset=UTF-8"
+ res.content_type.must_equal "text/yaml; charset=UTF-8"
+ res.media_type.must_equal "text/yaml"
+ res.media_type_params.must_equal "charset" => "UTF-8"
res.content_length.must_be_nil
res.location.must_be_nil
end
diff --git a/test/spec_rewindable_input.rb b/test/spec_rewindable_input.rb
index 64d56673..4efe7dc2 100644
--- a/test/spec_rewindable_input.rb
+++ b/test/spec_rewindable_input.rb
@@ -77,6 +77,27 @@ module RewindableTest
tempfile.must_be :closed?
end
+ it "handle partial writes to tempfile" do
+ def @rio.filesystem_has_posix_semantics?
+ def @rewindable_io.write(buffer)
+ super(buffer[0..1])
+ end
+ super
+ end
+ @rio.read(1)
+ tempfile = @rio.instance_variable_get(:@rewindable_io)
+ @rio.close
+ tempfile.must_be :closed?
+ end
+
+ it "close the underlying tempfile upon calling #close when not using posix semantics" do
+ def @rio.filesystem_has_posix_semantics?; false end
+ @rio.read(1)
+ tempfile = @rio.instance_variable_get(:@rewindable_io)
+ @rio.close
+ tempfile.must_be :closed?
+ end
+
it "be possible to call #close when no data has been buffered yet" do
@rio.close.must_be_nil
end
diff --git a/test/spec_show_exceptions.rb b/test/spec_show_exceptions.rb
index 82924391..441599b4 100644
--- a/test/spec_show_exceptions.rb
+++ b/test/spec_show_exceptions.rb
@@ -26,6 +26,27 @@ describe Rack::ShowExceptions do
assert_match(res, /No POST data/)
end
+ it "handles exceptions with backtrace lines for files that are not readable" do
+ res = nil
+
+ req = Rack::MockRequest.new(
+ show_exceptions(
+ lambda{|env| raise RuntimeError, "foo", ["nonexistant.rb:2:in `a': adf (RuntimeError)", "bad-backtrace"] }
+ ))
+
+ res = req.get("/", "HTTP_ACCEPT" => "text/html")
+
+ res.must_be :server_error?
+ res.status.must_equal 500
+
+ assert_includes(res.body, 'RuntimeError')
+ assert_includes(res.body, 'ShowExceptions')
+ assert_includes(res.body, 'No GET data')
+ assert_includes(res.body, 'No POST data')
+ assert_includes(res.body, 'nonexistant.rb')
+ refute_includes(res.body, 'bad-backtrace')
+ end
+
it "handles invalid POST data exceptions" do
res = nil
diff --git a/test/spec_show_status.rb b/test/spec_show_status.rb
index 2c6a2244..486076b8 100644
--- a/test/spec_show_status.rb
+++ b/test/spec_show_status.rb
@@ -40,6 +40,24 @@ describe Rack::ShowStatus do
assert_match(res, /too meta/)
end
+ it "let the app provide additional information with non-String details" do
+ req = Rack::MockRequest.new(
+ show_status(
+ lambda{|env|
+ env["rack.showstatus.detail"] = ['gone too meta.']
+ [404, { "Content-Type" => "text/plain", "Content-Length" => "0" }, []]
+ }))
+
+ res = req.get("/", lint: true)
+ res.must_be :not_found?
+ res.wont_be_empty
+
+ res["Content-Type"].must_equal "text/html"
+ assert_includes(res.body, '404')
+ assert_includes(res.body, 'Not Found')
+ assert_includes(res.body, '[&quot;gone too meta.&quot;]')
+ end
+
it "escape error" do
detail = "<script>alert('hi \"')</script>"
req = Rack::MockRequest.new(
diff --git a/test/spec_static.rb b/test/spec_static.rb
index 1f3ece9c..2a94d68c 100644
--- a/test/spec_static.rb
+++ b/test/spec_static.rb
@@ -159,7 +159,8 @@ describe Rack::Static do
[%w(png jpg), { 'Cache-Control' => 'public, max-age=300' }],
['/cgi/assets/folder/', { 'Cache-Control' => 'public, max-age=400' }],
['cgi/assets/javascripts', { 'Cache-Control' => 'public, max-age=500' }],
- [/\.(css|erb)\z/, { 'Cache-Control' => 'public, max-age=600' }]
+ [/\.(css|erb)\z/, { 'Cache-Control' => 'public, max-age=600' }],
+ [false, { 'Cache-Control' => 'public, max-age=600' }]
] }
it "supports header rule :all" do
diff --git a/test/spec_urlmap.rb b/test/spec_urlmap.rb
index b29b829b..29af5587 100644
--- a/test/spec_urlmap.rb
+++ b/test/spec_urlmap.rb
@@ -242,4 +242,10 @@ describe Rack::URLMap do
res["X-PathInfo"].must_equal "/"
res["X-ScriptName"].must_equal ""
end
+
+ it "not allow locations unless they start with /" do
+ lambda do
+ Rack::URLMap.new("a/" => lambda { |env| })
+ end.must_raise ArgumentError
+ end
end
diff --git a/test/spec_utils.rb b/test/spec_utils.rb
index 5064be43..890cf710 100644
--- a/test/spec_utils.rb
+++ b/test/spec_utils.rb
@@ -104,6 +104,12 @@ describe Rack::Utils do
Rack::Utils.parse_query(",foo=bar;,", ";,").must_equal "foo" => "bar"
end
+ it "parse query strings correctly using arrays" do
+ Rack::Utils.parse_query("a[]=1").must_equal "a[]" => "1"
+ Rack::Utils.parse_query("a[]=1&a[]=2").must_equal "a[]" => ["1", "2"]
+ Rack::Utils.parse_query("a[]=1&a[]=2&a[]=3").must_equal "a[]" => ["1", "2", "3"]
+ end
+
it "not create infinite loops with cycle structures" do
ex = { "foo" => nil }
ex["foo"] = ex