redis 4.0.2 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +2 -2
  4. data/CHANGELOG.md +6 -0
  5. data/lib/redis.rb +97 -11
  6. data/lib/redis/client.rb +19 -11
  7. data/lib/redis/cluster.rb +285 -0
  8. data/lib/redis/cluster/command.rb +81 -0
  9. data/lib/redis/cluster/command_loader.rb +32 -0
  10. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  11. data/lib/redis/cluster/node.rb +104 -0
  12. data/lib/redis/cluster/node_key.rb +35 -0
  13. data/lib/redis/cluster/node_loader.rb +35 -0
  14. data/lib/redis/cluster/option.rb +76 -0
  15. data/lib/redis/cluster/slot.rb +69 -0
  16. data/lib/redis/cluster/slot_loader.rb +47 -0
  17. data/lib/redis/errors.rb +46 -0
  18. data/lib/redis/version.rb +1 -1
  19. data/makefile +54 -16
  20. data/redis.gemspec +2 -1
  21. data/test/client_test.rb +17 -0
  22. data/test/cluster_abnormal_state_test.rb +38 -0
  23. data/test/cluster_blocking_commands_test.rb +15 -0
  24. data/test/cluster_client_internals_test.rb +77 -0
  25. data/test/cluster_client_key_hash_tags_test.rb +88 -0
  26. data/test/cluster_client_options_test.rb +147 -0
  27. data/test/cluster_client_pipelining_test.rb +59 -0
  28. data/test/cluster_client_replicas_test.rb +36 -0
  29. data/test/cluster_client_slots_test.rb +94 -0
  30. data/test/cluster_client_transactions_test.rb +71 -0
  31. data/test/cluster_commands_on_cluster_test.rb +165 -0
  32. data/test/cluster_commands_on_connection_test.rb +40 -0
  33. data/test/cluster_commands_on_geo_test.rb +74 -0
  34. data/test/cluster_commands_on_hashes_test.rb +11 -0
  35. data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
  36. data/test/cluster_commands_on_keys_test.rb +134 -0
  37. data/test/cluster_commands_on_lists_test.rb +15 -0
  38. data/test/cluster_commands_on_pub_sub_test.rb +101 -0
  39. data/test/cluster_commands_on_scripting_test.rb +56 -0
  40. data/test/cluster_commands_on_server_test.rb +221 -0
  41. data/test/cluster_commands_on_sets_test.rb +39 -0
  42. data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
  43. data/test/cluster_commands_on_streams_test.rb +196 -0
  44. data/test/cluster_commands_on_strings_test.rb +15 -0
  45. data/test/cluster_commands_on_transactions_test.rb +41 -0
  46. data/test/cluster_commands_on_value_types_test.rb +14 -0
  47. data/test/commands_on_hashes_test.rb +2 -14
  48. data/test/commands_on_hyper_log_log_test.rb +2 -14
  49. data/test/commands_on_lists_test.rb +2 -13
  50. data/test/commands_on_sets_test.rb +2 -70
  51. data/test/commands_on_sorted_sets_test.rb +2 -145
  52. data/test/commands_on_strings_test.rb +2 -94
  53. data/test/distributed_blocking_commands_test.rb +8 -0
  54. data/test/distributed_commands_on_hashes_test.rb +16 -3
  55. data/test/distributed_commands_on_hyper_log_log_test.rb +8 -13
  56. data/test/distributed_commands_on_lists_test.rb +4 -5
  57. data/test/distributed_commands_on_sets_test.rb +45 -46
  58. data/test/distributed_commands_on_sorted_sets_test.rb +51 -8
  59. data/test/distributed_commands_on_strings_test.rb +10 -0
  60. data/test/helper.rb +176 -32
  61. data/test/internals_test.rb +13 -0
  62. data/test/lint/blocking_commands.rb +40 -16
  63. data/test/lint/hashes.rb +26 -0
  64. data/test/lint/hyper_log_log.rb +15 -1
  65. data/test/lint/lists.rb +16 -0
  66. data/test/lint/sets.rb +142 -0
  67. data/test/lint/sorted_sets.rb +183 -2
  68. data/test/lint/strings.rb +102 -0
  69. data/test/support/cluster/orchestrator.rb +199 -0
  70. metadata +79 -4
