openstreetmap-actionpack-page_caching 1.1.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.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs = ["test"]
7
+ t.pattern = "test/**/*_test.rb"
8
+ t.ruby_opts = ["-w"]
9
+ end
10
+
11
+ task default: :test
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = "openstreetmap-actionpack-page_caching"
3
+ gem.version = "1.1.2"
4
+ gem.author = "David Heinemeier Hansson"
5
+ gem.email = "tom@compton.nu"
6
+ gem.description = "Static page caching for Action Pack (removed from core in Rails 4.0)"
7
+ gem.summary = "Static page caching for Action Pack (removed from core in Rails 4.0)"
8
+ gem.homepage = "https://github.com/rails/actionpack-page_caching"
9
+ gem.license = "MIT"
10
+
11
+ gem.required_ruby_version = '>= 2.4.6'
12
+ gem.files = `git ls-files`.split($/)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+ gem.license = 'MIT'
17
+
18
+ gem.add_dependency "actionpack", ">= 5.0.0"
19
+
20
+ gem.add_development_dependency "mocha"
21
+ end
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ gem "rails", github: "rails/rails", branch: "5-0-stable"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ gem "rails", github: "rails/rails", branch: "5-1-stable"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ gem "rails", github: "rails/rails", branch: "5-2-stable"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ gem "rails", github: "rails/rails", branch: "6-0-stable"
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ gem "rails", github: "rails/rails", branch: "master"
6
+ gem "arel", github: "rails/arel", branch: "master"
@@ -0,0 +1,306 @@
1
+ require "fileutils"
2
+ require "uri"
3
+ require "active_support/core_ext/class/attribute_accessors"
4
+ require "active_support/core_ext/string/strip"
5
+
6
+ module ActionController
7
+ module Caching
8
+ # Page caching is an approach to caching where the entire action output of is
9
+ # stored as a HTML file that the web server can serve without going through
10
+ # Action Pack. This is the fastest way to cache your content as opposed to going
11
+ # dynamically through the process of generating the content. Unfortunately, this
12
+ # incredible speed-up is only available to stateless pages where all visitors are
13
+ # treated the same. Content management systems -- including weblogs and wikis --
14
+ # have many pages that are a great fit for this approach, but account-based systems
15
+ # where people log in and manipulate their own data are often less likely candidates.
16
+ #
17
+ # Specifying which actions to cache is done through the +caches_page+ class method:
18
+ #
19
+ # class WeblogController < ActionController::Base
20
+ # caches_page :show, :new
21
+ # end
22
+ #
23
+ # This will generate cache files such as <tt>weblog/show/5.html</tt> and
24
+ # <tt>weblog/new.html</tt>, which match the URLs used that would normally trigger
25
+ # dynamic page generation. Page caching works by configuring a web server to first
26
+ # check for the existence of files on disk, and to serve them directly when found,
27
+ # without passing the request through to Action Pack. This is much faster than
28
+ # handling the full dynamic request in the usual way.
29
+ #
30
+ # Expiration of the cache is handled by deleting the cached file, which results
31
+ # in a lazy regeneration approach where the cache is not restored before another
32
+ # hit is made against it. The API for doing so mimics the options from +url_for+ and friends:
33
+ #
34
+ # class WeblogController < ActionController::Base
35
+ # def update
36
+ # List.update(params[:list][:id], params[:list])
37
+ # expire_page action: "show", id: params[:list][:id]
38
+ # redirect_to action: "show", id: params[:list][:id]
39
+ # end
40
+ # end
41
+ #
42
+ # Additionally, you can expire caches using Sweepers that act on changes in
43
+ # the model to determine when a cache is supposed to be expired.
44
+ module Pages
45
+ extend ActiveSupport::Concern
46
+
47
+ included do
48
+ # The cache directory should be the document root for the web server and is
49
+ # set using <tt>Base.page_cache_directory = "/document/root"</tt>. For Rails,
50
+ # this directory has already been set to Rails.public_path (which is usually
51
+ # set to <tt>Rails.root + "/public"</tt>). Changing this setting can be useful
52
+ # to avoid naming conflicts with files in <tt>public/</tt>, but doing so will
53
+ # likely require configuring your web server to look in the new location for
54
+ # cached files.
55
+ class_attribute :page_cache_directory
56
+ self.page_cache_directory ||= ""
57
+
58
+ # The compression used for gzip. If +false+ (default), the page is not compressed.
59
+ # If can be a symbol showing the ZLib compression method, for example, <tt>:best_compression</tt>
60
+ # or <tt>:best_speed</tt> or an integer configuring the compression level.
61
+ class_attribute :page_cache_compression
62
+ self.page_cache_compression ||= false
63
+ end
64
+
65
+ class PageCache #:nodoc:
66
+ def initialize(cache_directory, default_extension, controller = nil)
67
+ @cache_directory = cache_directory
68
+ @default_extension = default_extension
69
+ @controller = controller
70
+ end
71
+
72
+ def expire(path)
73
+ instrument :expire_page, path do
74
+ delete(cache_path(path))
75
+ end
76
+ end
77
+
78
+ def cache(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
79
+ instrument :write_page, path do
80
+ write(content, cache_path(path, extension), gzip)
81
+ end
82
+ end
83
+
84
+ private
85
+ def cache_directory
86
+ case @cache_directory
87
+ when Proc
88
+ handle_proc_cache_directory
89
+ when Symbol
90
+ handle_symbol_cache_directory
91
+ else
92
+ handle_default_cache_directory
93
+ end
94
+ end
95
+
96
+ def handle_proc_cache_directory
97
+ if @controller
98
+ @controller.instance_exec(&@cache_directory)
99
+ else
100
+ raise_runtime_error
101
+ end
102
+ end
103
+
104
+ def handle_symbol_cache_directory
105
+ if @controller
106
+ @controller.send(@cache_directory)
107
+ else
108
+ raise_runtime_error
109
+ end
110
+ end
111
+
112
+ def handle_callable_cache_directory
113
+ if @controller
114
+ @cache_directory.call(@controller.request)
115
+ else
116
+ raise_runtime_error
117
+ end
118
+ end
119
+
120
+ def handle_default_cache_directory
121
+ if @cache_directory.respond_to?(:call)
122
+ handle_callable_cache_directory
123
+ else
124
+ @cache_directory.to_s
125
+ end
126
+ end
127
+
128
+ def raise_runtime_error
129
+ raise RuntimeError, <<-MSG.strip_heredoc
130
+ Dynamic page_cache_directory used with class-level cache_page method
131
+
132
+ You have specified either a Proc, Symbol or callable object for page_cache_directory
133
+ which needs to be executed within the context of a request. If you need to call the
134
+ cache_page method from a class-level context then set the page_cache_directory to a
135
+ static value and override the setting at the instance-level using before_action.
136
+ MSG
137
+ end
138
+
139
+ def default_extension
140
+ @default_extension
141
+ end
142
+
143
+ def cache_file(path, extension)
144
+ if path.empty? || path =~ %r{\A/+\z}
145
+ name = "/index"
146
+ else
147
+ name = URI.parser.unescape(path.chomp("/"))
148
+ end
149
+
150
+ if File.extname(name).empty?
151
+ name + (extension || default_extension)
152
+ else
153
+ name
154
+ end
155
+ end
156
+
157
+ def cache_path(path, extension = nil)
158
+ File.join(cache_directory, cache_file(path, extension))
159
+ end
160
+
161
+ def delete(path)
162
+ File.delete(path) if File.exist?(path)
163
+ File.delete(path + ".gz") if File.exist?(path + ".gz")
164
+ end
165
+
166
+ def write(content, path, gzip)
167
+ FileUtils.makedirs(File.dirname(path))
168
+ File.open(path, "wb+") { |f| f.write(content) }
169
+
170
+ if gzip
171
+ Zlib::GzipWriter.open(path + ".gz", gzip) { |f| f.write(content) }
172
+ end
173
+ end
174
+
175
+ def instrument(name, path)
176
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", path: path) { yield }
177
+ end
178
+ end
179
+
180
+ module ClassMethods
181
+ # Expires the page that was cached with the +path+ as a key.
182
+ #
183
+ # expire_page "/lists/show"
184
+ def expire_page(path)
185
+ if perform_caching
186
+ page_cache.expire(path)
187
+ end
188
+ end
189
+
190
+ # Manually cache the +content+ in the key determined by +path+.
191
+ #
192
+ # cache_page "I'm the cached content", "/lists/show"
193
+ def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
194
+ if perform_caching
195
+ page_cache.cache(content, path, extension, gzip)
196
+ end
197
+ end
198
+
199
+ # Caches the +actions+ using the page-caching approach that'll store
200
+ # the cache in a path within the +page_cache_directory+ that
201
+ # matches the triggering url.
202
+ #
203
+ # You can also pass a <tt>:gzip</tt> option to override the class configuration one.
204
+ #
205
+ # # cache the index action
206
+ # caches_page :index
207
+ #
208
+ # # cache the index action except for JSON requests
209
+ # caches_page :index, if: Proc.new { !request.format.json? }
210
+ #
211
+ # # don't gzip images
212
+ # caches_page :image, gzip: false
213
+ def caches_page(*actions)
214
+ if perform_caching
215
+ options = actions.extract_options!
216
+
217
+ gzip_level = options.fetch(:gzip, page_cache_compression)
218
+ gzip_level = \
219
+ case gzip_level
220
+ when Symbol
221
+ Zlib.const_get(gzip_level.upcase)
222
+ when Integer
223
+ gzip_level
224
+ when false
225
+ nil
226
+ else
227
+ Zlib::BEST_COMPRESSION
228
+ end
229
+
230
+ after_action({ only: actions }.merge(options)) do |c|
231
+ c.cache_page(nil, nil, gzip_level)
232
+ end
233
+ end
234
+ end
235
+
236
+ private
237
+ def page_cache
238
+ PageCache.new(page_cache_directory, default_static_extension)
239
+ end
240
+ end
241
+
242
+ # Expires the page that was cached with the +options+ as a key.
243
+ #
244
+ # expire_page controller: "lists", action: "show"
245
+ def expire_page(options = {})
246
+ if perform_caching?
247
+ case options
248
+ when Hash
249
+ case options[:action]
250
+ when Array
251
+ options[:action].each { |action| expire_page(options.merge(action: action)) }
252
+ else
253
+ page_cache.expire(url_for(options.merge(only_path: true)))
254
+ end
255
+ else
256
+ page_cache.expire(options)
257
+ end
258
+ end
259
+ end
260
+
261
+ # Manually cache the +content+ in the key determined by +options+. If no content is provided,
262
+ # the contents of response.body is used. If no options are provided, the url of the current
263
+ # request being handled is used.
264
+ #
265
+ # cache_page "I'm the cached content", controller: "lists", action: "show"
266
+ def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
267
+ if perform_caching? && caching_allowed?
268
+ path = \
269
+ case options
270
+ when Hash
271
+ url_for(options.merge(only_path: true, format: params[:format]))
272
+ when String
273
+ options
274
+ else
275
+ request.path
276
+ end
277
+
278
+ type = if self.respond_to?(:media_type)
279
+ Mime::LOOKUP[self.media_type]
280
+ else
281
+ Mime::LOOKUP[self.content_type]
282
+ end
283
+
284
+ if type && (type_symbol = type.symbol).present?
285
+ extension = ".#{type_symbol}"
286
+ end
287
+
288
+ page_cache.cache(content || response.body, path, extension, gzip)
289
+ end
290
+ end
291
+
292
+ def caching_allowed?
293
+ (request.get? || request.head?) && response.status == 200
294
+ end
295
+
296
+ def perform_caching?
297
+ self.class.perform_caching
298
+ end
299
+
300
+ private
301
+ def page_cache
302
+ PageCache.new(page_cache_directory, default_static_extension, self)
303
+ end
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,13 @@
1
+ require "action_controller/caching/pages"
2
+
3
+ module ActionController
4
+ module Caching
5
+ eager_autoload do
6
+ autoload :Pages
7
+ end
8
+
9
+ include Pages
10
+ end
11
+ end
12
+
13
+ ActionController::Base.send(:include, ActionController::Caching::Pages)
@@ -0,0 +1 @@
1
+ require "actionpack/page_caching/railtie"
@@ -0,0 +1,17 @@
1
+ require "rails/railtie"
2
+
3
+ module ActionPack
4
+ module PageCaching
5
+ class Railtie < Rails::Railtie
6
+ initializer "action_pack.page_caching" do
7
+ ActiveSupport.on_load(:action_controller) do
8
+ require "action_controller/page_caching"
9
+ end
10
+ end
11
+
12
+ initializer "action_pack.page_caching.set_config", before: "action_controller.set_configs" do |app|
13
+ app.config.action_controller.page_cache_directory ||= app.config.paths["public"].first
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ require "bundler/setup"
2
+ require "minitest/autorun"
3
+ require "action_controller"
4
+ require "action_controller/page_caching"
5
+
6
+ if ActiveSupport.respond_to?(:test_order)
7
+ ActiveSupport.test_order = :random
8
+ end
9
+
10
+ if ActionController::Base.respond_to?(:enable_fragment_cache_logging=)
11
+ ActionController::Base.enable_fragment_cache_logging = true
12
+ end
@@ -0,0 +1,524 @@
1
+ require "abstract_unit"
2
+ require "mocha/setup"
3
+
4
+ CACHE_DIR = "test_cache"
5
+ # Don't change "../tmp" cavalierly or you might hose something you don't want hosed
6
+ TEST_TMP_DIR = File.expand_path("../tmp", __FILE__)
7
+ FILE_STORE_PATH = File.join(TEST_TMP_DIR, CACHE_DIR)
8
+
9
+ module PageCachingTestHelpers
10
+ def setup
11
+ super
12
+
13
+ @routes = ActionDispatch::Routing::RouteSet.new
14
+
15
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
16
+ FileUtils.mkdir_p(FILE_STORE_PATH)
17
+ end
18
+
19
+ def teardown
20
+ super
21
+
22
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
23
+ @controller.perform_caching = false
24
+ end
25
+
26
+ private
27
+
28
+ def assert_page_cached(action, options = {})
29
+ expected = options[:content] || action.to_s
30
+ path = cache_file(action, options)
31
+
32
+ assert File.exist?(path), "The cache file #{path} doesn't exist"
33
+
34
+ if File.extname(path) == ".gz"
35
+ actual = Zlib::GzipReader.open(path) { |f| f.read }
36
+ else
37
+ actual = File.read(path)
38
+ end
39
+
40
+ assert_equal expected, actual, "The cached content doesn't match the expected value"
41
+ end
42
+
43
+ def assert_page_not_cached(action, options = {})
44
+ path = cache_file(action, options)
45
+ assert !File.exist?(path), "The cache file #{path} still exists"
46
+ end
47
+
48
+ def cache_file(action, options = {})
49
+ path = options[:path] || FILE_STORE_PATH
50
+ controller = options[:controller] || self.class.name.underscore
51
+ format = options[:format] || "html"
52
+
53
+ "#{path}/#{controller}/#{action}.#{format}"
54
+ end
55
+
56
+ def draw(&block)
57
+ @routes = ActionDispatch::Routing::RouteSet.new
58
+ @routes.draw(&block)
59
+ @controller.extend(@routes.url_helpers)
60
+ end
61
+ end
62
+
63
+ class CachingMetalController < ActionController::Metal
64
+ abstract!
65
+
66
+ include AbstractController::Callbacks
67
+ include ActionController::Caching
68
+
69
+ self.page_cache_directory = FILE_STORE_PATH
70
+ self.cache_store = :file_store, FILE_STORE_PATH
71
+ end
72
+
73
+ class PageCachingMetalTestController < CachingMetalController
74
+ caches_page :ok
75
+
76
+ def ok
77
+ self.response_body = "ok"
78
+ end
79
+ end
80
+
81
+ class PageCachingMetalTest < ActionController::TestCase
82
+ include PageCachingTestHelpers
83
+ tests PageCachingMetalTestController
84
+
85
+ def test_should_cache_get_with_ok_status
86
+ draw do
87
+ get "/page_caching_metal_test/ok", to: "page_caching_metal_test#ok"
88
+ end
89
+
90
+ get :ok
91
+ assert_response :ok
92
+ assert_page_cached :ok
93
+ end
94
+ end
95
+
96
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
97
+
98
+ class CachingController < ActionController::Base
99
+ abstract!
100
+
101
+ self.cache_store = :file_store, FILE_STORE_PATH
102
+
103
+ protected
104
+ if ActionPack::VERSION::STRING < "4.1"
105
+ def render(options)
106
+ if options.key?(:html)
107
+ super({ text: options.delete(:html) }.merge(options))
108
+ else
109
+ super
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ class PageCachingTestController < CachingController
116
+ self.page_cache_compression = :best_compression
117
+
118
+ caches_page :ok, :no_content, if: Proc.new { |c| !c.request.format.json? }
119
+ caches_page :found, :not_found
120
+ caches_page :about_me
121
+ caches_page :default_gzip
122
+ caches_page :no_gzip, gzip: false
123
+ caches_page :gzip_level, gzip: :best_speed
124
+
125
+ def ok
126
+ render html: "ok"
127
+ end
128
+
129
+ def no_content
130
+ head :no_content
131
+ end
132
+
133
+ def found
134
+ redirect_to action: "ok"
135
+ end
136
+
137
+ def not_found
138
+ head :not_found
139
+ end
140
+
141
+ def custom_path
142
+ render html: "custom_path"
143
+ cache_page(nil, "/index.html")
144
+ end
145
+
146
+ def default_gzip
147
+ render html: "default_gzip"
148
+ end
149
+
150
+ def no_gzip
151
+ render html: "no_gzip"
152
+ end
153
+
154
+ def gzip_level
155
+ render html: "gzip_level"
156
+ end
157
+
158
+ def expire_custom_path
159
+ expire_page("/index.html")
160
+ head :ok
161
+ end
162
+
163
+ def trailing_slash
164
+ render html: "trailing_slash"
165
+ end
166
+
167
+ def about_me
168
+ respond_to do |format|
169
+ format.html { render html: "I am html" }
170
+ format.xml { render xml: "I am xml" }
171
+ end
172
+ end
173
+ end
174
+
175
+ class PageCachingTest < ActionController::TestCase
176
+ include PageCachingTestHelpers
177
+ tests PageCachingTestController
178
+
179
+ def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
180
+ draw do
181
+ get "posts.:format", to: "posts#index", as: :formatted_posts
182
+ get "/", to: "posts#index", as: :main
183
+ end
184
+
185
+ defaults = { controller: "posts", action: "index", only_path: true }
186
+
187
+ assert_equal "/posts.rss", @routes.url_for(defaults.merge(format: "rss"))
188
+ assert_equal "/", @routes.url_for(defaults.merge(format: nil))
189
+ end
190
+
191
+ def test_should_cache_head_with_ok_status
192
+ draw do
193
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
194
+ end
195
+
196
+ head :ok
197
+ assert_response :ok
198
+ assert_page_cached :ok
199
+ end
200
+
201
+ def test_should_cache_get_with_ok_status
202
+ draw do
203
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
204
+ end
205
+
206
+ get :ok
207
+ assert_response :ok
208
+ assert_page_cached :ok
209
+ end
210
+
211
+ def test_should_cache_with_custom_path
212
+ draw do
213
+ get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
214
+ end
215
+
216
+ get :custom_path
217
+ assert_page_cached :index, controller: ".", content: "custom_path"
218
+ end
219
+
220
+ def test_should_expire_cache_with_custom_path
221
+ draw do
222
+ get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
223
+ get "/page_caching_test/expire_custom_path", to: "page_caching_test#expire_custom_path"
224
+ end
225
+
226
+ get :custom_path
227
+ assert_page_cached :index, controller: ".", content: "custom_path"
228
+
229
+ get :expire_custom_path
230
+ assert_page_not_cached :index, controller: ".", content: "custom_path"
231
+ end
232
+
233
+ def test_should_gzip_cache
234
+ draw do
235
+ get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
236
+ get "/page_caching_test/expire_custom_path", to: "page_caching_test#expire_custom_path"
237
+ end
238
+
239
+ get :custom_path
240
+ assert_page_cached :index, controller: ".", format: "html.gz", content: "custom_path"
241
+
242
+ get :expire_custom_path
243
+ assert_page_not_cached :index, controller: ".", format: "html.gz"
244
+ end
245
+
246
+ def test_should_allow_to_disable_gzip
247
+ draw do
248
+ get "/page_caching_test/no_gzip", to: "page_caching_test#no_gzip"
249
+ end
250
+
251
+ get :no_gzip
252
+ assert_page_cached :no_gzip, format: "html"
253
+ assert_page_not_cached :no_gzip, format: "html.gz"
254
+ end
255
+
256
+ def test_should_use_config_gzip_by_default
257
+ draw do
258
+ get "/page_caching_test/default_gzip", to: "page_caching_test#default_gzip"
259
+ end
260
+
261
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_COMPRESSION)
262
+ get :default_gzip
263
+ end
264
+
265
+ def test_should_set_gzip_level
266
+ draw do
267
+ get "/page_caching_test/gzip_level", to: "page_caching_test#gzip_level"
268
+ end
269
+
270
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_SPEED)
271
+ get :gzip_level
272
+ end
273
+
274
+ def test_should_cache_without_trailing_slash_on_url
275
+ @controller.class.cache_page "cached content", "/page_caching_test/trailing_slash"
276
+ assert_page_cached :trailing_slash, content: "cached content"
277
+ end
278
+
279
+ def test_should_obey_http_accept_attribute
280
+ draw do
281
+ get "/page_caching_test/about_me", to: "page_caching_test#about_me"
282
+ end
283
+
284
+ @request.env["HTTP_ACCEPT"] = "text/xml"
285
+ get :about_me
286
+ assert_equal "I am xml", @response.body
287
+ assert_page_cached :about_me, format: "xml", content: "I am xml"
288
+ end
289
+
290
+ def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
291
+ @controller.class.cache_page "cached content", "/page_caching_test/trailing_slash/"
292
+ assert_page_cached :trailing_slash, content: "cached content"
293
+ end
294
+
295
+ def test_should_cache_ok_at_custom_path
296
+ draw do
297
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
298
+ end
299
+
300
+ @request.env["PATH_INFO"] = "/index.html"
301
+ get :ok
302
+ assert_response :ok
303
+ assert_page_cached :index, controller: ".", content: "ok"
304
+ end
305
+
306
+ [:ok, :no_content, :found, :not_found].each do |status|
307
+ [:get, :post, :patch, :put, :delete].each do |method|
308
+ unless method == :get && status == :ok
309
+ define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
310
+ draw do
311
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
312
+ match "/page_caching_test/#{status}", to: "page_caching_test##{status}", via: method
313
+ end
314
+
315
+ send(method, status)
316
+ assert_response status
317
+ assert_page_not_cached status
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ def test_page_caching_conditional_options
324
+ draw do
325
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
326
+ end
327
+
328
+ get :ok, format: "json"
329
+ assert_page_not_cached :ok
330
+ end
331
+
332
+ def test_page_caching_directory_set_as_pathname
333
+ begin
334
+ ActionController::Base.page_cache_directory = Pathname.new(FILE_STORE_PATH)
335
+
336
+ draw do
337
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
338
+ end
339
+
340
+ get :ok
341
+ assert_response :ok
342
+ assert_page_cached :ok
343
+ ensure
344
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
345
+ end
346
+ end
347
+
348
+ def test_page_caching_directory_set_on_controller_instance
349
+ draw do
350
+ get "/page_caching_test/ok", to: "page_caching_test#ok"
351
+ end
352
+
353
+ file_store_path = File.join(TEST_TMP_DIR, "instance_cache")
354
+ @controller.page_cache_directory = file_store_path
355
+
356
+ get :ok
357
+ assert_response :ok
358
+ assert_page_cached :ok, path: file_store_path
359
+ end
360
+ end
361
+
362
+ class ProcPageCachingTestController < CachingController
363
+ self.page_cache_directory = -> { File.join(TEST_TMP_DIR, request.domain) }
364
+
365
+ caches_page :ok
366
+
367
+ def ok
368
+ render html: "ok"
369
+ end
370
+
371
+ def expire_ok
372
+ expire_page action: :ok
373
+ head :ok
374
+ end
375
+ end
376
+
377
+ class ProcPageCachingTest < ActionController::TestCase
378
+ include PageCachingTestHelpers
379
+ tests ProcPageCachingTestController
380
+
381
+ def test_page_is_cached_by_domain
382
+ draw do
383
+ get "/proc_page_caching_test/ok", to: "proc_page_caching_test#ok"
384
+ get "/proc_page_caching_test/ok/expire", to: "proc_page_caching_test#expire_ok"
385
+ end
386
+
387
+ @request.env["HTTP_HOST"] = "www.foo.com"
388
+ get :ok
389
+ assert_response :ok
390
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
391
+
392
+ get :expire_ok
393
+ assert_response :ok
394
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
395
+
396
+ @request.env["HTTP_HOST"] = "www.bar.com"
397
+ get :ok
398
+ assert_response :ok
399
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
400
+
401
+ get :expire_ok
402
+ assert_response :ok
403
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
404
+ end
405
+
406
+ def test_class_level_cache_page_raise_error
407
+ assert_raises(RuntimeError, /class-level cache_page method/) do
408
+ @controller.class.cache_page "cached content", "/proc_page_caching_test/ok"
409
+ end
410
+ end
411
+ end
412
+
413
+ class SymbolPageCachingTestController < CachingController
414
+ self.page_cache_directory = :domain_cache_directory
415
+
416
+ caches_page :ok
417
+
418
+ def ok
419
+ render html: "ok"
420
+ end
421
+
422
+ def expire_ok
423
+ expire_page action: :ok
424
+ head :ok
425
+ end
426
+
427
+ protected
428
+ def domain_cache_directory
429
+ File.join(TEST_TMP_DIR, request.domain)
430
+ end
431
+ end
432
+
433
+ class SymbolPageCachingTest < ActionController::TestCase
434
+ include PageCachingTestHelpers
435
+ tests SymbolPageCachingTestController
436
+
437
+ def test_page_is_cached_by_domain
438
+ draw do
439
+ get "/symbol_page_caching_test/ok", to: "symbol_page_caching_test#ok"
440
+ get "/symbol_page_caching_test/ok/expire", to: "symbol_page_caching_test#expire_ok"
441
+ end
442
+
443
+ @request.env["HTTP_HOST"] = "www.foo.com"
444
+ get :ok
445
+ assert_response :ok
446
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
447
+
448
+ get :expire_ok
449
+ assert_response :ok
450
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
451
+
452
+ @request.env["HTTP_HOST"] = "www.bar.com"
453
+ get :ok
454
+ assert_response :ok
455
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
456
+
457
+ get :expire_ok
458
+ assert_response :ok
459
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
460
+ end
461
+
462
+ def test_class_level_cache_page_raise_error
463
+ assert_raises(RuntimeError, /class-level cache_page method/) do
464
+ @controller.class.cache_page "cached content", "/symbol_page_caching_test/ok"
465
+ end
466
+ end
467
+ end
468
+
469
+ class CallablePageCachingTestController < CachingController
470
+ class DomainCacheDirectory
471
+ def self.call(request)
472
+ File.join(TEST_TMP_DIR, request.domain)
473
+ end
474
+ end
475
+
476
+ self.page_cache_directory = DomainCacheDirectory
477
+
478
+ caches_page :ok
479
+
480
+ def ok
481
+ render html: "ok"
482
+ end
483
+
484
+ def expire_ok
485
+ expire_page action: :ok
486
+ head :ok
487
+ end
488
+ end
489
+
490
+ class CallablePageCachingTest < ActionController::TestCase
491
+ include PageCachingTestHelpers
492
+ tests CallablePageCachingTestController
493
+
494
+ def test_page_is_cached_by_domain
495
+ draw do
496
+ get "/callable_page_caching_test/ok", to: "callable_page_caching_test#ok"
497
+ get "/callable_page_caching_test/ok/expire", to: "callable_page_caching_test#expire_ok"
498
+ end
499
+
500
+ @request.env["HTTP_HOST"] = "www.foo.com"
501
+ get :ok
502
+ assert_response :ok
503
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
504
+
505
+ get :expire_ok
506
+ assert_response :ok
507
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
508
+
509
+ @request.env["HTTP_HOST"] = "www.bar.com"
510
+ get :ok
511
+ assert_response :ok
512
+ assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
513
+
514
+ get :expire_ok
515
+ assert_response :ok
516
+ assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
517
+ end
518
+
519
+ def test_class_level_cache_page_raise_error
520
+ assert_raises(RuntimeError, /class-level cache_page method/) do
521
+ @controller.class.cache_page "cached content", "/callable_page_caching_test/ok"
522
+ end
523
+ end
524
+ end