rack-cache 0.2.0
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.
Potentially problematic release.
This version of rack-cache might be problematic. Click here for more details.
- data/CHANGES +27 -0
- data/COPYING +18 -0
- data/README +96 -0
- data/Rakefile +144 -0
- data/TODO +40 -0
- data/doc/configuration.markdown +224 -0
- data/doc/events.dot +27 -0
- data/doc/faq.markdown +133 -0
- data/doc/index.markdown +113 -0
- data/doc/layout.html.erb +33 -0
- data/doc/license.markdown +24 -0
- data/doc/rack-cache.css +362 -0
- data/doc/storage.markdown +162 -0
- data/lib/rack/cache.rb +51 -0
- data/lib/rack/cache/config.rb +65 -0
- data/lib/rack/cache/config/busters.rb +16 -0
- data/lib/rack/cache/config/default.rb +134 -0
- data/lib/rack/cache/config/no-cache.rb +13 -0
- data/lib/rack/cache/context.rb +95 -0
- data/lib/rack/cache/core.rb +271 -0
- data/lib/rack/cache/entitystore.rb +224 -0
- data/lib/rack/cache/headers.rb +237 -0
- data/lib/rack/cache/metastore.rb +309 -0
- data/lib/rack/cache/options.rb +119 -0
- data/lib/rack/cache/request.rb +37 -0
- data/lib/rack/cache/response.rb +76 -0
- data/lib/rack/cache/storage.rb +50 -0
- data/lib/rack/utils/environment_headers.rb +78 -0
- data/rack-cache.gemspec +74 -0
- data/test/cache_test.rb +35 -0
- data/test/config_test.rb +66 -0
- data/test/context_test.rb +465 -0
- data/test/core_test.rb +84 -0
- data/test/entitystore_test.rb +176 -0
- data/test/environment_headers_test.rb +71 -0
- data/test/headers_test.rb +215 -0
- data/test/logging_test.rb +45 -0
- data/test/metastore_test.rb +210 -0
- data/test/options_test.rb +64 -0
- data/test/pony.jpg +0 -0
- data/test/response_test.rb +37 -0
- data/test/spec_setup.rb +189 -0
- data/test/storage_test.rb +94 -0
- metadata +120 -0
data/test/config_test.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/spec_setup"
|
2
|
+
require 'rack/cache/config'
|
3
|
+
|
4
|
+
class MockConfig
|
5
|
+
include Rack::Cache::Config
|
6
|
+
def configured!
|
7
|
+
@configured = true
|
8
|
+
end
|
9
|
+
def configured?
|
10
|
+
@configured
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'Rack::Cache::Config' do
|
15
|
+
before :each do
|
16
|
+
@config = MockConfig.new
|
17
|
+
@tempdir = create_temp_directory
|
18
|
+
$:.unshift @tempdir
|
19
|
+
end
|
20
|
+
after :each do
|
21
|
+
@config = nil
|
22
|
+
$:.shift if $:.first == @tempdir
|
23
|
+
remove_entry_secure @tempdir
|
24
|
+
end
|
25
|
+
|
26
|
+
def make_temp_file(filename, data='configured!')
|
27
|
+
create_temp_file @tempdir, filename, data
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'loads config files from the load path when file is relative' do
|
31
|
+
make_temp_file 'foo/bar.rb'
|
32
|
+
@config.import 'foo/bar.rb'
|
33
|
+
@config.should.be.configured
|
34
|
+
end
|
35
|
+
it 'assumes a .rb file extension when no file extension exists' do
|
36
|
+
make_temp_file 'foo/bar.rb'
|
37
|
+
@config.import 'foo/bar'
|
38
|
+
@config.should.be.configured
|
39
|
+
end
|
40
|
+
it 'does not assume a .rb file extension when other file extension exists' do
|
41
|
+
make_temp_file 'foo/bar.conf'
|
42
|
+
@config.import 'foo/bar.conf'
|
43
|
+
@config.should.be.configured
|
44
|
+
end
|
45
|
+
it 'should locate files with absolute path names' do
|
46
|
+
make_temp_file 'foo/bar.rb'
|
47
|
+
@config.import File.join(@tempdir, 'foo/bar.rb')
|
48
|
+
@config.should.be.configured
|
49
|
+
end
|
50
|
+
it 'raises a LoadError when the file cannot be found' do
|
51
|
+
assert_raises(LoadError) {
|
52
|
+
@config.import('this/file/is/very-likely/not/to/exist.rb')
|
53
|
+
}
|
54
|
+
end
|
55
|
+
it 'executes within the context of the object instance' do
|
56
|
+
make_temp_file 'foo/bar.rb',
|
57
|
+
'self.should.be.kind_of Rack::Cache::Config ; configured!'
|
58
|
+
@config.import 'foo/bar'
|
59
|
+
@config.should.be.configured
|
60
|
+
end
|
61
|
+
it 'does not import files more than once' do
|
62
|
+
make_temp_file 'foo/bar.rb', "import 'foo/bar'"
|
63
|
+
@config.import('foo/bar').should.be true
|
64
|
+
@config.import('foo/bar').should.be false
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,465 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/spec_setup"
|
2
|
+
require 'rack/cache/context'
|
3
|
+
|
4
|
+
describe 'Rack::Cache::Context' do
|
5
|
+
before(:each) { setup_cache_context }
|
6
|
+
after(:each) { teardown_cache_context }
|
7
|
+
|
8
|
+
it 'passes on non-GET/HEAD requests' do
|
9
|
+
respond_with 200
|
10
|
+
post '/'
|
11
|
+
|
12
|
+
app.should.be.called
|
13
|
+
response.should.be.ok
|
14
|
+
cache.should.a.performed :pass
|
15
|
+
response.headers.should.not.include 'Age'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'passes on requests with Authorization' do
|
19
|
+
respond_with 200
|
20
|
+
get '/', 'HTTP_AUTHORIZATION' => 'basic foobarbaz'
|
21
|
+
|
22
|
+
app.should.be.called
|
23
|
+
response.should.be.ok
|
24
|
+
cache.should.a.performed :pass
|
25
|
+
response.headers.should.not.include 'Age'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'passes on requests with a Cookie' do
|
29
|
+
respond_with 200
|
30
|
+
get '/', 'HTTP_COOKIE' => 'foo=bar'
|
31
|
+
|
32
|
+
response.should.be.ok
|
33
|
+
app.should.be.called
|
34
|
+
cache.should.a.performed :pass
|
35
|
+
response.headers.should.not.include 'Age'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'caches requests when Cache-Control request header set to no-cache' do
|
39
|
+
respond_with 200, 'Expires' => (Time.now + 5).httpdate
|
40
|
+
get '/', 'HTTP_CACHE_CONTROL' => 'no-cache'
|
41
|
+
|
42
|
+
response.should.be.ok
|
43
|
+
cache.should.a.performed :store
|
44
|
+
response.headers.should.not.include 'Age'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'fetches response from backend when cache misses' do
|
48
|
+
respond_with 200, 'Expires' => (Time.now + 5).httpdate
|
49
|
+
get '/'
|
50
|
+
|
51
|
+
response.should.be.ok
|
52
|
+
cache.should.a.performed :miss
|
53
|
+
cache.should.a.performed :fetch
|
54
|
+
response.headers.should.not.include 'Age'
|
55
|
+
end
|
56
|
+
|
57
|
+
[(201..202),(204..206),(303..305),(400..403),(405..409),(411..417),(500..505)].each do |range|
|
58
|
+
range.each do |response_code|
|
59
|
+
it "does not cache #{response_code} responses" do
|
60
|
+
respond_with response_code, 'Expires' => (Time.now + 5).httpdate
|
61
|
+
get '/'
|
62
|
+
|
63
|
+
cache.should.a.not.performed :store
|
64
|
+
response.status.should.be == response_code
|
65
|
+
response.headers.should.not.include 'Age'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not cache responses with explicit no-store directive" do
|
71
|
+
respond_with 200,
|
72
|
+
'Expires' => (Time.now + 5).httpdate,
|
73
|
+
'Cache-Control' => 'no-store'
|
74
|
+
get '/'
|
75
|
+
|
76
|
+
response.should.be.ok
|
77
|
+
cache.should.a.not.performed :store
|
78
|
+
response.headers.should.not.include 'Age'
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'does not cache responses without freshness information or a validator' do
|
82
|
+
respond_with 200
|
83
|
+
get '/'
|
84
|
+
|
85
|
+
response.should.be.ok
|
86
|
+
cache.should.a.not.performed :store
|
87
|
+
end
|
88
|
+
|
89
|
+
it "caches responses with explicit no-cache directive" do
|
90
|
+
respond_with 200,
|
91
|
+
'Expires' => (Time.now + 5).httpdate,
|
92
|
+
'Cache-Control' => 'no-cache'
|
93
|
+
get '/'
|
94
|
+
|
95
|
+
response.should.be.ok
|
96
|
+
cache.should.a.performed :store
|
97
|
+
response.headers.should.not.include 'Age'
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'caches responses with an Expiration header' do
|
101
|
+
respond_with 200, 'Expires' => (Time.now + 5).httpdate
|
102
|
+
get '/'
|
103
|
+
|
104
|
+
response.should.be.ok
|
105
|
+
response.body.should.be == 'Hello World'
|
106
|
+
response.headers.should.include 'Date'
|
107
|
+
response['Age'].should.be.nil
|
108
|
+
response['X-Content-Digest'].should.be.nil
|
109
|
+
cache.should.a.performed :miss
|
110
|
+
cache.should.a.performed :store
|
111
|
+
cache.metastore.to_hash.keys.length.should.be == 1
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'caches responses with a max-age directive' do
|
115
|
+
respond_with 200, 'Cache-Control' => 'max-age=5'
|
116
|
+
get '/'
|
117
|
+
|
118
|
+
response.should.be.ok
|
119
|
+
response.body.should.be == 'Hello World'
|
120
|
+
response.headers.should.include 'Date'
|
121
|
+
response['Age'].should.be.nil
|
122
|
+
response['X-Content-Digest'].should.be.nil
|
123
|
+
cache.should.a.performed :miss
|
124
|
+
cache.should.a.performed :store
|
125
|
+
cache.metastore.to_hash.keys.length.should.be == 1
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'caches responses with a Last-Modified validator but no freshness information' do
|
129
|
+
respond_with 200, 'Last-Modified' => Time.now.httpdate
|
130
|
+
get '/'
|
131
|
+
|
132
|
+
response.should.be.ok
|
133
|
+
response.body.should.be == 'Hello World'
|
134
|
+
cache.should.a.performed :miss
|
135
|
+
cache.should.a.performed :store
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'caches responses with an ETag validator but no freshness information' do
|
139
|
+
respond_with 200, 'Etag' => '"123456"'
|
140
|
+
get '/'
|
141
|
+
|
142
|
+
response.should.be.ok
|
143
|
+
response.body.should.be == 'Hello World'
|
144
|
+
cache.should.a.performed :miss
|
145
|
+
cache.should.a.performed :store
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'hits cached response with Expires header' do
|
149
|
+
respond_with 200,
|
150
|
+
'Date' => (Time.now - 5).httpdate,
|
151
|
+
'Expires' => (Time.now + 5).httpdate
|
152
|
+
|
153
|
+
get '/'
|
154
|
+
app.should.be.called
|
155
|
+
response.should.be.ok
|
156
|
+
response.headers.should.include 'Date'
|
157
|
+
cache.should.a.performed :miss
|
158
|
+
cache.should.a.performed :store
|
159
|
+
response.body.should.be == 'Hello World'
|
160
|
+
|
161
|
+
get '/'
|
162
|
+
response.should.be.ok
|
163
|
+
app.should.not.be.called
|
164
|
+
response['Date'].should.be == responses.first['Date']
|
165
|
+
response['Age'].to_i.should.be > 0
|
166
|
+
response['X-Content-Digest'].should.not.be.nil
|
167
|
+
cache.should.a.performed :hit
|
168
|
+
cache.should.a.not.performed :fetch
|
169
|
+
response.body.should.be == 'Hello World'
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'hits cached response with max-age directive' do
|
173
|
+
respond_with 200,
|
174
|
+
'Date' => (Time.now - 5).httpdate,
|
175
|
+
'Cache-Control' => 'max-age=10'
|
176
|
+
|
177
|
+
get '/'
|
178
|
+
app.should.be.called
|
179
|
+
response.should.be.ok
|
180
|
+
response.headers.should.include 'Date'
|
181
|
+
cache.should.a.performed :miss
|
182
|
+
cache.should.a.performed :store
|
183
|
+
response.body.should.be == 'Hello World'
|
184
|
+
|
185
|
+
get '/'
|
186
|
+
response.should.be.ok
|
187
|
+
app.should.not.be.called
|
188
|
+
response['Date'].should.be == responses.first['Date']
|
189
|
+
response['Age'].to_i.should.be > 0
|
190
|
+
response['X-Content-Digest'].should.not.be.nil
|
191
|
+
cache.should.a.performed :hit
|
192
|
+
cache.should.a.not.performed :fetch
|
193
|
+
response.body.should.be == 'Hello World'
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'fetches full response when cache stale and no validators present' do
|
197
|
+
respond_with 200, 'Expires' => (Time.now + 5).httpdate
|
198
|
+
|
199
|
+
# build initial request
|
200
|
+
get '/'
|
201
|
+
app.should.be.called
|
202
|
+
response.should.be.ok
|
203
|
+
response.headers.should.include 'Date'
|
204
|
+
response.headers.should.not.include 'X-Content-Digest'
|
205
|
+
response['Age'].should.be.nil
|
206
|
+
cache.should.a.performed :miss
|
207
|
+
cache.should.a.performed :store
|
208
|
+
response.body.should.be == 'Hello World'
|
209
|
+
|
210
|
+
# go in and play around with the cached metadata directly ...
|
211
|
+
cache.metastore.to_hash.values.length.should.be == 1
|
212
|
+
cache.metastore.to_hash.values.first.first[1]['Expires'] = Time.now.httpdate
|
213
|
+
|
214
|
+
# build subsequent request; should be found but miss due to freshness
|
215
|
+
get '/'
|
216
|
+
app.should.be.called
|
217
|
+
response.should.be.ok
|
218
|
+
response['Age'].to_i.should.be == 0
|
219
|
+
response['X-Content-Digest'].should.be.nil
|
220
|
+
cache.should.a.not.performed :hit
|
221
|
+
cache.should.a.not.performed :miss
|
222
|
+
cache.should.a.performed :fetch
|
223
|
+
cache.should.a.performed :store
|
224
|
+
response.body.should.be == 'Hello World'
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'validates cached responses with Last-Modified and no freshness information' do
|
228
|
+
timestamp = Time.now.httpdate
|
229
|
+
respond_with do |req,res|
|
230
|
+
res['Last-Modified'] = timestamp
|
231
|
+
if req.env['HTTP_IF_MODIFIED_SINCE'] == timestamp
|
232
|
+
res.status = 304
|
233
|
+
res.body = []
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# build initial request
|
238
|
+
get '/'
|
239
|
+
app.should.be.called
|
240
|
+
response.should.be.ok
|
241
|
+
response.headers.should.include 'Last-Modified'
|
242
|
+
response.headers.should.not.include 'X-Content-Digest'
|
243
|
+
response.body.should.be == 'Hello World'
|
244
|
+
cache.should.a.performed :miss
|
245
|
+
cache.should.a.performed :store
|
246
|
+
|
247
|
+
# build subsequent request; should be found but miss due to freshness
|
248
|
+
get '/'
|
249
|
+
app.should.be.called
|
250
|
+
response.should.be.ok
|
251
|
+
response.headers.should.include 'Last-Modified'
|
252
|
+
response.headers.should.include 'X-Content-Digest'
|
253
|
+
response['Age'].to_i.should.be == 0
|
254
|
+
response['X-Origin-Status'].should.be == '304'
|
255
|
+
response.body.should.be == 'Hello World'
|
256
|
+
cache.should.a.not.performed :miss
|
257
|
+
cache.should.a.performed :fetch
|
258
|
+
cache.should.a.performed :store
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'validates cached responses with ETag and no freshness information' do
|
262
|
+
timestamp = Time.now.httpdate
|
263
|
+
respond_with do |req,res|
|
264
|
+
res['ETAG'] = '"12345"'
|
265
|
+
if req.env['HTTP_IF_NONE_MATCH'] == res['Etag']
|
266
|
+
res.status = 304
|
267
|
+
res.body = []
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# build initial request
|
272
|
+
get '/'
|
273
|
+
app.should.be.called
|
274
|
+
response.should.be.ok
|
275
|
+
response.headers.should.include 'Etag'
|
276
|
+
response.headers.should.not.include 'X-Content-Digest'
|
277
|
+
response.body.should.be == 'Hello World'
|
278
|
+
cache.should.a.performed :miss
|
279
|
+
cache.should.a.performed :store
|
280
|
+
|
281
|
+
# build subsequent request; should be found but miss due to freshness
|
282
|
+
get '/'
|
283
|
+
app.should.be.called
|
284
|
+
response.should.be.ok
|
285
|
+
response.headers.should.include 'Etag'
|
286
|
+
response.headers.should.include 'X-Content-Digest'
|
287
|
+
response['Age'].to_i.should.be == 0
|
288
|
+
response['X-Origin-Status'].should.be == '304'
|
289
|
+
response.body.should.be == 'Hello World'
|
290
|
+
cache.should.a.not.performed :miss
|
291
|
+
cache.should.a.performed :fetch
|
292
|
+
cache.should.a.performed :store
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'replaces cached responses when validation results in non-304 response' do
|
296
|
+
timestamp = Time.now.httpdate
|
297
|
+
count = 0
|
298
|
+
respond_with do |req,res|
|
299
|
+
res['Last-Modified'] = timestamp
|
300
|
+
case (count+=1)
|
301
|
+
when 1 ; res.body = 'first response'
|
302
|
+
when 2 ; res.body = 'second response'
|
303
|
+
when 3
|
304
|
+
res.body = []
|
305
|
+
res.status = 304
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# first request should fetch from backend and store in cache
|
310
|
+
get '/'
|
311
|
+
response.status.should.be == 200
|
312
|
+
response.body.should.be == 'first response'
|
313
|
+
|
314
|
+
# second request is validated, is invalid, and replaces cached entry
|
315
|
+
get '/'
|
316
|
+
response.status.should.be == 200
|
317
|
+
response.body.should.be == 'second response'
|
318
|
+
|
319
|
+
# third respone is validated, valid, and returns cached entry
|
320
|
+
get '/'
|
321
|
+
response.status.should.be == 200
|
322
|
+
response.body.should.be == 'second response'
|
323
|
+
|
324
|
+
count.should.be == 3
|
325
|
+
end
|
326
|
+
|
327
|
+
describe 'with responses that include a Vary header' do
|
328
|
+
before(:each) do
|
329
|
+
count = 0
|
330
|
+
respond_with 200 do |req,res|
|
331
|
+
res['Vary'] = 'Accept User-Agent Foo'
|
332
|
+
res['Cache-Control'] = 'max-age=10'
|
333
|
+
res['X-Response-Count'] = (count+=1).to_s
|
334
|
+
res.body = req.env['HTTP_USER_AGENT']
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'serves from cache when headers match' do
|
339
|
+
get '/',
|
340
|
+
'HTTP_ACCEPT' => 'text/html',
|
341
|
+
'HTTP_USER_AGENT' => 'Bob/1.0'
|
342
|
+
response.should.be.ok
|
343
|
+
response.body.should.be == 'Bob/1.0'
|
344
|
+
cache.should.a.performed :miss
|
345
|
+
cache.should.a.performed :store
|
346
|
+
|
347
|
+
get '/',
|
348
|
+
'HTTP_ACCEPT' => 'text/html',
|
349
|
+
'HTTP_USER_AGENT' => 'Bob/1.0'
|
350
|
+
response.should.be.ok
|
351
|
+
response.body.should.be == 'Bob/1.0'
|
352
|
+
cache.should.a.performed :hit
|
353
|
+
cache.should.a.not.performed :fetch
|
354
|
+
response.headers.should.include 'X-Content-Digest'
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'stores multiple responses when headers differ' do
|
358
|
+
get '/',
|
359
|
+
'HTTP_ACCEPT' => 'text/html',
|
360
|
+
'HTTP_USER_AGENT' => 'Bob/1.0'
|
361
|
+
response.should.be.ok
|
362
|
+
response.body.should.be == 'Bob/1.0'
|
363
|
+
response['X-Response-Count'].should.be == '1'
|
364
|
+
|
365
|
+
get '/',
|
366
|
+
'HTTP_ACCEPT' => 'text/html',
|
367
|
+
'HTTP_USER_AGENT' => 'Bob/2.0'
|
368
|
+
cache.should.a.performed :miss
|
369
|
+
cache.should.a.performed :store
|
370
|
+
response.body.should.be == 'Bob/2.0'
|
371
|
+
response['X-Response-Count'].should.be == '2'
|
372
|
+
|
373
|
+
get '/',
|
374
|
+
'HTTP_ACCEPT' => 'text/html',
|
375
|
+
'HTTP_USER_AGENT' => 'Bob/1.0'
|
376
|
+
cache.should.a.performed :hit
|
377
|
+
response.body.should.be == 'Bob/1.0'
|
378
|
+
response['X-Response-Count'].should.be == '1'
|
379
|
+
|
380
|
+
get '/',
|
381
|
+
'HTTP_ACCEPT' => 'text/html',
|
382
|
+
'HTTP_USER_AGENT' => 'Bob/2.0'
|
383
|
+
cache.should.a.performed :hit
|
384
|
+
response.body.should.be == 'Bob/2.0'
|
385
|
+
response['X-Response-Count'].should.be == '2'
|
386
|
+
|
387
|
+
get '/',
|
388
|
+
'HTTP_USER_AGENT' => 'Bob/2.0'
|
389
|
+
cache.should.a.performed :miss
|
390
|
+
response.body.should.be == 'Bob/2.0'
|
391
|
+
response['X-Response-Count'].should.be == '3'
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
describe 'when transitioning to the error state' do
|
396
|
+
|
397
|
+
setup { respond_with(200) }
|
398
|
+
|
399
|
+
it 'creates a blank slate response object with 500 status with no args' do
|
400
|
+
cache_config do
|
401
|
+
on(:receive) { error! }
|
402
|
+
end
|
403
|
+
get '/'
|
404
|
+
response.status.should.be == 500
|
405
|
+
response.body.should.be.empty
|
406
|
+
cache.should.a.performed :error
|
407
|
+
end
|
408
|
+
|
409
|
+
it 'sets the status code with one arg' do
|
410
|
+
cache_config do
|
411
|
+
on(:receive) { error! 505 }
|
412
|
+
end
|
413
|
+
get '/'
|
414
|
+
response.status.should.be == 505
|
415
|
+
end
|
416
|
+
|
417
|
+
it 'sets the status and headers with args: status, Hash' do
|
418
|
+
cache_config do
|
419
|
+
on(:receive) { error! 504, 'Content-Type' => 'application/x-foo' }
|
420
|
+
end
|
421
|
+
get '/'
|
422
|
+
response.status.should.be == 504
|
423
|
+
response['Content-Type'].should.be == 'application/x-foo'
|
424
|
+
response.body.should.be.empty
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'sets the status and body with args: status, String' do
|
428
|
+
cache_config do
|
429
|
+
on(:receive) { error! 503, 'foo bar baz' }
|
430
|
+
end
|
431
|
+
get '/'
|
432
|
+
response.status.should.be == 503
|
433
|
+
response.body.should.be == 'foo bar baz'
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'sets the status and body with args: status, Array' do
|
437
|
+
cache_config do
|
438
|
+
on(:receive) { error! 503, ['foo bar baz'] }
|
439
|
+
end
|
440
|
+
get '/'
|
441
|
+
response.status.should.be == 503
|
442
|
+
response.body.should.be == 'foo bar baz'
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'fires the error event before finishing' do
|
446
|
+
fired = false
|
447
|
+
cache_config do
|
448
|
+
on(:receive) { error! }
|
449
|
+
on(:error) {
|
450
|
+
fired = true
|
451
|
+
response.status.should.be == 500
|
452
|
+
response['Content-Type'] = 'application/x-foo'
|
453
|
+
response.body = ['overridden response body']
|
454
|
+
}
|
455
|
+
end
|
456
|
+
get '/'
|
457
|
+
fired.should.be true
|
458
|
+
response.status.should.be == 500
|
459
|
+
response.body.should.be == 'overridden response body'
|
460
|
+
response['Content-Type'].should.be == 'application/x-foo'
|
461
|
+
end
|
462
|
+
|
463
|
+
end
|
464
|
+
|
465
|
+
end
|