redis 3.2.0 → 4.6.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.
Files changed (133) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +278 -15
  3. data/README.md +260 -76
  4. data/lib/redis/client.rb +239 -115
  5. data/lib/redis/cluster/command.rb +79 -0
  6. data/lib/redis/cluster/command_loader.rb +33 -0
  7. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  8. data/lib/redis/cluster/node.rb +120 -0
  9. data/lib/redis/cluster/node_key.rb +31 -0
  10. data/lib/redis/cluster/node_loader.rb +37 -0
  11. data/lib/redis/cluster/option.rb +93 -0
  12. data/lib/redis/cluster/slot.rb +86 -0
  13. data/lib/redis/cluster/slot_loader.rb +49 -0
  14. data/lib/redis/cluster.rb +315 -0
  15. data/lib/redis/commands/bitmaps.rb +63 -0
  16. data/lib/redis/commands/cluster.rb +45 -0
  17. data/lib/redis/commands/connection.rb +58 -0
  18. data/lib/redis/commands/geo.rb +84 -0
  19. data/lib/redis/commands/hashes.rb +251 -0
  20. data/lib/redis/commands/hyper_log_log.rb +37 -0
  21. data/lib/redis/commands/keys.rb +411 -0
  22. data/lib/redis/commands/lists.rb +289 -0
  23. data/lib/redis/commands/pubsub.rb +72 -0
  24. data/lib/redis/commands/scripting.rb +114 -0
  25. data/lib/redis/commands/server.rb +188 -0
  26. data/lib/redis/commands/sets.rb +207 -0
  27. data/lib/redis/commands/sorted_sets.rb +804 -0
  28. data/lib/redis/commands/streams.rb +382 -0
  29. data/lib/redis/commands/strings.rb +313 -0
  30. data/lib/redis/commands/transactions.rb +92 -0
  31. data/lib/redis/commands.rb +242 -0
  32. data/lib/redis/connection/command_helper.rb +7 -10
  33. data/lib/redis/connection/hiredis.rb +11 -6
  34. data/lib/redis/connection/registry.rb +2 -1
  35. data/lib/redis/connection/ruby.rb +173 -64
  36. data/lib/redis/connection/synchrony.rb +32 -8
  37. data/lib/redis/connection.rb +3 -1
  38. data/lib/redis/distributed.rb +233 -74
  39. data/lib/redis/errors.rb +48 -0
  40. data/lib/redis/hash_ring.rb +30 -72
  41. data/lib/redis/pipeline.rb +145 -12
  42. data/lib/redis/subscribe.rb +20 -13
  43. data/lib/redis/version.rb +3 -1
  44. data/lib/redis.rb +171 -2476
  45. metadata +71 -165
  46. data/.gitignore +0 -15
  47. data/.travis/Gemfile +0 -11
  48. data/.travis.yml +0 -54
  49. data/.yardopts +0 -3
  50. data/Gemfile +0 -4
  51. data/Rakefile +0 -68
  52. data/benchmarking/logging.rb +0 -71
  53. data/benchmarking/pipeline.rb +0 -51
  54. data/benchmarking/speed.rb +0 -21
  55. data/benchmarking/suite.rb +0 -24
  56. data/benchmarking/worker.rb +0 -71
  57. data/examples/basic.rb +0 -15
  58. data/examples/consistency.rb +0 -114
  59. data/examples/dist_redis.rb +0 -43
  60. data/examples/incr-decr.rb +0 -17
  61. data/examples/list.rb +0 -26
  62. data/examples/pubsub.rb +0 -37
  63. data/examples/sentinel/sentinel.conf +0 -9
  64. data/examples/sentinel/start +0 -49
  65. data/examples/sentinel.rb +0 -41
  66. data/examples/sets.rb +0 -36
  67. data/examples/unicorn/config.ru +0 -3
  68. data/examples/unicorn/unicorn.rb +0 -20
  69. data/redis.gemspec +0 -43
  70. data/test/bitpos_test.rb +0 -69
  71. data/test/blocking_commands_test.rb +0 -42
  72. data/test/command_map_test.rb +0 -30
  73. data/test/commands_on_hashes_test.rb +0 -21
  74. data/test/commands_on_hyper_log_log_test.rb +0 -21
  75. data/test/commands_on_lists_test.rb +0 -20
  76. data/test/commands_on_sets_test.rb +0 -77
  77. data/test/commands_on_sorted_sets_test.rb +0 -123
  78. data/test/commands_on_strings_test.rb +0 -101
  79. data/test/commands_on_value_types_test.rb +0 -131
  80. data/test/connection_handling_test.rb +0 -189
  81. data/test/db/.gitkeep +0 -0
  82. data/test/distributed_blocking_commands_test.rb +0 -46
  83. data/test/distributed_commands_on_hashes_test.rb +0 -10
  84. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  85. data/test/distributed_commands_on_lists_test.rb +0 -22
  86. data/test/distributed_commands_on_sets_test.rb +0 -83
  87. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  88. data/test/distributed_commands_on_strings_test.rb +0 -59
  89. data/test/distributed_commands_on_value_types_test.rb +0 -95
  90. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  91. data/test/distributed_connection_handling_test.rb +0 -23
  92. data/test/distributed_internals_test.rb +0 -70
  93. data/test/distributed_key_tags_test.rb +0 -52
  94. data/test/distributed_persistence_control_commands_test.rb +0 -26
  95. data/test/distributed_publish_subscribe_test.rb +0 -92
  96. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  97. data/test/distributed_scripting_test.rb +0 -102
  98. data/test/distributed_sorting_test.rb +0 -20
  99. data/test/distributed_test.rb +0 -58
  100. data/test/distributed_transactions_test.rb +0 -32
  101. data/test/encoding_test.rb +0 -18
  102. data/test/error_replies_test.rb +0 -59
  103. data/test/fork_safety_test.rb +0 -65
  104. data/test/helper.rb +0 -232
  105. data/test/helper_test.rb +0 -24
  106. data/test/internals_test.rb +0 -434
  107. data/test/lint/blocking_commands.rb +0 -150
  108. data/test/lint/hashes.rb +0 -162
  109. data/test/lint/hyper_log_log.rb +0 -60
  110. data/test/lint/lists.rb +0 -143
  111. data/test/lint/sets.rb +0 -125
  112. data/test/lint/sorted_sets.rb +0 -238
  113. data/test/lint/strings.rb +0 -260
  114. data/test/lint/value_types.rb +0 -122
  115. data/test/persistence_control_commands_test.rb +0 -26
  116. data/test/pipelining_commands_test.rb +0 -242
  117. data/test/publish_subscribe_test.rb +0 -210
  118. data/test/remote_server_control_commands_test.rb +0 -117
  119. data/test/scanning_test.rb +0 -413
  120. data/test/scripting_test.rb +0 -78
  121. data/test/sorting_test.rb +0 -59
  122. data/test/support/connection/hiredis.rb +0 -1
  123. data/test/support/connection/ruby.rb +0 -1
  124. data/test/support/connection/synchrony.rb +0 -17
  125. data/test/support/redis_mock.rb +0 -115
  126. data/test/support/wire/synchrony.rb +0 -24
  127. data/test/support/wire/thread.rb +0 -5
  128. data/test/synchrony_driver.rb +0 -88
  129. data/test/test.conf +0 -9
  130. data/test/thread_safety_test.rb +0 -32
  131. data/test/transactions_test.rb +0 -264
  132. data/test/unknown_commands_test.rb +0 -14
  133. data/test/url_param_test.rb +0 -132
