rtomayko-rack-cache 0.3.0 → 0.3.9

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/test/cache_test.rb CHANGED
@@ -12,22 +12,25 @@ describe 'Rack::Cache::new' do
12
12
  Rack::Cache.new(@app).
13
13
  should.respond_to :call
14
14
  end
15
+
15
16
  it 'takes an options Hash' do
16
17
  lambda { Rack::Cache.new(@app, {}) }.
17
18
  should.not.raise(ArgumentError)
18
19
  end
20
+
19
21
  it 'sets options provided in the options Hash' do
20
22
  object = Rack::Cache.new(@app, :foo => 'bar', 'foo.bar' => 'bling')
21
23
  object.options['foo.bar'].should.equal 'bling'
22
24
  object.options['rack-cache.foo'].should.equal 'bar'
23
25
  end
26
+
24
27
  it 'takes a block; executes it during initialization' do
25
28
  state, block_scope = 'not invoked', nil
26
29
  object =
27
30
  Rack::Cache.new @app do
28
31
  block_scope = self
29
32
  state = 'invoked'
30
- should.respond_to :on
33
+ should.respond_to :set
31
34
  end
32
35
  state.should.equal 'invoked'
33
36
  object.should.be block_scope
@@ -0,0 +1,139 @@
1
+ require "#{File.dirname(__FILE__)}/spec_setup"
2
+ require 'rack/cache/cachecontrol'
3
+
4
+ describe 'Rack::Cache::CacheControl' do
5
+ it 'takes no args and initializes with an empty set of values' do
6
+ cache_control = Rack::Cache::CacheControl.new
7
+ cache_control.should.be.empty
8
+ cache_control.to_s.should.equal ''
9
+ end
10
+
11
+ it 'takes a String and parses it into a Hash when created' do
12
+ cache_control = Rack::Cache::CacheControl.new('max-age=600, foo')
13
+ cache_control['max-age'].should.equal '600'
14
+ cache_control['foo'].should.be true
15
+ end
16
+
17
+ it 'takes a String with a single name=value pair' do
18
+ cache_control = Rack::Cache::CacheControl.new('max-age=600')
19
+ cache_control['max-age'].should.equal '600'
20
+ end
21
+
22
+ it 'takes a String with multiple name=value pairs' do
23
+ cache_control = Rack::Cache::CacheControl.new('max-age=600, max-stale=300, min-fresh=570')
24
+ cache_control['max-age'].should.equal '600'
25
+ cache_control['max-stale'].should.equal '300'
26
+ cache_control['min-fresh'].should.equal '570'
27
+ end
28
+
29
+ it 'takes a String with a single flag value' do
30
+ cache_control = Rack::Cache::CacheControl.new('no-cache')
31
+ cache_control.should.include 'no-cache'
32
+ cache_control['no-cache'].should.be true
33
+ end
34
+
35
+ it 'takes a String with a bunch of all kinds of stuff' do
36
+ cache_control =
37
+ Rack::Cache::CacheControl.new('max-age=600,must-revalidate,min-fresh=3000,foo=bar,baz')
38
+ cache_control['max-age'].should.equal '600'
39
+ cache_control['must-revalidate'].should.be true
40
+ cache_control['min-fresh'].should.equal '3000'
41
+ cache_control['foo'].should.equal 'bar'
42
+ cache_control['baz'].should.be true
43
+ end
44
+
45
+ it 'strips leading and trailing spaces from header value' do
46
+ cache_control = Rack::Cache::CacheControl.new(' public, max-age = 600 ')
47
+ cache_control.should.include 'public'
48
+ cache_control.should.include 'max-age'
49
+ cache_control['max-age'].should.equal '600'
50
+ end
51
+
52
+ it 'removes all directives with #clear' do
53
+ cache_control = Rack::Cache::CacheControl.new('max-age=600, must-revalidate')
54
+ cache_control.clear
55
+ cache_control.should.be.empty
56
+ end
57
+
58
+ it 'converts self into header String with #to_s' do
59
+ cache_control = Rack::Cache::CacheControl.new
60
+ cache_control['public'] = true
61
+ cache_control['max-age'] = '600'
62
+ cache_control.to_s.split(', ').sort.should.equal ['max-age=600', 'public']
63
+ end
64
+
65
+ it 'sorts alphabetically with boolean directives before value directives' do
66
+ cache_control = Rack::Cache::CacheControl.new('foo=bar, z, x, y, bling=baz, zoom=zib, b, a')
67
+ cache_control.to_s.should.equal 'a, b, x, y, z, bling=baz, foo=bar, zoom=zib'
68
+ end
69
+
70
+ it 'responds to #max_age with an integer when max-age directive present' do
71
+ cache_control = Rack::Cache::CacheControl.new('public, max-age=600')
72
+ cache_control.max_age.should.equal 600
73
+ end
74
+
75
+ it 'responds to #max_age with nil when no max-age directive present' do
76
+ cache_control = Rack::Cache::CacheControl.new('public')
77
+ cache_control.max_age.should.be nil
78
+ end
79
+
80
+ it 'responds to #shared_max_age with an integer when s-maxage directive present' do
81
+ cache_control = Rack::Cache::CacheControl.new('public, s-maxage=600')
82
+ cache_control.shared_max_age.should.equal 600
83
+ end
84
+
85
+ it 'responds to #shared_max_age with nil when no s-maxage directive present' do
86
+ cache_control = Rack::Cache::CacheControl.new('public')
87
+ cache_control.shared_max_age.should.be nil
88
+ end
89
+
90
+ it 'responds to #public? truthfully when public directive present' do
91
+ cache_control = Rack::Cache::CacheControl.new('public')
92
+ cache_control.should.be.public
93
+ end
94
+
95
+ it 'responds to #public? non-truthfully when no public directive present' do
96
+ cache_control = Rack::Cache::CacheControl.new('private')
97
+ cache_control.should.not.be.public
98
+ end
99
+
100
+ it 'responds to #private? truthfully when private directive present' do
101
+ cache_control = Rack::Cache::CacheControl.new('private')
102
+ cache_control.should.be.private
103
+ end
104
+
105
+ it 'responds to #private? non-truthfully when no private directive present' do
106
+ cache_control = Rack::Cache::CacheControl.new('public')
107
+ cache_control.should.not.be.private
108
+ end
109
+
110
+ it 'responds to #no_cache? truthfully when no-cache directive present' do
111
+ cache_control = Rack::Cache::CacheControl.new('no-cache')
112
+ cache_control.should.be.no_cache
113
+ end
114
+
115
+ it 'responds to #no_cache? non-truthfully when no no-cache directive present' do
116
+ cache_control = Rack::Cache::CacheControl.new('max-age=600')
117
+ cache_control.should.not.be.no_cache
118
+ end
119
+
120
+ it 'responds to #must_revalidate? truthfully when must-revalidate directive present' do
121
+ cache_control = Rack::Cache::CacheControl.new('must-revalidate')
122
+ cache_control.should.be.must_revalidate
123
+ end
124
+
125
+ it 'responds to #must_revalidate? non-truthfully when no must-revalidate directive present' do
126
+ cache_control = Rack::Cache::CacheControl.new('max-age=600')
127
+ cache_control.should.not.be.no_cache
128
+ end
129
+
130
+ it 'responds to #proxy_revalidate? truthfully when proxy-revalidate directive present' do
131
+ cache_control = Rack::Cache::CacheControl.new('proxy-revalidate')
132
+ cache_control.should.be.proxy_revalidate
133
+ end
134
+
135
+ it 'responds to #proxy_revalidate? non-truthfully when no proxy-revalidate directive present' do
136
+ cache_control = Rack::Cache::CacheControl.new('max-age=600')
137
+ cache_control.should.not.be.no_cache
138
+ end
139
+ end
data/test/context_test.rb CHANGED
@@ -11,21 +11,31 @@ describe 'Rack::Cache::Context' do
11
11
 
