redis-store 0.3.7 → 0.3.8

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 redis-store might be problematic. Click here for more details.

Files changed (39) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +13 -7
  3. data/README.md +11 -1
  4. data/Rakefile +19 -5
  5. data/VERSION +1 -1
  6. data/lib/cache/merb/redis_store.rb +6 -6
  7. data/lib/cache/rails/redis_store.rb +10 -10
  8. data/lib/cache/sinatra/redis_store.rb +14 -11
  9. data/lib/rack/cache/redis_entitystore.rb +2 -2
  10. data/lib/rack/cache/redis_metastore.rb +5 -5
  11. data/lib/rack/session/rails.rb +61 -0
  12. data/lib/rack/session/redis.rb +10 -10
  13. data/lib/redis-store.rb +8 -4
  14. data/lib/redis/distributed_marshaled.rb +18 -0
  15. data/lib/redis/factory.rb +26 -0
  16. data/lib/redis/marshaled_client.rb +54 -0
  17. data/lib/redis/namespace.rb +9 -0
  18. data/redis-store.gemspec +18 -13
  19. data/spec/cache/merb/redis_store_spec.rb +9 -14
  20. data/spec/cache/rails/redis_session_store_spec.rb +77 -0
  21. data/spec/cache/rails/redis_store_spec.rb +13 -17
  22. data/spec/cache/sinatra/redis_store_spec.rb +9 -14
  23. data/spec/config/master.conf +5 -5
  24. data/spec/config/single.conf +5 -5
  25. data/spec/config/slave.conf +6 -6
  26. data/spec/rack/cache/entitystore/redis_spec.rb +21 -11
  27. data/spec/rack/cache/metastore/redis_spec.rb +169 -16
  28. data/spec/rack/session/redis_spec.rb +7 -11
  29. data/spec/redis/distributed_marshaled_redis_spec.rb +9 -11
  30. data/spec/redis/factory_spec.rb +68 -0
  31. data/spec/redis/marshaled_client_spec.rb +54 -0
  32. data/spec/spec_helper.rb +11 -5
  33. data/tasks/redis.tasks.rb +16 -5
  34. metadata +28 -12
  35. data/lib/redis/distributed_marshaled_redis.rb +0 -10
  36. data/lib/redis/marshaled_redis.rb +0 -33
  37. data/lib/redis/redis_factory.rb +0 -27
  38. data/spec/redis/marshaled_redis_spec.rb +0 -54
  39. data/spec/redis/redis_factory_spec.rb +0 -34
@@ -124,10 +124,10 @@ databases 16
124
124
  #
125
125
  # The name of the append only file is "appendonly.log"
126
126
 
127
- appendonly no
127
+ #appendonly no
128
128
 
129
129
  # The fsync() call tells the Operating System to actually write data on disk
130
- # instead to wait for more data in the output buffer. Some OS will really flush
130
+ # instead to wait for more data in the output buffer. Some OS will really flush
131
131
  # data on disk, some other OS will just try to do it ASAP.
132
132
  #
133
133
  # Redis supports three different modes:
@@ -142,7 +142,7 @@ appendonly no
142
142
  # it want, for better performances (but if you can live with the idea of
143
143
  # some data loss consider the default persistence mode that's snapshotting).
144
144
 
145
- appendfsync always
145
+ #appendfsync always
146
146
  # appendfsync everysec
147
147
  # appendfsync no
148
148
 
@@ -167,5 +167,5 @@ glueoutputbuf yes
167
167
  # WARNING: object sharing is experimental, don't enable this feature
168
168
  # in production before of Redis 1.0-stable. Still please try this feature in
169
169
  # your development environment so that we can test it better.
170
- shareobjects no
171
- shareobjectspoolsize 1024
170
+ #shareobjects no
171
+ #shareobjectspoolsize 1024
@@ -124,10 +124,10 @@ databases 16
124
124
  #
125
125
  # The name of the append only file is "appendonly.log"
126
126
 
127
- appendonly no
127
+ #appendonly no
128
128
 
129
129
  # The fsync() call tells the Operating System to actually write data on disk
130
- # instead to wait for more data in the output buffer. Some OS will really flush
130
+ # instead to wait for more data in the output buffer. Some OS will really flush
131
131
  # data on disk, some other OS will just try to do it ASAP.
