redis-objects 1.5.1 → 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,419 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'redis/objects'
4
+ Redis::Objects.redis = REDIS_HANDLE
5
+
6
+ require 'securerandom'
7
+
8
+ require "stringio"
9
+
10
+ def capture_stderr
11
+ # The output stream must be an IO-like object. In this case we capture it in
12
+ # an in-memory IO object so we can return the string value. You can assign any
13
+ # IO object here.
14
+ previous_stderr, $stderr = $stderr, StringIO.new
15
+ yield
16
+ $stderr.string
17
+ ensure
18
+ # Restore the previous value of stderr (typically equal to STDERR).
19
+ $stderr = previous_stderr
20
+ end
21
+
22
+ describe 'Legacy redis key prefix naming compatibility' do
23
+ it 'verifies single level classes work the same' do
24
+ class SingleLevelOne
25
+ include Redis::Objects
26
+
27
+ def id
28
+ 1
29
+ end
30
+ end
31
+
32
+ obj = SingleLevelOne.new
33
+ obj.class.redis_prefix.should == 'single_level_one'
34
+ end
35
+
36
+ it 'verifies single level classes obey the legacy naming flag' do
37
+ class SingleLevelTwo
38
+ include Redis::Objects
39
+ self.redis_legacy_naming = true
40
+
41
+ def id
42
+ 1
43
+ end
44
+ end
45
+
46
+ obj = SingleLevelTwo.new
47
+ obj.class.redis_prefix.should == 'single_level_two'
48
+ end
49
+
50
+ it 'verifies nested classes do NOT work the same' do
51
+ module Nested
52
+ class NamingOne
53
+ include Redis::Objects
54
+ self.redis_silence_warnings = true
55
+
56
+ def id
57
+ 1
58
+ end
59
+ end
60
+ end
61
+
62
+ obj = Nested::NamingOne.new
63
+ obj.class.redis_prefix.should == 'nested__naming_one'
64
+ end
65
+
66
+ it 'verifies the legacy naming flag is respected' do
67
+ module Nested
68
+ class NamingTwo
69
+ include Redis::Objects
70
+ self.redis_legacy_naming = true
71
+ self.redis_silence_warnings = true
72
+
73
+ def id
74
+ 1
75
+ end
76
+ end
77
+ end
78
+
79
+ Nested::NamingTwo.redis_legacy_naming.should == true
80
+ obj = Nested::NamingTwo.new
81
+ obj.class.redis_prefix.should == 'naming_two'
82
+ end
83
+
84
+ it 'verifies that multiple levels respect __ vs _' do
85
+ module NestedLevel
86
+ module Further
87
+ class NamingThree
88
+ include Redis::Objects
89
+ self.redis_silence_warnings = true
90
+
91
+ def id
92
+ 1
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ obj = NestedLevel::Further::NamingThree.new
99
+ obj.class.redis_prefix.should == 'nested_level__further__naming_three'
100
+ end
101
+
102
+ it 'verifies that multiple levels respect the legacy naming' do
103
+ module NestedLevel
104
+ module Further
105
+ class NamingFour
106
+ include Redis::Objects
107
+ self.redis_legacy_naming = true
108
+
109
+ def id
110
+ 1
111
+ end
112
+
113
+ redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31)
114
+ value :redis_value, :redis => redis_handle
115
+ end
116
+ end
117
+ end
118
+
119
+ NestedLevel::Further::NamingFour.redis_legacy_naming.should == true
120
+ obj = NestedLevel::Further::NamingFour.new
121
+ obj.class.redis_prefix.should == 'naming_four'
122
+ val = SecureRandom.hex(10)
123
+ obj.redis_value = val
124
+ obj.redis_value.should == val
125
+ obj.redis_value.key.should == 'naming_four:1:redis_value'
126
+ end
127
+
128
+ it 'verifies that multiple levels do not conflict 1' do
129
+ module NestedLevel
130
+ module Further
131
+ class NamingFive
132
+ include Redis::Objects
133
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
134
+ self.redis_silence_warnings = true
135
+
136
+ def id
137
+ 1
138
+ end
139
+
140
+ value :redis_value
141
+ end
142
+ end
143
+ end
144
+
145
+ obj = NestedLevel::Further::NamingFive.new
146
+ obj.class.redis_prefix.should == 'nested_level__further__naming_five'
147
+ val = SecureRandom.hex(10)
148
+ obj.redis_value = val
149
+ obj.redis_value.should == val
150
+ obj.redis_value.key.should == 'nested_level__further__naming_five:1:redis_value'
151
+ obj.redis_value.redis.should == obj.redis
152
+ obj.redis.get('nested_level__further__naming_five:1:redis_value').should == val
153
+ end
154
+
155
+ it 'verifies that multiple levels do not conflict 2' do
156
+ module Nested
157
+ module LevelFurtherNaming
158
+ class Five
159
+ include Redis::Objects
160
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
161
+ self.redis_silence_warnings = true
162
+
163
+ def id
164
+ 1
165
+ end
166
+
167
+ value :redis_value
168
+ end
169
+ end
170
+ end
171
+
172
+ obj = Nested::LevelFurtherNaming::Five.new
173
+ obj.class.redis_prefix.should == 'nested__level_further_naming__five'
174
+ val = SecureRandom.hex(10)
175
+ obj.redis_value = val
176
+ obj.redis_value.should == val
177
+ obj.redis_value.key.should == 'nested__level_further_naming__five:1:redis_value'
178
+ obj.redis.get('nested__level_further_naming__five:1:redis_value').should == val
179
+ end
180
+
181
+ it 'verifies that multiple levels do not conflict 3' do
182
+ module Nested
183
+ module LevelFurther
184
+ class NamingFive
185
+ include Redis::Objects
186
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
187
+ self.redis_silence_warnings = true
188
+
189
+ def id
190
+ 1
191
+ end
192
+
193
+ value :redis_value
194
+ end
195
+ end
196
+ end
197
+
198
+ obj = Nested::LevelFurther::NamingFive.new
199
+ obj.class.redis_prefix.should == 'nested__level_further__naming_five'
200
+ val = SecureRandom.hex(10)
201
+ obj.redis_value = val
202
+ obj.redis_value.should == val
203
+ obj.redis_value.key.should == 'nested__level_further__naming_five:1:redis_value'
204
+ obj.redis.get('nested__level_further__naming_five:1:redis_value').should == val
205
+ end
206
+
207
+ it 'handles dynamically created classes correctly' do
208
+ module Nested
209
+ class LevelSix
210
+ include Redis::Objects
211
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
212
+ self.redis_silence_warnings = true
213
+
214
+ def id
215
+ 1
216
+ end
217
+
218
+ value :redis_value
219
+ end
220
+ end
221
+
222
+ obj = Nested::LevelSix.new
223
+ obj.class.redis_prefix.should == 'nested__level_six'
224
+ val = SecureRandom.hex(10)
225
+ obj.redis_value = val
226
+ obj.redis_value.should == val
227
+ obj.redis_value.key.should == 'nested__level_six:1:redis_value'
228
+ obj.redis.get('nested__level_six:1:redis_value').should == val
229
+
230
+ DynamicClass = Class.new(Nested::LevelSix)
231
+ DynamicClass.value :redis_value2
232
+ obj2 = DynamicClass.new
233
+ DynamicClass.redis_prefix.should == 'dynamic_class'
234
+ obj2.redis_value.should.be.kind_of(Redis::Value)
235
+ obj2.redis_value2.should.be.kind_of(Redis::Value)
236
+ obj2.redis_value.key.should == 'dynamic_class:1:redis_value'
237
+ obj2.redis_value2.key.should == 'dynamic_class:1:redis_value2'
238
+
239
+ end
240
+
241
+ it 'handles dynamically created classes correctly in legacy mode' do
242
+ module Nested
243
+ class LevelSeven
244
+ include Redis::Objects
245
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
246
+ self.redis_legacy_naming = true
247
+
248
+ def id
249
+ 1
250
+ end
251
+
252
+ value :redis_value
253
+ end
254
+ end
255
+
256
+ obj = Nested::LevelSeven.new
257
+ obj.class.redis_prefix.should == 'level_seven'
258
+ val = SecureRandom.hex(10)
259
+ obj.redis_value = val
260
+ obj.redis_value.should == val
261
+ obj.redis_value.key.should == 'level_seven:1:redis_value'
262
+ obj.redis.get('level_seven:1:redis_value').should == val
263
+
264
+ DynamicClass2 = Class.new(Nested::LevelSeven)
265
+ DynamicClass2.value :redis_value2
266
+ obj2 = DynamicClass2.new
267
+ DynamicClass2.redis_prefix.should == 'dynamic_class2'
268
+ obj2.redis_value.should.be.kind_of(Redis::Value)
269
+ obj2.redis_value2.should.be.kind_of(Redis::Value)
270
+ obj2.redis_value.key.should == 'dynamic_class2:1:redis_value'
271
+ obj2.redis_value2.key.should == 'dynamic_class2:1:redis_value2'
272
+ end
273
+
274
+ it 'prints a warning message if the key name changes' do
275
+ module Nested
276
+ class LevelNine
277
+ include Redis::Objects
278
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
279
+
280
+ def id
281
+ 1
282
+ end
283
+
284
+ value :redis_value
285
+ end
286
+ end
287
+
288
+ captured_output = capture_stderr do
289
+ # Does not output anything directly.
290
+ obj = Nested::LevelNine.new
291
+ val = SecureRandom.hex(10)
292
+ obj.redis_value = val
293
+ obj.redis_value.should == val
294
+ end
295
+
296
+ captured_output.should =~ /Warning:/i
297
+ end
298
+
299
+ it 'supports a method to migrate legacy key names' do
300
+ module Nested
301
+ class Legacy
302
+ include Redis::Objects
303
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
304
+ self.redis_legacy_naming = true
305
+
306
+ # override this for testing - need two classes as if we imagine an old and new one
307
+ # also use the legacy flat prefix that ignores the nested class name
308
+ self.redis_prefix = 'modern'
309
+
310
+ def initialize(id)
311
+ @id = id
312
+ end
313
+ def id
314
+ @id
315
+ end
316
+
317
+ value :redis_value
318
+ counter :redis_counter
319
+ hash_key :redis_hash
320
+ list :redis_list
321
+ set :redis_set
322
+ sorted_set :redis_sorted_set
323
+
324
+ # global class counters
325
+ value :global_value, :global => true
326
+ counter :global_counter, :global => true
327
+ hash_key :global_hash_key, :global => true
328
+ list :global_list, :global => true
329
+ set :global_set, :global => true
330
+ sorted_set :global_sorted_set, :global => true
331
+
332
+ #callable as key
333
+ value :global_proc_value, :global => true, :key => Proc.new { |roster| "#{roster.name}:#{Time.now.strftime('%Y-%m-%dT%H')}:daily" }
334
+ end
335
+ end
336
+
337
+ module Nested
338
+ class Modern
339
+ include Redis::Objects
340
+ self.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
341
+
342
+ def initialize(id)
343
+ @id = id
344
+ end
345
+ def id
346
+ @id
347
+ end
348
+
349
+ value :redis_value
350
+ counter :redis_counter
351
+ hash_key :redis_hash
352
+ list :redis_list
353
+ set :redis_set
354
+ sorted_set :redis_sorted_set
355
+
356
+ # global class counters
357
+ value :global_value, :global => true
358
+ counter :global_counter, :global => true
359
+ hash_key :global_hash_key, :global => true
360
+ list :global_list, :global => true
361
+ set :global_set, :global => true
362
+ sorted_set :global_sorted_set, :global => true
363
+
364
+ #callable as key
365
+ value :global_proc_value, :global => true, :key => Proc.new { |roster| "#{roster.name}:#{Time.now.strftime('%Y-%m-%dT%H')}:daily" }
366
+ end
367
+ end
368
+
369
+ # Iterate over them
370
+ Nested::Modern.redis_objects.length.should == 13
371
+ Nested::Modern.redis_objects.length.should == Nested::Legacy.redis_objects.length.should
372
+ Nested::Legacy.redis_prefix.should == 'modern'
373
+ Nested::Modern.redis_prefix.should == 'nested__modern'
374
+
375
+ # Create a whole bunch of keys using the legacy names
376
+ 30.times do |i|
377
+ # warn i.inspect
378
+ obj = Nested::Legacy.new(i)
379
+ obj.redis_value = i
380
+ obj.redis_value.to_i.should == i
381
+ obj.redis_counter.increment
382
+ obj.redis_hash[:key] = i
383
+ obj.redis_list << i
384
+ obj.redis_set << i
385
+ obj.redis_sorted_set[i] = i
386
+ end
387
+
388
+ obj = Nested::Legacy.new(99)
389
+ obj.global_value = 42
390
+ obj.global_counter.increment
391
+ obj.global_counter.increment
392
+ obj.global_counter.increment
393
+ obj.global_hash_key[:key] = 'value'
394
+ obj.global_set << 'a' << 'b'
395
+ obj.global_sorted_set[:key] = 2.2
396
+
397
+ Nested::Modern.migrate_redis_legacy_keys
398
+
399
+ # Try to access the keys through modern names now
400
+ 30.times do |i|
401
+ # warn i.inspect
402
+ obj = Nested::Modern.new(i)
403
+ obj.redis_value.to_i.should == i
404
+ obj.redis_counter.to_i.should == 1
405
+ obj.redis_hash[:key].to_i.should == i
406
+ obj.redis_list[0].to_i.should == i
407
+ obj.redis_set.include?(i).should == true
408
+ obj.redis_sorted_set[i].should == i
409
+ end
410
+
411
+ obj = Nested::Modern.new(99)
412
+ obj.global_value.to_i.should == 42
413
+ obj.global_counter.to_i.should == 3
414
+ obj.global_hash_key[:key].should == 'value'
415
+ obj.global_set.should.include?('a').should == true
416
+ obj.global_set.should.include?('b').should == true
417
+ obj.global_sorted_set[:key].should == 2.2
418
+ end
419
+ end
@@ -5,6 +5,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
5
5
 