12
12
  app.should.be.called
13
13
  response.should.be.ok
14
- cache.should.a.performed :pass
14
+ cache.trace.should.include :pass
15
15
  response.headers.should.not.include 'Age'
16
16
  end
17
17
 
18
+ %w[post put delete].each do |request_method|
19
+ it "invalidates on #{request_method} requests" do
20
+ respond_with 200
21
+ request request_method, '/'
22
+
23
+ app.should.be.called
24
+ response.should.be.ok
25
+ cache.trace.should.include :invalidate
26
+ cache.trace.should.include :pass
27
+ end
28
+ end
29
+
18
30
  it 'does not cache with Authorization request header and non public response' do
19
- respond_with 200, 'Etag' => '"FOO"'
31
+ respond_with 200, 'ETag' => '"FOO"'
20
32
  get '/', 'HTTP_AUTHORIZATION' => 'basic foobarbaz'
21
33
 
22
34
  app.should.be.called
23
35
  response.should.be.ok
24
36
  response.headers['Cache-Control'].should.equal 'private'
25
- cache.should.a.performed :miss
26
- cache.should.a.performed :fetch
27
- cache.should.a.not.performed :store
28
- cache.should.a.performed :deliver
37
+ cache.trace.should.include :miss
38
+ cache.trace.should.not.include :store
29
39
  response.headers.should.not.include 'Age'