132
132
  #
133
133
  # Redis supports three different modes:
@@ -142,7 +142,7 @@ appendonly no
142
142
  # it want, for better performances (but if you can live with the idea of
143
143
  # some data loss consider the default persistence mode that's snapshotting).
144
144
 
145
- appendfsync always
145
+ #appendfsync always
146
146
  # appendfsync everysec
147
147
  # appendfsync no
148
148
 
@@ -167,5 +167,5 @@ glueoutputbuf yes
167
167
  # WARNING: object sharing is experimental, don't enable this feature
168
168
  # in production before of Redis 1.0-stable. Still please try this feature in
169
169
  # your development environment so that we can test it better.
170
- shareobjects no
171
- shareobjectspoolsize 1024
170
+ #shareobjects no
171
+ #shareobjectspoolsize 1024
@@ -65,7 +65,7 @@ databases 16
65
65
  # so for example it is possible to configure the slave to save the DB with a
66
66
  # different interval, or to listen to another port, and so on.
67
67
 
68
- slaveof localhost 6380
68
+ slaveof localhost 6380
69
69
 
70
70
  ################################## SECURITY ###################################
71
71
 
@@ -124,10 +124,10 @@ slaveof localhost 6380
124
124
  #
125
125
  # The name of the append only file is "appendonly.log"
126
126
 
127
- appendonly no
127
+ #appendonly no
128
128
 
129
129
  # The fsync() call tells the Operating System to actually write data on disk
130
- # instead to wait for more data in the output buffer. Some OS will really flush
130
+ # instead to wait for more data in the output buffer. Some OS will really flush
131
131
  # data on disk, some other OS will just try to do it ASAP.
132
132
  #
133
133
  # Redis supports three different modes:
@@ -142,7 +142,7 @@ appendonly no
142
142
  # it want, for better performances (but if you can live with the idea of
143
143
  # some data loss consider the default persistence mode that's snapshotting).
144
144
 
145
- appendfsync always
145
+ #appendfsync always
146
146
  # appendfsync everysec
147
147
  # appendfsync no
148
148
 
@@ -167,5 +167,5 @@ glueoutputbuf yes
167
167
  # WARNING: object sharing is experimental, don't enable this feature
168
168
  # in production before of Redis 1.0-stable. Still please try this feature in
169
169
  # your development environment so that we can test it better.
170
- shareobjects no
171
- shareobjectspoolsize 1024
170
+ #shareobjects no
171
+ #shareobjectspoolsize 1024
@@ -1,31 +1,40 @@
1
1
  require File.join(File.dirname(__FILE__), "/../../../spec_helper")
2
2
 
3
+ class Object
4
+ def sha_like?
5
+ length == 40 && self =~ /^[0-9a-z]+$/
6
+ end
7
+ end
8
+
3
9
  module Rack
4
10
  module Cache
5
11
  class EntityStore
12
+ # courtesy of http://github.com/rtomayko/rack-cache team
6
13
  describe "Rack::Cache::EntityStore::Redis" do
7
14
  before(:each) do
8
15
  @store = Rack::Cache::EntityStore::Redis.new :host => "localhost"
9
16
  end
10
17
 
18
+ # Redis store specific examples ===========================================
19
+
11
20
  it "should have the class referenced by homonym constant" do
12
21
  Rack::Cache::EntityStore::REDIS.should be(Rack::Cache::EntityStore::Redis)
13
22
  end
14
23
 
15
24
  it "should resolve the connection uri" do
16
25
  cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1")).cache
17
- cache.should be_kind_of(::Redis)
18
- cache.host.should == "127.0.0.1"
19
- cache.port.should == 6379
20
- cache.db.should == 0
26
+ cache.should be_kind_of(::Redis::Client)
27
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 0"
21
28
 
22
29
  cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
23
- cache.port.should == 6380
30
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6380 against DB 0"
24
31
 
25
32
  cache = Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
26
- cache.db.should == 13
33
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 13"
27
34
  end
28
35
 
36
+ # Entity store shared examples ===========================================
37
+
29
38
  it 'responds to all required messages' do
30
39
  %w[read open write exist?].each do |message|
31
40
  @store.should respond_to(message)