6
6
  require 'redis/objects'
7
7
  require 'connection_pool'
8
+ Redis::Objects.redis = REDIS_HANDLE
8
9
 
9
10
  BAD_REDIS = "totally bad bogus redis handle"
10
11
 
@@ -33,8 +34,8 @@ describe 'Connection tests' do
33
34
  obj.redis_value.value.should == nil
34
35
 
35
36
  obj.default_redis_value.clear
36
- obj.redis_value.value = 'foo'
37
- obj.redis_value.value.should == 'foo'
37
+ obj.redis_value.value = 'bar'
38
+ obj.redis_value.value.should == 'bar'
38
39
  obj.default_redis_value.value.should == nil
39
40
 
40
41
  obj.redis_value.clear
@@ -95,13 +96,13 @@ describe 'Connection tests' do
95
96
  end
96
97
 
97
98
  it "should support local handles with a vanilla redis connection" do
98
- Redis.current = nil # reset from other tests
99
+ # Redis.current = nil # reset from other tests
99
100
  Redis::Objects.redis = nil
100
101
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
101
102
 
102
103
  # Redis.current is lazily auto-populated to touch 6379
103
104
  # This why we choose the weird 9212 port to avoid
104
- Redis.current.inspect.should == Redis.new.inspect
105
+ # Redis.current.inspect.should == Redis.new.inspect
105
106
  Redis::Objects.redis.inspect.should == Redis.new.inspect
