Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/actionpack/test/controller/caching_test.rb

Revision 8630, 15.0 kB (checked in by david, 11 months ago)

Fix a few caching errors, expose a case thats still not working (ref #107330 [catfish]

Line 
1 require 'fileutils'
2 require 'abstract_unit'
3
4 CACHE_DIR = 'test_cache'
5 # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
6 FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
7 ActionController::Base.page_cache_directory = FILE_STORE_PATH
8 ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
9
10 class PageCachingTestController < ActionController::Base
11   caches_page :ok, :no_content, :found, :not_found
12
13   def ok
14     head :ok
15   end
16
17   def no_content
18     head :no_content
19   end
20
21   def found
22     redirect_to :action => 'ok'
23   end
24
25   def not_found
26     head :not_found
27   end
28
29   def custom_path
30     render :text => "Super soaker"
31     cache_page("Super soaker", "/index.html")
32   end
33
34   def expire_custom_path
35     expire_page("/index.html")
36     head :ok
37   end
38
39   def trailing_slash
40     render :text => "Sneak attack"
41   end
42 end
43
44 class PageCachingTest < Test::Unit::TestCase
45   def setup
46     ActionController::Base.perform_caching = true
47
48     ActionController::Routing::Routes.draw do |map|
49       map.main '', :controller => 'posts'
50       map.resources :posts
51       map.connect ':controller/:action/:id'
52     end
53
54     @request = ActionController::TestRequest.new
55     @request.host = 'hostname.com'
56
57     @response   = ActionController::TestResponse.new
58     @controller = PageCachingTestController.new
59
60     @params = {:controller => 'posts', :action => 'index', :only_path => true, :skip_relative_url_root => true}
61     @rewriter = ActionController::UrlRewriter.new(@request, @params)
62
63     FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
64     FileUtils.mkdir_p(FILE_STORE_PATH)
65   end
66
67   def teardown
68     FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
69
70     ActionController::Base.perform_caching = false
71   end
72
73   def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
74     @params[:format] = 'rss'
75     assert_equal '/posts.rss', @rewriter.rewrite(@params)
76     @params[:format] = nil
77     assert_equal '/', @rewriter.rewrite(@params)
78   end
79
80   def test_should_cache_get_with_ok_status
81     get :ok
82     assert_response :ok
83     assert_page_cached :ok, "get with ok status should have been cached"
84   end
85
86   def test_should_cache_with_custom_path
87     get :custom_path
88     assert File.exist?("#{FILE_STORE_PATH}/index.html")
89   end
90
91   def test_should_expire_cache_with_custom_path
92     get :custom_path
93     assert File.exist?("#{FILE_STORE_PATH}/index.html")
94
95     get :expire_custom_path
96     assert !File.exist?("#{FILE_STORE_PATH}/index.html")
97   end
98
99   def test_should_cache_without_trailing_slash_on_url
100     @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash'
101     assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
102   end
103
104   def test_should_cache_with_trailing_slash_on_url
105     @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
106     assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
107   end
108
109   uses_mocha("should_cache_ok_at_custom_path") do
110     def test_should_cache_ok_at_custom_path
111       @request.expects(:path).returns("/index.html")
112       get :ok
113       assert_response :ok
114       assert File.exist?("#{FILE_STORE_PATH}/index.html")
115     end
116   end
117
118   [:ok, :no_content, :found, :not_found].each do |status|
119     [:get, :post, :put, :delete].each do |method|
120       unless method == :get and status == :ok
121         define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
122           @request.env['REQUEST_METHOD'] = method.to_s.upcase
123           process status
124           assert_response status
125           assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
126         end
127       end
128     end
129   end
130
131   private
132     def assert_page_cached(action, message = "#{action} should have been cached")
133       assert page_cached?(action), message
134     end
135
136     def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
137       assert !page_cached?(action), message
138     end
139
140     def page_cached?(action)
141       File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
142     end
143 end
144
145
146 class ActionCachingTestController < ActionController::Base
147   caches_action :index, :redirected, :forbidden
148   caches_action :show, :cache_path => 'http://test.host/custom/show'
149   caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
150
151   def index
152     @cache_this = Time.now.to_f.to_s
153     render :text => @cache_this
154   end
155
156   def redirected
157     redirect_to :action => 'index'
158   end
159
160   def forbidden
161     render :text => "Forbidden"
162     headers["Status"] = "403 Forbidden"
163   end
164
165   alias_method :show, :index
166   alias_method :edit, :index
167
168   def expire
169     expire_action :controller => 'action_caching_test', :action => 'index'
170     render :nothing => true
171   end
172
173 end
174
175 class ActionCachingMockController
176   attr_accessor :mock_url_for
177   attr_accessor :mock_path
178
179   def initialize
180     yield self if block_given?
181   end
182
183   def url_for(*args)
184     @mock_url_for
185   end
186
187   def request
188     mocked_path = @mock_path
189     Object.new.instance_eval(<<-EVAL)
190       def path; '#{@mock_path}' end
191       self
192     EVAL
193   end
194 end
195
196 class ActionCacheTest < Test::Unit::TestCase
197   def setup
198     reset!
199     FileUtils.mkdir_p(FILE_STORE_PATH)
200     @path_class = ActionController::Caching::Actions::ActionCachePath
201     @mock_controller = ActionCachingMockController.new
202   end
203
204   def teardown
205     FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
206   end
207
208   def test_simple_action_cache
209     get :index
210     cached_time = content_to_cache
211     assert_equal cached_time, @response.body
212     assert_cache_exists 'hostname.com/action_caching_test'
213     reset!
214
215     get :index
216     assert_equal cached_time, @response.body
217   end
218
219   def test_action_cache_with_custom_cache_path
220     get :show
221     cached_time = content_to_cache
222     assert_equal cached_time, @response.body
223     assert_cache_exists 'test.host/custom/show'
224     reset!
225
226     get :show
227     assert_equal cached_time, @response.body
228   end
229
230   def test_action_cache_with_custom_cache_path_in_block
231     get :edit
232     assert_cache_exists 'test.host/edit'
233     reset!
234
235     get :edit, :id => 1
236     assert_cache_exists 'test.host/1;edit'
237   end
238
239   def test_cache_expiration
240     get :index
241     cached_time = content_to_cache
242     reset!
243
244     get :index
245     assert_equal cached_time, @response.body
246     reset!
247
248     get :expire
249     reset!
250
251     get :index
252     new_cached_time = content_to_cache
253     assert_not_equal cached_time, @response.body
254     reset!
255
256     get :index
257     assert_response :success
258     assert_equal new_cached_time, @response.body
259   end
260
261   def test_cache_is_scoped_by_subdomain
262     @request.host = 'jamis.hostname.com'
263     get :index
264     jamis_cache = content_to_cache
265
266     reset!
267
268     @request.host = 'david.hostname.com'
269     get :index
270     david_cache = content_to_cache
271     assert_not_equal jamis_cache, @response.body
272
273     reset!
274
275     @request.host = 'jamis.hostname.com'
276     get :index
277     assert_equal jamis_cache, @response.body
278
279     reset!
280
281     @request.host = 'david.hostname.com'
282     get :index
283     assert_equal david_cache, @response.body
284   end
285
286   def test_redirect_is_not_cached
287     get :redirected
288     assert_response :redirect
289     reset!
290
291     get :redirected
292     assert_response :redirect
293   end
294
295   def test_forbidden_is_not_cached
296     get :forbidden
297     assert_response :forbidden
298     reset!
299
300     get :forbidden
301     assert_response :forbidden
302   end
303
304   def test_xml_version_of_resource_is_treated_as_different_cache
305     @mock_controller.mock_url_for = 'http://example.org/posts/'
306     @mock_controller.mock_path    = '/posts/index.xml'
307     path_object = @path_class.new(@mock_controller, {})
308     assert_equal 'xml', path_object.extension
309     assert_equal 'example.org/posts/index.xml', path_object.path
310   end
311
312   def test_correct_content_type_is_returned_for_cache_hit
313     # run it twice to cache it the first time
314     get :index, :id => 'content-type.xml'
315     get :index, :id => 'content-type.xml'
316     assert_equal 'application/xml', @response.content_type
317   end
318
319   def test_empty_path_is_normalized
320     @mock_controller.mock_url_for = 'http://example.org/'
321     @mock_controller.mock_path    = '/'
322
323     assert_equal 'example.org/index', @path_class.path_for(@mock_controller, {})
324   end
325
326   def test_file_extensions
327     get :index, :id => 'kitten.jpg'
328     get :index, :id => 'kitten.jpg'
329
330     assert_response :success
331   end
332
333   private
334     def content_to_cache
335       assigns(:cache_this)
336     end
337
338     def reset!
339       @request    = ActionController::TestRequest.new
340       @response   = ActionController::TestResponse.new
341       @controller = ActionCachingTestController.new
342       @request.host = 'hostname.com'
343     end
344
345     def assert_cache_exists(path)
346       full_path = File.join(FILE_STORE_PATH, "views", path + '.cache')
347       assert File.exist?(full_path), "#{full_path.inspect} does not exist."
348     end
349 end
350
351 class FragmentCachingTestController < ActionController::Base
352   def some_action; end;
353 end
354
355 class FragmentCachingTest < Test::Unit::TestCase
356   def setup
357     ActionController::Base.perform_caching = true
358     @store = ActiveSupport::Cache::MemoryStore.new
359     ActionController::Base.cache_store = @store
360     @controller = FragmentCachingTestController.new
361     @params = {:controller => 'posts', :action => 'index'}
362     @request = ActionController::TestRequest.new
363     @response = ActionController::TestResponse.new
364     @controller.params = @params
365     @controller.request = @request
366     @controller.response = @response
367     @controller.send(:initialize_current_url)
368   end
369
370   def test_fragment_cache_key
371     assert_equal 'views/what a key', @controller.fragment_cache_key('what a key')
372     assert_equal( "views/test.host/fragment_caching_test/some_action",
373                   @controller.fragment_cache_key(:controller => 'fragment_caching_test',:action => 'some_action'))
374   end
375
376   def test_read_fragment__with_caching_enabled
377     @store.write('views/name', 'value')
378     assert_equal 'value', @controller.read_fragment('name')
379   end
380
381   def test_read_fragment__with_caching_disabled
382     ActionController::Base.perform_caching = false
383     @store.write('views/name', 'value')
384     assert_nil @controller.read_fragment('name')
385   end
386
387   def test_write_fragment__with_caching_enabled
388     assert_nil @store.read('views/name')
389     assert_equal 'value', @controller.write_fragment('name', 'value')
390     assert_equal 'value', @store.read('views/name')
391   end
392
393   def test_write_fragment__with_caching_disabled
394     assert_nil @store.read('views/name')
395     ActionController::Base.perform_caching = false
396     assert_equal nil, @controller.write_fragment('name', 'value')
397     assert_nil @store.read('views/name')
398   end
399
400   def test_expire_fragment__with_simple_key
401     @store.write('views/name', 'value')
402     @controller.expire_fragment 'name'
403     assert_nil @store.read('views/name')
404   end
405
406   def test_expire_fragment__with__regexp
407     @store.write('views/name', 'value')
408     @store.write('views/another_name', 'another_value')
409     @store.write('views/primalgrasp', 'will not expire ;-)')
410
411     @controller.expire_fragment /name/
412
413     assert_nil @store.read('views/name')
414     assert_nil @store.read('views/another_name')
415     assert_equal 'will not expire ;-)', @store.read('views/primalgrasp')
416   end
417
418   def test_fragment_for__with_disabled_caching
419     ActionController::Base.perform_caching = false
420
421     @store.write('views/expensive', 'fragment content')
422     fragment_computed = false
423
424     buffer = 'generated till now -> '
425     @controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer }
426
427     assert fragment_computed
428     assert_equal 'generated till now -> ', buffer
429   end
430
431
432   def test_fragment_for
433     @store.write('views/expensive', 'fragment content')
434     fragment_computed = false
435
436     buffer = 'generated till now -> '
437     @controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer}
438
439     assert !fragment_computed
440     assert_equal 'generated till now -> fragment content', buffer
441   end
442
443   def test_cache_erb_fragment
444     @store.write('views/expensive', 'fragment content')
445     _erbout = 'generated till now -> '
446
447     assert_equal( 'generated till now -> fragment content',
448                   ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
449   end
450
451   def test_cache_rxml_fragment
452     @store.write('views/expensive', 'fragment content')
453     xml = 'generated till now -> '
454     class << xml; def target!; to_s; end; end
455
456     assert_equal( 'generated till now -> fragment content',
457                   ActionView::TemplateHandlers::Builder.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
458   end
459
460   def test_cache_rjs_fragment
461     @store.write('views/expensive', 'fragment content')
462     page = 'generated till now -> '
463
464     assert_equal( 'generated till now -> fragment content',
465                   ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
466   end
467
468   def test_cache_rjs_fragment_debug_mode_does_not_interfere
469     @store.write('views/expensive', 'fragment content')
470     page = 'generated till now -> '
471
472     begin
473       debug_mode, ActionView::Base.debug_rjs = ActionView::Base.debug_rjs, true
474       assert_equal( 'generated till now -> fragment content',
475                      ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
476       assert ActionView::Base.debug_rjs
477     ensure
478       ActionView::Base.debug_rjs = debug_mode
479     end
480   end
481 end
482
483
484 class FunctionalCachingController < ActionController::Base
485   def fragment_cached
486   end
487
488   def html_fragment_cached_with_partial
489     respond_to do |format|
490       format.html
491     end
492   end
493
494   def js_fragment_cached_with_partial
495     respond_to do |format|
496       format.js
497     end
498   end
499
500
501   def rescue_action(e)
502     raise e
503   end
504 end
505
506 FunctionalCachingController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
507
508 class FunctionalFragmentCachingTest < Test::Unit::TestCase
509   def setup
510     ActionController::Base.perform_caching = true
511     @store = ActiveSupport::Cache::MemoryStore.new
512     ActionController::Base.cache_store = @store   
513     @controller = FunctionalCachingController.new
514     @request = ActionController::TestRequest.new
515     @response = ActionController::TestResponse.new
516   end
517   def test_fragment_caching
518     get :fragment_cached
519     assert_response :success
520     expected_body = <<-CACHED
521 Hello
522 This bit's fragment cached
523 CACHED
524     assert_equal expected_body, @response.body
525    
526     assert_equal "This bit's fragment cached", @store.read('views/test.host/functional_caching/fragment_cached')
527   end
528  
529   def test_fragment_caching_in_partials
530     get :html_fragment_cached_with_partial
531     assert_response :success
532     assert_match /Fragment caching in a partial/, @response.body
533     assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial')
534   end
535  
536   def test_fragment_caching_in_rjs_partials
537     xhr :get, :js_fragment_cached_with_partial
538     assert_response :success
539     assert_match /Fragment caching in a partial/, @response.body
540     assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/js_fragment_cached_with_partial')
541   end
542 end
543
544
545
546
547
Note: See TracBrowser for help on using the browser.