corntrace-rack-contrib 1.0.2

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.
Files changed (72) hide show
  1. data/AUTHORS +26 -0
  2. data/COPYING +18 -0
  3. data/README.rdoc +87 -0
  4. data/Rakefile +89 -0
  5. data/lib/rack/contrib/accept_format.rb +46 -0
  6. data/lib/rack/contrib/access.rb +85 -0
  7. data/lib/rack/contrib/backstage.rb +20 -0
  8. data/lib/rack/contrib/bounce_favicon.rb +16 -0
  9. data/lib/rack/contrib/callbacks.rb +37 -0
  10. data/lib/rack/contrib/config.rb +16 -0
  11. data/lib/rack/contrib/cookies.rb +50 -0
  12. data/lib/rack/contrib/csshttprequest.rb +39 -0
  13. data/lib/rack/contrib/deflect.rb +137 -0
  14. data/lib/rack/contrib/evil.rb +12 -0
  15. data/lib/rack/contrib/expectation_cascade.rb +32 -0
  16. data/lib/rack/contrib/garbagecollector.rb +14 -0
  17. data/lib/rack/contrib/host_meta.rb +47 -0
  18. data/lib/rack/contrib/jsonp.rb +78 -0
  19. data/lib/rack/contrib/lighttpd_script_name_fix.rb +16 -0
  20. data/lib/rack/contrib/locale.rb +31 -0
  21. data/lib/rack/contrib/mailexceptions.rb +120 -0
  22. data/lib/rack/contrib/nested_params.rb +143 -0
  23. data/lib/rack/contrib/not_found.rb +18 -0
  24. data/lib/rack/contrib/post_body_content_type_parser.rb +40 -0
  25. data/lib/rack/contrib/proctitle.rb +30 -0
  26. data/lib/rack/contrib/profiler.rb +108 -0
  27. data/lib/rack/contrib/relative_redirect.rb +44 -0
  28. data/lib/rack/contrib/response_cache.rb +59 -0
  29. data/lib/rack/contrib/response_headers.rb +24 -0
  30. data/lib/rack/contrib/route_exceptions.rb +49 -0
  31. data/lib/rack/contrib/runtime.rb +31 -0
  32. data/lib/rack/contrib/sendfile.rb +142 -0
  33. data/lib/rack/contrib/signals.rb +63 -0
  34. data/lib/rack/contrib/simple_endpoint.rb +81 -0
  35. data/lib/rack/contrib/static_cache.rb +93 -0
  36. data/lib/rack/contrib/time_zone.rb +25 -0
  37. data/lib/rack/contrib.rb +39 -0
  38. data/rack-contrib.gemspec +104 -0
  39. data/test/404.html +1 -0
  40. data/test/Maintenance.html +1 -0
  41. data/test/documents/test +1 -0
  42. data/test/mail_settings.rb +12 -0
  43. data/test/spec_rack_accept_format.rb +72 -0
  44. data/test/spec_rack_access.rb +154 -0
  45. data/test/spec_rack_backstage.rb +26 -0
  46. data/test/spec_rack_callbacks.rb +65 -0
  47. data/test/spec_rack_config.rb +22 -0
  48. data/test/spec_rack_contrib.rb +8 -0
  49. data/test/spec_rack_cookies.rb +56 -0
  50. data/test/spec_rack_csshttprequest.rb +66 -0
  51. data/test/spec_rack_deflect.rb +107 -0
  52. data/test/spec_rack_evil.rb +19 -0
  53. data/test/spec_rack_expectation_cascade.rb +72 -0
  54. data/test/spec_rack_garbagecollector.rb +13 -0
  55. data/test/spec_rack_host_meta.rb +50 -0
  56. data/test/spec_rack_jsonp.rb +83 -0
  57. data/test/spec_rack_lighttpd_script_name_fix.rb +16 -0
  58. data/test/spec_rack_mailexceptions.rb +97 -0
  59. data/test/spec_rack_nested_params.rb +46 -0
  60. data/test/spec_rack_not_found.rb +17 -0
  61. data/test/spec_rack_post_body_content_type_parser.rb +32 -0
  62. data/test/spec_rack_proctitle.rb +26 -0
  63. data/test/spec_rack_profiler.rb +37 -0
  64. data/test/spec_rack_relative_redirect.rb +78 -0
  65. data/test/spec_rack_response_cache.rb +137 -0
  66. data/test/spec_rack_response_headers.rb +35 -0
  67. data/test/spec_rack_runtime.rb +35 -0
  68. data/test/spec_rack_sendfile.rb +86 -0
  69. data/test/spec_rack_simple_endpoint.rb +95 -0
  70. data/test/spec_rack_static_cache.rb +91 -0
  71. data/test/statics/test +1 -0
  72. metadata +234 -0