@@ -202,6 +202,19 @@ class TestInternals < Test::Unit::TestCase
202
202
  end
203
203
  end
204
204
 
205
+ def test_retry_with_custom_reconnect_attempts_and_exponential_backoff
206
+ close_on_ping([0, 1, 2], :reconnect_attempts => 3,
207
+ :reconnect_delay_max => 0.5,
208
+ :reconnect_delay => 0.01) do |redis|
209
+
210
+ Kernel.expects(:sleep).with(0.01).returns(true)
211
+ Kernel.expects(:sleep).with(0.02).returns(true)
212
+ Kernel.expects(:sleep).with(0.04).returns(true)
213
+
214
+ assert_equal "3", redis.ping
215
+ end
216
+ end
217
+
205
218
  def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
206
219
  close_on_ping([1]) do |redis|
207
220
  assert_raise Redis::ConnectionError do
@@ -1,14 +1,15 @@
1
1
  module Lint
2
-
3
2
  module BlockingCommands
4
-
5
3
  def setup
6
4
  super
7
5
 
8
- r.rpush("{zap}foo", "s1")
9
- r.rpush("{zap}foo", "s2")
10
- r.rpush("{zap}bar", "s1")
11
- r.rpush("{zap}bar", "s2")
6
+ r.rpush('{zap}foo', 's1')
7
+ r.rpush('{zap}foo', 's2')
8
+ r.rpush('{zap}bar', 's1')
9
+ r.rpush('{zap}bar', 's2')
10
+
11
+ r.zadd('{szap}foo', %w[0 a 1 b 2 c])
12
+ r.zadd('{szap}bar', %w[0 c 1 d 2 e])
12
13
  end
13
14
 
14
15
  def to_protocol(obj)
@@ -18,27 +19,38 @@ module Lint
18
19
  when Array
19
20
  "*#{obj.length}\r\n" + obj.map { |e| to_protocol(e) }.join
20
21
  else
21
- fail
22
+ raise
22
23
  end
23
24
  end
24
25
 
25
26
  def mock(options = {}, &blk)