30
40
  end
31
41
 
@@ -35,24 +45,21 @@ describe 'Rack::Cache::Context' do
35
45
 
36
46
  app.should.be.called
37
47
  response.should.be.ok
38
- cache.should.a.performed :miss
39
- cache.should.a.performed :fetch
40
- cache.should.a.performed :store
48
+ cache.trace.should.include :miss
49
+ cache.trace.should.include :store
41
50
  response.headers.should.include 'Age'
42
51
  response.headers['Cache-Control'].should.equal 'public'
43
52
  end
44
53
 
45
54
  it 'does not cache with Cookie header and non public response' do
46
- respond_with 200, 'Etag' => '"FOO"'
55
+ respond_with 200, 'ETag' => '"FOO"'
47
56
  get '/', 'HTTP_COOKIE' => 'foo=bar'
48
57
 
49
58
  app.should.be.called
50
59
  response.should.be.ok
51
60
  response.headers['Cache-Control'].should.equal 'private'
52
- cache.should.a.performed :miss
53
- cache.should.a.performed :fetch
54
- cache.should.a.not.performed :store
55
- cache.should.a.performed :deliver
61
+ cache.trace.should.include :miss
62
+ cache.trace.should.not.include :store
56
63
  response.headers.should.not.include 'Age'
57
64
  end
58
65
 
@@ -62,9 +69,8 @@ describe 'Rack::Cache::Context' do
62
69
 
63
70
  response.should.be.ok
64
71
  app.should.be.called
65
- cache.should.a.performed :miss
66
- cache.should.a.performed :fetch
67
- cache.should.a.performed :deliver
72
+ cache.trace.should.include :miss
73
+ cache.trace.should.not.include :store
68
74
  response.headers.should.not.include 'Age'
69
75
  response.headers['Cache-Control'].should.equal 'private'
70
76
  end
@@ -85,14 +91,14 @@ describe 'Rack::Cache::Context' do
85
91
  response.headers.should.not.include 'Content-Length'
86
92
  response.headers.should.not.include 'Content-Type'
87
93
  response.body.should.empty
88
- cache.should.a.performed :miss
89
- cache.should.a.performed :store
94
+ cache.trace.should.include :miss
95
+ cache.trace.should.include :store
90
96
  end
91
97
 
92
98
  it 'responds with 304 when If-None-Match matches ETag' do
93
99
  respond_with do |req,res|
94
100
  res.status = 200
95
- res['Etag'] = '12345'
101
+ res['ETag'] = '12345'
96
102
  res['Content-Type'] = 'text/plain'
97
103
  res.body = ['Hello World']
98
104
  end
@@ -103,28 +109,78 @@ describe 'Rack::Cache::Context' do
103
109
  response.status.should.equal 304
104
110
  response.headers.should.not.include 'Content-Length'
105
111
  response.headers.should.not.include 'Content-Type'
106
- response.headers.should.include 'Etag'
112
+ response.headers.should.include 'ETag'
107
113
  response.body.should.empty
108
- cache.should.a.performed :miss
109
- cache.should.a.performed :store
114
+ cache.trace.should.include :miss
115
+ cache.trace.should.include :store
110
116
  end
111
117
 
112
- it 'caches requests when Cache-Control request header set to no-cache' do
118
+ it 'stores responses when no-cache request directive present' do
113
119
  respond_with 200, 'Expires' => (Time.now + 5).httpdate
114
- get '/', 'HTTP_CACHE_CONTROL' => 'no-cache'
115
120
 
121
+ get '/', 'HTTP_CACHE_CONTROL' => 'no-cache'
116
122
  response.should.be.ok
117
- cache.should.a.performed :store
123
+ cache.trace.should.include :store
118
124
  response.headers.should.include 'Age'
119
125
  end
120
126
 
