actionpack-page_caching_multithread 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.
@@ -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