rack-cache 0.2.0 → 0.3.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 +58 -0
- data/README +14 -9
- data/Rakefile +11 -5
- data/TODO +11 -19
- data/doc/configuration.markdown +9 -1
- data/doc/index.markdown +17 -10
- data/doc/layout.html.erb +1 -0
- data/doc/server.ru +34 -0
- data/lib/rack/cache/config/default.rb +1 -2
- data/lib/rack/cache/core.rb +37 -9
- data/lib/rack/cache/entitystore.rb +29 -6
- data/lib/rack/cache/headers.rb +118 -30
- data/lib/rack/cache/metastore.rb +22 -39
- data/lib/rack/cache/options.rb +11 -1
- data/lib/rack/cache/response.rb +2 -2
- data/rack-cache.gemspec +5 -4
- data/test/cache_test.rb +3 -3
- data/test/context_test.rb +255 -75
- data/test/core_test.rb +8 -8
- data/test/entitystore_test.rb +23 -11
- data/test/environment_headers_test.rb +10 -12
- data/test/headers_test.rb +106 -23
- data/test/metastore_test.rb +28 -18
- data/test/options_test.rb +13 -10
- data/test/spec_setup.rb +13 -7
- metadata +8 -4
data/test/core_test.rb
CHANGED
@@ -24,15 +24,15 @@ describe 'Rack::Cache::Core' do
|
|
24
24
|
it 'executes multiple handlers in LIFO order' do
|
25
25
|
x = 'nothing executed'
|
26
26
|
@core.on :foo do
|
27
|
-
x.should.
|
27
|
+
x.should.equal 'bottom executed'
|
28
28
|
x = 'top executed'
|
29
29
|
end
|
30
30
|
@core.on :foo do
|
31
|
-
x.should.
|
31
|
+
x.should.equal 'nothing executed'
|
32
32
|
x = 'bottom executed'
|
33
33
|
end
|
34
34
|
@core.trigger :foo
|
35
|
-
x.should.
|
35
|
+
x.should.equal 'top executed'
|
36
36
|
end
|
37
37
|
it 'records event execution history' do
|
38
38
|
@core.on(:foo) {}
|
@@ -59,8 +59,8 @@ describe 'Rack::Cache::Core' do
|
|
59
59
|
@core.on(:bar) {}
|
60
60
|
@core.on(:foo) { throw(:transition, [:bar, 1, 2, 3]) }
|
61
61
|
result = @core.transition(from=:foo, to=[:bar])
|
62
|
-
passed.should.
|
63
|
-
result.should.
|
62
|
+
passed.should.equal [1,2,3]
|
63
|
+
result.should.equal 'hi'
|
64
64
|
end
|
65
65
|
it 'fully transitions out of handlers when the next event is invoked' do
|
66
66
|
x = []
|
@@ -70,15 +70,15 @@ describe 'Rack::Cache::Core' do
|
|
70
70
|
x << 'in foo, after transitioning to bar'
|
71
71
|
}
|
72
72
|
@core.on(:bar) { x << 'in bar' }
|
73
|
-
@core.trigger(:foo).should.
|
73
|
+
@core.trigger(:foo).should.equal [:bar]
|
74
74
|
@core.trigger(:bar).should.be.nil
|
75
|
-
x.should.
|
75
|
+
x.should.equal [
|
76
76
|
'in foo, before transitioning to bar',
|
77
77
|
'in bar'
|
78
78
|
]
|
79
79
|
end
|
80
80
|
it 'returns the transition event name' do
|
81
81
|
@core.on(:foo) { throw(:transition, [:bar]) }
|
82
|
-
@core.trigger(:foo).should.
|
82
|
+
@core.trigger(:foo).should.equal [:bar]
|
83
83
|
end
|
84
84
|
end
|
data/test/entitystore_test.rb
CHANGED
@@ -21,7 +21,7 @@ describe_shared 'A Rack::Cache::EntityStore Implementation' do
|
|
21
21
|
key.should.be.sha_like
|
22
22
|
|
23
23
|
data = @store.read(key)
|
24
|
-
data.should.
|
24
|
+
data.should.equal 'My wild love went riding,'
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'correctly determines whether cached body exists for key with #exist?' do
|
@@ -33,20 +33,20 @@ describe_shared 'A Rack::Cache::EntityStore Implementation' do
|
|
33
33
|
it 'can read data written with #write' do
|
34
34
|
key, size = @store.write('And asked him to pay.')
|
35
35
|
data = @store.read(key)
|
36
|
-
data.should.
|
36
|
+
data.should.equal 'And asked him to pay.'
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'gives a 40 character SHA1 hex digest from #write' do
|
40
40
|
key, size = @store.write('she rode to the sea;')
|
41
41
|
key.should.not.be.nil
|
42
|
-
key.length.should.
|
42
|
+
key.length.should.equal 40
|
43
43
|
key.should.be =~ /^[0-9a-z]+$/
|
44
|
-
key.should.
|
44
|
+
key.should.equal '90a4c84d51a277f3dafc34693ca264531b9f51b6'
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'returns the entire body as a String from #read' do
|
48
48
|
key, size = @store.write('She gathered together')
|
49
|
-
@store.read(key).should.
|
49
|
+
@store.read(key).should.equal 'She gathered together'
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'returns nil from #read when key does not exist' do
|
@@ -59,7 +59,7 @@ describe_shared 'A Rack::Cache::EntityStore Implementation' do
|
|
59
59
|
body.should.respond_to :each
|
60
60
|
buf = ''
|
61
61
|
body.each { |part| buf << part }
|
62
|
-
buf.should.
|
62
|
+
buf.should.equal 'Some shells for her hair.'
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'returns nil from #open when key does not exist' do
|
@@ -69,12 +69,17 @@ describe_shared 'A Rack::Cache::EntityStore Implementation' do
|
|
69
69
|
it 'can store largish bodies with binary data' do
|
70
70
|
pony = File.read(File.dirname(__FILE__) + '/pony.jpg')
|
71
71
|
key, size = @store.write(pony)
|
72
|
-
key.should.
|
72
|
+
key.should.equal 'd0f30d8659b4d268c5c64385d9790024c2d78deb'
|
73
73
|
data = @store.read(key)
|
74
|
-
data.length.should.
|
75
|
-
data.hash.should.
|
74
|
+
data.length.should.equal pony.length
|
75
|
+
data.hash.should.equal pony.hash
|
76
76
|
end
|
77
77
|
|
78
|
+
it 'deletes stored entries with #purge' do
|
79
|
+
key, size = @store.write('My wild love went riding,')
|
80
|
+
@store.purge(key).should.be.nil
|
81
|
+
@store.read(key).should.be.nil
|
82
|
+
end
|
78
83
|
end
|
79
84
|
|
80
85
|
describe 'Rack::Cache::EntityStore' do
|
@@ -84,7 +89,7 @@ describe 'Rack::Cache::EntityStore' do
|
|
84
89
|
before { @store = Rack::Cache::EntityStore::Heap.new }
|
85
90
|
it 'takes a Hash to ::new' do
|
86
91
|
@store = Rack::Cache::EntityStore::Heap.new('foo' => ['bar'])
|
87
|
-
@store.read('foo').should.
|
92
|
+
@store.read('foo').should.equal 'bar'
|
88
93
|
end
|
89
94
|
it 'uses its own Hash with no args to ::new' do
|
90
95
|
@store.read('foo').should.be.nil
|
@@ -106,6 +111,13 @@ describe 'Rack::Cache::EntityStore' do
|
|
106
111
|
@store = Rack::Cache::EntityStore::Disk.new(path)
|
107
112
|
File.should.be.a.directory path
|
108
113
|
end
|
114
|
+
it 'produces a body that responds to #to_path' do
|
115
|
+
key, size = @store.write('Some shells for her hair.')
|
116
|
+
body = @store.open(key)
|
117
|
+
body.should.respond_to :to_path
|
118
|
+
path = "#{@temp_dir}/#{key[0..1]}/#{key[2..-1]}"
|
119
|
+
body.to_path.should.equal path
|
120
|
+
end
|
109
121
|
it 'spreads data over a 36² hash radius' do
|
110
122
|
(<<-PROSE).each { |line| @store.write(line).first.should.be.sha_like }
|
111
123
|
My wild love went riding,
|
@@ -158,7 +170,7 @@ describe 'Rack::Cache::EntityStore' do
|
|
158
170
|
end
|
159
171
|
files.length.should.be > 0
|
160
172
|
end
|
161
|
-
subdirs.length.should.
|
173
|
+
subdirs.length.should.equal 28
|
162
174
|
end
|
163
175
|
end
|
164
176
|
|
@@ -21,27 +21,27 @@ describe 'Rack::Utils::EnvironmentHeaders' do
|
|
21
21
|
|
22
22
|
it 'retrieves headers with #[]' do
|
23
23
|
@h.should.respond_to :[]
|
24
|
-
@h['X-Foo'].should.
|
25
|
-
@h['If-Modified-Since'].should.
|
24
|
+
@h['X-Foo'].should.equal 'BAR'
|
25
|
+
@h['If-Modified-Since'].should.equal @now
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'sets headers with #[]=' do
|
29
29
|
@h.should.respond_to :[]=
|
30
30
|
@h['X-Foo'] = 'BAZZLE'
|
31
|
-
@h['X-Foo'].should.
|
31
|
+
@h['X-Foo'].should.equal 'BAZZLE'
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'sets values on the underlying environment hash' do
|
35
35
|
@h['X-Something-Else'] = 'FOO'
|
36
|
-
@env['HTTP_X_SOMETHING_ELSE'].should.
|
36
|
+
@env['HTTP_X_SOMETHING_ELSE'].should.equal 'FOO'
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'handles Content-Type special case' do
|
40
|
-
@h['Content-Type'].should.
|
40
|
+
@h['Content-Type'].should.equal 'text/plain'
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'handles Content-Length special case' do
|
44
|
-
@h['Content-Length'].should.
|
44
|
+
@h['Content-Length'].should.equal '0x1A4'
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'implements #include? with RFC 2616 header name' do
|
@@ -60,12 +60,10 @@ describe 'Rack::Utils::EnvironmentHeaders' do
|
|
60
60
|
it 'iterates over all headers with #each' do
|
61
61
|
hash = {}
|
62
62
|
@h.each { |name,value| hash[name] = value }
|
63
|
-
hash.should.
|
64
|
-
'Content-
|
65
|
-
'
|
66
|
-
'
|
67
|
-
'If-Modified-Since' => @now
|
68
|
-
}
|
63
|
+
hash.should.equal 'Content-Type' => 'text/plain',
|
64
|
+
'Content-Length' => '0x1A4',
|
65
|
+
'X-Foo' => 'BAR',
|
66
|
+
'If-Modified-Since' => @now
|
69
67
|
end
|
70
68
|
|
71
69
|
end
|
data/test/headers_test.rb
CHANGED
@@ -8,7 +8,7 @@ end
|
|
8
8
|
|
9
9
|
describe 'Rack::Cache::Headers' do
|
10
10
|
before :each do
|
11
|
-
@now = Time.now
|
11
|
+
@now = Time.httpdate(Time.now.httpdate)
|
12
12
|
@res = MockResponse.new(200, {'Date' => @now.httpdate}, '')
|
13
13
|
@one_hour_ago = Time.httpdate((Time.now - (60**2)).httpdate)
|
14
14
|
end
|
@@ -19,13 +19,13 @@ describe 'Rack::Cache::Headers' do
|
|
19
19
|
describe '#cache_control' do
|
20
20
|
it 'handles single name=value pair' do
|
21
21
|
@res.headers['Cache-Control'] = 'max-age=600'
|
22
|
-
@res.cache_control['max-age'].should.
|
22
|
+
@res.cache_control['max-age'].should.equal '600'
|
23
23
|
end
|
24
24
|
it 'handles multiple name=value pairs' do
|
25
25
|
@res.headers['Cache-Control'] = 'max-age=600, max-stale=300, min-fresh=570'
|
26
|
-
@res.cache_control['max-age'].should.
|
27
|
-
@res.cache_control['max-stale'].should.
|
28
|
-
@res.cache_control['min-fresh'].should.
|
26
|
+
@res.cache_control['max-age'].should.equal '600'
|
27
|
+
@res.cache_control['max-stale'].should.equal '300'
|
28
|
+
@res.cache_control['min-fresh'].should.equal '570'
|
29
29
|
end
|
30
30
|
it 'handles a single flag value' do
|
31
31
|
@res.headers['Cache-Control'] = 'no-cache'
|
@@ -34,15 +34,15 @@ describe 'Rack::Cache::Headers' do
|
|
34
34
|
end
|
35
35
|
it 'handles a bunch of all kinds of stuff' do
|
36
36
|
@res.headers['Cache-Control'] = 'max-age=600,must-revalidate,min-fresh=3000,foo=bar,baz'
|
37
|
-
@res.cache_control['max-age'].should.
|
37
|
+
@res.cache_control['max-age'].should.equal '600'
|
38
38
|
@res.cache_control['must-revalidate'].should.be true
|
39
|
-
@res.cache_control['min-fresh'].should.
|
40
|
-
@res.cache_control['foo'].should.
|
39
|
+
@res.cache_control['min-fresh'].should.equal '3000'
|
40
|
+
@res.cache_control['foo'].should.equal 'bar'
|
41
41
|
@res.cache_control['baz'].should.be true
|
42
42
|
end
|
43
43
|
it 'removes the header when given an empty hash' do
|
44
44
|
@res.headers['Cache-Control'] = 'max-age=600, must-revalidate'
|
45
|
-
@res.cache_control['max-age'].should.
|
45
|
+
@res.cache_control['max-age'].should.equal '600'
|
46
46
|
@res.cache_control = {}
|
47
47
|
@res.headers.should.not.include 'Cache-Control'
|
48
48
|
end
|
@@ -51,7 +51,7 @@ end
|
|
51
51
|
|
52
52
|
describe 'Rack::Cache::ResponseHeaders' do
|
53
53
|
before :each do
|
54
|
-
@now = Time.now
|
54
|
+
@now = Time.httpdate(Time.now.httpdate)
|
55
55
|
@one_hour_ago = Time.httpdate((Time.now - (60**2)).httpdate)
|
56
56
|
@one_hour_later = Time.httpdate((Time.now + (60**2)).httpdate)
|
57
57
|
@res = MockResponse.new(200, {'Date' => @now.httpdate}, '')
|
@@ -82,23 +82,30 @@ describe 'Rack::Cache::ResponseHeaders' do
|
|
82
82
|
it 'uses the Date header if present' do
|
83
83
|
@res = MockResponse.new(200, { 'Date' => @one_hour_ago.httpdate }, '')
|
84
84
|
@res.extend Rack::Cache::ResponseHeaders
|
85
|
-
@res.date.should.
|
85
|
+
@res.date.should.equal @one_hour_ago
|
86
86
|
end
|
87
87
|
it 'uses the current time when no Date header present' do
|
88
88
|
@res = MockResponse.new(200, {}, '')
|
89
89
|
@res.extend Rack::Cache::ResponseHeaders
|
90
90
|
@res.date.should.be.close Time.now, 1
|
91
91
|
end
|
92
|
+
it 'returns the correct date when the header is modified directly' do
|
93
|
+
@res = MockResponse.new(200, { 'Date' => @one_hour_ago.httpdate }, '')
|
94
|
+
@res.extend Rack::Cache::ResponseHeaders
|
95
|
+
@res.date.should.equal @one_hour_ago
|
96
|
+
@res.headers['Date'] = @now.httpdate
|
97
|
+
@res.date.should.equal @now
|
98
|
+
end
|
92
99
|
end
|
93
100
|
|
94
101
|
describe '#expires_at' do
|
95
102
|
it 'returns #date + #max_age when Cache-Control/max-age is present' do
|
96
103
|
@res.headers['Cache-Control'] = 'max-age=500'
|
97
|
-
@res.expires_at.should.
|
104
|
+
@res.expires_at.should.equal @res.date + 500
|
98
105
|
end
|
99
106
|
it 'uses the Expires header when present and no Cache-Control/max-age' do
|
100
107
|
@res.headers['Expires'] = @one_hour_ago.httpdate
|
101
|
-
@res.expires_at.should.
|
108
|
+
@res.expires_at.should.equal @one_hour_ago
|
102
109
|
end
|
103
110
|
it 'returns nil when no Expires or Cache-Control provided' do
|
104
111
|
@res.expires_at.should.be nil
|
@@ -106,14 +113,18 @@ describe 'Rack::Cache::ResponseHeaders' do
|
|
106
113
|
end
|
107
114
|
|
108
115
|
describe '#max_age' do
|
109
|
-
it 'uses
|
116
|
+
it 'uses s-maxage cache control directive when present' do
|
117
|
+
@res.headers['Cache-Control'] = 's-maxage=600, max-age=0'
|
118
|
+
@res.max_age.should.equal 600
|
119
|
+
end
|
120
|
+
it 'falls back to max-age when no s-maxage directive present' do
|
110
121
|
@res.headers['Cache-Control'] = 'max-age=600'
|
111
|
-
@res.max_age.should.
|
122
|
+
@res.max_age.should.equal 600
|
112
123
|
end
|
113
|
-
it '
|
124
|
+
it 'falls back to Expires when no max-age or s-maxage directive present' do
|
114
125
|
@res.headers['Cache-Control'] = 'must-revalidate'
|
115
126
|
@res.headers['Expires'] = @one_hour_later.httpdate
|
116
|
-
@res.max_age.should.
|
127
|
+
@res.max_age.should.equal 60 ** 2
|
117
128
|
end
|
118
129
|
it 'gives a #max_age of nil when no freshness information available' do
|
119
130
|
@res.max_age.should.be.nil
|
@@ -129,18 +140,90 @@ describe 'Rack::Cache::ResponseHeaders' do
|
|
129
140
|
@res.headers['Cache-Control'] = 'max-age=500'
|
130
141
|
@res.freshness_information?.should.be true
|
131
142
|
end
|
143
|
+
it 'is true when a Cache-Control s-maxage directive is present' do
|
144
|
+
@res.headers['Cache-Control'] = 's-maxage=500'
|
145
|
+
@res.freshness_information?.should.be true
|
146
|
+
end
|
132
147
|
it 'is not true otherwise' do
|
133
148
|
@res.freshness_information?.should.be false
|
134
149
|
end
|
135
150
|
end
|
136
151
|
|
152
|
+
describe '#public=' do
|
153
|
+
it 'adds the public Cache-Control directive when set true' do
|
154
|
+
@res.headers['Cache-Control'] = 'max-age=100'
|
155
|
+
@res.public = true
|
156
|
+
@res.headers['Cache-Control'].should.equal 'public, max-age=100'
|
157
|
+
end
|
158
|
+
it 'removes the private Cache-Control directive' do
|
159
|
+
@res.headers['Cache-Control'] = 'private, max-age=100'
|
160
|
+
@res.public = true
|
161
|
+
@res.headers['Cache-Control'].should.equal 'public, max-age=100'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#public?' do
|
166
|
+
it 'is true when the public directive is present' do
|
167
|
+
@res.headers['Cache-Control'] = 'public'
|
168
|
+
@res.should.be.public
|
169
|
+
end
|
170
|
+
it 'is false when only the private directive is present' do
|
171
|
+
@res.headers['Cache-Control'] = 'private'
|
172
|
+
@res.should.not.be.public
|
173
|
+
end
|
174
|
+
it 'is false when no Cache-Control header is present' do
|
175
|
+
@res.should.not.be.public
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '#private=' do
|
180
|
+
it 'adds the private Cache-Control directive when set true' do
|
181
|
+
@res.headers['Cache-Control'] = 'max-age=100'
|
182
|
+
@res.private = true
|
183
|
+
@res.headers['Cache-Control'].should.equal 'private, max-age=100'
|
184
|
+
end
|
185
|
+
it 'removes the public Cache-Control directive' do
|
186
|
+
@res.headers['Cache-Control'] = 'public, max-age=100'
|
187
|
+
@res.private = true
|
188
|
+
@res.headers['Cache-Control'].should.equal 'private, max-age=100'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '#private?' do
|
193
|
+
it 'is true when the private directive is present' do
|
194
|
+
@res.headers['Cache-Control'] = 'private'
|
195
|
+
@res.should.be.private
|
196
|
+
end
|
197
|
+
it 'is false when the private directive is not present' do
|
198
|
+
@res.headers['Cache-Control'] = 'public'
|
199
|
+
@res.should.not.be.private
|
200
|
+
end
|
201
|
+
it 'is false when no Cache-Control header is present' do
|
202
|
+
@res.should.not.be.private
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
137
206
|
describe '#no_cache?' do
|
138
207
|
it 'is true when a Cache-Control no-cache directive is present' do
|
139
208
|
@res.headers['Cache-Control'] = 'no-cache'
|
140
|
-
@res.no_cache
|
209
|
+
assert @res.no_cache?
|
210
|
+
end
|
211
|
+
it 'is false otherwise' do
|
212
|
+
assert !@res.no_cache?
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#must_revalidate?' do
|
217
|
+
it 'is true when a Cache-Control must-revalidate directive is present' do
|
218
|
+
@res.headers['Cache-Control'] = 'private, must-revalidate'
|
219
|
+
assert @res.must_revalidate?
|
220
|
+
end
|
221
|
+
it 'is true when a Cache-Control proxy-revalidate directive is present' do
|
222
|
+
@res.headers['Cache-Control'] = 'public, proxy-revalidate'
|
223
|
+
assert @res.must_revalidate?
|
141
224
|
end
|
142
225
|
it 'is false otherwise' do
|
143
|
-
|
226
|
+
assert !@res.must_revalidate?
|
144
227
|
end
|
145
228
|
end
|
146
229
|
|
@@ -183,7 +266,7 @@ describe 'Rack::Cache::ResponseHeaders' do
|
|
183
266
|
end
|
184
267
|
it 'returns the literal value of the Vary header' do
|
185
268
|
@res.headers['Vary'] = 'Foo Bar Baz'
|
186
|
-
@res.vary.should.
|
269
|
+
@res.vary.should.equal 'Foo Bar Baz'
|
187
270
|
end
|
188
271
|
it 'can be checked for existence using the #vary? method' do
|
189
272
|
@res.should.respond_to :vary?
|
@@ -199,16 +282,16 @@ describe 'Rack::Cache::ResponseHeaders' do
|
|
199
282
|
end
|
200
283
|
it 'parses a single header name value' do
|
201
284
|
@res.headers['Vary'] = 'Accept-Language'
|
202
|
-
@res.vary_header_names.should.
|
285
|
+
@res.vary_header_names.should.equal ['Accept-Language']
|
203
286
|
end
|
204
287
|
it 'parses multiple header name values separated by spaces' do
|
205
288
|
@res.headers['Vary'] = 'Accept-Language User-Agent X-Foo'
|
206
|
-
@res.vary_header_names.should.
|
289
|
+
@res.vary_header_names.should.equal \
|
207
290
|
['Accept-Language', 'User-Agent', 'X-Foo']
|
208
291
|
end
|
209
292
|
it 'parses multiple header name values separated by commas' do
|
210
293
|
@res.headers['Vary'] = 'Accept-Language,User-Agent, X-Foo'
|
211
|
-
@res.vary_header_names.should.
|
294
|
+
@res.vary_header_names.should.equal \
|
212
295
|
['Accept-Language', 'User-Agent', 'X-Foo']
|
213
296
|
end
|
214
297
|
end
|
data/test/metastore_test.rb
CHANGED
@@ -2,7 +2,6 @@ require "#{File.dirname(__FILE__)}/spec_setup"
|
|
2
2
|
require 'rack/cache/metastore'
|
3
3
|
|
4
4
|
describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
5
|
-
|
6
5
|
before do
|
7
6
|
@request = mock_request('/', {})
|
8
7
|
@response = mock_response(200, {}, ['hello world'])
|
@@ -22,7 +21,7 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
22
21
|
it 'reads a list of negotation tuples with #read' do
|
23
22
|
@store.write('/test', [[{},{}],[{},{}]])
|
24
23
|
tuples = @store.read('/test')
|
25
|
-
tuples.should.
|
24
|
+
tuples.should.equal [ [{},{}], [{},{}] ]
|
26
25
|
end
|
27
26
|
|
28
27
|
it 'reads an empty list with #read when nothing cached at key' do
|
@@ -45,20 +44,20 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
45
44
|
it 'returns nil from #purge' do
|
46
45
|
@store.write('/test', [[{},{}]])
|
47
46
|
@store.purge('/test').should.be nil
|
48
|
-
@store.read('/test').should.
|
47
|
+
@store.read('/test').should.equal []
|
49
48
|
end
|
50
49
|
|
51
50
|
%w[/test http://example.com:8080/ /test?x=y /test?x=y&p=q].each do |key|
|
52
51
|
it "can read and write key: '#{key}'" do
|
53
52
|
lambda { @store.write(key, [[{},{}]]) }.should.not.raise
|
54
|
-
@store.read(key).should.
|
53
|
+
@store.read(key).should.equal [[{},{}]]
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
58
57
|
it "can read and write fairly large keys" do
|
59
58
|
key = "b" * 4096
|
60
59
|
lambda { @store.write(key, [[{},{}]]) }.should.not.raise
|
61
|
-
@store.read(key).should.
|
60
|
+
@store.read(key).should.equal [[{},{}]]
|
62
61
|
end
|
63
62
|
|
64
63
|
# Abstract methods ===========================================================
|
@@ -79,7 +78,7 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
79
78
|
it 'sets the X-Content-Digest response header before storing' do
|
80
79
|
store_simple_entry
|
81
80
|
req, res = @store.read('/test').first
|
82
|
-
res['X-Content-Digest'].should.
|
81
|
+
res['X-Content-Digest'].should.equal 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
|
83
82
|
end
|
84
83
|
|
85
84
|
it 'finds a stored entry with #lookup' do
|
@@ -89,18 +88,30 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
89
88
|
response.should.be.kind_of Rack::Cache::Response
|
90
89
|
end
|
91
90
|
|
91
|
+
it 'does not find an entry with #lookup when none exists' do
|
92
|
+
req = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
93
|
+
@store.lookup(req, @entity_store).should.be.nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'does not find an entry with #lookup when the body does not exist' do
|
97
|
+
store_simple_entry
|
98
|
+
@response['X-Content-Digest'].should.not.be.nil
|
99
|
+
@entity_store.purge(@response['X-Content-Digest'])
|
100
|
+
@store.lookup(@request, @entity_store).should.be.nil
|
101
|
+
end
|
102
|
+
|
92
103
|
it 'restores response headers properly with #lookup' do
|
93
104
|
store_simple_entry
|
94
105
|
response = @store.lookup(@request, @entity_store)
|
95
|
-
response.headers.
|
96
|
-
should.
|
106
|
+
response.headers.
|
107
|
+
should.equal @response.headers.merge('Age' => '0', 'Content-Length' => '4')
|
97
108
|
end
|
98
109
|
|
99
110
|
it 'restores response body from entity store with #lookup' do
|
100
111
|
store_simple_entry
|
101
112
|
response = @store.lookup(@request, @entity_store)
|
102
113
|
body = '' ; response.body.each {|p| body << p}
|
103
|
-
body.should.
|
114
|
+
body.should.equal 'test'
|
104
115
|
end
|
105
116
|
|
106
117
|
# Vary =======================================================================
|
@@ -127,30 +138,30 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
127
138
|
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
128
139
|
@store.store(req3, res3, @entity_store)
|
129
140
|
|
130
|
-
slurp(@store.lookup(req3, @entity_store).body).should.
|
131
|
-
slurp(@store.lookup(req1, @entity_store).body).should.
|
132
|
-
slurp(@store.lookup(req2, @entity_store).body).should.
|
141
|
+
slurp(@store.lookup(req3, @entity_store).body).should.equal 'test 3'
|
142
|
+
slurp(@store.lookup(req1, @entity_store).body).should.equal 'test 1'
|
143
|
+
slurp(@store.lookup(req2, @entity_store).body).should.equal 'test 2'
|
133
144
|
|
134
|
-
@store.read('/test').length.should.
|
145
|
+
@store.read('/test').length.should.equal 3
|
135
146
|
end
|
136
147
|
|
137
148
|
it 'overwrites non-varying responses with #store' do
|
138
149
|
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
139
150
|
res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
|
140
151
|
@store.store(req1, res1, @entity_store)
|
141
|
-
slurp(@store.lookup(req1, @entity_store).body).should.
|
152
|
+
slurp(@store.lookup(req1, @entity_store).body).should.equal 'test 1'
|
142
153
|
|
143
154
|
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
144
155
|
res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
|
145
156
|
@store.store(req2, res2, @entity_store)
|
146
|
-
slurp(@store.lookup(req2, @entity_store).body).should.
|
157
|
+
slurp(@store.lookup(req2, @entity_store).body).should.equal 'test 2'
|
147
158
|
|
148
159
|
req3 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
149
160
|
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
150
161
|
@store.store(req3, res3, @entity_store)
|
151
|
-
slurp(@store.lookup(req1, @entity_store).body).should.
|
162
|
+
slurp(@store.lookup(req1, @entity_store).body).should.equal 'test 3'
|
152
163
|
|
153
|
-
@store.read('/test').length.should.
|
164
|
+
@store.read('/test').length.should.equal 2
|
154
165
|
end
|
155
166
|
|
156
167
|
# Helper Methods =============================================================
|
@@ -171,7 +182,6 @@ describe_shared 'A Rack::Cache::MetaStore Implementation' do
|
|
171
182
|
body.each {|part| buf << part }
|
172
183
|
buf
|
173
184
|
end
|
174
|
-
|
175
185
|
end
|
176
186
|
|
177
187
|
|