127
+ it 'reloads responses when cache hits but no-cache request directive present' do
128
+ count = 0
129
+ respond_with 200, 'Cache-Control' => 'max-age=10000' do |req,res|
130
+ count+= 1
131
+ res.body = (count == 1) ? ['Hello World'] : ['Goodbye World']
132
+ end
133
+
134
+ get '/'
135
+ response.should.be.ok
136
+ response.body.should.equal 'Hello World'
137
+ cache.trace.should.include :store
138
+
139
+ get '/'
140
+ response.should.be.ok
141
+ response.body.should.equal 'Hello World'
142
+ cache.trace.should.include :fresh
143
+
144
+ get '/', 'HTTP_CACHE_CONTROL' => 'no-cache'
145
+ response.should.be.ok
146
+ response.body.should.equal 'Goodbye World'
147
+ cache.trace.should.include :reload
148
+ cache.trace.should.include :store
149
+ end
150
+
151
+ it 'revalidates fresh cache entry when max-age request directive is exceeded' do
152
+ count = 0
153
+ respond_with do |req,res|
154
+ count+= 1
155
+ res['Cache-Control'] = 'max-age=10000'
156
+ res['ETag'] = count.to_s
157
+ res.body = (count == 1) ? ['Hello World'] : ['Goodbye World']
158
+ end
159
+
160
+ get '/'
161
+ response.should.be.ok
162
+ response.body.should.equal 'Hello World'
163
+ cache.trace.should.include :store
164
+
165
+ get '/'
166
+ response.should.be.ok
167
+ response.body.should.equal 'Hello World'
168
+ cache.trace.should.include :fresh
169
+
170
+ get '/', 'HTTP_CACHE_CONTROL' => 'max-age=0'
171
+ response.should.be.ok
172
+ response.body.should.equal 'Goodbye World'
173
+ cache.trace.should.include :stale
174
+ cache.trace.should.include :invalid
175
+ cache.trace.should.include :store
176
+ end
177
+
121
178
  it 'fetches response from backend when cache misses' do
122
179
  respond_with 200, 'Expires' => (Time.now + 5).httpdate
123
180
  get '/'
124
181
 
125
182
  response.should.be.ok
126
- cache.should.a.performed :miss
127
- cache.should.a.performed :fetch
183
+ cache.trace.should.include :miss
128
184
  response.headers.should.include 'Age'
129
185
  end
130
186
 
@@ -134,7 +190,7 @@ describe 'Rack::Cache::Context' do
134
190
  respond_with response_code, 'Expires' => (Time.now + 5).httpdate
135
191
  get '/'
136
192
 
137
- cache.should.a.not.performed :store
193
+ cache.trace.should.not.include :store
138
194
  response.status.should.equal response_code
139
195
  response.headers.should.not.include 'Age'
140
196
  end
@@ -148,7 +204,7 @@ describe 'Rack::Cache::Context' do
148
204
  get '/'
149
205
 
150
206
  response.should.be.ok
151
- cache.should.a.not.performed :store
207
+ cache.trace.should.not.include :store
152
208
  response.headers.should.not.include 'Age'
153
209
  end
154
210
 
@@ -157,7 +213,7 @@ describe 'Rack::Cache::Context' do
157
213
  get '/'
158
214
 
159
215
  response.should.be.ok
160
- cache.should.a.not.performed :store
216
+ cache.trace.should.not.include :store
161
217
  end
162
218
 
163
219
  it "caches responses with explicit no-cache directive" do
@@ -167,7 +223,7 @@ describe 'Rack::Cache::Context' do
167
223
  get '/'
168
224
 
169
225
  response.should.be.ok
170
- cache.should.a.performed :store
226
+ cache.trace.should.include :store
171
227
  response.headers.should.include 'Age'
172
228
  end
173
229
 
@@ -180,8 +236,8 @@ describe 'Rack::Cache::Context' do
180
236
  response.headers.should.include 'Date'
181
237
  response['Age'].should.not.be.nil
182
238
  response['X-Content-Digest'].should.not.be.nil
183
- cache.should.a.performed :miss
184
- cache.should.a.performed :store
239
+ cache.trace.should.include :miss
240
+ cache.trace.should.include :store
185
241
  cache.metastore.to_hash.keys.length.should.equal 1
186
242
  end
187
243
 
@@ -194,8 +250,8 @@ describe 'Rack::Cache::Context' do
194
250
  response.headers.should.include 'Date'
195
251
  response['Age'].should.not.be.nil
196
252
  response['X-Content-Digest'].should.not.be.nil
197
- cache.should.a.performed :miss
198
- cache.should.a.performed :store
253
+ cache.trace.should.include :miss
254
+ cache.trace.should.include :store
199
255
  cache.metastore.to_hash.keys.length.should.equal 1
200
256
  end
201
257
 
