instructure-redis-store 1.0.0.1.instructure1
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/.travis.yml +7 -0
- data/CHANGELOG +311 -0
- data/Gemfile +34 -0
- data/MIT-LICENSE +20 -0
- data/README.md +239 -0
- data/Rakefile +60 -0
- data/VERSION +1 -0
- data/lib/action_controller/session/redis_session_store.rb +81 -0
- data/lib/active_support/cache/redis_store.rb +254 -0
- data/lib/cache/merb/redis_store.rb +79 -0
- data/lib/cache/sinatra/redis_store.rb +131 -0
- data/lib/i18n/backend/redis.rb +67 -0
- data/lib/rack/cache/redis_entitystore.rb +48 -0
- data/lib/rack/cache/redis_metastore.rb +40 -0
- data/lib/rack/session/merb.rb +32 -0
- data/lib/rack/session/redis.rb +88 -0
- data/lib/redis-store.rb +45 -0
- data/lib/redis/distributed_store.rb +39 -0
- data/lib/redis/factory.rb +46 -0
- data/lib/redis/store.rb +39 -0
- data/lib/redis/store/interface.rb +17 -0
- data/lib/redis/store/marshalling.rb +51 -0
- data/lib/redis/store/namespace.rb +62 -0
- data/lib/redis/store/ttl.rb +37 -0
- data/lib/redis/store/version.rb +12 -0
- data/spec/action_controller/session/redis_session_store_spec.rb +126 -0
- data/spec/active_support/cache/redis_store_spec.rb +426 -0
- data/spec/cache/merb/redis_store_spec.rb +143 -0
- data/spec/cache/sinatra/redis_store_spec.rb +192 -0
- data/spec/config/node-one.conf +417 -0
- data/spec/config/node-two.conf +417 -0
- data/spec/config/redis.conf +417 -0
- data/spec/i18n/backend/redis_spec.rb +72 -0
- data/spec/rack/cache/entitystore/pony.jpg +0 -0
- data/spec/rack/cache/entitystore/redis_spec.rb +124 -0
- data/spec/rack/cache/metastore/redis_spec.rb +259 -0
- data/spec/rack/session/redis_spec.rb +234 -0
- data/spec/redis/distributed_store_spec.rb +55 -0
- data/spec/redis/factory_spec.rb +110 -0
- data/spec/redis/store/interface_spec.rb +23 -0
- data/spec/redis/store/marshalling_spec.rb +119 -0
- data/spec/redis/store/namespace_spec.rb +76 -0
- data/spec/redis/store/version_spec.rb +7 -0
- data/spec/redis/store_spec.rb +13 -0
- data/spec/spec_helper.rb +43 -0
- data/tasks/redis.tasks.rb +235 -0
- metadata +249 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "I18n::Backend::Redis" do
|
4
|
+
before :each do
|
5
|
+
@backend = I18n::Backend::Redis.new
|
6
|
+
@store = @backend.store
|
7
|
+
I18n.backend = @backend
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should instantiate a store" do
|
11
|
+
@store.should be_kind_of(Redis::Store)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should instantiate a distributed store" do
|
15
|
+
store = I18n::Backend::Redis.new([ "redis://127.0.0.1:6379", "redis://127.0.0.1:6380" ]).store
|
16
|
+
store.should be_kind_of(Redis::DistributedStore)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should accept string uri" do
|
20
|
+
store = I18n::Backend::Redis.new("redis://127.0.0.1:6380/13/theplaylist").store
|
21
|
+
store.to_s.should == "Redis Client connected to 127.0.0.1:6380 against DB 13 with namespace theplaylist"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should accept hash params" do
|
25
|
+
store = I18n::Backend::Redis.new(:host => "127.0.0.1", :port => "6380", :db =>"13", :namespace => "theplaylist").store
|
26
|
+
store.to_s.should == "Redis Client connected to 127.0.0.1:6380 against DB 13 with namespace theplaylist"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should store translations" do
|
30
|
+
I18n.backend.store_translations :en, :foo => { :bar => :baz }
|
31
|
+
I18n.t(:"foo.bar").should == :baz
|
32
|
+
|
33
|
+
I18n.backend.store_translations :en, "foo" => { "bar" => "baz" }
|
34
|
+
I18n.t(:"foo.bar").should == "baz"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should get translations" do
|
38
|
+
I18n.backend.store_translations :en, :foo => { :bar => { :baz => :bang } }
|
39
|
+
I18n.t(:"foo.bar.baz").should == :bang
|
40
|
+
I18n.t(:"baz", :scope => :"foo.bar").should == :bang
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not store proc translations" do
|
44
|
+
lambda { I18n.backend.store_translations :en, :foo => lambda {|| } }.should raise_error("Key-value stores cannot handle procs")
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "available locales" do
|
48
|
+
before :each do
|
49
|
+
@locales = [ :en, :it, :es, :fr, :de ]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should list" do
|
53
|
+
@locales.each { |locale| I18n.backend.store_translations locale, :foo => "bar" }
|
54
|
+
available_locales = I18n.backend.available_locales
|
55
|
+
|
56
|
+
@locales.each do |locale|
|
57
|
+
available_locales.should include(locale)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should list when namespaced" do
|
62
|
+
I18n.backend = I18n::Backend::Redis.new :namespace => 'foo'
|
63
|
+
|
64
|
+
@locales.each { |locale| I18n.backend.store_translations locale, :foo => "bar" }
|
65
|
+
available_locales = I18n.backend.available_locales
|
66
|
+
|
67
|
+
@locales.each do |locale|
|
68
|
+
available_locales.should include(locale)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
Binary file
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def sha_like?
|
5
|
+
length == 40 && self =~ /^[0-9a-z]+$/
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Rack
|
10
|
+
module Cache
|
11
|
+
class EntityStore
|
12
|
+
# courtesy of http://github.com/rtomayko/rack-cache team
|
13
|
+
describe "Rack::Cache::EntityStore::Redis" do
|
14
|
+
before(:each) do
|
15
|
+
@store = Rack::Cache::EntityStore::Redis.new :host => "localhost"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Redis store specific examples ===========================================
|
19
|
+
|
20
|
+
it "should have the class referenced by homonym constant" do
|
21
|
+
Rack::Cache::EntityStore::REDIS.should be(Rack::Cache::EntityStore::Redis)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should resolve the connection uri" do
|
25
|
+
cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1")).cache
|
26
|
+
cache.should be_kind_of(::Redis)
|
27
|
+
cache.id.should == "redis://127.0.0.1:6379/0"
|
28
|
+
|
29
|
+
cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
|
30
|
+
cache.id.should == "redis://127.0.0.1:6380/0"
|
31
|
+
|
32
|
+
cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
|
33
|
+
cache.id.should == "redis://127.0.0.1:6379/13"
|
34
|
+
|
35
|
+
cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://:secret@127.0.0.1")).cache
|
36
|
+
cache.id.should == "redis://127.0.0.1:6379/0"
|
37
|
+
cache.client.password.should == 'secret'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Entity store shared examples ===========================================
|
41
|
+
|
42
|
+
it 'responds to all required messages' do
|
43
|
+
%w[read open write exist?].each do |message|
|
44
|
+
@store.should respond_to(message)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'stores bodies with #write' do
|
49
|
+
key, size = @store.write(['My wild love went riding,'])
|
50
|
+
key.should_not be_nil
|
51
|
+
key.should be_sha_like
|
52
|
+
|
53
|
+
data = @store.read(key)
|
54
|
+
data.should == 'My wild love went riding,'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'correctly determines whether cached body exists for key with #exist?' do
|
58
|
+
key, size = @store.write(['She rode to the devil,'])
|
59
|
+
@store.should be_exist(key)
|
60
|
+
@store.should_not be_exist('938jasddj83jasdh4438021ksdfjsdfjsdsf')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can read data written with #write' do
|
64
|
+
key, size = @store.write(['And asked him to pay.'])
|
65
|
+
data = @store.read(key)
|
66
|
+
data.should == 'And asked him to pay.'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'gives a 40 character SHA1 hex digest from #write' do
|
70
|
+
key, size = @store.write(['she rode to the sea;'])
|
71
|
+
key.should_not be_nil
|
72
|
+
key.length.should == 40
|
73
|
+
key.should =~ /^[0-9a-z]+$/
|
74
|
+
key.should == '90a4c84d51a277f3dafc34693ca264531b9f51b6'
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns the entire body as a String from #read' do
|
78
|
+
key, size = @store.write(['She gathered together'])
|
79
|
+
@store.read(key).should == 'She gathered together'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns nil from #read when key does not exist' do
|
83
|
+
@store.read('87fe0a1ae82a518592f6b12b0183e950b4541c62').should be_nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'returns a Rack compatible body from #open' do
|
87
|
+
key, size = @store.write(['Some shells for her hair.'])
|
88
|
+
body = @store.open(key)
|
89
|
+
body.should respond_to(:each)
|
90
|
+
buf = ''
|
91
|
+
body.each { |part| buf << part }
|
92
|
+
buf.should == 'Some shells for her hair.'
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns nil from #open when key does not exist' do
|
96
|
+
@store.open('87fe0a1ae82a518592f6b12b0183e950b4541c62').should be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
if RUBY_VERSION < '1.9'
|
100
|
+
it 'can store largish bodies with binary data' do
|
101
|
+
pony = ::File.open(::File.dirname(__FILE__) + '/pony.jpg', 'rb') { |f| f.read }
|
102
|
+
key, size = @store.write([pony])
|
103
|
+
key.should == 'd0f30d8659b4d268c5c64385d9790024c2d78deb'
|
104
|
+
data = @store.read(key)
|
105
|
+
data.length.should == pony.length
|
106
|
+
data.hash.should == pony.hash
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'deletes stored entries with #purge' do
|
111
|
+
key, size = @store.write(['My wild love went riding,'])
|
112
|
+
@store.purge(key).should be_nil
|
113
|
+
@store.read(key).should be_nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# Helper Methods =============================================================
|
117
|
+
|
118
|
+
define_method :uri do |uri|
|
119
|
+
URI.parse uri
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Cache
|
5
|
+
class MetaStore
|
6
|
+
# courtesy of http://github.com/rtomayko/rack-cache team
|
7
|
+
describe "Rack::Cache::MetaStore::Redis" do
|
8
|
+
before :each do
|
9
|
+
@store = Rack::Cache::MetaStore::Redis.resolve uri("redis://127.0.0.1")
|
10
|
+
@entity_store = Rack::Cache::EntityStore::Redis.resolve uri("redis://127.0.0.1:6380")
|
11
|
+
@request = mock_request('/', {})
|
12
|
+
@response = mock_response(200, {}, ['hello world'])
|
13
|
+
end
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
@store.cache.flushall
|
17
|
+
@entity_store.cache.flushall
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have the class referenced by homonym constant" do
|
21
|
+
Rack::Cache::MetaStore::REDIS.should be(Rack::Cache::MetaStore::Redis)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should resolve the connection uri" do
|
25
|
+
cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1")).cache
|
26
|
+
cache.should be_kind_of(::Redis::Store)
|
27
|
+
cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 0"
|
28
|
+
|
29
|
+
cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
|
30
|
+
cache.to_s.should == "Redis Client connected to 127.0.0.1:6380 against DB 0"
|
31
|
+
|
32
|
+
cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
|
33
|
+
cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 13"
|
34
|
+
|
35
|
+
cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://:secret@127.0.0.1")).cache
|
36
|
+
cache.id.should == "redis://127.0.0.1:6379/0"
|
37
|
+
cache.client.password.should == 'secret'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Low-level implementation methods ===========================================
|
41
|
+
|
42
|
+
it 'writes a list of negotation tuples with #write' do
|
43
|
+
lambda { @store.write('/test', [[{}, {}]]) }.should_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'reads a list of negotation tuples with #read' do
|
47
|
+
@store.write('/test', [[{},{}],[{},{}]])
|
48
|
+
tuples = @store.read('/test')
|
49
|
+
tuples.should == [ [{},{}], [{},{}] ]
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'reads an empty list with #read when nothing cached at key' do
|
53
|
+
@store.read('/nothing').should be_empty
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'removes entries for key with #purge' do
|
57
|
+
@store.write('/test', [[{},{}]])
|
58
|
+
@store.read('/test').should_not be_empty
|
59
|
+
|
60
|
+
@store.purge('/test')
|
61
|
+
@store.read('/test').should be_empty
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'succeeds when purging non-existing entries' do
|
65
|
+
@store.read('/test').should be_empty
|
66
|
+
@store.purge('/test')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns nil from #purge' do
|
70
|
+
@store.write('/test', [[{},{}]])
|
71
|
+
@store.purge('/test').should be_nil
|
72
|
+
@store.read('/test').should == []
|
73
|
+
end
|
74
|
+
|
75
|
+
%w[/test http://example.com:8080/ /test?x=y /test?x=y&p=q].each do |key|
|
76
|
+
it "can read and write key: '#{key}'" do
|
77
|
+
lambda { @store.write(key, [[{},{}]]) }.should_not raise_error
|
78
|
+
@store.read(key).should == [[{},{}]]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can read and write fairly large keys" do
|
83
|
+
key = "b" * 4096
|
84
|
+
lambda { @store.write(key, [[{},{}]]) }.should_not raise_error
|
85
|
+
@store.read(key).should == [[{},{}]]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "allows custom cache keys from block" do
|
89
|
+
request = mock_request('/test', {})
|
90
|
+
request.env['rack-cache.cache_key'] =
|
91
|
+
lambda { |request| request.path_info.reverse }
|
92
|
+
@store.cache_key(request).should == 'tset/'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "allows custom cache keys from class" do
|
96
|
+
request = mock_request('/test', {})
|
97
|
+
request.env['rack-cache.cache_key'] = Class.new do
|
98
|
+
def self.call(request); request.path_info.reverse end
|
99
|
+
end
|
100
|
+
@store.cache_key(request).should == 'tset/'
|
101
|
+
end
|
102
|
+
|
103
|
+
# Abstract methods ===========================================================
|
104
|
+
|
105
|
+
# Stores an entry for the given request args, returns a url encoded cache key
|
106
|
+
# for the request.
|
107
|
+
define_method :store_simple_entry do |*request_args|
|
108
|
+
path, headers = request_args
|
109
|
+
@request = mock_request(path || '/test', headers || {})
|
110
|
+
@response = mock_response(200, {'Cache-Control' => 'max-age=420'}, ['test'])
|
111
|
+
body = @response.body
|
112
|
+
cache_key = @store.store(@request, @response, @entity_store)
|
113
|
+
@response.body.should_not equal(body)
|
114
|
+
cache_key
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'stores a cache entry' do
|
118
|
+
cache_key = store_simple_entry
|
119
|
+
@store.read(cache_key).should_not be_empty
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'sets the X-Content-Digest response header before storing' do
|
123
|
+
cache_key = store_simple_entry
|
124
|
+
req, res = @store.read(cache_key).first
|
125
|
+
res['X-Content-Digest'].should == 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'finds a stored entry with #lookup' do
|
129
|
+
store_simple_entry
|
130
|
+
response = @store.lookup(@request, @entity_store)
|
131
|
+
response.should_not be_nil
|
132
|
+
response.should be_kind_of(Rack::Cache::Response)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'does not find an entry with #lookup when none exists' do
|
136
|
+
req = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
137
|
+
@store.lookup(req, @entity_store).should be_nil
|
138
|
+
end
|
139
|
+
|
140
|
+
it "canonizes urls for cache keys" do
|
141
|
+
store_simple_entry(path='/test?x=y&p=q')
|
142
|
+
|
143
|
+
hits_req = mock_request(path, {})
|
144
|
+
miss_req = mock_request('/test?p=x', {})
|
145
|
+
|
146
|
+
@store.lookup(hits_req, @entity_store).should_not be_nil
|
147
|
+
@store.lookup(miss_req, @entity_store).should be_nil
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'does not find an entry with #lookup when the body does not exist' do
|
151
|
+
store_simple_entry
|
152
|
+
@response.headers['X-Content-Digest'].should_not be_nil
|
153
|
+
@entity_store.purge(@response.headers['X-Content-Digest'])
|
154
|
+
@store.lookup(@request, @entity_store).should be_nil
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'restores response headers properly with #lookup' do
|
158
|
+
store_simple_entry
|
159
|
+
response = @store.lookup(@request, @entity_store)
|
160
|
+
response.headers.should == @response.headers.merge('Content-Length' => '4')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'restores response body from entity store with #lookup' do
|
164
|
+
store_simple_entry
|
165
|
+
response = @store.lookup(@request, @entity_store)
|
166
|
+
body = '' ; response.body.each {|p| body << p}
|
167
|
+
body.should == 'test'
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'invalidates meta and entity store entries with #invalidate' do
|
171
|
+
store_simple_entry
|
172
|
+
@store.invalidate(@request, @entity_store)
|
173
|
+
response = @store.lookup(@request, @entity_store)
|
174
|
+
response.should be_kind_of(Rack::Cache::Response)
|
175
|
+
response.should_not be_fresh
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'succeeds quietly when #invalidate called with no matching entries' do
|
179
|
+
req = mock_request('/test', {})
|
180
|
+
@store.invalidate(req, @entity_store)
|
181
|
+
@store.lookup(@request, @entity_store).should be_nil
|
182
|
+
end
|
183
|
+
|
184
|
+
# Vary =======================================================================
|
185
|
+
|
186
|
+
it 'does not return entries that Vary with #lookup' do
|
187
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
188
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
189
|
+
res = mock_response(200, {'Vary' => 'Foo Bar'}, ['test'])
|
190
|
+
@store.store(req1, res, @entity_store)
|
191
|
+
|
192
|
+
@store.lookup(req2, @entity_store).should be_nil
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'stores multiple responses for each Vary combination' do
|
196
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
197
|
+
res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
|
198
|
+
key = @store.store(req1, res1, @entity_store)
|
199
|
+
|
200
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
201
|
+
res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
|
202
|
+
@store.store(req2, res2, @entity_store)
|
203
|
+
|
204
|
+
req3 = mock_request('/test', {'HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom'})
|
205
|
+
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
206
|
+
@store.store(req3, res3, @entity_store)
|
207
|
+
|
208
|
+
slurp(@store.lookup(req3, @entity_store).body).should == 'test 3'
|
209
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
|
210
|
+
slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
|
211
|
+
|
212
|
+
@store.read(key).length.should == 3
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'overwrites non-varying responses with #store' do
|
216
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
217
|
+
res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
|
218
|
+
key = @store.store(req1, res1, @entity_store)
|
219
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
|
220
|
+
|
221
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
222
|
+
res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
|
223
|
+
@store.store(req2, res2, @entity_store)
|
224
|
+
slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
|
225
|
+
|
226
|
+
req3 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
227
|
+
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
228
|
+
@store.store(req3, res3, @entity_store)
|
229
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 3'
|
230
|
+
|
231
|
+
@store.read(key).length.should == 2
|
232
|
+
end
|
233
|
+
|
234
|
+
# Helper Methods =============================================================
|
235
|
+
|
236
|
+
define_method :mock_request do |uri,opts|
|
237
|
+
env = Rack::MockRequest.env_for(uri, opts || {})
|
238
|
+
Rack::Cache::Request.new(env)
|
239
|
+
end
|
240
|
+
|
241
|
+
define_method :mock_response do |status,headers,body|
|
242
|
+
headers ||= {}
|
243
|
+
body = Array(body).compact
|
244
|
+
Rack::Cache::Response.new(status, headers, body)
|
245
|
+
end
|
246
|
+
|
247
|
+
define_method :slurp do |body|
|
248
|
+
buf = ''
|
249
|
+
body.each {|part| buf << part }
|
250
|
+
buf
|
251
|
+
end
|
252
|
+
|
253
|
+
define_method :uri do |uri|
|
254
|
+
URI.parse uri
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|