1 require File.dirname(__FILE__) + '/../spec_helper'
3 describe ResponseCache do
5 def method_missing(*args); end
8 class TestResponse < ActionController::TestResponse
9 def initialize(body = '', headers = {})
11 self.headers = headers
16 @dir = File.expand_path("#{RAILS_ROOT}/test/cache")
17 @baddir = File.expand_path("#{RAILS_ROOT}/test/badcache")
18 @old_perform_caching = ResponseCache.defaults[:perform_caching]
19 ResponseCache.defaults[:perform_caching] = true
23 FileUtils.rm_rf @baddir
24 @cache = ResponseCache.new(
26 :perform_caching => true
32 FileUtils.rm_rf @dir if File.exists? @dir
36 ResponseCache.defaults[:perform_caching] = @old_preform_caching
39 it 'should initialize with defaults' do
40 @cache = ResponseCache.new
41 @cache.directory.should == "#{RAILS_ROOT}/cache"
42 @cache.expire_time.should == 5.minutes
43 @cache.default_extension.should == '.yml'
44 @cache.logger.should be_kind_of(ActiveSupport::BufferedLogger)
47 it 'should initialize with options' do
48 @cache = ResponseCache.new(
51 :default_extension => ".xhtml",
52 :perform_caching => false,
53 :logger => SilentLogger.new
55 @cache.directory.should == "test"
56 @cache.expire_time.should == 5
57 @cache.default_extension.should == ".xhtml"
58 @cache.perform_caching.should == false
59 @cache.logger.should be_kind_of(SilentLogger)
62 it 'should cache response' do
63 ['test/me', '/test/me', 'test/me/', '/test/me/', 'test//me'].each do |url|
65 response = response('content', 'Last-Modified' => 'Tue, 27 Feb 2007 06:13:43 GMT')
66 response.cache_timeout = Time.gm(2007, 2, 8, 17, 37, 9)
67 @cache.cache_response(url, response)
68 name = "#{@dir}/test/me.yml"
69 File.exists?(name).should == true
70 file(name).should == "--- \nexpires: 2007-02-08 17:37:09 Z\nheaders: \n Last-Modified: Tue, 27 Feb 2007 06:13:43 GMT\n"
71 data_name = "#{@dir}/test/me.data"
72 file(data_name).should == "content"
76 it 'cache response with extension' do
77 @cache.cache_response("styles.css", response('content'))
78 File.exists?("#{@dir}/styles.css.yml").should == true
81 it 'cache response without caching' do
82 @cache.perform_caching = false
83 @cache.cache_response('test', response('content'))
84 File.exists?("#{@dir}/test.yml").should == false
87 it 'update response' do
88 @cache.cache_response('/test/me', response('content'))
89 ['test/me', '/test/me', 'test/me/', '/test/me/', 'test//me'].each do |url|
90 @cache.update_response(url, response, ActionController::TestRequest).body.should == 'content'
94 it 'update response nonexistant' do
95 @cache.update_response('nothing/here', response, ActionController::TestRequest).body.should == ''
98 it 'update response without caching' do
99 @cache.cache_response('/test/me', response('content'))
100 @cache.perform_caching = false
101 @cache.update_response('/test/me', response, ActionController::TestRequest).body.should == ''
105 result = @cache.cache_response('test', response('content', 'Content-Type' => 'text/plain'))
106 cached = @cache.update_response('test', response, ActionController::TestRequest)
107 cached.body.should == 'content'
108 cached.headers['Content-Type'].should == 'text/plain'
109 result.should be_kind_of(TestResponse)
112 it 'expire response' do
113 @cache.cache_response('test', response('content'))
114 @cache.expire_response('test')
115 @cache.update_response('test', response, ActionController::TestRequest).body.should == ''
119 @cache.cache_response('test1', response('content'))
120 @cache.cache_response('test2', response('content'))
121 Dir["#{@dir}/*"].size.should == 4
124 Dir["#{@dir}/*"].size.should == 0
127 it 'response_cached?' do
128 @cache.response_cached?('test').should == false
129 result = @cache.cache_response('test', response('content'))
130 @cache.response_cached?('test').should == true
133 it 'response_cached? should not answer true when response is cached but preform_caching option is false' do
134 @cache.cache_response('test', response('content'))
135 @cache.perform_caching = false
136 @cache.response_cached?('test').should == false
139 it 'response_cached? with timeout' do
140 @cache.expire_time = 1
141 result = @cache.cache_response('test', response('content'))
143 @cache.response_cached?('test').should == false
146 it 'response_cached? timeout with response setting' do
147 @cache.expire_time = 1
148 response = response('content')
149 response.cache_timeout = 3.seconds
150 result = @cache.cache_response('test', response)
152 @cache.response_cached?('test').should == true
154 @cache.response_cached?('test').should == false
157 it 'send using x_sendfile header' do
158 @cache.use_x_sendfile = true
159 result = @cache.cache_response('test', response('content', 'Content-Type' => 'text/plain'))
160 cached = @cache.update_response('test', response, ActionController::TestRequest)
161 cached.body.should == ''
162 cached.headers['X-Sendfile'].should == "#{@dir}/test.data"
163 cached.headers['Content-Type'].should == 'text/plain'
164 result.should be_kind_of(TestResponse)
167 it 'send cached page with last modified' do
168 last_modified = Time.now.httpdate
169 result = @cache.cache_response('test', response('content', 'Last-Modified' => last_modified))
170 request = ActionController::TestRequest.new
171 request.env = { 'HTTP_IF_MODIFIED_SINCE' => last_modified }
172 second_call = @cache.update_response('test', response, request)
173 second_call.headers['Status'].should match(/^304/)
174 second_call.body.should == ''
175 result.should be_kind_of(TestResponse)
178 it 'send cached page with old last modified' do
179 last_modified = Time.now.httpdate
180 result = @cache.cache_response('test', response('content', 'Last-Modified' => last_modified))
181 request = ActionController::TestRequest.new
182 request.env = { 'HTTP_IF_MODIFIED_SINCE' => 5.minutes.ago.httpdate }
183 second_call = @cache.update_response('test', response, request)
184 second_call.body.should == 'content'
185 result.should be_kind_of(TestResponse)
188 it 'not cached if metadata empty' do
189 FileUtils.makedirs(@dir)
190 File.open("#{@dir}/test_me.yml", 'w') { }
191 @cache.response_cached?('/test_me').should == false
194 it 'not cached if metadata broken' do
195 FileUtils.makedirs(@dir)
196 File.open("#{@dir}/test_me.yml", 'w') {|f| f.puts '::: bad yaml file:::' }
197 @cache.response_cached?('/test_me').should == false
200 it 'not cached if metadata not hash' do
201 FileUtils.makedirs(@dir)
202 File.open("#{@dir}/test_me.yml", 'w') {|f| f.puts ':symbol' }
203 @cache.response_cached?('/test_me').should == false
206 it 'not cached if metadata has no expire' do
207 FileUtils.makedirs(@dir)
208 File.open("#{@dir}/test_me.yml", 'w') { |f| f.puts "--- \nheaders: \n Last-Modified: Tue, 27 Feb 2007 06:13:43 GMT\n" }
209 @cache.response_cached?('/test_me').should == false
212 it 'cache cant write outside dir' do
213 @cache.cache_response('../badcache/cache_cant_write_outside_dir', response('content'))
214 File.exist?("#{RAILS_ROOT}/test/badcache/cache_cant_write_outside_dir.yml").should == false
217 it 'cache cannot read outside dir' do
218 FileUtils.makedirs(@baddir)
219 @cache.cache_response('/test_me', response('content'))
220 File.rename "#{@dir}/test_me.yml", "#{@baddir}/test_me.yml"
221 File.rename "#{@dir}/test_me.data", "#{@baddir}/test_me.data"
222 @cache.response_cached?('/../badcache/test_me').should == false
225 it 'cache cannot expire outside dir' do
226 FileUtils.makedirs(@baddir)
227 @cache.cache_response('/test_me', response('content'))
228 File.rename "#{@dir}/test_me.yml", "#{@baddir}/test_me.yml"
229 File.rename "#{@dir}/test_me.data", "#{@baddir}/test_me.data"
230 @cache.expire_response('/../badcache/test_me')
231 File.exist?("#{@baddir}/test_me.yml").should == true
232 File.exist?("#{@baddir}/test_me.data").should == true
235 it 'should store indexes correctly' do
236 @cache.cache_response('/', response('content'))
237 @cache.response_cached?('_site-root').should == true
238 @cache.response_cached?('/') .should == true
239 File.exist?("#{@dir}/../cache.yml").should == false
240 File.exist?("#{@dir}/../cache.data").should == false
245 it 'should give access to a global instance' do
246 ResponseCache.instance.should equal(ResponseCache.instance)
252 open(filename) { |f| f.read } rescue ''
256 TestResponse.new(*args)