@@ -208,8 +264,8 @@ describe 'Rack::Cache::Context' do
208
264
  response.headers.should.include 'Date'
209
265
  response['Age'].should.not.be.nil
210
266
  response['X-Content-Digest'].should.not.be.nil
211
- cache.should.a.performed :miss
212
- cache.should.a.performed :store
267
+ cache.trace.should.include :miss
268
+ cache.trace.should.include :store
213
269
  cache.metastore.to_hash.keys.length.should.equal 1
214
270
  end
215
271
 
@@ -219,18 +275,18 @@ describe 'Rack::Cache::Context' do
219
275
 
220
276
  response.should.be.ok
221
277
  response.body.should.equal 'Hello World'
222
- cache.should.a.performed :miss
223
- cache.should.a.performed :store
278
+ cache.trace.should.include :miss
279
+ cache.trace.should.include :store
224
280
  end
225
281
 
226
282
  it 'caches responses with an ETag validator but no freshness information' do
227
- respond_with 200, 'Etag' => '"123456"'
283
+ respond_with 200, 'ETag' => '"123456"'
228
284
  get '/'
229
285
 
230
286
  response.should.be.ok
231
287
  response.body.should.equal 'Hello World'
232
- cache.should.a.performed :miss
233
- cache.should.a.performed :store
288
+ cache.trace.should.include :miss
289
+ cache.trace.should.include :store
234
290
  end
235
291
 
236
292
  it 'hits cached response with Expires header' do
@@ -242,8 +298,8 @@ describe 'Rack::Cache::Context' do
242
298
  app.should.be.called
243
299
  response.should.be.ok
244
300
  response.headers.should.include 'Date'
245
- cache.should.a.performed :miss
246
- cache.should.a.performed :store
301
+ cache.trace.should.include :miss
302
+ cache.trace.should.include :store
247
303
  response.body.should.equal 'Hello World'
248
304
 
249
305
  get '/'
@@ -252,8 +308,8 @@ describe 'Rack::Cache::Context' do
252
308
  response['Date'].should.equal responses.first['Date']
253
309
  response['Age'].to_i.should.satisfy { |age| age > 0 }
254
310
  response['X-Content-Digest'].should.not.be.nil
255
- cache.should.a.performed :hit
256
- cache.should.a.not.performed :fetch
311
+ cache.trace.should.include :fresh
312
+ cache.trace.should.not.include :store
257
313
  response.body.should.equal 'Hello World'
258
314
  end
259
315
 
@@ -266,8 +322,8 @@ describe 'Rack::Cache::Context' do
266
322
  app.should.be.called
267
323
  response.should.be.ok
268
324
  response.headers.should.include 'Date'
269
- cache.should.a.performed :miss
270
- cache.should.a.performed :store
325
+ cache.trace.should.include :miss
326
+ cache.trace.should.include :store
271
327
  response.body.should.equal 'Hello World'
272
328
 
273
329
  get '/'
@@ -276,8 +332,8 @@ describe 'Rack::Cache::Context' do
276
332
  response['Date'].should.equal responses.first['Date']
277
333
  response['Age'].to_i.should.satisfy { |age| age > 0 }
278
334
  response['X-Content-Digest'].should.not.be.nil
279
- cache.should.a.performed :hit
280
- cache.should.a.not.performed :fetch
335
+ cache.trace.should.include :fresh
336
+ cache.trace.should.not.include :store
281
337
  response.body.should.equal 'Hello World'
282
338
  end
283
339
 
@@ -290,8 +346,8 @@ describe 'Rack::Cache::Context' do
290
346
  app.should.be.called
291
347
  response.should.be.ok
292
348
  response.headers.should.include 'Date'
293
- cache.should.a.performed :miss
294
- cache.should.a.performed :store
349
+ cache.trace.should.include :miss
350
+ cache.trace.should.include :store
295
351
  response.body.should.equal 'Hello World'
296
352
 
297
353
  get '/'
@@ -300,8 +356,8 @@ describe 'Rack::Cache::Context' do
300
356
  response['Date'].should.equal responses.first['Date']
301
357
  response['Age'].to_i.should.satisfy { |age| age > 0 }
302
358
  response['X-Content-Digest'].should.not.be.nil
303
- cache.should.a.performed :hit
304
- cache.should.a.not.performed :fetch
359
+ cache.trace.should.include :fresh
360
+ cache.trace.should.not.include :store
305
361
  response.body.should.equal 'Hello World'
306
362
  end
307
363
 
