actionpack-page_caching_multithread 1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a147a8417128e01b369621434196fd328aa1c29a
4
+ data.tar.gz: ce604c979d8946929e535e7ef1c0ce697a1d6e50
5
+ SHA512:
6
+ metadata.gz: ce048215299a130b477b9ea7974d04b8966c0d014c7cd3d9fe60d5c5c39854678b54427549a9f1f95d6780a137b45792de3a0f039e56180672eb2bf0372ec6ce
7
+ data.tar.gz: 409c1e2c4cea069c07448693a10b327f6eb073dfd6bb2cb3bca88c274cf314519bfe47230462c7595345a507e3b261442ba8a61ac76edbf0d4bab733bb8eb821
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,25 @@
1
+ language: ruby
2
+ before_install:
3
+ - gem install bundler
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ gemfile:
8
+ - Gemfile
9
+ - gemfiles/Gemfile-4-0-stable
10
+ - gemfiles/Gemfile-edge
11
+ matrix:
12
+ allow_failures:
13
+ - gemfile: gemfiles/Gemfile-edge
14
+ notifications:
15
+ email: false
16
+ irc:
17
+ on_success: change
18
+ on_failure: always
19
+ channels:
20
+ - "irc.freenode.org#rails-contrib"
21
+ campfire:
22
+ on_success: change
23
+ on_failure: always
24
+ rooms:
25
+ - secure: "eRCx+FMvH50pmLu0GZTF7NN+2X+CesgodYUlHvCr5EXQ0ZO/YUmeW8vAh/N8\njSrLWYpk/4P/JA63JGWsvFor/zpkTnfwzX3LWgw04GV0V3T9jsn9CD2Coiu6\nFll5u4fUCUwpfbB4RlCkjvFdQmW+F9mmbRGMCDO5CmuPHOyyPH0="
@@ -0,0 +1,11 @@
1
+ # 1.0.2
2
+
3
+ * Fix load order problem with other gems.
4
+
5
+ # 1.0.1
6
+
7
+ * Add Railtie to set `page_cache_directory` by default to `public` folder. (Fixes #5)
8
+
9
+ # 1.0.0
10
+
11
+ * First Release
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rails'
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Dimelo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,81 @@
1
+ actionpack-page_caching_multithread
2
+ =======================
3
+
4
+ Static page caching for Action Pack (removed from core in Rails 4.0).
5
+
6
+ **NOTE:** It will continue to be officially maintained until Rails 4.1.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'actionpack-page_caching_multithread'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install actionpack-page_caching_multithread
22
+
23
+ Usage
24
+ -----
25
+
26
+ Page caching is an approach to caching where the entire action output of is
27
+ stored as a HTML file that the web server can serve without going through
28
+ Action Pack. This is the fastest way to cache your content as opposed to going
29
+ dynamically through the process of generating the content. Unfortunately, this
30
+ incredible speed-up is only available to stateless pages where all visitors are
31
+ treated the same. Content management systems -- including weblogs and wikis --
32
+ have many pages that are a great fit for this approach, but account-based systems
33
+ where people log in and manipulate their own data are often less likely candidates.
34
+
35
+ First you need to set `page_cache_directory` in your configuration file:
36
+
37
+ config.action_controller.page_cache_directory = "#{Rails.root.to_s}/public/deploy"
38
+
39
+ Specifying which actions to cache is done through the `caches_page` class method:
40
+
41
+ class WeblogController < ActionController::Base
42
+ caches_page :show, :new
43
+ end
44
+
45
+ This will generate cache files such as `weblog/show/5.html` and
46
+ `weblog/new.html`, which match the URLs used that would normally trigger
47
+ dynamic page generation. Page caching works by configuring a web server to first
48
+ check for the existence of files on disk, and to serve them directly when found,
49
+ without passing the request through to Action Pack. This is much faster than
50
+ handling the full dynamic request in the usual way.
51
+
52
+ Expiration of the cache is handled by deleting the cached file, which results
53
+ in a lazy regeneration approach where the cache is not restored before another
54
+ hit is made against it. The API for doing so mimics the options from `url_for`
55
+ and friends:
56
+
57
+ class WeblogController < ActionController::Base
58
+ def update
59
+ List.update(params[:list][:id], params[:list])
60
+ expire_page action: 'show', id: params[:list][:id]
61
+ redirect_to action: 'show', id: params[:list][:id]
62
+ end
63
+ end
64
+
65
+ Additionally, you can expire caches using [Sweepers](https://github.com/rails/rails-observers#action-controller-sweeper)
66
+ that act on changes in the model to determine when a cache is supposed to be expired.
67
+
68
+ Contributing
69
+ ------------
70
+
71
+ 1. Fork it.
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
74
+ 4. Push to the branch (`git push origin my-new-feature`).
75
+ 5. Create a new Pull Request.
76
+
77
+ Code Status
78
+ -----------
79
+
80
+ * [![Build Status](https://travis-ci.org/dimelo/actionpack-page_caching_multithread.png?branch=master)](https://travis-ci.org/dimelo/page_caching_multithread)
81
+ * [![Dependency Status](https://gemnasium.com/dimelo/actionpack-page_caching_multithread.png)](https://gemnasium.com/dimelo/actionpack-page_caching_multithread)
@@ -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
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'actionpack-page_caching_multithread'
5
+ gem.version = '1.2'
6
+ gem.author = 'Dimelo'
7
+ gem.email = 'contact@dimelo.com'
8
+ gem.description = 'Threadsafe Static page caching for Action Pack 4.x'
9
+ gem.summary = 'Threadsafe Static page caching for Action Pack 4.x'
10
+ gem.homepage = 'https://github.com/dimelo/actionpack-page_caching_multithread'
11
+ gem.license = 'MIT'
12
+
13
+ gem.files = `git ls-files`.split($/)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_dependency 'actionpack', '>= 4.0.0', '< 5'
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: '4-0-stable'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'rails', github: 'rails/rails', branch: 'master'
@@ -0,0 +1,213 @@
1
+ require 'fileutils'
2
+ require 'active_support/core_ext/class/attribute_accessors'
3
+
4
+ module ActionController
5
+ module Caching
6
+ # Page caching is an approach to caching where the entire action output of is
7
+ # stored as a HTML file that the web server can serve without going through
8
+ # Action Pack. This is the fastest way to cache your content as opposed to going
9
+ # dynamically through the process of generating the content. Unfortunately, this
10
+ # incredible speed-up is only available to stateless pages where all visitors are
11
+ # treated the same. Content management systems -- including weblogs and wikis --
12
+ # have many pages that are a great fit for this approach, but account-based systems
13
+ # where people log in and manipulate their own data are often less likely candidates.
14
+ #
15
+ # Specifying which actions to cache is done through the +caches_page+ class method:
16
+ #
17
+ # class WeblogController < ActionController::Base
18
+ # caches_page :show, :new
19
+ # end
20
+ #
21
+ # This will generate cache files such as <tt>weblog/show/5.html</tt> and
22
+ # <tt>weblog/new.html</tt>, which match the URLs used that would normally trigger
23
+ # dynamic page generation. Page caching works by configuring a web server to first
24
+ # check for the existence of files on disk, and to serve them directly when found,
25
+ # without passing the request through to Action Pack. This is much faster than
26
+ # handling the full dynamic request in the usual way.
27
+ #
28
+ # Expiration of the cache is handled by deleting the cached file, which results
29
+ # in a lazy regeneration approach where the cache is not restored before another
30
+ # hit is made against it. The API for doing so mimics the options from +url_for+ and friends:
31
+ #
32
+ # class WeblogController < ActionController::Base
33
+ # def update
34
+ # List.update(params[:list][:id], params[:list])
35
+ # expire_page action: 'show', id: params[:list][:id]
36
+ # redirect_to action: 'show', id: params[:list][:id]
37
+ # end
38
+ # end
39
+ #
40
+ # Additionally, you can expire caches using Sweepers that act on changes in
41
+ # the model to determine when a cache is supposed to be expired.
42
+ module Pages
43
+ extend ActiveSupport::Concern
44
+
45
+ module ClassMethods
46
+ # The cache directory should be the document root for the web server and is
47
+ # set using <tt>Base.page_cache_directory = "/document/root"</tt>. For Rails,
48
+ # this directory has already been set to Rails.public_path (which is usually
49
+ # set to <tt>Rails.root + "/public"</tt>). Changing this setting can be useful
50
+ # to avoid naming conflicts with files in <tt>public/</tt>, but doing so will
51
+ # likely require configuring your web server to look in the new location for
52
+ # cached files.
53
+ def page_cache_directory
54
+ thread_storage[:page_cache_directory]
55
+ end
56
+
57
+ # The compression used for gzip. If +false+ (default), the page is not compressed.
58
+ # If can be a symbol showing the ZLib compression method, for example, <tt>:best_compression</tt>
59
+ # or <tt>:best_speed</tt> or an integer configuring the compression level.
60
+ def page_cache_compression
61
+ thread_storage[:page_cache_compression]
62
+ end
63
+
64
+ def page_cache_directory=(value)
65
+ thread_storage[:page_cache_directory] = value
66
+ end
67
+
68
+ def page_cache_compression=(value)
69
+ thread_storage[:page_cache_compression] = value
70
+ end
71
+
72
+ def thread_storage
73
+ Thread.current[:multiple_page_caching] ||= {}
74
+ end
75
+
76
+ # Expires the page that was cached with the +path+ as a key.
77
+ #
78
+ # expire_page '/lists/show'
79
+ def expire_page(path)
80
+ return unless perform_caching
81
+ path = page_cache_path(path)
82
+
83
+ instrument_page_cache :expire_page, path do
84
+ File.delete(path) if File.exist?(path)
85
+ File.delete(path + '.gz') if File.exist?(path + '.gz')
86
+ end
87
+ end
88
+
89
+ # Manually cache the +content+ in the key determined by +path+.
90
+ #
91
+ # cache_page "I'm the cached content", '/lists/show'
92
+ def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
93
+ return unless perform_caching
94
+ path = page_cache_path(path, extension)
95
+
96
+ instrument_page_cache :write_page, path do
97
+ tmpfile = Tempfile.new([File.basename(path), File.extname(path)])
98
+ tmpfile.write(content)
99
+ tmpfile.close
100
+
101
+ dirname = File.dirname(path)
102
+ FileUtils.makedirs(dirname) unless File.directory?(dirname)
103
+ FileUtils.mv(tmpfile.path, path)
104
+
105
+ if gzip
106
+ Zlib::GzipWriter.open(tmpfile.path + '.gz', gzip) { |gz| gz.write(content) }
107
+ FileUtils.mv(tmpfile.path + '.gz', path + '.gz')
108
+ end
109
+ end
110
+ end
111
+
112
+ # Caches the +actions+ using the page-caching approach that'll store
113
+ # the cache in a path within the +page_cache_directory+ that
114
+ # matches the triggering url.
115
+ #
116
+ # You can also pass a <tt>:gzip</tt> option to override the class configuration one.
117
+ #
118
+ # # cache the index action
119
+ # caches_page :index
120
+ #
121
+ # # cache the index action except for JSON requests
122
+ # caches_page :index, if: Proc.new { !request.format.json? }
123
+ #
124
+ # # don't gzip images
125
+ # caches_page :image, gzip: false
126
+ def caches_page(*actions)
127
+ return unless perform_caching
128
+ options = actions.extract_options!
129
+
130
+ gzip_level = options.fetch(:gzip, page_cache_compression)
131
+ gzip_level = case gzip_level
132
+ when Symbol
133
+ Zlib.const_get(gzip_level.upcase)
134
+ when Fixnum
135
+ gzip_level
136
+ when false
137
+ nil
138
+ else
139
+ Zlib::BEST_COMPRESSION
140
+ end
141
+
142
+ after_filter({only: actions}.merge(options)) do |c|
143
+ c.cache_page(nil, nil, gzip_level)
144
+ end
145
+ end
146
+
147
+ private
148
+ def page_cache_file(path, extension)
149
+ name = (path.empty? || path == '/') ? '/index' : URI.parser.unescape(path.chomp('/'))
150
+ unless (name.split('/').last || name).include? '.'
151
+ name << (extension || self.default_static_extension)
152
+ end
153
+ return name
154
+ end
155
+
156
+ def page_cache_path(path, extension = nil)
157
+ page_cache_directory.to_s + page_cache_file(path, extension)
158
+ end
159
+
160
+ def instrument_page_cache(name, path)
161
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", path: path){ yield }
162
+ end
163
+ end
164
+
165
+ # Expires the page that was cached with the +options+ as a key.
166
+ #
167
+ # expire_page controller: 'lists', action: 'show'
168
+ def expire_page(options = {})
169
+ return unless self.class.perform_caching
170
+
171
+ if options.is_a?(Hash)
172
+ if options[:action].is_a?(Array)
173
+ options[:action].each do |action|
174
+ self.class.expire_page(url_for(options.merge(only_path: true, action: action)))
175
+ end
176
+ else
177
+ self.class.expire_page(url_for(options.merge(only_path: true)))
178
+ end
179
+ else
180
+ self.class.expire_page(options)
181
+ end
182
+ end
183
+
184
+ # Manually cache the +content+ in the key determined by +options+. If no content is provided,
185
+ # the contents of response.body is used. If no options are provided, the url of the current
186
+ # request being handled is used.
187
+ #
188
+ # cache_page "I'm the cached content", controller: 'lists', action: 'show'
189
+ def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
190
+ return unless self.class.perform_caching && caching_allowed?
191
+
192
+ path = case options
193
+ when Hash
194
+ url_for(options.merge(only_path: true, format: params[:format]))
195
+ when String
196
+ options
197
+ else
198
+ request.path
199
+ end
200
+
201
+ if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
202
+ extension = ".#{type_symbol}"
203
+ end
204
+
205
+ self.class.cache_page(content || response.body, path, extension, gzip)
206
+ end
207
+
208
+ def caching_allowed?
209
+ (request.get? || request.head?) && response.status == 200
210
+ end
211
+ end
212
+ end
213
+ 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_multithread/railtie'
@@ -0,0 +1,17 @@
1
+ require 'rails/railtie'
2
+
3
+ module ActionPack
4
+ module PageCachingMultithread
5
+ class Railtie < Rails::Railtie
6
+ initializer 'action_pack.page_caching_multithread' do
7
+ ActiveSupport.on_load(:action_controller) do
8
+ require 'action_controller/page_caching_multithread'
9
+ end
10
+ end
11
+
12
+ initializer 'action_pack.page_caching_multithread.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,22 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'action_controller'
4
+ require 'action_controller/page_caching_multithread'
5
+
6
+ SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
7
+
8
+ module ActionController
9
+ class Base
10
+ include SharedTestRoutes.url_helpers
11
+ end
12
+
13
+ class TestCase
14
+ def setup
15
+ @routes = SharedTestRoutes
16
+
17
+ @routes.draw do
18
+ get ':controller(/:action)'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,265 @@
1
+ require 'abstract_unit'
2
+
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
+
7
+ class CachingMetalController < ActionController::Metal
8
+ abstract!
9
+
10
+ include ActionController::Caching
11
+
12
+ self.page_cache_directory = FILE_STORE_PATH
13
+ self.cache_store = :file_store, FILE_STORE_PATH
14
+ end
15
+
16
+ class PageCachingMetalTestController < CachingMetalController
17
+ caches_page :ok
18
+
19
+ def ok
20
+ self.response_body = 'ok'
21
+ end
22
+ end
23
+
24
+ class PageCachingMetalTest < ActionController::TestCase
25
+ tests PageCachingMetalTestController
26
+
27
+ def setup
28
+ super
29
+
30
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
31
+ FileUtils.mkdir_p(FILE_STORE_PATH)
32
+ end
33
+
34
+ def teardown
35
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
36
+ end
37
+
38
+ def test_should_cache_get_with_ok_status
39
+ get :ok
40
+ assert_response :ok
41
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_metal_test/ok.html"), 'get with ok status should have been cached'
42
+ end
43
+ end
44
+
45
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
46
+
47
+ class CachingController < ActionController::Base
48
+ abstract!
49
+
50
+ self.cache_store = :file_store, FILE_STORE_PATH
51
+ end
52
+
53
+ class PageCachingTestController < CachingController
54
+ self.page_cache_compression = :best_compression
55
+
56
+ caches_page :ok, :no_content, if: Proc.new { |c| !c.request.format.json? }
57
+ caches_page :found, :not_found
58
+ caches_page :about_me
59
+ caches_page :default_gzip
60
+ caches_page :no_gzip, gzip: false
61
+ caches_page :gzip_level, gzip: :best_speed
62
+
63
+ def ok
64
+ head :ok
65
+ end
66
+
67
+ def no_content
68
+ head :no_content
69
+ end
70
+
71
+ def found
72
+ redirect_to action: 'ok'
73
+ end
74
+
75
+ def not_found
76
+ head :not_found
77
+ end
78
+
79
+ def custom_path
80
+ render text: 'Super soaker'
81
+ cache_page('Super soaker', '/index.html')
82
+ end
83
+
84
+ def default_gzip
85
+ render text: 'Text'
86
+ end
87
+
88
+ def no_gzip
89
+ render text: 'PNG'
90
+ end
91
+
92
+ def gzip_level
93
+ render text: 'Big text'
94
+ end
95
+
96
+ def expire_custom_path
97
+ expire_page('/index.html')
98
+ head :ok
99
+ end
100
+
101
+ def trailing_slash
102
+ render text: 'Sneak attack'
103
+ end
104
+
105
+ def about_me
106
+ respond_to do |format|
107
+ format.html { render text: 'I am html' }
108
+ format.xml { render text: 'I am xml' }
109
+ end
110
+ end
111
+ end
112
+
113
+ class PageCachingTest < ActionController::TestCase
114
+ def setup
115
+ super
116
+
117
+ @request = ActionController::TestRequest.new
118
+ @request.host = 'hostname.com'
119
+ @request.env.delete('PATH_INFO')
120
+
121
+ @controller = PageCachingTestController.new
122
+ @controller.perform_caching = true
123
+ @controller.cache_store = :file_store, FILE_STORE_PATH
124
+
125
+ @response = ActionController::TestResponse.new
126
+
127
+ @params = { controller: 'posts', action: 'index', only_path: true }
128
+
129
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
130
+ FileUtils.mkdir_p(FILE_STORE_PATH)
131
+ end
132
+
133
+ def teardown
134
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
135
+ @controller.perform_caching = false
136
+ end
137
+
138
+ def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
139
+ with_routing do |set|
140
+ set.draw do
141
+ get 'posts.:format', to: 'posts#index', as: :formatted_posts
142
+ get '/', to: 'posts#index', as: :main
143
+ end
144
+ @params[:format] = 'rss'
145
+ assert_equal '/posts.rss', @routes.url_for(@params)
146
+ @params[:format] = nil
147
+ assert_equal '/', @routes.url_for(@params)
148
+ end
149
+ end
150
+
151
+ def test_should_cache_head_with_ok_status
152
+ head :ok
153
+ assert_response :ok
154
+ assert_page_cached :ok, 'head with ok status should have been cached'
155
+ end
156
+
157
+ def test_should_cache_get_with_ok_status
158
+ get :ok
159
+ assert_response :ok
160
+ assert_page_cached :ok, 'get with ok status should have been cached'
161
+ end
162
+
163
+ def test_should_cache_with_custom_path
164
+ get :custom_path
165
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
166
+ end
167
+
168
+ def test_should_expire_cache_with_custom_path
169
+ get :custom_path
170
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
171
+
172
+ get :expire_custom_path
173
+ assert !File.exist?("#{FILE_STORE_PATH}/index.html")
174
+ end
175
+
176
+ def test_should_gzip_cache
177
+ get :custom_path
178
+ assert File.exist?("#{FILE_STORE_PATH}/index.html.gz")
179
+
180
+ get :expire_custom_path
181
+ assert !File.exist?("#{FILE_STORE_PATH}/index.html.gz")
182
+ end
183
+
184
+ def test_should_allow_to_disable_gzip
185
+ get :no_gzip
186
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html")
187
+ assert !File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html.gz")
188
+ end
189
+
190
+ def test_should_use_config_gzip_by_default
191
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_COMPRESSION)
192
+ get :default_gzip
193
+ end
194
+
195
+ def test_should_set_gzip_level
196
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_SPEED)
197
+ get :gzip_level
198
+ end
199
+
200
+ def test_should_cache_without_trailing_slash_on_url
201
+ @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash'
202
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
203
+ end
204
+
205
+ def test_should_obey_http_accept_attribute
206
+ @request.env['HTTP_ACCEPT'] = 'text/xml'
207
+ get :about_me
208
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/about_me.xml")
209
+ assert_equal 'I am xml', @response.body
210
+ end
211
+
212
+ def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
213
+ @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
214
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
215
+ end
216
+
217
+ def test_should_cache_ok_at_custom_path
218
+ @request.env['PATH_INFO'] = '/index.html'
219
+ get :ok
220
+ assert_response :ok
221
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
222
+ end
223
+
224
+ [:ok, :no_content, :found, :not_found].each do |status|
225
+ [:get, :post, :patch, :put, :delete].each do |method|
226
+ unless method == :get && status == :ok
227
+ define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
228
+ send(method, status)
229
+ assert_response status
230
+ assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ def test_page_caching_conditional_options
237
+ get :ok, format: 'json'
238
+ assert_page_not_cached :ok
239
+ end
240
+
241
+ def test_page_caching_directory_set_as_pathname
242
+ begin
243
+ ActionController::Base.page_cache_directory = Pathname.new(FILE_STORE_PATH)
244
+ get :ok
245
+ assert_response :ok
246
+ assert_page_cached :ok
247
+ ensure
248
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
249
+ end
250
+ end
251
+
252
+ private
253
+
254
+ def assert_page_cached(action, message = "#{action} should have been cached")
255
+ assert page_cached?(action), message
256
+ end
257
+
258
+ def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
259
+ assert !page_cached?(action), message
260
+ end
261
+
262
+ def page_cached?(action)
263
+ File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
264
+ end
265
+ end
@@ -0,0 +1,54 @@
1
+ require 'abstract_unit'
2
+ require 'active_support/log_subscriber/test_helper'
3
+ require 'action_controller/log_subscriber'
4
+
5
+ module Another
6
+ class LogSubscribersController < ActionController::Base
7
+ abstract!
8
+
9
+ self.perform_caching = true
10
+
11
+ def with_page_cache
12
+ cache_page('Super soaker', '/index.html')
13
+ render nothing: true
14
+ end
15
+ end
16
+ end
17
+
18
+ class ACLogSubscriberTest < ActionController::TestCase
19
+ tests Another::LogSubscribersController
20
+ include ActiveSupport::LogSubscriber::TestHelper
21
+
22
+ def setup
23
+ super
24
+
25
+ @routes = SharedTestRoutes
26
+ @routes.draw do
27
+ get ':controller(/:action)'
28
+ end
29
+
30
+ @cache_path = File.expand_path('../temp/test_cache', File.dirname(__FILE__))
31
+ ActionController::Base.page_cache_directory = @cache_path
32
+ @controller.cache_store = :file_store, @cache_path
33
+ ActionController::LogSubscriber.attach_to :action_controller
34
+ end
35
+
36
+ def teardown
37
+ ActiveSupport::LogSubscriber.log_subscribers.clear
38
+ FileUtils.rm_rf(@cache_path)
39
+ end
40
+
41
+ def set_logger(logger)
42
+ ActionController::Base.logger = logger
43
+ end
44
+
45
+ def test_with_page_cache
46
+ get :with_page_cache
47
+ wait
48
+
49
+ logs = @logger.logged(:info)
50
+ assert_equal 3, logs.size
51
+ assert_match(/Write page/, logs[1])
52
+ assert_match(/\/index\.html/, logs[1])
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actionpack-page_caching_multithread
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.2'
5
+ platform: ruby
6
+ authors:
7
+ - Dimelo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
33
+ - !ruby/object:Gem::Dependency
34
+ name: mocha
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Threadsafe Static page caching for Action Pack 4.x
48
+ email: contact@dimelo.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - ".gitignore"
54
+ - ".travis.yml"
55
+ - CHANGELOG.md
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - actionpack-page_caching_multithread.gemspec
61
+ - gemfiles/Gemfile-4-0-stable
62
+ - gemfiles/Gemfile-edge
63
+ - lib/action_controller/caching/pages.rb
64
+ - lib/action_controller/page_caching_multithread.rb
65
+ - lib/actionpack/page_caching_multithread.rb
66
+ - lib/actionpack/page_caching_multithread/railtie.rb
67
+ - test/abstract_unit.rb
68
+ - test/caching_test.rb
69
+ - test/log_subscriber_test.rb
70
+ homepage: https://github.com/dimelo/actionpack-page_caching_multithread
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.2.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Threadsafe Static page caching for Action Pack 4.x
94
+ test_files:
95
+ - test/abstract_unit.rb
96
+ - test/caching_test.rb
97
+ - test/log_subscriber_test.rb