tennpipes-memory 3.6.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ module ObjectCache
5
+ def cache_object(key, opts = {})
6
+ if settings.caching?
7
+ began_at = Time.now
8
+ if value = settings.cache[key.to_s]
9
+ logger.debug "GET Object", began_at, key.to_s if defined?(logger)
10
+ else
11
+ value = yield
12
+ settings.cache.store(key.to_s, value, opts)
13
+ logger.debug "SET Object", began_at, key.to_s if defined?(logger)
14
+ end
15
+ value
16
+ else
17
+ yield
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ module CacheStore
5
+ def expire(*key)
6
+ if key.size == 1 and (key.first.is_a?(String) or key.first.is_a?(Symbol))
7
+ settings.cache.delete(key.first)
8
+ else
9
+ settings.cache.delete(self.class.url(*key))
10
+ end
11
+ nil
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ ##
5
+ # Whereas page-level caching, described in the first section of this document, works by
6
+ # grabbing the entire output of a route, fragment caching gives the developer fine-grained
7
+ # control of what gets cached. This type of caching occurs at whatever level you choose.
8
+ #
9
+ # Possible uses for fragment caching might include:
10
+ #
11
+ # - a 'feed' of some items on a page
12
+ # - output fetched (by proxy) from an API on a third-party site
13
+ # - parts of your page which are largely static/do not need re-rendering every request
14
+ # - any output which is expensive to render
15
+ #
16
+ module Fragment
17
+ include Tennpipes::Helpers::OutputHelpers
18
+
19
+ ##
20
+ # This helper is used anywhere in your application you would like to associate a fragment
21
+ # to be cached. It can be used in within a route:
22
+ #
23
+ # @param [String] key
24
+ # cache key
25
+ # @param [Hash] opts
26
+ # cache options, e.g :expires
27
+ # @param [Proc]
28
+ # Execution result to store in the cache
29
+ #
30
+ # @example
31
+ # # Caching a fragment
32
+ # class MyTweets < Tennpipes::Application
33
+ # enable :caching # turns on caching mechanism
34
+ #
35
+ # controller '/tweets' do
36
+ # get :feed, :map => '/:username' do
37
+ # username = params[:username]
38
+ #
39
+ # @feed = cache( "feed_for_#{username}", :expires => 3 ) do
40
+ # @tweets = Tweet.all( :username => username )
41
+ # render 'partials/feedcontent'
42
+ # end
43
+ #
44
+ # # Below outputs @feed somewhere in its markup.
45
+ # render 'feeds/show'
46
+ # end
47
+ # end
48
+ # end
49
+ #
50
+ # @api public
51
+ def cache(key, opts = {}, &block)
52
+ if settings.caching?
53
+ began_at = Time.now
54
+ if value = settings.cache[key.to_s]
55
+ logger.debug "GET Fragment", began_at, key.to_s if defined?(logger)
56
+ concat_content(value.html_safe)
57
+ else
58
+ value = capture_html(&block)
59
+ settings.cache.store(key.to_s, value, opts)
60
+ logger.debug "SET Fragment", began_at, key.to_s if defined?(logger)
61
+ concat_content(value)
62
+ end
63
+ else
64
+ value = capture_html(&block)
65
+ concat_content(value)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,169 @@
1
+ module Tennpipes
2
+ module Cache
3
+ ##
4
+ # Helpers supporting page or fragment caching within a request route.
5
+ #
6
+ module Helpers
7
+ ##
8
+ # Page caching is easy to integrate into your application. To turn it on, simply provide the
9
+ # <tt>:cache => true</tt> option on either a controller or one of its routes.
10
+ # By default, cached content is persisted with a "file store" --that is, in a
11
+ # subdirectory of your application root.
12
+ #
13
+ # @example
14
+ # # Setting content expiry time.
15
+ # class CachedApp < Tennpipes::Application
16
+ # enable :caching # turns on caching mechanism
17
+ #
18
+ # controller '/blog', :cache => true do
19
+ # expires 15
20
+ #
21
+ # get '/entries' do
22
+ # # expires 15 => can also be defined inside a single route
23
+ # 'Just broke up eating twinkies, lol'
24
+ # end
25
+ #
26
+ # get '/post/:id' do
27
+ # cache_key :my_name
28
+ # @post = Post.find(params[:id])
29
+ # end
30
+ # end
31
+ # end
32
+ #
33
+ # You can manually expire cache with CachedApp.cache.delete(:my_name)
34
+ #
35
+ # Note that the "latest" method call to <tt>expires</tt> determines its value: if
36
+ # called within a route, as opposed to a controller definition, the route's
37
+ # value will be assumed.
38
+ #
39
+ module Page
40
+ ##
41
+ # This helper is used within a controller or route to indicate how often content
42
+ # should persist in the cache.
43
+ #
44
+ # After <tt>seconds</tt> seconds have passed, content previously cached will
45
+ # be discarded and re-rendered. Code associated with that route will <em>not</em>
46
+ # be executed; rather, its previous output will be sent to the client with a
47
+ # 200 OK status code.
48
+ #
49
+ # @param [Integer] time
50
+ # Time til expiration (seconds)
51
+ #
52
+ # @example
53
+ # controller '/blog', :cache => true do
54
+ # expires 15
55
+ #
56
+ # get '/entries' do
57
+ # 'Just broke up eating twinkies, lol'
58
+ # end
59
+ # end
60
+ #
61
+ # @api public
62
+ def expires(time)
63
+ @route.cache_expires = time
64
+ end
65
+
66
+ ##
67
+ # This helper is used within a route or route to indicate the name in the cache.
68
+ #
69
+ # @param [Symbol] name
70
+ # cache key
71
+ # @param [Proc] block
72
+ # block to be evaluated to cache key
73
+ #
74
+ # @example
75
+ # controller '/blog', :cache => true do
76
+ #
77
+ # get '/post/:id' do
78
+ # cache_key :my_name
79
+ # @post = Post.find(params[:id])
80
+ # end
81
+ # end
82
+ #
83
+ # @example
84
+ # get '/foo', :cache => true do
85
+ # cache_key { param[:id] }
86
+ # "My id is #{param[:id}"
87
+ # end
88
+ # end
89
+ #
90
+ def cache_key(name = nil, &block)
91
+ fail "Can not provide both cache_key and a block" if name && block
92
+ @route.cache_key = name || block
93
+ end
94
+
95
+ CACHED_VERBS = { 'GET' => true, 'HEAD' => true }.freeze
96
+
97
+ def self.tennpipes_route_added(route, verb, *)
98
+ return unless route.cache && CACHED_VERBS[verb]
99
+
100
+ route.before_filters do
101
+ next unless settings.caching?
102
+ if cached_response = load_cached_response
103
+ content_type cached_response[:content_type]
104
+ halt 200, cached_response[:body]
105
+ end
106
+ end
107
+
108
+ route.after_filters do
109
+ save_cached_response(route.cache_expires) if settings.caching?
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def load_cached_response
116
+ began_at = Time.now
117
+ route_cache_key = resolve_cache_key || env['PATH_INFO']
118
+
119
+ value = settings.cache[route_cache_key]
120
+ logger.debug "GET Cache", began_at, route_cache_key if defined?(logger) && value
121
+
122
+ value
123
+ end
124
+
125
+ def save_cached_response(cache_expires)
126
+ return unless @_response_buffer.kind_of?(String)
127
+
128
+ began_at = Time.now
129
+ route_cache_key = resolve_cache_key || env['PATH_INFO']
130
+
131
+ content = {
132
+ :body => @_response_buffer,
133
+ :content_type => @_content_type
134
+ }
135
+
136
+ settings.cache.store(route_cache_key, content, :expires => cache_expires)
137
+
138
+ logger.debug "SET Cache", began_at, route_cache_key if defined?(logger)
139
+ end
140
+
141
+ ##
142
+ # Resolve the cache_key when it's a block in the correct context.
143
+ #
144
+ def resolve_cache_key
145
+ key = @route.cache_key
146
+ key.is_a?(Proc) ? instance_eval(&key) : key
147
+ end
148
+
149
+ module ClassMethods
150
+ ##
151
+ # A method to set `expires` time inside `controller` blocks.
152
+ #
153
+ # @example
154
+ # controller :users do
155
+ # expires 15
156
+ #
157
+ # get :show do
158
+ # 'shown'
159
+ # end
160
+ # end
161
+ #
162
+ def expires(time)
163
+ @_expires = time
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,24 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+ TENNPIPES_ROOT = File.dirname(__FILE__) unless defined?(TENNPIPES_ROOT)
3
+
4
+ require 'minitest/autorun'
5
+ require 'minitest/pride'
6
+ require 'rack/test'
7
+ require 'tennpipes-memory'
8
+
9
+ require 'ext/rack-test-methods'
10
+
11
+ class MiniTest::Spec
12
+ include Rack::Test::Methods
13
+
14
+ # Sets up a Sinatra::Base subclass defined with the block
15
+ # given. Used in setup or individual spec methods to establish
16
+ # the application.
17
+ def mock_app(base=Tennpipes::Application, &block)
18
+ @app = Sinatra.new(base, &block)
19
+ end
20
+
21
+ def app
22
+ Rack::Lint.new(@app)
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe 'Tennpipes::Cache - Moneta store' do
4
+ def setup
5
+ @test_key = "val_#{Time.now.to_i}"
6
+ end
7
+
8
+ def teardown
9
+ Tennpipes.cache.clear
10
+ end
11
+
12
+ class Foo
13
+ def bar; "bar"; end
14
+ end
15
+
16
+ it "return nil trying to get a value that doesn't exist" do
17
+ Tennpipes.cache.clear
18
+ assert_equal nil, Tennpipes.cache[@test_key]
19
+ end
20
+
21
+ it 'set and get an object with marshal' do
22
+ Tennpipes.cache[@test_key] = Foo.new
23
+ assert_equal "bar", Tennpipes.cache[@test_key].bar
24
+ end
25
+
26
+ it 'set and get a nil value' do
27
+ Tennpipes.cache[@test_key] = nil
28
+ assert_equal '', Tennpipes.cache[@test_key].to_s
29
+ end
30
+
31
+ it 'set and get a raw value' do
32
+ Tennpipes.cache[@test_key] = 'foo'
33
+ assert_equal 'foo', Tennpipes.cache[@test_key]
34
+ end
35
+
36
+ it "set a value that expires" do
37
+ init_time = ( Time.now - 20 )
38
+ Time.stub(:now, init_time) { Tennpipes.cache.store(@test_key, 'test', :expires => 1) }
39
+ Time.stub(:now, init_time + 20) { assert_equal nil, Tennpipes.cache[@test_key] }
40
+ end
41
+
42
+ it "be able to cache forever" do
43
+ Tennpipes.cache.store('forever', 'cached', :expires => false)
44
+ 2.times { |i| assert_equal 'cached', Tennpipes.cache['forever'] }
45
+ end
46
+
47
+ it 'delete a value' do
48
+ Tennpipes.cache[@test_key] = 'test'
49
+ assert_equal 'test', Tennpipes.cache[@test_key]
50
+ Tennpipes.cache.delete(@test_key)
51
+ assert_equal nil, Tennpipes.cache[@test_key]
52
+ end
53
+ end
@@ -0,0 +1,478 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe "TennpipesCache" do
4
+ after do
5
+ tmp = File.expand_path("../tmp", __FILE__)
6
+ %x[rm -rf #{tmp}]
7
+ end
8
+
9
+ it 'should cache a fragment' do
10
+ called = false
11
+ mock_app do
12
+ register Tennpipes::Cache
13
+ enable :caching
14
+ get("/foo"){ cache(:test) { called ? halt(500) : (called = 'test fragment') } }
15
+ end
16
+ get "/foo"
17
+ assert_equal 200, status
18
+ assert_equal 'test fragment', body
19
+ get "/foo"
20
+ assert_equal 200, status
21
+ assert_equal 'test fragment', body
22
+ refute_equal called, false
23
+ end
24
+
25
+ it 'should cache a page' do
26
+ called = false
27
+ mock_app do
28
+ register Tennpipes::Cache
29
+ enable :caching
30
+ get('/foo', :cache => true){ called ? halt(500) : (called = 'test page') }
31
+ end
32
+ get "/foo"
33
+ assert_equal 200, status
34
+ assert_equal 'test page', body
35
+ get "/foo"
36
+ assert_equal 200, status
37
+ assert_equal 'test page', body
38
+ refute_equal false, called
39
+ end
40
+
41
+ it 'should cache HEAD verb' do
42
+ called_times = 0
43
+ mock_app do
44
+ register Tennpipes::Cache
45
+ enable :caching
46
+ get('/foo', :cache => true){ called_times += 1; called_times.to_s }
47
+ end
48
+ head "/foo"
49
+ head "/foo"
50
+ assert_equal 1, called_times
51
+ end
52
+
53
+ it 'should not cache POST verb' do
54
+ called_times = 0
55
+ mock_app do
56
+ register Tennpipes::Cache
57
+ enable :caching
58
+ post('/foo', :cache => true){ called_times += 1; called_times.to_s }
59
+ end
60
+ post "/foo"
61
+ assert_equal 1, called_times
62
+ post "/foo"
63
+ assert_equal 2, called_times
64
+ end
65
+
66
+ it 'should not cache DELETE verb' do
67
+ called_times = 0
68
+ mock_app do
69
+ register Tennpipes::Cache
70
+ enable :caching
71
+ delete('/foo', :cache => true){ called_times += 1; called_times.to_s }
72
+ end
73
+ delete "/foo"
74
+ assert_equal 1, called_times
75
+ delete "/foo"
76
+ assert_equal 2, called_times
77
+ end
78
+
79
+ it 'should not cache PUT verb' do
80
+ called_times = 0
81
+ mock_app do
82
+ register Tennpipes::Cache
83
+ enable :caching
84
+ put('/foo', :cache => true){ called_times += 1; called_times.to_s }
85
+ end
86
+ put "/foo"
87
+ assert_equal 1, called_times
88
+ put "/foo"
89
+ assert_equal 2, called_times
90
+ end
91
+
92
+ it 'should delete from the cache' do
93
+ called = false
94
+ mock_app do
95
+ register Tennpipes::Cache
96
+ enable :caching
97
+ get('/foo', :cache => true){ called ? 'test page again' : (called = 'test page') }
98
+ get('/delete_foo'){ expire('/foo') }
99
+ end
100
+ get "/foo"
101
+ assert_equal 200, status
102
+ assert_equal 'test page', body
103
+ get "/delete_foo"
104
+ get "/foo"
105
+ assert_equal 200, status
106
+ assert_equal 'test page again', body
107
+ refute_equal false, called
108
+ end
109
+
110
+ it 'should accept custom cache keys' do
111
+ called = false
112
+ mock_app do
113
+ register Tennpipes::Cache
114
+ enable :caching
115
+ get '/foo', :cache => true do
116
+ if called
117
+ "you'll never see me"
118
+ else
119
+ cache_key :foo
120
+ called = 'foo'
121
+
122
+ called
123
+ end
124
+ end
125
+
126
+ get '/bar', :cache => true do
127
+ if called
128
+ cache_key :bar
129
+ called = 'bar'
130
+
131
+ called
132
+ else
133
+ "you'll never see me"
134
+ end
135
+ end
136
+ end
137
+ get "/foo"
138
+ assert_equal 200, status
139
+ assert_equal 'foo', body
140
+ assert_equal 'foo', @app.cache[:foo][:body]
141
+ get "/foo"
142
+ assert_equal 'foo', body
143
+
144
+ get "/bar"
145
+ assert_equal 200, status
146
+ assert_equal 'bar', body
147
+ assert_equal 'bar', @app.cache[:bar][:body]
148
+ get "/bar"
149
+ assert_equal 'bar', body
150
+ end
151
+
152
+ it 'should delete based on urls' do
153
+ called = false
154
+ mock_app do
155
+ register Tennpipes::Cache
156
+ enable :caching
157
+ get(:foo, :with => :id, :cache => true) { called ? 'test page again' : (called = 'test page') }
158
+ get(:delete_foo, :with => :id) { expire(:foo, params[:id]) }
159
+ end
160
+ get "/foo/12"
161
+ assert_equal 200, status
162
+ assert_equal 'test page', body
163
+ get "/delete_foo/12"
164
+ get "/foo/12"
165
+ assert_equal 200, status
166
+ assert_equal 'test page again', body
167
+ end
168
+
169
+ it 'should allow controller-wide caching' do
170
+ called = false
171
+ mock_app do
172
+ controller :cache => true do
173
+ register Tennpipes::Cache
174
+ enable :caching
175
+ get("/foo"){ called ? halt(500) : (called = 'test') }
176
+ end
177
+ end
178
+ get "/foo"
179
+ assert_equal 200, status
180
+ assert_equal 'test', body
181
+ get "/foo"
182
+ assert_equal 200, status
183
+ assert_equal 'test', body
184
+ end
185
+
186
+ it 'should allow controller-wide expires' do
187
+ called = false
188
+ mock_app do
189
+ register Tennpipes::Cache
190
+ controller :cache => true do
191
+ enable :caching
192
+ expires 1
193
+ get("/foo"){ called ? halt(500) : (called = 'test') }
194
+ end
195
+ end
196
+ get "/foo"
197
+ assert_equal 200, status
198
+ assert_equal 'test', body
199
+ get "/foo"
200
+ assert_equal 200, status
201
+ assert_equal 'test', body
202
+ Time.stub(:now, Time.now + 2) { get "/foo" }
203
+ assert_equal 500, status
204
+ end
205
+
206
+ it 'should allow cache disabling on a per route basis' do
207
+ called = false
208
+ mock_app do
209
+ register Tennpipes::Cache
210
+ enable :caching
211
+ controller :cache => true do
212
+ get("/foo", :cache => false){ called ? 'test again' : (called = 'test') }
213
+ end
214
+ end
215
+ get "/foo"
216
+ assert_equal 200, status
217
+ assert_equal 'test', body
218
+ get "/foo"
219
+ assert_equal 200, status
220
+ assert_equal 'test again', body
221
+ end
222
+
223
+ it 'should allow expiring for pages' do
224
+ called = false
225
+ mock_app do
226
+ register Tennpipes::Cache
227
+ enable :caching
228
+ controller :cache => true do
229
+ get("/foo") {
230
+ expires 1
231
+ called ? 'test again' : (called = 'test')
232
+ }
233
+ end
234
+ end
235
+ get "/foo"
236
+ assert_equal 200, status
237
+ assert_equal 'test', body
238
+ get "/foo"
239
+ assert_equal 200, status
240
+ assert_equal 'test', body
241
+ Time.stub(:now, Time.now + 3) { get "/foo" }
242
+ assert_equal 200, status
243
+ assert_equal 'test again', body
244
+ end
245
+
246
+ it 'should allow expiring for fragments' do
247
+ called = false
248
+ mock_app do
249
+ register Tennpipes::Cache
250
+ enable :caching
251
+ controller do
252
+ get("/foo") {
253
+ expires 1
254
+ cache(:test, :expires => 2) do
255
+ called ? 'test again' : (called = 'test')
256
+ end
257
+ }
258
+ end
259
+ end
260
+ get "/foo"
261
+ assert_equal 200, status
262
+ assert_equal 'test', body
263
+ get "/foo"
264
+ assert_equal 200, status
265
+ assert_equal 'test', body
266
+ Time.stub(:now, Time.now + 3) { get "/foo" }
267
+ assert_equal 200, status
268
+ assert_equal 'test again', body
269
+ end
270
+
271
+ it 'should allow disabling of the cache' do
272
+ called = false
273
+ mock_app do
274
+ register Tennpipes::Cache
275
+ disable :caching
276
+ controller :cache => true do
277
+ get("/foo"){ called ? halt(500) : (called = 'test') }
278
+ end
279
+ end
280
+ get "/foo"
281
+ assert_equal 200, status
282
+ assert_equal 'test', body
283
+ get "/foo"
284
+ assert_equal 500, status
285
+ end
286
+
287
+ it 'should not cache integer statuses' do
288
+ mock_app do
289
+ register Tennpipes::Cache
290
+ enable :caching
291
+ get( '/404', :cache => true ) { not_found }
292
+ get( '/503', :cache => true ) { error 503 }
293
+ not_found { 'fancy 404' }
294
+ error( 503 ) { 'fancy 503' }
295
+ end
296
+ get '/404'
297
+ assert_equal 'fancy 404', body
298
+ assert_equal 404, status
299
+ assert_equal nil, @app.cache['/404']
300
+ get '/404'
301
+ assert_equal 'fancy 404', body
302
+ assert_equal 404, status
303
+ get '/503'
304
+ assert_equal 'fancy 503', body
305
+ assert_equal 503, status
306
+ assert_equal nil, @app.cache['/503']
307
+ get '/503'
308
+ assert_equal 'fancy 503', body
309
+ assert_equal 503, status
310
+ end
311
+
312
+ it 'should cache should not hit with unique params' do
313
+ call_count = 0
314
+ mock_app do
315
+ register Tennpipes::Cache
316
+ enable :caching
317
+ before do
318
+ param = params[:test] || 'none'
319
+ cache_key "foo?#{param}"
320
+ end
321
+ get '/foo/:test', :cache => true do
322
+ param = params[:test] || 'none'
323
+ call_count += 1
324
+ "foo?#{param}"
325
+ end
326
+ end
327
+
328
+ get '/foo/none'
329
+ get '/foo/none'
330
+ assert_equal 200, status
331
+ assert_equal 'foo?none', body
332
+ assert_equal 1, call_count
333
+
334
+ get '/foo/yes'
335
+ assert_equal 'foo?yes', body
336
+ assert_equal 2, call_count
337
+ end
338
+
339
+ it 'should resolve block cache keys' do
340
+ call_count = 0
341
+ mock_app do
342
+ register Tennpipes::Cache
343
+ enable :caching
344
+
345
+ get '/foo', :cache => true do
346
+ cache_key { "key #{params[:id]}" }
347
+ call_count += 1
348
+ params[:id]
349
+ end
350
+ end
351
+
352
+ get '/foo?id=1'
353
+ get '/foo?id=2'
354
+ get '/foo?id=2'
355
+ get '/foo?id=1&something_else=42'
356
+ get '/foo?id=3&something_else=42'
357
+
358
+ assert_equal 3, call_count
359
+ end
360
+
361
+ it 'should raise an error if providing both a cache_key and block' do
362
+ mock_app do
363
+ register Tennpipes::Cache
364
+ enable :caching
365
+
366
+ get '/foo', :cache => true do
367
+ cache_key(:some_key) { "key #{params[:id]}" }
368
+ end
369
+ end
370
+
371
+ assert_raises(RuntimeError) { get '/foo' }
372
+ end
373
+
374
+ it 'should cache content_type' do
375
+ called = false
376
+ mock_app do
377
+ register Tennpipes::Cache
378
+ enable :caching
379
+ get '/foo', :cache => true do
380
+ content_type :json
381
+ if called
382
+ "you'll never see me"
383
+ else
384
+ cache_key :foo
385
+ called = '{"foo":"bar"}'
386
+
387
+ called
388
+ end
389
+ end
390
+ end
391
+ get "/foo"
392
+ assert_equal 200, status
393
+ assert_equal '{"foo":"bar"}', body
394
+ assert_equal '{"foo":"bar"}', @app.cache[:foo][:body]
395
+ get "/foo"
396
+ assert_equal '{"foo":"bar"}', body
397
+ assert_match /json/, last_response.content_type
398
+ end
399
+
400
+ it 'should cache an object' do
401
+ counter = 0
402
+ mock_app do
403
+ register Tennpipes::Cache
404
+ enable :caching
405
+ get '/' do
406
+ result = ''
407
+ 2.times do
408
+ result = cache_object 'object1' do
409
+ counter += 1
410
+ { :foo => 'bar' }
411
+ end
412
+ end
413
+ result[:foo].to_s
414
+ end
415
+ end
416
+ get '/'
417
+ assert_equal 'bar', body
418
+ assert_equal 1, counter
419
+ end
420
+
421
+ it 'should allow different expiring times for different pages' do
422
+ skip
423
+ called_times_a = 0
424
+ called_times_b = 0
425
+ mock_app do
426
+ register Tennpipes::Cache
427
+ enable :caching
428
+ controller :cache => true do
429
+ get("/foo") do
430
+ expires 1
431
+ called_times_a += 1
432
+ called_times_b.to_s
433
+ end
434
+ get("/bar") do
435
+ expires 3
436
+ called_times_b += 1
437
+ called_times_b.to_s
438
+ end
439
+ end
440
+ end
441
+ Time.stub(:now, Time.now) { get "/foo"; get "/bar" }
442
+ assert_equal 1, called_times_a
443
+ assert_equal 1, called_times_b
444
+ Time.stub(:now, Time.now + 0.5) { get "/foo"; get "/bar" }
445
+ assert_equal 1, called_times_a
446
+ assert_equal 1, called_times_b
447
+ Time.stub(:now, Time.now + 2) { get "/foo"; get "/bar" }
448
+ assert_equal 2, called_times_a
449
+ assert_equal 1, called_times_b
450
+ Time.stub(:now, Time.now + 2.5) { get "/foo"; get "/bar" }
451
+ assert_equal 2, called_times_a
452
+ assert_equal 1, called_times_b
453
+ Time.stub(:now, Time.now + 4) { get "/foo"; get "/bar" }
454
+ assert_equal 3, called_times_a
455
+ assert_equal 2, called_times_b
456
+ Time.stub(:now, Time.now + 5.5) { get "/foo"; get "/bar" }
457
+ assert_equal 4, called_times_a
458
+ assert_equal 2, called_times_b
459
+ end
460
+
461
+ it "preserve the app's `caching` setting if set before registering the module" do
462
+ mock_app do
463
+ enable :caching
464
+ register Tennpipes::Cache
465
+ end
466
+
467
+ assert @app.caching
468
+ end
469
+
470
+ it "preserve the app's `cache` setting if set before registering the module" do
471
+ mock_app do
472
+ set :cache, Tennpipes::Cache.new(:Memory)
473
+ register Tennpipes::Cache
474
+ end
475
+
476
+ assert @app.cache.adapter.adapter.is_a?(Moneta::Adapters::Memory)
477
+ end
478
+ end