@@ -35,7 +44,7 @@ module Rack
35
44
  it 'stores bodies with #write' do
36
45
  key, size = @store.write(['My wild love went riding,'])
37
46
  key.should_not be_nil
38
- # key.should be_sha_like TODO re-enable
47
+ key.should be_sha_like
39
48
 
40
49
  data = @store.read(key)
41
50
  data.should == 'My wild love went riding,'
@@ -98,10 +107,11 @@ module Rack
98
107
  @store.read(key).should be_nil
99
108
  end
100
109
 
101
- private
102
- def uri(uri)
103
- URI.parse uri
104
- end
110
+ # Helper Methods =============================================================
111
+
112
+ define_method :uri do |uri|
113
+ URI.parse uri
114
+ end
105
115
  end
106
116
  end
107
117
  end
@@ -3,9 +3,18 @@ require File.join(File.dirname(__FILE__), "/../../../spec_helper")
3
3
  module Rack
4
4
  module Cache
5
5
  class MetaStore
6
+ # courtesy of http://github.com/rtomayko/rack-cache team
6
7
  describe "Rack::Cache::MetaStore::Redis" do
7
- before(:each) do
8
- @store = Rack::Cache::MetaStore::Redis.resolve uri("redis://127.0.0.1")
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
9
18
  end
10
19
 
11
20
  it "should have the class referenced by homonym constant" do
@@ -14,18 +23,18 @@ module Rack
14
23
 
15
24
  it "should resolve the connection uri" do
16
25
  cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1")).cache
17
- cache.should be_kind_of(::MarshaledRedis)
18
- cache.host.should == "127.0.0.1"
19
- cache.port.should == 6379
20
- cache.db.should == 0
26
+ cache.should be_kind_of(::Redis::MarshaledClient)
27
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 0"
21
28
 
22
29
  cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
23
- cache.port.should == 6380
30
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6380 against DB 0"
24
31
 
25
32
  cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
26
- cache.db.should == 13
33
+ cache.to_s.should == "Redis Client connected to 127.0.0.1:6379 against DB 13"
27
34
  end
28
35
 
36
+ # Low-level implementation methods ===========================================
37
+
29
38
  it 'writes a list of negotation tuples with #write' do
30
39
  lambda { @store.write('/test', [[{}, {}]]) }.should_not raise_error
31
40
  end
@@ -87,15 +96,159 @@ module Rack
87
96
  @store.cache_key(request).should == 'tset/'
88
97
  end
89
98
 
90
- private
91
- def mock_request(uri, opts)
92
- env = Rack::MockRequest.env_for(uri, opts || {})
93
- Rack::Cache::Request.new(env)
94
- end
99
+ # Abstract methods ===========================================================
100
+
101
+ # Stores an entry for the given request args, returns a url encoded cache key
102
+ # for the request.
103
+ define_method :store_simple_entry do |*request_args|
104
+ path, headers = request_args
105
+ @request = mock_request(path || '/test', headers || {})
106
+ @response = mock_response(200, {'Cache-Control' => 'max-age=420'}, ['test'])
107
+ body = @response.body
108
+ cache_key = @store.store(@request, @response, @entity_store)
109
+ @response.body.should_not equal(body)
110
+ cache_key
111
+ end
95
112
 