26
- commands = {
27
- :blpop => lambda do |*args|
28
- sleep options[:delay] if options.has_key?(:delay)
27
+ commands = build_mock_commands(options)
28
+ redis_mock(commands, &blk)
29
+ end
30
+
31
+ def build_mock_commands(options = {})
32
+ {
33
+ blpop: lambda do |*args|
34
+ sleep options[:delay] if options.key?(:delay)
29
35
  to_protocol([args.first, args.last])
30
36
  end,
31
- :brpop => lambda do |*args|
32
- sleep options[:delay] if options.has_key?(:delay)
37
+ brpop: lambda do |*args|
38
+ sleep options[:delay] if options.key?(:delay)
33
39
  to_protocol([args.first, args.last])
34
40
  end,
35
- :brpoplpush => lambda do |*args|
36
- sleep options[:delay] if options.has_key?(:delay)
41
+ brpoplpush: lambda do |*args|
42
+ sleep options[:delay] if options.key?(:delay)
37
43
  to_protocol(args.last)
44
+ end,
45
+ bzpopmax: lambda do |*args|
46
+ sleep options[:delay] if options.key?(:delay)
47
+ to_protocol([args.first, args.last])
48
+ end,
49
+ bzpopmin: lambda do |*args|
50
+ sleep options[:delay] if options.key?(:delay)
51
+ to_protocol([args.first, args.last])
38
52
  end
39
53
  }
40
-
41
- redis_mock(commands, &blk)
42
54
  end
43
55
 
44
56
  def test_blpop
@@ -121,6 +133,18 @@ module Lint
121
133
  end
122
134
  end
123
135
 
136
+ def test_bzpopmin
137
+ target_version('4.9.0') do
138
+ assert_equal %w[{szap}foo a 0], r.bzpopmin('{szap}foo', '{szap}bar', 0)
139
+ end
140
+ end
141
+
142
+ def test_bzpopmax
143
+ target_version('4.9.0') do
144
+ assert_equal %w[{szap}foo c 2], r.bzpopmax('{szap}foo', '{szap}bar', 0)
145
+ end
146
+ end
147
+
124
148
  driver(:ruby, :hiredis) do
125
149
  def test_blpop_socket_timeout
126
150
  mock(:delay => 1 + OPTIONS[:timeout] * 2) do |r|
@@ -144,6 +144,17 @@ module Lint
144
144
  assert({"f1" => "s1", "f2" => "s2"} == r.mapped_hmget("foo", "f1", "f2"))
145
145
  end
146
146
 
147
+ def test_mapped_hmget_in_a_pipeline_returns_hash
148
+ r.hset("foo", "f1", "s1")
149
+ r.hset("foo", "f2", "s2")
150
+
151
+ result = r.pipelined do
152
+ r.mapped_hmget("foo", "f1", "f2")
153
+ end
154
+
155
+ assert_equal result[0], { "f1" => "s1", "f2" => "s2" }
156
+ end
157
+
147
158
  def test_hincrby
148
159
  r.hincrby("foo", "f1", 1)
149
160
 
@@ -173,5 +184,20 @@ module Lint
173
184
  assert_equal "1.9", r.hget("foo", "f1")
174
185
  end
175
186
  end
187
+
188
+ def test_hstrlen
189
+ target_version('3.2.0') do
190
+ redis.hmset('foo', 'f1', 'HelloWorld', 'f2', 99, 'f3', -256)
191
+ assert_equal 10, r.hstrlen('foo', 'f1')
192
+ assert_equal 2, r.hstrlen('foo', 'f2')
193
+ assert_equal 4, r.hstrlen('foo', 'f3')
194
+ end
195
+ end
196
+
197
+ def test_hscan
198
+ redis.hmset('foo', 'f1', 'Jack', 'f2', 33)
199
+ expected = ['0', [%w[f1 Jack], %w[f2 33]]]
200
+ assert_equal expected, redis.hscan('foo', 0)
201
+ end
176
202
  end
177
203
  end
@@ -55,6 +55,20 @@ module Lint
55
55
  end
56
56
  end
57
57
 
58
- end
58
+ def test_pfmerge
59
+ target_version '2.8.9' do
60
+ r.pfadd 'foo', 's1'
61
+ r.pfadd 'bar', 's2'
62
+
63
+ assert_equal true, r.pfmerge('res', 'foo', 'bar')
64
+ assert_equal 2, r.pfcount('res')
65
+ end
66
+ end
59
67
 
68
+ def test_variadic_pfmerge_expanded
69
+ redis.pfadd('{1}foo', %w[foo bar zap a])
70
+ redis.pfadd('{1}bar', %w[a b c foo])
71
+ assert_equal true, redis.pfmerge('{1}baz', '{1}foo', '{1}bar')
72
+ end
73
+ end
60
74
  end
@@ -139,5 +139,21 @@ module Lint
139
139
  r.linsert "foo", :anywhere, "s3", "s2"
140
140
  end
141
141
  end
142
+
143
+ def test_rpoplpush
144
+ r.rpush 'foo', 's1'
145
+ r.rpush 'foo', 's2'
146
+
147
+ assert_equal 's2', r.rpoplpush('foo', 'bar')
148
+ assert_equal ['s2'], r.lrange('bar', 0, -1)
149
+ assert_equal 's1', r.rpoplpush('foo', 'bar')
150
+ assert_equal %w[s1 s2], r.lrange('bar', 0, -1)
151
+ end
152
+
153
+ def test_variadic_rpoplpush_expand
154
+ redis.rpush('{1}foo', %w[a b c])
155
+ redis.rpush('{1}bar', %w[d e f])
156
+ assert_equal 'c', redis.rpoplpush('{1}foo', '{1}bar')
157
+ end
142
158
  end
143
159
  end
@@ -136,5 +136,147 @@ module Lint
136
136
 
137
137
  assert_equal 4, r.scard("foo")
138
138
  end
139
+
140
+ def test_smove
141
+ r.sadd 'foo', 's1'
142
+ r.sadd 'bar', 's2'
143
+
144
+ assert r.smove('foo', 'bar', 's1')
145
+ assert r.sismember('bar', 's1')
146
+ end
147
+
148
+ def test_sinter
149
+ r.sadd 'foo', 's1'
150
+ r.sadd 'foo', 's2'
151
+ r.sadd 'bar', 's2'
152
+
153
+ assert_equal ['s2'], r.sinter('foo', 'bar')
154
+ end
155
+
156
+ def test_variadic_smove_expand
157
+ r.sadd('{1}foo', 's1')
158
+ r.sadd('{1}foo', 's2')
159
+ r.sadd('{1}foo', 's3')
160
+ r.sadd('{1}bar', 's3')
161
+ r.sadd('{1}bar', 's4')
162
+ r.sadd('{1}bar', 's5')
163
+ assert_equal true, r.smove('{1}foo', '{1}bar', 's2')
164
+ end
165
+
166
+ def test_variadic_sinter_expand
167
+ r.sadd('{1}foo', 's1')
168
+ r.sadd('{1}foo', 's2')
169
+ r.sadd('{1}foo', 's3')
170
+ r.sadd('{1}bar', 's3')
171
+ r.sadd('{1}bar', 's4')
172
+ r.sadd('{1}bar', 's5')
173
+ assert_equal %w[s3], r.sinter('{1}foo', '{1}bar')
174
+ end
175
+
176
+ def test_sinterstore
177
+ r.sadd 'foo', 's1'
178
+ r.sadd 'foo', 's2'
179
+ r.sadd 'bar', 's2'
180
+
181
+ r.sinterstore('baz', 'foo', 'bar')
182
+
183
+ assert_equal ['s2'], r.smembers('baz')
184
+ end
185
+
186
+ def test_variadic_sinterstore_expand
187
+ r.sadd('{1}foo', 's1')
188
+ r.sadd('{1}foo', 's2')
189
+ r.sadd('{1}foo', 's3')
190
+ r.sadd('{1}bar', 's3')
191
+ r.sadd('{1}bar', 's4')
192
+ r.sadd('{1}bar', 's5')
193
+ assert_equal 1, r.sinterstore('{1}baz', '{1}foo', '{1}bar')
194
+ end
195
+
196
+ def test_sunion
197
+ r.sadd 'foo', 's1'
198
+ r.sadd 'foo', 's2'
199
+ r.sadd 'bar', 's2'
200
+ r.sadd 'bar', 's3'
201
+
202
+ assert_equal %w[s1 s2 s3], r.sunion('foo', 'bar').sort
203
+ end
204
+
205
+ def test_variadic_sunion_expand
206
+ r.sadd('{1}foo', 's1')
207
+ r.sadd('{1}foo', 's2')
208
+ r.sadd('{1}foo', 's3')
209
+ r.sadd('{1}bar', 's3')
210
+ r.sadd('{1}bar', 's4')
211
+ r.sadd('{1}bar', 's5')
212
+ assert_equal %w[s1 s2 s3 s4 s5], r.sunion('{1}foo', '{1}bar').sort
213
+ end
214
+
215
+ def test_sunionstore
216
+ r.sadd 'foo', 's1'
217
+ r.sadd 'foo', 's2'
218
+ r.sadd 'bar', 's2'
219
+ r.sadd 'bar', 's3'
220
+
221
+ r.sunionstore('baz', 'foo', 'bar')
222
+
223
+ assert_equal %w[s1 s2 s3], r.smembers('baz').sort
224
+ end
225
+
226
+ def test_variadic_sunionstore_expand
227
+ r.sadd('{1}foo', 's1')
228
+ r.sadd('{1}foo', 's2')
229
+ r.sadd('{1}foo', 's3')
230
+ r.sadd('{1}bar', 's3')
231
+ r.sadd('{1}bar', 's4')
232
+ r.sadd('{1}bar', 's5')
233
+ assert_equal 5, r.sunionstore('{1}baz', '{1}foo', '{1}bar')
234
+ end
235
+
236
+ def test_sdiff
237
+ r.sadd 'foo', 's1'
238
+ r.sadd 'foo', 's2'
239
+ r.sadd 'bar', 's2'
240
+ r.sadd 'bar', 's3'
241
+
242
+ assert_equal ['s1'], r.sdiff('foo', 'bar')
243
+ assert_equal ['s3'], r.sdiff('bar', 'foo')
244
+ end
245
+
246
+ def test_variadic_sdiff_expand
247
+ r.sadd('{1}foo', 's1')
248
+ r.sadd('{1}foo', 's2')
249
+ r.sadd('{1}foo', 's3')
250
+ r.sadd('{1}bar', 's3')
251
+ r.sadd('{1}bar', 's4')
252
+ r.sadd('{1}bar', 's5')
253
+ assert_equal %w[s1 s2], r.sdiff('{1}foo', '{1}bar').sort
254
+ end
255
+
256
+ def test_sdiffstore
257
+ r.sadd 'foo', 's1'
258
+ r.sadd 'foo', 's2'
259
+ r.sadd 'bar', 's2'
260
+ r.sadd 'bar', 's3'
261
+
262
+ r.sdiffstore('baz', 'foo', 'bar')
263
+
264
+ assert_equal ['s1'], r.smembers('baz')
265
+ end
266
+
267
+ def test_variadic_sdiffstore_expand
268
+ r.sadd('{1}foo', 's1')
269
+ r.sadd('{1}foo', 's2')
270
+ r.sadd('{1}foo', 's3')
271
+ r.sadd('{1}bar', 's3')
272
+ r.sadd('{1}bar', 's4')
273
+ r.sadd('{1}bar', 's5')
274
+ assert_equal 2, r.sdiffstore('{1}baz', '{1}foo', '{1}bar')
275
+ end
276
+
277
+ def test_sscan
278
+ r.sadd('foo', %w[1 2 3 foo foobar feelsgood])
279
+ assert_equal %w[0 feelsgood foo foobar], r.sscan('foo', 0, match: 'f*').flatten.sort
280
+ end
139
281
  end
140
282
  end
@@ -41,7 +41,8 @@ module Lint
41
41
  assert_equal 11.0, r.zadd("foo", 10, "s1", :incr => true)
42
42
  assert_equal(-Infinity, r.zadd("bar", "-inf", "s1", :incr => true))
43
43
  assert_equal(+Infinity, r.zadd("bar", "+inf", "s2", :incr => true))
44
- r.del "foo", "bar"
44
+ r.del 'foo'
45
+ r.del 'bar'
45
46
 
46
47
  # Incompatible options combination
47
48
  assert_raise(Redis::CommandError) { r.zadd("foo", 1, "s1", :xx => true, :nx => true) }
@@ -104,7 +105,8 @@ module Lint
104
105
  assert_equal(-Infinity, r.zadd("bar", ["-inf", "s1"], :incr => true))
105
106
  assert_equal(+Infinity, r.zadd("bar", ["+inf", "s2"], :incr => true))
106
107
  assert_raise(Redis::CommandError) { r.zadd("foo", [1, "s1", 2, "s2"], :incr => true) }
107
- r.del "foo", "bar"
108
+ r.del 'foo'
109
+ r.del 'bar'
108
110
 
109
111
  # Incompatible options combination
110
112
  assert_raise(Redis::CommandError) { r.zadd("foo", [1, "s1"], :xx => true, :nx => true) }
@@ -312,5 +314,184 @@ module Lint
312
314
  assert_equal 3, r.zremrangebyscore("foo", 2, 4)
313
315
  assert_equal ["s1"], r.zrange("foo", 0, -1)
314
316
  end
317
+
318
+ def test_zpopmax
319
+ target_version('4.9.0') do
320
+ r.zadd('foo', %w[0 a 1 b 2 c])
321
+ assert_equal %w[c 2], r.zpopmax('foo')
322
+ end
323
+ end
324
+
325
+ def test_zpopmin
326
+ target_version('4.9.0') do
327
+ r.zadd('foo', %w[0 a 1 b 2 c])
328
+ assert_equal %w[a 0], r.zpopmin('foo')
329
+ end
330
+ end
331
+
332
+ def test_zremrangebylex
333
+ r.zadd('foo', %w[0 a 0 b 0 c 0 d 0 e 0 f 0 g])
334
+ assert_equal 5, r.zremrangebylex('foo', '(b', '[g')
335
+ end
336
+
337
+ def test_zlexcount
338
+ target_version '2.8.9' do
339
+ r.zadd 'foo', 0, 'aaren'
340
+ r.zadd 'foo', 0, 'abagael'
341
+ r.zadd 'foo', 0, 'abby'
342
+ r.zadd 'foo', 0, 'abbygail'
343
+
344
+ assert_equal 4, r.zlexcount('foo', '[a', "[a\xff")
345
+ assert_equal 4, r.zlexcount('foo', '[aa', "[ab\xff")
346
+ assert_equal 3, r.zlexcount('foo', '(aaren', "[ab\xff")
347
+ assert_equal 2, r.zlexcount('foo', '[aba', '(abbygail')
348
+ assert_equal 1, r.zlexcount('foo', '(aaren', '(abby')
349
+ end
350
+ end
351
+
352
+ def test_zrangebylex
353
+ target_version '2.8.9' do
354
+ r.zadd 'foo', 0, 'aaren'
355
+ r.zadd 'foo', 0, 'abagael'
356
+ r.zadd 'foo', 0, 'abby'
357
+ r.zadd 'foo', 0, 'abbygail'
358
+
359
+ assert_equal %w[aaren abagael abby abbygail], r.zrangebylex('foo', '[a', "[a\xff")
360
+ assert_equal %w[aaren abagael], r.zrangebylex('foo', '[a', "[a\xff", limit: [0, 2])
361
+ assert_equal %w[abby abbygail], r.zrangebylex('foo', '(abb', "(abb\xff")
362
+ assert_equal %w[abbygail], r.zrangebylex('foo', '(abby', "(abby\xff")
363
+ end
364
+ end
365
+
366
+ def test_zrevrangebylex
367
+ target_version '2.9.9' do
368
+ r.zadd 'foo', 0, 'aaren'
369
+ r.zadd 'foo', 0, 'abagael'
370
+ r.zadd 'foo', 0, 'abby'
371
+ r.zadd 'foo', 0, 'abbygail'
372
+
373
+ assert_equal %w[abbygail abby abagael aaren], r.zrevrangebylex('foo', "[a\xff", '[a')
374
+ assert_equal %w[abbygail abby], r.zrevrangebylex('foo', "[a\xff", '[a', limit: [0, 2])
375
+ assert_equal %w[abbygail abby], r.zrevrangebylex('foo', "(abb\xff", '(abb')
376
+ assert_equal %w[abbygail], r.zrevrangebylex('foo', "(abby\xff", '(abby')
377
+ end
378
+ end
379
+
380
+ def test_zcount
381
+ r.zadd 'foo', 1, 's1'
382
+ r.zadd 'foo', 2, 's2'
383
+ r.zadd 'foo', 3, 's3'
384
+
385
+ assert_equal 2, r.zcount('foo', 2, 3)
386
+ end
387
+
388
+ def test_zunionstore
389
+ r.zadd 'foo', 1, 's1'
390
+ r.zadd 'bar', 2, 's2'
391
+ r.zadd 'foo', 3, 's3'
392
+ r.zadd 'bar', 4, 's4'
393
+
394
+ assert_equal 4, r.zunionstore('foobar', %w[foo bar])
395
+ assert_equal %w[s1 s2 s3 s4], r.zrange('foobar', 0, -1)
396
+ end
397
+
398
+ def test_zunionstore_with_weights
399
+ r.zadd 'foo', 1, 's1'
400
+ r.zadd 'foo', 3, 's3'
401
+ r.zadd 'bar', 20, 's2'
402
+ r.zadd 'bar', 40, 's4'
403
+
404
+ assert_equal 4, r.zunionstore('foobar', %w[foo bar])
405
+ assert_equal %w[s1 s3 s2 s4], r.zrange('foobar', 0, -1)
406
+
407
+ assert_equal 4, r.zunionstore('foobar', %w[foo bar], weights: [10, 1])
408
+ assert_equal %w[s1 s2 s3 s4], r.zrange('foobar', 0, -1)
409
+ end
410
+
411
+ def test_zunionstore_with_aggregate
412
+ r.zadd 'foo', 1, 's1'
413
+ r.zadd 'foo', 2, 's2'
414
+ r.zadd 'bar', 4, 's2'
415
+ r.zadd 'bar', 3, 's3'
416
+
417
+ assert_equal 3, r.zunionstore('foobar', %w[foo bar])
418
+ assert_equal %w[s1 s3 s2], r.zrange('foobar', 0, -1)
419
+
420
+ assert_equal 3, r.zunionstore('foobar', %w[foo bar], aggregate: :min)
421
+ assert_equal %w[s1 s2 s3], r.zrange('foobar', 0, -1)
422
+
423
+ assert_equal 3, r.zunionstore('foobar', %w[foo bar], aggregate: :max)
424
+ assert_equal %w[s1 s3 s2], r.zrange('foobar', 0, -1)
425
+ end
426
+
427
+ def test_zunionstore_expand
428
+ r.zadd('{1}foo', %w[0 a 1 b 2 c])
429
+ r.zadd('{1}bar', %w[0 c 1 d 2 e])
430
+ assert_equal 5, r.zunionstore('{1}baz', %w[{1}foo {1}bar])
431
+ end
432
+
433
+ def test_zinterstore
434
+ r.zadd 'foo', 1, 's1'
435
+ r.zadd 'bar', 2, 's1'
436
+ r.zadd 'foo', 3, 's3'
437
+ r.zadd 'bar', 4, 's4'
438
+
439
+ assert_equal 1, r.zinterstore('foobar', %w[foo bar])
440
+ assert_equal ['s1'], r.zrange('foobar', 0, -1)
441
+ end
442
+
443
+ def test_zinterstore_with_weights
444
+ r.zadd 'foo', 1, 's1'
445
+ r.zadd 'foo', 2, 's2'
446
+ r.zadd 'foo', 3, 's3'
447
+ r.zadd 'bar', 20, 's2'
448
+ r.zadd 'bar', 30, 's3'
449
+ r.zadd 'bar', 40, 's4'
450
+
451
+ assert_equal 2, r.zinterstore('foobar', %w[foo bar])
452
+ assert_equal %w[s2 s3], r.zrange('foobar', 0, -1)
453
+
454
+ assert_equal 2, r.zinterstore('foobar', %w[foo bar], weights: [10, 1])
455
+ assert_equal %w[s2 s3], r.zrange('foobar', 0, -1)
456
+
457
+ assert_equal 40.0, r.zscore('foobar', 's2')
458
+ assert_equal 60.0, r.zscore('foobar', 's3')
459
+ end
460
+
461
+ def test_zinterstore_with_aggregate
462
+ r.zadd 'foo', 1, 's1'
463
+ r.zadd 'foo', 2, 's2'
464
+ r.zadd 'foo', 3, 's3'
465
+ r.zadd 'bar', 20, 's2'
466
+ r.zadd 'bar', 30, 's3'
467
+ r.zadd 'bar', 40, 's4'
468
+
469
+ assert_equal 2, r.zinterstore('foobar', %w[foo bar])
470
+ assert_equal %w[s2 s3], r.zrange('foobar', 0, -1)
471
+ assert_equal 22.0, r.zscore('foobar', 's2')
472
+ assert_equal 33.0, r.zscore('foobar', 's3')
473
+
474
+ assert_equal 2, r.zinterstore('foobar', %w[foo bar], aggregate: :min)
475
+ assert_equal %w[s2 s3], r.zrange('foobar', 0, -1)
476
+ assert_equal 2.0, r.zscore('foobar', 's2')
477
+ assert_equal 3.0, r.zscore('foobar', 's3')
478
+
479
+ assert_equal 2, r.zinterstore('foobar', %w[foo bar], aggregate: :max)
480
+ assert_equal %w[s2 s3], r.zrange('foobar', 0, -1)
481
+ assert_equal 20.0, r.zscore('foobar', 's2')
482
+ assert_equal 30.0, r.zscore('foobar', 's3')
483
+ end
484
+
485
+ def test_zinterstore_expand
486
+ r.zadd '{1}foo', %w[0 s1 1 s2 2 s3]
487
+ r.zadd '{1}bar', %w[0 s3 1 s4 2 s5]
488
+ assert_equal 1, r.zinterstore('{1}baz', %w[{1}foo {1}bar], weights: [2.0, 3.0])
489
+ end
490
+
491
+ def test_zscan
492
+ r.zadd('foo', %w[0 a 1 b 2 c])
493
+ expected = ['0', [['a', 0.0], ['b', 1.0], ['c', 2.0]]]
494
+ assert_equal expected, r.zscan('foo', 0)
495
+ end
315
496
  end
316
497
  end