@@ -311,16 +367,16 @@ describe 'Rack::Cache::Context' do
311
367
  get '/', 'rack-cache.default_ttl' => 10
312
368
  app.should.be.called
313
369
  response.should.be.ok
314
- cache.should.a.performed :miss
315
- cache.should.a.performed :store
370
+ cache.trace.should.include :miss
371
+ cache.trace.should.include :store
316
372
  response.body.should.equal 'Hello World'
317
373
  response['Cache-Control'].should.include 's-maxage=10'
318
374
 
319
375
  get '/', 'rack-cache.default_ttl' => 10
320
376
  response.should.be.ok
321
377
  app.should.not.be.called
322
- cache.should.a.performed :hit
323
- cache.should.a.not.performed :fetch
378
+ cache.trace.should.include :fresh
379
+ cache.trace.should.not.include :store
324
380
  response.body.should.equal 'Hello World'
325
381
  end
326
382
 
@@ -331,8 +387,8 @@ describe 'Rack::Cache::Context' do
331
387
  get '/', 'rack-cache.default_ttl' => 10
332
388
  app.should.be.called
333
389
  response.should.be.ok
334
- cache.should.a.performed :miss
335
- cache.should.a.not.performed :store
390
+ cache.trace.should.include :miss
391
+ cache.trace.should.not.include :store
336
392
  response['Cache-Control'].should.not.include 's-maxage'
337
393
  response.body.should.equal 'Hello World'
338
394
  end
@@ -347,8 +403,8 @@ describe 'Rack::Cache::Context' do
347
403
  response.headers.should.include 'Date'
348
404
  response.headers.should.include 'X-Content-Digest'
349
405
  response.headers.should.include 'Age'
350
- cache.should.a.performed :miss
351
- cache.should.a.performed :store
406
+ cache.trace.should.include :miss
407
+ cache.trace.should.include :store
352
408
  response.body.should.equal 'Hello World'
353
409
 
354
410
  # go in and play around with the cached metadata directly ...
@@ -361,10 +417,10 @@ describe 'Rack::Cache::Context' do
361
417
  response.should.be.ok
362
418
  response['Age'].to_i.should.equal 0
363
419
  response.headers.should.include 'X-Content-Digest'
364
- cache.should.a.not.performed :hit
365
- cache.should.a.not.performed :miss
366
- cache.should.a.performed :fetch
367
- cache.should.a.performed :store
420
+ cache.trace.should.include :stale
421
+ cache.trace.should.not.include :fresh
422
+ cache.trace.should.not.include :miss
423
+ cache.trace.should.include :store
368
424
  response.body.should.equal 'Hello World'
369
425
  end
370
426
 
@@ -385,8 +441,9 @@ describe 'Rack::Cache::Context' do
385
441
  response.headers.should.include 'Last-Modified'
386
442
  response.headers.should.include 'X-Content-Digest'
387
443
  response.body.should.equal 'Hello World'
388
- cache.should.a.performed :miss
389
- cache.should.a.performed :store
444
+ cache.trace.should.include :miss
445
+ cache.trace.should.include :store
446
+ cache.trace.should.not.include :stale
390
447
 
391
448
  # build subsequent request; should be found but miss due to freshness
392
449
  get '/'
@@ -395,11 +452,11 @@ describe 'Rack::Cache::Context' do
395
452
  response.headers.should.include 'Last-Modified'
396
453
  response.headers.should.include 'X-Content-Digest'
397
454
  response['Age'].to_i.should.equal 0
398
- response['X-Origin-Status'].should.equal '304'
399
455
  response.body.should.equal 'Hello World'
400
- cache.should.a.not.performed :miss
401
- cache.should.a.performed :fetch
402
- cache.should.a.performed :store
456
+ cache.trace.should.include :stale
457
+ cache.trace.should.include :valid
458
+ cache.trace.should.include :store
459
+ cache.trace.should.not.include :miss
403
460
  end
404
461
 
405
462
  it 'validates cached responses with ETag and no freshness information' do
@@ -416,24 +473,24 @@ describe 'Rack::Cache::Context' do
416
473
  get '/'
417
474
  app.should.be.called
418
475
  response.should.be.ok
419
- response.headers.should.include 'Etag'
476
+ response.headers.should.include 'ETag'
420
477
  response.headers.should.include 'X-Content-Digest'
421
478
  response.body.should.equal 'Hello World'
422
- cache.should.a.performed :miss
423
- cache.should.a.performed :store
479
+ cache.trace.should.include :miss
480
+ cache.trace.should.include :store
424
481
 