106
107
 
107
108
  v = Redis::Value.new('conn/value', @redis_handle)
@@ -140,13 +141,13 @@ describe 'Connection tests' do
140
141
  end
141
142
 
142
143
  it "should support local handles with a connection_pool" do
143
- Redis.current = nil # reset from other tests
144
+ # Redis.current = nil # reset from other tests
144
145
  Redis::Objects.redis = nil
145
146
  @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
146
147
 
147
148
  # Redis.current is lazily auto-populated to touch 6379
148
149
  # This why we choose the weird 9212 port to avoid
149
- Redis.current.inspect.should == Redis.new.inspect
150
+ # Redis.current.inspect.should == Redis.new.inspect
150
151
  Redis::Objects.redis.inspect.should == Redis.new.inspect
151
152
 
152
153
  v = Redis::Value.new('conn/value', @redis_handle)
@@ -184,24 +185,19 @@ describe 'Connection tests' do
184
185
  c.decr(1)
185
186
  end
186
187
 
187
- it "should support Redis.current" do
188
- Redis.current = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
189
-
190
- Redis::Value.new('conn/value').should == 'yay'
191
- Redis::HashKey.new('conn/hash').keys.should == ['k']
192
- Redis::List.new('conn/list').sort.should == ['3', '4', '5']
193
- Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
194
- Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
195
- Redis::Counter.new('conn/counter').should == 2
188
+ it "should properly support fallback handle variables" do
189
+ # Redis.current is lazily auto-populated to touch 6379
190
+ # This why we choose the weird 9212 port to avoid
191
+ old_redis = $redis
192
+ $redis = BAD_REDIS
193
+ Redis::Objects.redis.should == BAD_REDIS
194
+ $redis = old_redis
196
195
  end