@@ -0,0 +1,78 @@
1
+ require 'test/spec'
2
+ require 'rack/mock'
3
+ require 'rack/contrib/relative_redirect'
4
+ require 'fileutils'
5
+
6
+ context Rack::RelativeRedirect do
7
+ def request(opts={}, &block)
8
+ @def_status = opts[:status] if opts[:status]
9
+ @def_location = opts[:location] if opts[:location]
10
+ yield Rack::MockRequest.new(Rack::RelativeRedirect.new(@def_app, &opts[:block])).get(opts[:path]||@def_path, opts[:headers]||{})
11
+ end
12
+
13
+ setup do
14
+ @def_path = '/path/to/blah'
15
+ @def_status = 301
16
+ @def_location = '/redirect/to/blah'
17
+ @def_app = lambda { |env| [@def_status, {'Location' => @def_location}, [""]]}
18
+ end
19
+
20
+ specify "should make the location url an absolute url if currently a relative url" do
21
+ request do |r|
22
+ r.status.should.equal(301)
23
+ r.headers['Location'].should.equal('http://example.org/redirect/to/blah')
24
+ end
25
+ request(:status=>302, :location=>'/redirect') do |r|
26
+ r.status.should.equal(302)
27
+ r.headers['Location'].should.equal('http://example.org/redirect')
28
+ end
29
+ end
30
+
31
+ specify "should use the request path if the relative url is given and doesn't start with a slash" do
32
+ request(:status=>303, :location=>'redirect/to/blah') do |r|
33
+ r.status.should.equal(303)
34
+ r.headers['Location'].should.equal('http://example.org/path/to/redirect/to/blah')
35
+ end
36
+ request(:status=>303, :location=>'redirect') do |r|
37
+ r.status.should.equal(303)
38
+ r.headers['Location'].should.equal('http://example.org/path/to/redirect')
39
+ end
40
+ end
41
+
42
+ specify "should use a given block to make the url absolute" do
43
+ request(:block=>proc{|env, res| "https://example.org"}) do |r|
44
+ r.status.should.equal(301)
45
+ r.headers['Location'].should.equal('https://example.org/redirect/to/blah')
46
+ end
47
+ request(:status=>303, :location=>'/redirect', :block=>proc{|env, res| "https://e.org:9999/blah"}) do |r|
48
+ r.status.should.equal(303)
49
+ r.headers['Location'].should.equal('https://e.org:9999/blah/redirect')
50
+ end
51
+ end
52
+
53
+ specify "should not modify the location url unless the response is a redirect" do
54
+ status = 200
55
+ @def_app = lambda { |env| [status, {'Content-Type' => "text/html"}, [""]]}
56
+ request do |r|
57
+ r.status.should.equal(200)
58
+ r.headers.should.not.include?('Location')
59
+ end
60
+ status = 404
61
+ @def_app = lambda { |env| [status, {'Content-Type' => "text/html", 'Location' => 'redirect'}, [""]]}
62
+ request do |r|
63
+ r.status.should.equal(404)
64
+ r.headers['Location'].should.equal('redirect')
65
+ end
66
+ end
67
+
68
+ specify "should not modify the location url if it is already an absolute url" do
69
+ request(:location=>'https://example.org/') do |r|
70
+ r.status.should.equal(301)
71
+ r.headers['Location'].should.equal('https://example.org/')
72
+ end
73
+ request(:status=>302, :location=>'https://e.org:9999/redirect') do |r|
74
+ r.status.should.equal(302)
75
+ r.headers['Location'].should.equal('https://e.org:9999/redirect')
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,137 @@
1
+ require 'test/spec'
2
+ require 'rack/mock'
3
+ require 'rack/contrib/response_cache'
4
+ require 'fileutils'
5
+
6
+ context Rack::ResponseCache do
7
+ F = ::File
8
+
9
+ def request(opts={}, &block)
10
+ Rack::MockRequest.new(Rack::ResponseCache.new(block||@def_app, opts[:cache]||@cache, &opts[:rc_block])).send(opts[:meth]||:get, opts[:path]||@def_path, opts[:headers]||{})
11
+ end
12
+
13
+ setup do
14
+ @cache = {}
15
+ @def_disk_cache = F.join(F.dirname(__FILE__), 'response_cache_test_disk_cache')
16
+ @def_value = ["rack-response-cache"]
17
+ @def_path = '/path/to/blah'
18
+ @def_app = lambda { |env| [200, {'Content-Type' => env['CT'] || 'text/html'}, @def_value]}
19
+ end
20
+ teardown do
21
+ FileUtils.rm_rf(@def_disk_cache)
22
+ end
23
+
24
+ specify "should cache results to disk if cache is a string" do
25
+ request(:cache=>@def_disk_cache)
26
+ F.read(F.join(@def_disk_cache, 'path', 'to', 'blah.html')).should.equal @def_value.first
27
+ request(:path=>'/path/3', :cache=>@def_disk_cache)
28
+ F.read(F.join(@def_disk_cache, 'path', '3.html')).should.equal @def_value.first
29
+ end
30
+
31
+ specify "should cache results to given cache if cache is not a string" do
32
+ request
33
+ @cache.should.equal('/path/to/blah.html'=>@def_value)
34
+ request(:path=>'/path/3')
35
+ @cache.should.equal('/path/to/blah.html'=>@def_value, '/path/3.html'=>@def_value)
36
+ end
37
+
38
+ specify "should not CACHE RESults if request method is not GET" do
39
+ request(:meth=>:post)
40
+ @cache.should.equal({})
41
+ request(:meth=>:put)
42
+ @cache.should.equal({})
43
+ request(:meth=>:delete)
44
+ @cache.should.equal({})
45
+ end
46
+
47
+ specify "should not cache results if there is a query string" do
48
+ request(:path=>'/path/to/blah?id=1')
49
+ @cache.should.equal({})
50
+ request(:path=>'/path/to/?id=1')
51
+ @cache.should.equal({})
52
+ request(:path=>'/?id=1')
53
+ @cache.should.equal({})
54
+ end
55
+
56
+ specify "should cache results if there is an empty query string" do
57
+ request(:path=>'/?')
58
+ @cache.should.equal('/index.html'=>@def_value)
59
+ end
60
+
61
+ specify "should not cache results if the request is not sucessful (status 200)" do
62
+ request{|env| [404, {'Content-Type' => 'text/html'}, ['']]}
63
+ @cache.should.equal({})
64
+ request{|env| [500, {'Content-Type' => 'text/html'}, ['']]}
65
+ @cache.should.equal({})
66
+ request{|env| [302, {'Content-Type' => 'text/html'}, ['']]}
67
+ @cache.should.equal({})
68
+ end
69
+
70
+ specify "should not cache results if the block returns nil or false" do
71
+ request(:rc_block=>proc{false})
72
+ @cache.should.equal({})
73
+ request(:rc_block=>proc{nil})
74
+ @cache.should.equal({})
75
+ end
76
+
77
+ specify "should cache results to path returned by block" do
78
+ request(:rc_block=>proc{"1"})
79
+ @cache.should.equal("1"=>@def_value)
80
+ request(:rc_block=>proc{"2"})
81
+ @cache.should.equal("1"=>@def_value, "2"=>@def_value)
82
+ end
83
+
84
+ specify "should pass the environment and response to the block" do
85
+ e, r = nil, nil
86
+ request(:rc_block=>proc{|env,res| e, r = env, res; nil})
87
+ e['PATH_INFO'].should.equal @def_path
88
+ e['REQUEST_METHOD'].should.equal 'GET'
89
+ e['QUERY_STRING'].should.equal ''
90
+ r.should.equal([200, {"Content-Type"=>"text/html"}, ["rack-response-cache"]])
91
+ end
92
+
93
+ specify "should unescape the path by default" do
94
+ request(:path=>'/path%20with%20spaces')
95
+ @cache.should.equal('/path with spaces.html'=>@def_value)
96
+ request(:path=>'/path%3chref%3e')
97
+ @cache.should.equal('/path with spaces.html'=>@def_value, '/path<href>.html'=>@def_value)
98
+ end
99
+
100
+ specify "should cache html, css, and xml responses by default" do
101
+ request(:path=>'/a')
102
+ @cache.should.equal('/a.html'=>@def_value)
103
+ request(:path=>'/b', :headers=>{'CT'=>'text/xml'})
104
+ @cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value)
105
+ request(:path=>'/c', :headers=>{'CT'=>'text/css'})
106
+ @cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value, '/c.css'=>@def_value)
107
+ end
108
+
109
+ specify "should cache responses by default with the extension added if not already present" do
110
+ request(:path=>'/a.html')
111
+ @cache.should.equal('/a.html'=>@def_value)
112
+ request(:path=>'/b.xml', :headers=>{'CT'=>'text/xml'})
113
+ @cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value)
114
+ request(:path=>'/c.css', :headers=>{'CT'=>'text/css'})
115
+ @cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value, '/c.css'=>@def_value)
116
+ end
117
+
118
+ specify "should not delete existing extensions" do
119
+ request(:path=>'/d.css', :headers=>{'CT'=>'text/html'})
120
+ @cache.should.equal('/d.css.html'=>@def_value)
121
+ end
122
+
123
+ specify "should cache html responses with empty basename to index.html by default" do
124
+ request(:path=>'/')
125
+ @cache.should.equal('/index.html'=>@def_value)
126
+ request(:path=>'/blah/')
127
+ @cache.should.equal('/index.html'=>@def_value, '/blah/index.html'=>@def_value)
128
+ request(:path=>'/blah/2/')
129
+ @cache.should.equal('/index.html'=>@def_value, '/blah/index.html'=>@def_value, '/blah/2/index.html'=>@def_value)
130
+ end
131
+
132
+ specify "should raise an error if a cache argument is not provided" do
133
+ app = Rack::Builder.new{use Rack::ResponseCache; run lambda { |env| [200, {'Content-Type' => 'text/plain'}, Rack::Request.new(env).POST]}}
134
+ proc{Rack::MockRequest.new(app).get('/')}.should.raise(ArgumentError)
135
+ end
136
+
137
+ end
@@ -0,0 +1,35 @@
1
+ require 'test/spec'
2
+ require 'rack'
3
+ require 'rack/contrib/response_headers'
4
+
5
+ context "Rack::ResponseHeaders" do
6
+
7
+ specify "yields a HeaderHash of response headers" do
8
+ orig_headers = {'X-Foo' => 'foo', 'X-Bar' => 'bar'}
9
+ app = Proc.new {[200, orig_headers, []]}
10
+ middleware = Rack::ResponseHeaders.new(app) do |headers|
11
+ assert_instance_of Rack::Utils::HeaderHash, headers
12
+ orig_headers.should == headers
13
+ end
14
+ middleware.call({})
15
+ end
16
+
17
+ specify "allows adding headers" do
18
+ app = Proc.new {[200, {'X-Foo' => 'foo'}, []]}
19
+ middleware = Rack::ResponseHeaders.new(app) do |headers|
20
+ headers['X-Bar'] = 'bar'
21
+ end
22
+ r = middleware.call({})
23
+ r[1].should == {'X-Foo' => 'foo', 'X-Bar' => 'bar'}
24
+ end
25
+
26
+ specify "allows deleting headers" do
27
+ app = Proc.new {[200, {'X-Foo' => 'foo', 'X-Bar' => 'bar'}, []]}
28
+ middleware = Rack::ResponseHeaders.new(app) do |headers|
29
+ headers.delete('X-Bar')
30
+ end
31
+ r = middleware.call({})
32
+ r[1].should == {'X-Foo' => 'foo'}
33
+ end
34
+
35
+ end
@@ -0,0 +1,35 @@
1
+ require 'test/spec'
2
+ require 'rack/mock'
3
+ require 'rack/contrib/runtime'
4
+
5
+ context "Rack::Runtime" do
6
+ specify "sets X-Runtime is none is set" do
7
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
8
+ response = Rack::Runtime.new(app).call({})
9
+ response[1]['X-Runtime'].should =~ /[\d\.]+/
10
+ end
11
+
12
+ specify "does not set the X-Runtime if it is already set" do
13
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
14
+ response = Rack::Runtime.new(app).call({})
15
+ response[1]['X-Runtime'].should == "foobar"
16
+ end
17
+
18
+ specify "should allow a suffix to be set" do
19
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
20
+ response = Rack::Runtime.new(app, "Test").call({})
21
+ response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
22
+ end
23
+
24
+ specify "should allow multiple timers to be set" do
25
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
26
+ runtime1 = Rack::Runtime.new(app, "App")
27
+ runtime2 = Rack::Runtime.new(runtime1, "All")
28
+ response = runtime2.call({})
29
+
30
+ response[1]['X-Runtime-App'].should =~ /[\d\.]+/
31
+ response[1]['X-Runtime-All'].should =~ /[\d\.]+/
32
+
33
+ Float(response[1]['X-Runtime-All']).should > Float(response[1]['X-Runtime-App'])
34
+ end
35
+ end
@@ -0,0 +1,86 @@
1
+ require 'test/spec'
2
+ require 'rack/mock'
3
+ require 'rack/contrib/sendfile'
4
+
5
+ context "Rack::File" do
6
+ specify "should respond to #to_path" do
7
+ Rack::File.new(Dir.pwd).should.respond_to :to_path
8
+ end
9
+ end
10
+
11
+ context "Rack::Sendfile" do
12
+ def sendfile_body
13
+ res = ['Hello World']
14
+ def res.to_path ; "/tmp/hello.txt" ; end
15
+ res
16
+ end
17
+
18
+ def simple_app(body=sendfile_body)
19
+ lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
20
+ end
21
+
22
+ def sendfile_app(body=sendfile_body)
23
+ Rack::Sendfile.new(simple_app(body))
24
+ end
25
+
26
+ setup do
27
+ @request = Rack::MockRequest.new(sendfile_app)
28
+ end
29
+
30
+ def request(headers={})
31
+ yield @request.get('/', headers)
32
+ end
33
+
34
+ specify "does nothing when no X-Sendfile-Type header present" do
35
+ request do |response|
36
+ response.should.be.ok
37
+ response.body.should.equal 'Hello World'
38
+ response.headers.should.not.include 'X-Sendfile'
39
+ end
40
+ end
41
+
42
+ specify "sets X-Sendfile response header and discards body" do
43
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
44
+ response.should.be.ok
45
+ response.body.should.be.empty
46
+ response.headers['X-Sendfile'].should.equal '/tmp/hello.txt'
47
+ end
48
+ end
49
+
50
+ specify "sets X-Lighttpd-Send-File response header and discards body" do
51
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
52
+ response.should.be.ok
53
+ response.body.should.be.empty
54
+ response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt'
55
+ end
56
+ end
57
+
58
+ specify "sets X-Accel-Redirect response header and discards body" do
59
+ headers = {
60
+ 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
61
+ 'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
62
+ }
63
+ request headers do |response|
64
+ response.should.be.ok
65
+ response.body.should.be.empty
66
+ response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt'
67
+ end
68
+ end
69
+
70
+ specify 'writes to rack.error when no X-Accel-Mapping is specified' do
71
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
72
+ response.should.be.ok
73
+ response.body.should.equal 'Hello World'
74
+ response.headers.should.not.include 'X-Accel-Redirect'
75
+ response.errors.should.include 'X-Accel-Mapping'
76
+ end
77
+ end
78
+
79
+ specify 'does nothing when body does not respond to #to_path' do
80
+ @request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
81
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
82
+ response.body.should.equal 'Not a file...'
83
+ response.headers.should.not.include 'X-Sendfile'
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,95 @@
1
+ require 'test/spec'
2
+ require 'rack'
3
+ require 'rack/contrib/simple_endpoint'
4
+
5
+ context "Rack::SimpleEndpoint" do
6
+ setup do
7
+ @app = Proc.new { Rack::Response.new {|r| r.write "Downstream app"}.finish }
8
+ end
9
+
10
+ specify "calls downstream app when no match" do
11
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { 'bar' }
12
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/baz'))
13
+ status.should == 200
14
+ body.body.should == ['Downstream app']
15
+ end
16
+
17
+ specify "calls downstream app when path matches but method does not" do
18
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => :get) { 'bar' }
19
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo', :method => 'post'))
20
+ status.should == 200
21
+ body.body.should == ['Downstream app']
22
+ end
23
+
24
+ specify "calls downstream app when path matches but block returns :pass" do
25
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { :pass }
26
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
27
+ status.should == 200
28
+ body.body.should == ['Downstream app']
29
+ end
30
+
31
+ specify "returns endpoint response when path matches" do
32
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { 'bar' }
33
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
34
+ status.should == 200
35
+ body.body.should == ['bar']
36
+ end
37
+
38
+ specify "returns endpoint response when path and single method requirement match" do
39
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => :get) { 'bar' }
40
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
41
+ status.should == 200
42
+ body.body.should == ['bar']
43
+ end
44
+
45
+ specify "returns endpoint response when path and one of multiple method requirements match" do
46
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => [:get, :post]) { 'bar' }
47
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo', :method => 'post'))
48
+ status.should == 200
49
+ body.body.should == ['bar']
50
+ end
51
+
52
+ specify "returns endpoint response when path matches regex" do
53
+ endpoint = Rack::SimpleEndpoint.new(@app, /foo/) { 'bar' }
54
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/bar/foo'))
55
+ status.should == 200
56
+ body.body.should == ['bar']
57
+ end
58
+
59
+ specify "block yields Rack::Request and Rack::Response objects" do
60
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') do |req, res|
61
+ assert_instance_of ::Rack::Request, req
62
+ assert_instance_of ::Rack::Response, res
63
+ end
64
+ endpoint.call(Rack::MockRequest.env_for('/foo'))
65
+ end
66
+
67
+ specify "block yields MatchData object when Regex path matcher specified" do
68
+ endpoint = Rack::SimpleEndpoint.new(@app, /foo(.+)/) do |req, res, match|
69
+ assert_instance_of MatchData, match
70
+ assert_equal 'bar', match[1]
71
+ end
72
+ endpoint.call(Rack::MockRequest.env_for('/foobar'))
73
+ end
74
+
75
+ specify "block does NOT yield MatchData object when String path matcher specified" do
76
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') do |req, res, match|
77
+ assert_nil match
78
+ end
79
+ endpoint.call(Rack::MockRequest.env_for('/foo'))
80
+ end
81
+
82
+ specify "response honors headers set in block" do
83
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') {|req, res| res['X-Foo'] = 'bar'; 'baz' }
84
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
85
+ status.should == 200
86
+ headers['X-Foo'].should == 'bar'
87
+ body.body.should == ['baz']
88
+ end
89
+
90
+ specify "sets Content-Length header" do
91
+ endpoint = Rack::SimpleEndpoint.new(@app, '/foo') {|req, res| 'bar' }
92
+ status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
93
+ headers['Content-Length'].should == '3'
94
+ end
95
+ end
@@ -0,0 +1,91 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack'
4
+ require 'rack/contrib/static_cache'
5
+ require 'rack/mock'
6
+
7
+ class DummyApp
8
+ def call(env)
9
+ [200, {}, ["Hello World"]]
10
+ end
11
+ end
12
+
13
+ describe "Rack::StaticCache" do
14
+
15
+ setup do
16
+ @root = ::File.expand_path(::File.dirname(__FILE__))
17
+ end
18
+
19
+ it "should serve files with required headers" do
20
+ default_app_request
21
+ res = @request.get("/statics/test")
22
+ res.should.be.ok
23
+ res.body.should =~ /rubyrack/
24
+ res.headers['Cache-Control'].should == 'max-age=31536000, public'
25
+ next_year = Time.now().year + 1
26
+ res.headers['Expires'].should =~ Regexp.new(
27
+ "[A-Z][a-z]{2}[,][\s][0-9]{2}[\s][A-Z][a-z]{2}[\s]" << "#{next_year}" <<
28
+ "[\s][0-9]{2}[:][0-9]{2}[:][0-9]{2} GMT$")
29
+ res.headers.has_key?('Etag').should == false
30
+ res.headers.has_key?('Pragma').should == false
31
+ res.headers.has_key?('Last-Modified').should == false
32
+ end
33
+
34
+ it "should return 404s if url root is known but it can't find the file" do
35
+ default_app_request
36
+ res = @request.get("/statics/foo")
37
+ res.should.be.not_found
38
+ end
39
+
40
+ it "should call down the chain if url root is not known" do
41
+ default_app_request
42
+ res = @request.get("/something/else")
43
+ res.should.be.ok
44
+ res.body.should == "Hello World"
45
+ end
46
+
47
+ it "should serve files if requested with version number and versioning is enabled" do
48
+ default_app_request
49
+ res = @request.get("/statics/test-0.0.1")
50
+ res.should.be.ok
51
+ end
52
+
53
+ it "should change cache duration if specified thorugh option" do
54
+ configured_app_request
55
+ res = @request.get("/statics/test")
56
+ res.should.be.ok
57
+ res.body.should =~ /rubyrack/
58
+ next_next_year = Time.now().year + 2
59
+ res.headers['Expires'].should =~ Regexp.new("#{next_next_year}")
60
+ end
61
+
62
+ it "should return 404s if requested with version number but versioning is disabled" do
63
+ configured_app_request
64
+ res = @request.get("/statics/test-0.0.1")
65
+ res.should.be.not_found
66
+ end
67
+
68
+ it "should serve files with plain headers when * is added to the directory name" do
69
+ configured_app_request
70
+ res = @request.get("/documents/test")
71
+ res.should.be.ok
72
+ res.body.should =~ /nocache/
73
+ next_next_year = Time.now().year + 2
74
+ res.headers['Expires'].should.not =~ Regexp.new("#{next_next_year}")
75
+ end
76
+
77
+ def default_app_request
78
+ @options = {:urls => ["/statics"], :root => @root}
79
+ request
80
+ end
81
+
82
+ def configured_app_request
83
+ @options = {:urls => ["/statics", "/documents*"], :root => @root, :versioning => false, :duration => 2}
84
+ request
85
+ end
86
+
87
+ def request
88
+ @request = Rack::MockRequest.new(Rack::StaticCache.new(DummyApp.new, @options))
89
+ end
90
+
91
+ end
data/test/statics/test ADDED
@@ -0,0 +1 @@
1
+ rubyrack