425
482
  # build subsequent request; should be found but miss due to freshness
426
483
  get '/'
427
484
  app.should.be.called
428
485
  response.should.be.ok
429
- response.headers.should.include 'Etag'
486
+ response.headers.should.include 'ETag'
430
487
  response.headers.should.include 'X-Content-Digest'
431
488
  response['Age'].to_i.should.equal 0
432
- response['X-Origin-Status'].should.equal '304'
433
489
  response.body.should.equal 'Hello World'
434
- cache.should.a.not.performed :miss
435
- cache.should.a.performed :fetch
436
- cache.should.a.performed :store
490
+ cache.trace.should.include :stale
491
+ cache.trace.should.include :valid
492
+ cache.trace.should.include :store
493
+ cache.trace.should.not.include :miss
437
494
  end
438
495
 
439
496
  it 'replaces cached responses when validation results in non-304 response' do
@@ -442,8 +499,8 @@ describe 'Rack::Cache::Context' do
442
499
  respond_with do |req,res|
443
500
  res['Last-Modified'] = timestamp
444
501
  case (count+=1)
445
- when 1 ; res.body = 'first response'
446
- when 2 ; res.body = 'second response'
502
+ when 1 ; res.body = ['first response']
503
+ when 2 ; res.body = ['second response']
447
504
  when 3
448
505
  res.body = []
449
506
  res.status = 304
@@ -475,11 +532,7 @@ describe 'Rack::Cache::Context' do
475
532
  req.request_method.should.equal 'HEAD'
476
533
  end
477
534
 
478
- cache_config do
479
- on(:receive) { pass! }
480
- end
481
-
482
- head '/'
535
+ head '/', 'HTTP_EXPECT' => 'something ...'
483
536
  app.should.be.called
484
537
  response.body.should.equal ''
485
538
  end
@@ -503,6 +556,53 @@ describe 'Rack::Cache::Context' do
503
556
  response['Content-Length'].should.equal 'Hello World'.length.to_s
504
557
  end
505
558
 
559
+ it 'invalidates cached responses on POST' do
560
+ respond_with do |req,res|
561
+ if req.request_method == 'GET'
562
+ res.status = 200
563
+ res['Cache-Control'] = 'public, max-age=500'
564
+ res.body = ['Hello World']
565
+ elsif req.request_method == 'POST'
566
+ res.status = 303
567
+ res['Location'] = '/'
568
+ res.headers.delete('Cache-Control')
569
+ res.body = []
570
+ end
571
+ end
572
+
573
+ # build initial request to enter into the cache
574
+ get '/'
575
+ app.should.be.called
576
+ response.should.be.ok
577
+ response.body.should.equal 'Hello World'
578
+ cache.trace.should.include :miss
579
+ cache.trace.should.include :store
580
+
581
+ # make sure it is valid
582
+ get '/'
583
+ app.should.not.called
584
+ response.should.be.ok
585
+ response.body.should.equal 'Hello World'
586
+ cache.trace.should.include :fresh
587
+
588
+ # now POST to same URL
589
+ post '/'
590
+ app.should.be.called
591
+ response.should.be.redirect
592
+ response['Location'].should.equal '/'
593
+ cache.trace.should.include :invalidate
594
+ cache.trace.should.include :pass
595
+ response.body.should.equal ''
596
+
597
+ # now make sure it was actually invalidated
598
+ get '/'
599
+ app.should.be.called
600
+ response.should.be.ok
601
+ response.body.should.equal 'Hello World'
602
+ cache.trace.should.include :stale
603
+ cache.trace.should.include :invalid
604
+ cache.trace.should.include :store
605
+ end
506
606
 
507
607
  describe 'with responses that include a Vary header' do
508
608
  before(:each) do
@@ -511,7 +611,7 @@ describe 'Rack::Cache::Context' do
511
611
  res['Vary'] = 'Accept User-Agent Foo'
512
612
  res['Cache-Control'] = 'max-age=10'
513
613
  res['X-Response-Count'] = (count+=1).to_s
514
- res.body = req.env['HTTP_USER_AGENT']
614
+ res.body = [req.env['HTTP_USER_AGENT']]
515
615
  end
516
616
  end
517
617
 
@@ -521,16 +621,16 @@ describe 'Rack::Cache::Context' do
521
621
  'HTTP_USER_AGENT' => 'Bob/1.0'
522
622
  response.should.be.ok
523
623
  response.body.should.equal 'Bob/1.0'