197
196
 
198
197
  it "should support Redis::Objects.redis= with a connection_pool" do
198
+ # reset redis
199
199
  @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
200
-
201
- # Redis.current is lazily auto-populated to touch 6379
202
- # This why we choose the weird 9212 port to avoid
203
- Redis.current = BAD_REDIS
204
- Redis::Objects.redis.should == BAD_REDIS
200
+ Redis::Objects.redis = @redis_handle
205
201
 
206
202
  # This set of tests sucks, it fucks up the per-data-type handles
207
203
  # because Redis.current is then set to a BS value, and the lazy
@@ -229,13 +225,8 @@ describe 'Connection tests' do
229
225
 
230
226
  it "should support Redis::Objects.redis= with a vanilla redis connection" do
231
227
  # reset redis
232
- Redis::Objects.redis = nil
233
228
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
234
-
235
- # Redis.current is lazily auto-populated to touch 6379
236
- # This why we choose the weird 9212 port to avoid
237
- Redis.current = BAD_REDIS
238
- Redis::Objects.redis.should == BAD_REDIS
229
+ Redis::Objects.redis = @redis_handle
239
230
 
240
231
  # This set of tests sucks, it fucks up the per-data-type handles
241
232
  # because Redis.current is then set to a BS value, and the lazy
@@ -260,7 +251,7 @@ describe 'Connection tests' do
260
251
  Redis::Counter.new('conn/counter').should == 2
261
252
 
262
253
  # Fix for future tests
263
- Redis.current = @redis_handle
254
+ # Redis.current = @redis_handle
264
255
  end
265
256
 
266
257
  it "should support pipelined changes" do
@@ -2,6 +2,7 @@
2
2
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
4
  require 'redis/objects'
5
+ Redis::Objects.redis = REDIS_HANDLE
5
6
 
6
7
  class CustomSerializer
7
8
  class << self