96
- def uri(uri)
97
- URI.parse uri
98
- end
113
+ it 'stores a cache entry' do
114
+ cache_key = store_simple_entry
115
+ @store.read(cache_key).should_not be_empty
116
+ end
117
+
118
+ it 'sets the X-Content-Digest response header before storing' do
119
+ cache_key = store_simple_entry
120
+ req, res = @store.read(cache_key).first
121
+ res['X-Content-Digest'].should == 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
122
+ end
123
+
124
+ it 'finds a stored entry with #lookup' do
125
+ store_simple_entry
126
+ response = @store.lookup(@request, @entity_store)
127
+ response.should_not be_nil
128
+ response.should be_kind_of(Rack::Cache::Response)
129
+ end
130
+
131
+ it 'does not find an entry with #lookup when none exists' do
132
+ req = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
133
+ @store.lookup(req, @entity_store).should be_nil
134
+ end
135
+
136
+ it "canonizes urls for cache keys" do
137
+ store_simple_entry(path='/test?x=y&p=q')
138
+
139
+ hits_req = mock_request(path, {})
140
+ miss_req = mock_request('/test?p=x', {})
141
+
142
+ @store.lookup(hits_req, @entity_store).should_not be_nil
143
+ @store.lookup(miss_req, @entity_store).should be_nil
144
+ end
145
+
146
+ it 'does not find an entry with #lookup when the body does not exist' do
147
+ store_simple_entry
148
+ @response.headers['X-Content-Digest'].should_not be_nil
149
+ @entity_store.purge(@response.headers['X-Content-Digest'])
150
+ @store.lookup(@request, @entity_store).should be_nil
151
+ end
152
+
153
+ it 'restores response headers properly with #lookup' do
154
+ store_simple_entry
155
+ response = @store.lookup(@request, @entity_store)
156
+ response.headers.should == @response.headers.merge('Content-Length' => '4')
157
+ end
158
+
159
+ it 'restores response body from entity store with #lookup' do
160
+ store_simple_entry
161
+ response = @store.lookup(@request, @entity_store)
162
+ body = '' ; response.body.each {|p| body << p}
163
+ body.should == 'test'
164
+ end
165
+
166
+ it 'invalidates meta and entity store entries with #invalidate' do
167
+ store_simple_entry
168
+ @store.invalidate(@request, @entity_store)
169
+ response = @store.lookup(@request, @entity_store)
170
+ response.should be_kind_of(Rack::Cache::Response)
171
+ response.should_not be_fresh
172
+ end
173
+
174
+ it 'succeeds quietly when #invalidate called with no matching entries' do
175
+ req = mock_request('/test', {})
176
+ @store.invalidate(req, @entity_store)
177
+ @store.lookup(@request, @entity_store).should be_nil
178
+ end
179
+
180
+ # Vary =======================================================================
181
+
182
+ it 'does not return entries that Vary with #lookup' do
183
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
184
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
185
+ res = mock_response(200, {'Vary' => 'Foo Bar'}, ['test'])
186
+ @store.store(req1, res, @entity_store)
187
+
188
+ @store.lookup(req2, @entity_store).should be_nil
189
+ end
190
+
191
+ it 'stores multiple responses for each Vary combination' do
192
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
193
+ res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
194
+ key = @store.store(req1, res1, @entity_store)
195
+
196
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
197
+ res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
198
+ @store.store(req2, res2, @entity_store)
199
+
200
+ req3 = mock_request('/test', {'HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom'})
201
+ res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
202
+ @store.store(req3, res3, @entity_store)
203
+
204
+ slurp(@store.lookup(req3, @entity_store).body).should == 'test 3'
205
+ slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
206
+ slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
207
+
208
+ @store.read(key).length.should == 3
209
+ end
210
+
211
+ it 'overwrites non-varying responses with #store' do
212
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
213
+ res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
214
+ key = @store.store(req1, res1, @entity_store)
215
+ slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
216
+
217
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
218
+ res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
219
+ @store.store(req2, res2, @entity_store)
220
+ slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
221
+
222
+ req3 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
223
+ res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
224
+ @store.store(req3, res3, @entity_store)
225
+ slurp(@store.lookup(req1, @entity_store).body).should == 'test 3'
226
+
227
+ @store.read(key).length.should == 2
228
+ end
229
+
230
+ # Helper Methods =============================================================
231
+
232
+ define_method :mock_request do |uri,opts|
233
+ env = Rack::MockRequest.env_for(uri, opts || {})
234
+ Rack::Cache::Request.new(env)
235
+ end
236
+
237
+ define_method :mock_response do |status,headers,body|
238
+ headers ||= {}
239
+ body = Array(body).compact
240
+ Rack::Cache::Response.new(status, headers, body)
241
+ end
242
+
243
+ define_method :slurp do |body|
244
+ buf = ''
245
+ body.each {|part| buf << part }
246
+ buf
247
+ end
248
+
249
+ define_method :uri do |uri|
250
+ URI.parse uri
251
+ end
99
252
  end
100
253
  end
101
254
  end
@@ -27,13 +27,11 @@ module Rack
27
27
 
28
28
  it "should specify connection params" do