524
- cache.should.a.performed :miss
525
- cache.should.a.performed :store
624
+ cache.trace.should.include :miss
625
+ cache.trace.should.include :store
526
626
 
527
627
  get '/',
528
628
  'HTTP_ACCEPT' => 'text/html',
529
629
  'HTTP_USER_AGENT' => 'Bob/1.0'
530
630
  response.should.be.ok
531
631
  response.body.should.equal 'Bob/1.0'
532
- cache.should.a.performed :hit
533
- cache.should.a.not.performed :fetch
632
+ cache.trace.should.include :fresh
633
+ cache.trace.should.not.include :store
534
634
  response.headers.should.include 'X-Content-Digest'
535
635
  end
536
636
 
@@ -545,101 +645,30 @@ describe 'Rack::Cache::Context' do
545
645
  get '/',
546
646
  'HTTP_ACCEPT' => 'text/html',
547
647
  'HTTP_USER_AGENT' => 'Bob/2.0'
548
- cache.should.a.performed :miss
549
- cache.should.a.performed :store
648
+ cache.trace.should.include :miss
649
+ cache.trace.should.include :store
550
650
  response.body.should.equal 'Bob/2.0'
551
651
  response['X-Response-Count'].should.equal '2'
552
652
 
553
653
  get '/',
554
654
  'HTTP_ACCEPT' => 'text/html',
555
655
  'HTTP_USER_AGENT' => 'Bob/1.0'
556
- cache.should.a.performed :hit
656
+ cache.trace.should.include :fresh
557
657
  response.body.should.equal 'Bob/1.0'
558
658
  response['X-Response-Count'].should.equal '1'
559
659
 
560
660
  get '/',
561
661
  'HTTP_ACCEPT' => 'text/html',
562
662
  'HTTP_USER_AGENT' => 'Bob/2.0'
563
- cache.should.a.performed :hit
663
+ cache.trace.should.include :fresh
564
664
  response.body.should.equal 'Bob/2.0'
565
665
  response['X-Response-Count'].should.equal '2'
566
666
 
567
667
  get '/',
568
668
  'HTTP_USER_AGENT' => 'Bob/2.0'
569
- cache.should.a.performed :miss
669
+ cache.trace.should.include :miss
570
670
  response.body.should.equal 'Bob/2.0'
571
671
  response['X-Response-Count'].should.equal '3'
572
672
  end
573
673
  end
574
-
575
- describe 'when transitioning to the error state' do
576
-
577
- setup { respond_with(200) }
578
-
579
- it 'creates a blank slate response object with 500 status with no args' do
580
- cache_config do
581
- on(:receive) { error! }
582
- end
583
- get '/'
584
- response.status.should.equal 500
585
- response.body.should.be.empty
586
- cache.should.a.performed :error
587
- end
588
-
589
- it 'sets the status code with one arg' do
590
- cache_config do
591
- on(:receive) { error! 505 }
592
- end
593
- get '/'
594
- response.status.should.equal 505
595
- end
596
-
597
- it 'sets the status and headers with args: status, Hash' do
598
- cache_config do
599
- on(:receive) { error! 504, 'Content-Type' => 'application/x-foo' }
600
- end
601
- get '/'
602
- response.status.should.equal 504
603
- response['Content-Type'].should.equal 'application/x-foo'
604
- response.body.should.be.empty
605
- end
606
-
607
- it 'sets the status and body with args: status, String' do
608
- cache_config do
609
- on(:receive) { error! 503, 'foo bar baz' }
610
- end
611
- get '/'
612
- response.status.should.equal 503
613
- response.body.should.equal 'foo bar baz'
614
- end
615
-
616
- it 'sets the status and body with args: status, Array' do
617
- cache_config do
618
- on(:receive) { error! 503, ['foo bar baz'] }
619
- end
620
- get '/'
621
- response.status.should.equal 503
622
- response.body.should.equal 'foo bar baz'
623
- end
624
-
625
- it 'fires the error event before finishing' do
626
- fired = false
627
- cache_config do
628
- on(:receive) { error! }
629
- on(:error) {
630
- fired = true
631
- response.status.should.equal 500
632
- response['Content-Type'] = 'application/x-foo'
633
- response.body = ['overridden response body']
634
- }
635
- end
636
- get '/'
637
- fired.should.be true
638
- response.status.should.equal 500
639
- response.body.should.equal 'overridden response body'
640
- response['Content-Type'].should.equal 'application/x-foo'
641
- end
642
-
643
- end
644
-
645
674
  end