PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/actionpack/test/controller/caching_test.rb

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