29
29
  pool = Rack::Session::Redis.new(@incrementor, :redis_server => "localhost:6380/1").pool
30
- pool.should be_kind_of(MarshaledRedis)
31
- pool.host.should == "localhost"
32
- pool.port.should == 6380
33
- pool.db.should == 1
30
+ pool.should be_kind_of(::Redis::MarshaledClient)
31
+ pool.to_s.should == "Redis Client connected to localhost:6380 against DB 1"
34
32
 
35
33
  pool = Rack::Session::Redis.new(@incrementor, :redis_server => ["localhost:6379", "localhost:6380"]).pool
36
- pool.should be_kind_of(DistributedMarshaledRedis)
34
+ pool.should be_kind_of(::Redis::DistributedMarshaled)
37
35
  end
38
36
 
39
37
  it "creates a new cookie" do
@@ -48,12 +46,10 @@ module Rack
48
46
  req = Rack::MockRequest.new(pool)
49
47
  res = req.get("/")
50
48
  cookie = res["Set-Cookie"]
51
- req.get("/", "HTTP_COOKIE" => cookie).
52
- body.should == '{"counter"=>2}'
53
- req.get("/", "HTTP_COOKIE" => cookie).
54
- body.should == '{"counter"=>3}'
49
+ req.get("/", "HTTP_COOKIE" => cookie).body.should == '{"counter"=>2}'
50
+ req.get("/", "HTTP_COOKIE" => cookie).body.should == '{"counter"=>3}'
55
51
  end
56
-
52
+
57
53
  it "survives nonexistant cookies" do
58
54
  bad_cookie = "rack.session=blarghfasel"
59
55
  pool = Rack::Session::Redis.new(@incrementor)
@@ -211,7 +207,7 @@ module Rack
211
207
  session['counter'].should == 3
212
208
 
213
209
  drop_counter = proc do |env|
214
- env['rack.session'].delete 'counter'
210
+ env['rack.session'].del 'counter'
215
211
  env['rack.session']['foo'] = 'bar'
216
212
  [200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
217
213
  end
@@ -1,35 +1,33 @@
1
1
  require File.join(File.dirname(__FILE__), "/../spec_helper")
2
2
 
3
- describe "DistributedMarshaledRedis" do
3
+ describe "Redis::DistributedMarshaled" do
4
4
  before(:each) do
5
- @dmr = DistributedMarshaledRedis.new [
5
+ @dmr = Redis::DistributedMarshaled.new [
6
6
  {:host => "localhost", :port => "6380", :db => 0},
7
7
  {:host => "localhost", :port => "6381", :db => 0}
8
8
  ]
9
9
  @rabbit = OpenStruct.new :name => "bunny"
10
10
  @white_rabbit = OpenStruct.new :color => "white"
11
- @dmr.set "rabbit", @rabbit
11
+ @dmr.marshalled_set "rabbit", @rabbit
12
12
  end
13
13
 
14
14
  after(:all) do
15
- @dmr.ring.nodes.each { |server| server.flush_db }
15
+ @dmr.ring.nodes.each { |server| server.flushdb }
16
16
  end
17
17
 
18
18
  it "should accept connection params" do
19
- dmr = DistributedMarshaledRedis.new [ :host => "localhost", :port => "6380", :db => "1" ]
19
+ dmr = Redis::DistributedMarshaled.new [ :host => "localhost", :port => "6380", :db => "1" ]
20
20
  dmr.ring.should have(1).node
21
21
  mr = dmr.ring.nodes.first
22
- mr.host.should == "localhost"
23
- mr.port.should == 6380
24
- mr.db.should == 1
22
+ mr.to_s.should == "Redis Client connected to localhost:6380 against DB 1"
25
23
  end
26
24
 
27
25
  it "should set an object" do
28
- @dmr.set "rabbit", @white_rabbit
29
- @dmr.get("rabbit").should == @white_rabbit
26
+ @dmr.marshalled_set "rabbit", @white_rabbit
27
+ @dmr.marshalled_get("rabbit").should == @white_rabbit
30
28
  end
31
29
 
32
30
  it "should get an object" do
33
- @dmr.get("rabbit").should == @rabbit
31
+ @dmr.marshalled_get("rabbit").should == @rabbit
34
32
  end
35
33
  end