test/response_test.rb in rack-cache-0.3.0 vs test/response_test.rb in rack-cache-0.4

- old
+ new

@@ -1,37 +1,178 @@ require "#{File.dirname(__FILE__)}/spec_setup" describe 'Rack::Cache::Response' do - - before(:each) { - @now = Time.now - @response = Rack::Cache::Response.new(200, {'Date' => @now.httpdate}, '') + before :each do + @now = Time.httpdate(Time.now.httpdate) @one_hour_ago = Time.httpdate((Time.now - (60**2)).httpdate) - } + @one_hour_later = Time.httpdate((Time.now + (60**2)).httpdate) + @res = Rack::Cache::Response.new(200, {'Date' => @now.httpdate}, []) + end - after(:each) { - @now, @response, @one_hour_ago = nil - } - - it 'responds to cache-related methods' do - @response.should.respond_to :ttl - @response.should.respond_to :age - @response.should.respond_to :date + after :each do + @now, @res, @one_hour_ago = nil end it 'responds to #to_a with a Rack response tuple' do - @response.should.respond_to :to_a - @response.to_a.should.be == [200, {'Date' => @now.httpdate}, ''] + @res.should.respond_to :to_a + @res.to_a.should.equal [200, {'Date' => @now.httpdate}, []] end - it 'retrieves headers with #[]' do - @response.headers['X-Foo'] = 'bar' - @response.should.respond_to :[] - @response['X-Foo'].should.be == 'bar' + describe '#cache_control' do + it 'handles multiple name=value pairs' do + @res.headers['Cache-Control'] = 'max-age=600, max-stale=300, min-fresh=570' + @res.cache_control['max-age'].should.equal '600' + @res.cache_control['max-stale'].should.equal '300' + @res.cache_control['min-fresh'].should.equal '570' + end + it 'removes the header when given an empty hash' do + @res.headers['Cache-Control'] = 'max-age=600, must-revalidate' + @res.cache_control['max-age'].should.equal '600' + @res.cache_control = {} + @res.headers.should.not.include 'Cache-Control' + end end - it 'sets headers with #[]=' do - @response.should.respond_to :[]= - @response['X-Foo'] = 'bar' - @response.headers['X-Foo'].should.be == 'bar' + describe '#validateable?' do + it 'is true when Last-Modified header present' do + @res = Rack::Cache::Response.new(200, {'Last-Modified' => @one_hour_ago.httpdate}, []) + @res.should.be.validateable + end + it 'is true when ETag header present' do + @res = Rack::Cache::Response.new(200, {'ETag' => '"12345"'}, []) + @res.should.be.validateable + end + it 'is false when no validator is present' do + @res = Rack::Cache::Response.new(200, {}, []) + @res.should.not.be.validateable + end + end + + describe '#date' do + it 'uses the Date header if present' do + @res = Rack::Cache::Response.new(200, {'Date' => @one_hour_ago.httpdate}, []) + @res.date.should.equal @one_hour_ago + end + it 'uses the current time when no Date header present' do + @res = Rack::Cache::Response.new(200, {}, []) + @res.date.should.be.close Time.now, 1 + end + it 'returns the correct date when the header is modified directly' do + @res = Rack::Cache::Response.new(200, { 'Date' => @one_hour_ago.httpdate }, []) + @res.date.should.equal @one_hour_ago + @res.headers['Date'] = @now.httpdate + @res.date.should.equal @now + end + end + + describe '#max_age' do + it 'uses s-maxage cache control directive when present' do + @res.headers['Cache-Control'] = 's-maxage=600, max-age=0' + @res.max_age.should.equal 600 + end + it 'falls back to max-age when no s-maxage directive present' do + @res.headers['Cache-Control'] = 'max-age=600' + @res.max_age.should.equal 600 + end + it 'falls back to Expires when no max-age or s-maxage directive present' do + @res.headers['Cache-Control'] = 'must-revalidate' + @res.headers['Expires'] = @one_hour_later.httpdate + @res.max_age.should.equal 60 ** 2 + end + it 'gives a #max_age of nil when no freshness information available' do + @res.max_age.should.be.nil + end + end + + describe '#private=' do + it 'adds the private Cache-Control directive when set true' do + @res.headers['Cache-Control'] = 'max-age=100' + @res.private = true + @res.headers['Cache-Control'].split(', ').sort. + should.equal ['max-age=100', 'private'] + end + it 'removes the public Cache-Control directive' do + @res.headers['Cache-Control'] = 'public, max-age=100' + @res.private = true + @res.headers['Cache-Control'].split(', ').sort. + should.equal ['max-age=100', 'private'] + end + end + + describe '#expire!' do + it 'sets the Age to be equal to the max-age' do + @res.headers['Cache-Control'] = 'max-age=100' + @res.expire! + @res.headers['Age'].should.equal '100' + end + it 'sets the Age to be equal to the s-maxage when both max-age and s-maxage present' do + @res.headers['Cache-Control'] = 'max-age=100, s-maxage=500' + @res.expire! + @res.headers['Age'].should.equal '500' + end + it 'does nothing when the response is already stale/expired' do + @res.headers['Cache-Control'] = 'max-age=5, s-maxage=500' + @res.headers['Age'] = '1000' + @res.expire! + @res.headers['Age'].should.equal '1000' + end + it 'does nothing when the response does not include freshness information' do + @res.expire! + @res.headers.should.not.include 'Age' + end + end + + describe '#ttl' do + it 'is nil when no Expires or Cache-Control headers present' do + @res.ttl.should.be.nil + end + it 'uses the Expires header when no max-age is present' do + @res.headers['Expires'] = (@res.now + (60**2)).httpdate + @res.ttl.should.be.close(60**2, 1) + end + it 'returns negative values when Expires is in part' do + @res.ttl.should.be.nil + @res.headers['Expires'] = @one_hour_ago.httpdate + @res.ttl.should.be < 0 + end + it 'uses the Cache-Control max-age value when present' do + @res.headers['Cache-Control'] = 'max-age=60' + @res.ttl.should.be.close(60, 1) + end + end + + describe '#vary' do + it 'is nil when no Vary header is present' do + @res.vary.should.be.nil + end + it 'returns the literal value of the Vary header' do + @res.headers['Vary'] = 'Foo Bar Baz' + @res.vary.should.equal 'Foo Bar Baz' + end + it 'can be checked for existence using the #vary? method' do + @res.should.respond_to :vary? + @res.should.not.vary + @res.headers['Vary'] = '*' + @res.should.vary + end + end + + describe '#vary_header_names' do + it 'returns an empty Array when no Vary header is present' do + @res.vary_header_names.should.be.empty + end + it 'parses a single header name value' do + @res.headers['Vary'] = 'Accept-Language' + @res.vary_header_names.should.equal ['Accept-Language'] + end + it 'parses multiple header name values separated by spaces' do + @res.headers['Vary'] = 'Accept-Language User-Agent X-Foo' + @res.vary_header_names.should.equal \ + ['Accept-Language', 'User-Agent', 'X-Foo'] + end + it 'parses multiple header name values separated by commas' do + @res.headers['Vary'] = 'Accept-Language,User-Agent, X-Foo' + @res.vary_header_names.should.equal \ + ['Accept-Language', 'User-Agent', 'X-Foo'] + end end end