@@ -1,413 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- unless defined?(Enumerator)
6
- Enumerator = Enumerable::Enumerator
7
- end
8
-
9
- class TestScanning < Test::Unit::TestCase
10
-
11
- include Helper::Client
12
-
13
- def test_scan_basic
14
- target_version "2.7.105" do
15
- r.debug :populate, 1000
16
-
17
- cursor = 0
18
- all_keys = []
19
- loop {
20
- cursor, keys = r.scan cursor
21
- all_keys += keys
22
- break if cursor == "0"
23
- }
24
-
25
- assert_equal 1000, all_keys.uniq.size
26
- end
27
- end
28
-
29
- def test_scan_count
30
- target_version "2.7.105" do
31
- r.debug :populate, 1000
32
-
33
- cursor = 0
34
- all_keys = []
35
- loop {
36
- cursor, keys = r.scan cursor, :count => 5
37
- all_keys += keys
38
- break if cursor == "0"
39
- }
40
-
41
- assert_equal 1000, all_keys.uniq.size
42
- end
43
- end
44
-
45
- def test_scan_match
46
- target_version "2.7.105" do
47
- r.debug :populate, 1000
48
-
49
- cursor = 0
50
- all_keys = []
51
- loop {
52
- cursor, keys = r.scan cursor, :match => "key:1??"
53
- all_keys += keys
54
- break if cursor == "0"
55
- }
56
-
57
- assert_equal 100, all_keys.uniq.size
58
- end
59
- end
60
-
61
- def test_scan_each_enumerator
62
- target_version "2.7.105" do
63
-
64
- r.debug :populate, 1000
65
-
66
- scan_enumerator = r.scan_each
67
- assert_equal true, scan_enumerator.is_a?(::Enumerator)
68
-
69
- keys_from_scan = scan_enumerator.to_a.uniq
70
- all_keys = r.keys "*"
71
-
72
- assert all_keys.sort == keys_from_scan.sort
73
- end
74
- end
75
-
76
- def test_scan_each_enumerator_match
77
- target_version "2.7.105" do
78
-
79
- r.debug :populate, 1000
80
-
81
- keys_from_scan = r.scan_each(:match => "key:1??").to_a.uniq
82
- all_keys = r.keys "key:1??"
83
-
84
- assert all_keys.sort == keys_from_scan.sort
85
- end
86
- end
87
-
88
- def test_scan_each_block
89
- target_version "2.7.105" do
90
-
91
- r.debug :populate, 100
92
-
93
- keys_from_scan = []
94
- r.scan_each {|key|
95
- keys_from_scan << key
96
- }
97
-
98
- all_keys = r.keys "*"
99
-
100
- assert all_keys.sort == keys_from_scan.uniq.sort
101
- end
102
- end
103
-
104
- def test_scan_each_block_match
105
- target_version "2.7.105" do
106
-
107
- r.debug :populate, 100
108
-
109
- keys_from_scan = []
110
- r.scan_each(:match => "key:1?") {|key|
111
- keys_from_scan << key
112
- }
113
-
114
- all_keys = r.keys "key:1?"
115
-
116
- assert all_keys.sort == keys_from_scan.uniq.sort
117
- end
118
- end
119
-
120
- def test_sscan_with_encoding
121
- target_version "2.7.105" do
122
- [:intset, :hashtable].each do |enc|
123
- r.del "set"
124
-
125
- prefix = ""
126
- prefix = "ele:" if enc == :hashtable
127
-
128
- elements = []
129
- 100.times { |j| elements << "#{prefix}#{j}" }
130
-
131
- r.sadd "set", elements
132
-
133
- assert_equal enc.to_s, r.object("encoding", "set")
134
-
135
- cursor = 0
136
- all_keys = []
137
- loop {
138
- cursor, keys = r.sscan "set", cursor
139
- all_keys += keys
140
- break if cursor == "0"
141
- }
142
-
143
- assert_equal 100, all_keys.uniq.size
144
- end
145
- end
146
- end
147
-
148
- def test_sscan_each_enumerator
149
- target_version "2.7.105" do
150
- elements = []
151
- 100.times { |j| elements << "ele:#{j}" }
152
- r.sadd "set", elements
153
-
154
- scan_enumerator = r.sscan_each("set")
155
- assert_equal true, scan_enumerator.is_a?(::Enumerator)
156
-
157
- keys_from_scan = scan_enumerator.to_a.uniq
158
- all_keys = r.smembers("set")
159
-
160
- assert all_keys.sort == keys_from_scan.sort
161
- end
162
- end
163
-
164
- def test_sscan_each_enumerator_match
165
- target_version "2.7.105" do
166
- elements = []
167
- 100.times { |j| elements << "ele:#{j}" }
168
- r.sadd "set", elements
169
-
170
- keys_from_scan = r.sscan_each("set", :match => "ele:1?").to_a.uniq
171
-
172
- all_keys = r.smembers("set").grep(/^ele:1.$/)
173
-
174
- assert all_keys.sort == keys_from_scan.sort
175
- end
176
- end
177
-
178
- def test_sscan_each_enumerator_block
179
- target_version "2.7.105" do
180
- elements = []
181
- 100.times { |j| elements << "ele:#{j}" }
182
- r.sadd "set", elements
183
-
184
- keys_from_scan = []
185
- r.sscan_each("set") do |key|
186
- keys_from_scan << key
187
- end
188
-
189
- all_keys = r.smembers("set")
190
-
191
- assert all_keys.sort == keys_from_scan.uniq.sort
192
- end
193
- end
194
-
195
- def test_sscan_each_enumerator_block_match
196
- target_version "2.7.105" do
197
- elements = []
198
- 100.times { |j| elements << "ele:#{j}" }
199
- r.sadd "set", elements
200
-
201
- keys_from_scan = []
202
- r.sscan_each("set", :match => "ele:1?") do |key|
203
- keys_from_scan << key
204
- end
205
-
206
- all_keys = r.smembers("set").grep(/^ele:1.$/)
207
-
208
- assert all_keys.sort == keys_from_scan.uniq.sort
209
- end
210
- end
211
-
212
- def test_hscan_with_encoding
213
- target_version "2.7.105" do
214
- [:ziplist, :hashtable].each do |enc|
215
- r.del "set"
216
-
217
- count = 1000
218
- count = 30 if enc == :ziplist
219
-
220
- elements = []
221
- count.times { |j| elements << "key:#{j}" << j.to_s }
222
-
223
- r.hmset "hash", *elements
224
-
225
- assert_equal enc.to_s, r.object("encoding", "hash")
226
-
227
- cursor = 0
228
- all_key_values = []
229
- loop {
230
- cursor, key_values = r.hscan "hash", cursor
231
- all_key_values.concat key_values
232
- break if cursor == "0"
233
- }
234
-
235
- keys2 = []
236
- all_key_values.each do |k, v|
237
- assert_equal "key:#{v}", k
238
- keys2 << k
239
- end
240
-
241
- assert_equal count, keys2.uniq.size
242
- end
243
- end
244
- end
245
-
246
- def test_hscan_each_enumerator
247
- target_version "2.7.105" do
248
- count = 1000
249
- elements = []
250
- count.times { |j| elements << "key:#{j}" << j.to_s }
251
- r.hmset "hash", *elements
252
-
253
- scan_enumerator = r.hscan_each("hash")
254
- assert_equal true, scan_enumerator.is_a?(::Enumerator)
255
-
256
- keys_from_scan = scan_enumerator.to_a.uniq
257
- all_keys = r.hgetall("hash").to_a
258
-
259
- assert all_keys.sort == keys_from_scan.sort
260
- end
261
- end
262
-
263
- def test_hscan_each_enumerator_match
264
- target_version "2.7.105" do
265
- count = 100
266
- elements = []
267
- count.times { |j| elements << "key:#{j}" << j.to_s }
268
- r.hmset "hash", *elements
269
-
270
- keys_from_scan = r.hscan_each("hash", :match => "key:1?").to_a.uniq
271
- all_keys = r.hgetall("hash").to_a.select{|k,v| k =~ /^key:1.$/}
272
-
273
- assert all_keys.sort == keys_from_scan.sort
274
- end
275
- end
276
-
277
- def test_hscan_each_block
278
- target_version "2.7.105" do
279
- count = 1000
280
- elements = []
281
- count.times { |j| elements << "key:#{j}" << j.to_s }
282
- r.hmset "hash", *elements
283
-
284
- keys_from_scan = []
285
- r.hscan_each("hash") do |field, value|
286
- keys_from_scan << [field, value]
287
- end
288
- all_keys = r.hgetall("hash").to_a
289
-
290
- assert all_keys.sort == keys_from_scan.uniq.sort
291
- end
292
- end
293
-
294
- def test_hscan_each_block_match
295
- target_version "2.7.105" do
296
- count = 1000
297
- elements = []
298
- count.times { |j| elements << "key:#{j}" << j.to_s }
299
- r.hmset "hash", *elements
300
-
301
- keys_from_scan = []
302
- r.hscan_each("hash", :match => "key:1?") do |field, value|
303
- keys_from_scan << [field, value]
304
- end
305
- all_keys = r.hgetall("hash").to_a.select{|k,v| k =~ /^key:1.$/}
306
-
307
- assert all_keys.sort == keys_from_scan.uniq.sort
308
- end
309
- end
310
-
311
- def test_zscan_with_encoding
312
- target_version "2.7.105" do
313
- [:ziplist, :skiplist].each do |enc|
314
- r.del "zset"
315
-
316
- count = 1000
317
- count = 30 if enc == :ziplist
318
-
319
- elements = []
320
- count.times { |j| elements << j << "key:#{j}" }
321
-
322
- r.zadd "zset", elements
323
-
324
- assert_equal enc.to_s, r.object("encoding", "zset")
325
-
326
- cursor = 0
327
- all_key_scores = []
328
- loop {
329
- cursor, key_scores = r.zscan "zset", cursor
330
- all_key_scores.concat key_scores
331
- break if cursor == "0"
332
- }
333
-
334
- keys2 = []
335
- all_key_scores.each do |k, v|
336
- assert_equal true, v.is_a?(Float)
337
- assert_equal "key:#{Integer(v)}", k
338
- keys2 << k
339
- end
340
-
341
- assert_equal count, keys2.uniq.size
342
- end
343
- end
344
- end
345
-
346
- def test_zscan_each_enumerator
347
- target_version "2.7.105" do
348
- count = 1000
349
- elements = []
350
- count.times { |j| elements << j << "key:#{j}" }
351
- r.zadd "zset", elements
352
-
353
- scan_enumerator = r.zscan_each "zset"
354
- assert_equal true, scan_enumerator.is_a?(::Enumerator)
355
-
356
- scores_from_scan = scan_enumerator.to_a.uniq
357
- member_scores = r.zrange("zset", 0, -1, :with_scores => true)
358
-
359
- assert member_scores.sort == scores_from_scan.sort
360
- end
361
- end
362
-
363
- def test_zscan_each_enumerator_match
364
- target_version "2.7.105" do
365
- count = 1000
366
- elements = []
367
- count.times { |j| elements << j << "key:#{j}" }
368
- r.zadd "zset", elements
369
-
370
- scores_from_scan = r.zscan_each("zset", :match => "key:1??").to_a.uniq
371
- member_scores = r.zrange("zset", 0, -1, :with_scores => true)
372
- filtered_members = member_scores.select{|k,s| k =~ /^key:1..$/}
373
-
374
- assert filtered_members.sort == scores_from_scan.sort
375
- end
376
- end
377
-
378
- def test_zscan_each_block
379
- target_version "2.7.105" do
380
- count = 1000
381
- elements = []
382
- count.times { |j| elements << j << "key:#{j}" }
383
- r.zadd "zset", elements
384
-
385
- scores_from_scan = []
386
- r.zscan_each("zset") do |member, score|
387
- scores_from_scan << [member, score]
388
- end
389
- member_scores = r.zrange("zset", 0, -1, :with_scores => true)
390
-
391
- assert member_scores.sort == scores_from_scan.sort
392
- end
393
- end
394
-
395
- def test_zscan_each_block_match
396
- target_version "2.7.105" do
397
- count = 1000
398
- elements = []
399
- count.times { |j| elements << j << "key:#{j}" }
400
- r.zadd "zset", elements
401
-
402
- scores_from_scan = []
403
- r.zscan_each("zset", :match => "key:1??") do |member, score|
404
- scores_from_scan << [member, score]
405
- end
406
- member_scores = r.zrange("zset", 0, -1, :with_scores => true)
407
- filtered_members = member_scores.select{|k,s| k =~ /^key:1..$/}
408
-
409
- assert filtered_members.sort == scores_from_scan.sort
410
- end
411
- end
412
-
413
- end
@@ -1,78 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class TestScripting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def to_sha(script)
10
- r.script(:load, script)
11
- end
12
-
13
- def test_script_exists
14
- target_version "2.5.9" do # 2.6-rc1
15
- a = to_sha("return 1")
16
- b = a.succ
17
-
18
- assert_equal true, r.script(:exists, a)
19
- assert_equal false, r.script(:exists, b)
20
- assert_equal [true], r.script(:exists, [a])
21
- assert_equal [false], r.script(:exists, [b])
22
- assert_equal [true, false], r.script(:exists, [a, b])
23
- end
24
- end
25
-
26
- def test_script_flush
27
- target_version "2.5.9" do # 2.6-rc1
28
- sha = to_sha("return 1")
29
- assert r.script(:exists, sha)
30
- assert_equal "OK", r.script(:flush)
31
- assert !r.script(:exists, sha)
32
- end
33
- end
34
-
35
- def test_script_kill
36
- target_version "2.5.9" do # 2.6-rc1
37
- redis_mock(:script => lambda { |arg| "+#{arg.upcase}" }) do |redis|
38
- assert_equal "KILL", redis.script(:kill)
39
- end
40
- end
41
- end
42
-
43
- def test_eval
44
- target_version "2.5.9" do # 2.6-rc1
45
- assert_equal 0, r.eval("return #KEYS")
46
- assert_equal 0, r.eval("return #ARGV")
47
- assert_equal ["k1", "k2"], r.eval("return KEYS", ["k1", "k2"])
48
- assert_equal ["a1", "a2"], r.eval("return ARGV", [], ["a1", "a2"])
49
- end
50
- end
51
-
52
- def test_eval_with_options_hash
53
- target_version "2.5.9" do # 2.6-rc1
54
- assert_equal 0, r.eval("return #KEYS", {})
55
- assert_equal 0, r.eval("return #ARGV", {})
56
- assert_equal ["k1", "k2"], r.eval("return KEYS", { :keys => ["k1", "k2"] })
57
- assert_equal ["a1", "a2"], r.eval("return ARGV", { :argv => ["a1", "a2"] })
58
- end
59
- end
60
-
61
- def test_evalsha
62
- target_version "2.5.9" do # 2.6-rc1
63
- assert_equal 0, r.evalsha(to_sha("return #KEYS"))
64
- assert_equal 0, r.evalsha(to_sha("return #ARGV"))
65
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), ["k1", "k2"])
66
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), [], ["a1", "a2"])
67
- end
68
- end
69
-
70
- def test_evalsha_with_options_hash
71
- target_version "2.5.9" do # 2.6-rc1
72
- assert_equal 0, r.evalsha(to_sha("return #KEYS"), {})
73
- assert_equal 0, r.evalsha(to_sha("return #ARGV"), {})
74
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), { :keys => ["k1", "k2"] })
75
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), { :argv => ["a1", "a2"] })
76
- end
77
- end
78
- end
data/test/sorting_test.rb DELETED
@@ -1,59 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class TestSorting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_sort
10
- r.set("foo:1", "s1")
11
- r.set("foo:2", "s2")
12
-
13
- r.rpush("bar", "1")
14
- r.rpush("bar", "2")
15
-
16
- assert_equal ["s1"], r.sort("bar", :get => "foo:*", :limit => [0, 1])
17
- assert_equal ["s2"], r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
18
- end
19
-
20
- def test_sort_with_an_array_of_gets
21
- r.set("foo:1:a", "s1a")
22
- r.set("foo:1:b", "s1b")
23
-
24
- r.set("foo:2:a", "s2a")
25
- r.set("foo:2:b", "s2b")
26
-
27
- r.rpush("bar", "1")
28
- r.rpush("bar", "2")
29
-
30
- assert_equal [["s1a", "s1b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
31
- assert_equal [["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
32
- assert_equal [["s1a", "s1b"], ["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"])
33
- end
34
-
35
- def test_sort_with_store
36
- r.set("foo:1", "s1")
37
- r.set("foo:2", "s2")
38
-
39
- r.rpush("bar", "1")
40
- r.rpush("bar", "2")
41
-
42
- r.sort("bar", :get => "foo:*", :store => "baz")
43
- assert_equal ["s1", "s2"], r.lrange("baz", 0, -1)
44
- end
45
-
46
- def test_sort_with_an_array_of_gets_and_with_store
47
- r.set("foo:1:a", "s1a")
48
- r.set("foo:1:b", "s1b")
49
-
50
- r.set("foo:2:a", "s2a")
51
- r.set("foo:2:b", "s2b")
52
-
53
- r.rpush("bar", "1")
54
- r.rpush("bar", "2")
55
-
56
- r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :store => 'baz')
57
- assert_equal ["s1a", "s1b", "s2a", "s2b"], r.lrange("baz", 0, -1)
58
- end
59
- end
@@ -1 +0,0 @@
1
- require "support/wire/thread"
@@ -1 +0,0 @@
1
- require "support/wire/thread"
@@ -1,17 +0,0 @@
1
- require "support/wire/synchrony"
2
-
3
- module Helper
4
- def around
5
- rv = nil
6
-
7
- EM.synchrony do
8
- begin
9
- rv = yield
10
- ensure
11
- EM.stop
12
- end
13
- end
14
-
15
- rv
16
- end
17
- end
@@ -1,115 +0,0 @@
1
- require "socket"
2
-
3
- module RedisMock
4
- class Server
5
- VERBOSE = false
6
-
7
- def initialize(port, options = {}, &block)
8
- @server = TCPServer.new(options[:host] || "127.0.0.1", port)
9
- @server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
10
- end
11
-
12
- def start(&block)
13
- @thread = Thread.new { run(&block) }
14
- end
15
-
16
- # Bail out of @server.accept before closing the socket. This is required
17
- # to avoid EADDRINUSE after a couple of iterations.
18
- def shutdown
19
- @thread.terminate if @thread
20
- @server.close if @server
21
- rescue => ex
22
- $stderr.puts "Error closing mock server: #{ex.message}" if VERBOSE
23
- $stderr.puts ex.backtrace if VERBOSE
24
- end
25
-
26
- def run
27
- loop do
28
- session = @server.accept
29
-
30
- begin
31
- return if yield(session) == :exit
32
- ensure
33
- session.close
34
- end
35
- end
36
- rescue => ex
37
- $stderr.puts "Error running mock server: #{ex.message}" if VERBOSE
38
- $stderr.puts ex.backtrace if VERBOSE
39
- ensure
40
- @server.close
41
- end
42
- end
43
-
44
- MOCK_PORT = 6382
45
-
46
- # Starts a mock Redis server in a thread.
47
- #
48
- # The server will use the lambda handler passed as argument to handle
49
- # connections. For example:
50
- #
51
- # handler = lambda { |session| session.close }
52
- # RedisMock.start_with_handler(handler) do
53
- # # Every connection will be closed immediately
54
- # end
55
- #
56
- def self.start_with_handler(blk, options = {})
57
- server = Server.new(MOCK_PORT, options)
58
-
59
- begin
60
- server.start(&blk)
61
-
62
- yield(MOCK_PORT)
63
-
64
- ensure
65
- server.shutdown
66
- end
67
- end
68
-
69
- # Starts a mock Redis server in a thread.
70
- #
71
- # The server will reply with a `+OK` to all commands, but you can
72
- # customize it by providing a hash. For example:
73
- #
74
- # RedisMock.start(:ping => lambda { "+PONG" }) do
75
- # assert_equal "PONG", Redis.new(:port => MOCK_PORT).ping
76
- # end
77
- #
78
- def self.start(commands, options = {}, &blk)
79
- handler = lambda do |session|
80
- while line = session.gets
81
- argv = Array.new(line[1..-3].to_i) do
82
- bytes = session.gets[1..-3].to_i
83
- arg = session.read(bytes)
84
- session.read(2) # Discard \r\n
85
- arg
86
- end
87
-
88
- command = argv.shift
89
- blk = commands[command.to_sym]
90
- blk ||= lambda { |*_| "+OK" }
91
-
92
- response = blk.call(*argv)
93
-
94
- # Convert a nil response to :close
95
- response ||= :close
96
-
97
- if response == :exit
98
- break :exit
99
- elsif response == :close
100
- break :close
101
- elsif response.is_a?(Array)
102
- session.write("*%d\r\n" % response.size)
103
- response.each do |e|
104
- session.write("$%d\r\n%s\r\n" % [e.length, e])
105
- end
106
- else
107
- session.write(response)
108
- session.write("\r\n") unless response.end_with?("\r\n")
109
- end
110
- end
111
- end
112
-
113
- start_with_handler(handler, options, &blk)
114
- end
115
- end
@@ -1,24 +0,0 @@
1
- class Wire < Fiber
2
- # We cannot run this fiber explicitly because EM schedules it. Resuming the
3
- # current fiber on the next tick to let the reactor do work.
4
- def self.pass
5
- f = Fiber.current
6
- EM.next_tick { f.resume }
7
- Fiber.yield
8
- end
9
-
10
- def self.sleep(sec)
11
- EM::Synchrony.sleep(sec)
12
- end
13
-
14
- def initialize(&blk)
15
- super
16
-
17
- # Schedule run in next tick
18
- EM.next_tick { resume }
19
- end
20
-
21
- def join
22
- self.class.pass while alive?
23
- end
24
- end