redis 3.3.5 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis/Gemfile +8 -1
  4. data/.travis.yml +34 -62
  5. data/CHANGELOG.md +45 -2
  6. data/Gemfile +5 -1
  7. data/README.md +32 -76
  8. data/benchmarking/logging.rb +1 -1
  9. data/bin/build +71 -0
  10. data/bors.toml +14 -0
  11. data/lib/redis/client.rb +38 -20
  12. data/lib/redis/cluster/command.rb +81 -0
  13. data/lib/redis/cluster/command_loader.rb +32 -0
  14. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  15. data/lib/redis/cluster/node.rb +104 -0
  16. data/lib/redis/cluster/node_key.rb +35 -0
  17. data/lib/redis/cluster/node_loader.rb +35 -0
  18. data/lib/redis/cluster/option.rb +76 -0
  19. data/lib/redis/cluster/slot.rb +69 -0
  20. data/lib/redis/cluster/slot_loader.rb +47 -0
  21. data/lib/redis/cluster.rb +285 -0
  22. data/lib/redis/connection/command_helper.rb +2 -8
  23. data/lib/redis/connection/hiredis.rb +2 -2
  24. data/lib/redis/connection/ruby.rb +13 -30
  25. data/lib/redis/connection/synchrony.rb +12 -4
  26. data/lib/redis/connection.rb +2 -2
  27. data/lib/redis/distributed.rb +29 -8
  28. data/lib/redis/errors.rb +46 -0
  29. data/lib/redis/hash_ring.rb +20 -64
  30. data/lib/redis/pipeline.rb +9 -7
  31. data/lib/redis/version.rb +1 -1
  32. data/lib/redis.rb +287 -52
  33. data/makefile +74 -0
  34. data/redis.gemspec +9 -10
  35. data/test/bitpos_test.rb +13 -19
  36. data/test/blocking_commands_test.rb +3 -5
  37. data/test/client_test.rb +18 -1
  38. data/test/cluster_abnormal_state_test.rb +38 -0
  39. data/test/cluster_blocking_commands_test.rb +15 -0
  40. data/test/cluster_client_internals_test.rb +77 -0
  41. data/test/cluster_client_key_hash_tags_test.rb +88 -0
  42. data/test/cluster_client_options_test.rb +147 -0
  43. data/test/cluster_client_pipelining_test.rb +59 -0
  44. data/test/cluster_client_replicas_test.rb +36 -0
  45. data/test/cluster_client_slots_test.rb +94 -0
  46. data/test/cluster_client_transactions_test.rb +71 -0
  47. data/test/cluster_commands_on_cluster_test.rb +165 -0
  48. data/test/cluster_commands_on_connection_test.rb +40 -0
  49. data/test/cluster_commands_on_geo_test.rb +74 -0
  50. data/test/cluster_commands_on_hashes_test.rb +11 -0
  51. data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
  52. data/test/cluster_commands_on_keys_test.rb +134 -0
  53. data/test/cluster_commands_on_lists_test.rb +15 -0
  54. data/test/cluster_commands_on_pub_sub_test.rb +101 -0
  55. data/test/cluster_commands_on_scripting_test.rb +56 -0
  56. data/test/cluster_commands_on_server_test.rb +221 -0
  57. data/test/cluster_commands_on_sets_test.rb +39 -0
  58. data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
  59. data/test/cluster_commands_on_streams_test.rb +196 -0
  60. data/test/cluster_commands_on_strings_test.rb +15 -0
  61. data/test/cluster_commands_on_transactions_test.rb +41 -0
  62. data/test/cluster_commands_on_value_types_test.rb +14 -0
  63. data/test/command_map_test.rb +3 -5
  64. data/test/commands_on_geo_test.rb +116 -0
  65. data/test/commands_on_hashes_test.rb +2 -16
  66. data/test/commands_on_hyper_log_log_test.rb +3 -17
  67. data/test/commands_on_lists_test.rb +2 -15
  68. data/test/commands_on_sets_test.rb +2 -72
  69. data/test/commands_on_sorted_sets_test.rb +2 -132
  70. data/test/commands_on_strings_test.rb +2 -96
  71. data/test/commands_on_value_types_test.rb +80 -6
  72. data/test/connection_handling_test.rb +5 -7
  73. data/test/distributed_blocking_commands_test.rb +10 -4
  74. data/test/distributed_commands_on_hashes_test.rb +16 -5
  75. data/test/distributed_commands_on_hyper_log_log_test.rb +8 -15
  76. data/test/distributed_commands_on_lists_test.rb +4 -7
  77. data/test/distributed_commands_on_sets_test.rb +58 -36
  78. data/test/distributed_commands_on_sorted_sets_test.rb +51 -10
  79. data/test/distributed_commands_on_strings_test.rb +30 -10
  80. data/test/distributed_commands_on_value_types_test.rb +38 -4
  81. data/test/distributed_commands_requiring_clustering_test.rb +1 -3
  82. data/test/distributed_connection_handling_test.rb +1 -3
  83. data/test/distributed_internals_test.rb +8 -19
  84. data/test/distributed_key_tags_test.rb +4 -6
  85. data/test/distributed_persistence_control_commands_test.rb +1 -3
  86. data/test/distributed_publish_subscribe_test.rb +1 -3
  87. data/test/distributed_remote_server_control_commands_test.rb +1 -3
  88. data/test/distributed_scripting_test.rb +1 -3
  89. data/test/distributed_sorting_test.rb +1 -3
  90. data/test/distributed_test.rb +12 -14
  91. data/test/distributed_transactions_test.rb +1 -3
  92. data/test/encoding_test.rb +4 -8
  93. data/test/error_replies_test.rb +2 -4
  94. data/test/fork_safety_test.rb +1 -6
  95. data/test/helper.rb +179 -66
  96. data/test/helper_test.rb +1 -3
  97. data/test/internals_test.rb +47 -56
  98. data/test/lint/blocking_commands.rb +40 -16
  99. data/test/lint/hashes.rb +41 -0
  100. data/test/lint/hyper_log_log.rb +15 -1
  101. data/test/lint/lists.rb +16 -0
  102. data/test/lint/sets.rb +142 -0
  103. data/test/lint/sorted_sets.rb +183 -2
  104. data/test/lint/strings.rb +108 -20
  105. data/test/lint/value_types.rb +8 -0
  106. data/test/persistence_control_commands_test.rb +1 -3
  107. data/test/pipelining_commands_test.rb +12 -8
  108. data/test/publish_subscribe_test.rb +1 -3
  109. data/test/remote_server_control_commands_test.rb +60 -3
  110. data/test/scanning_test.rb +1 -7
  111. data/test/scripting_test.rb +1 -3
  112. data/test/sentinel_command_test.rb +1 -3
  113. data/test/sentinel_test.rb +1 -3
  114. data/test/sorting_test.rb +1 -3
  115. data/test/ssl_test.rb +45 -49
  116. data/test/support/cluster/orchestrator.rb +199 -0
  117. data/test/support/connection/hiredis.rb +1 -1
  118. data/test/support/connection/ruby.rb +1 -1
  119. data/test/support/connection/synchrony.rb +1 -1
  120. data/test/support/redis_mock.rb +1 -1
  121. data/test/synchrony_driver.rb +6 -9
  122. data/test/thread_safety_test.rb +1 -3
  123. data/test/transactions_test.rb +11 -3
  124. data/test/unknown_commands_test.rb +1 -3
  125. data/test/url_param_test.rb +44 -46
  126. metadata +109 -16
  127. data/Rakefile +0 -87
@@ -1,18 +1,14 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestEncoding < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
6
 
9
7
  def test_returns_properly_encoded_strings
10
- if defined?(Encoding)
11
- with_external_encoding("UTF-8") do
12
- r.set "foo", "שלום"
8
+ with_external_encoding("UTF-8") do
9
+ r.set "foo", "שלום"
13
10
 
14
- assert_equal "Shalom שלום", "Shalom " + r.get("foo")
15
- end
11
+ assert_equal "Shalom שלום", "Shalom " + r.get("foo")
16
12
  end
17
13
  end
18
14
  end
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestErrorReplies < Test::Unit::TestCase
6
4
 
@@ -47,7 +45,7 @@ class TestErrorReplies < Test::Unit::TestCase
47
45
  def test_recover_from_raise_in__call_loop
48
46
  with_reconnection_check do
49
47
  begin
50
- r.client.call_loop([:invalid_monitor]) do
48
+ r._client.call_loop([:invalid_monitor]) do
51
49
  assert false # Should never be executed
52
50
  end
53
51
  rescue => ex
@@ -1,11 +1,8 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestForkSafety < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
- include Helper::Skipable
9
6
 
10
7
  driver(:ruby, :hiredis) do
11
8
  def test_fork_safety
@@ -32,7 +29,6 @@ class TestForkSafety < Test::Unit::TestCase
32
29
 
33
30
  rescue NotImplementedError => error
34
31
  raise unless error.message =~ /fork is not available/
35
- return skip(error.message)
36
32
  end
37
33
 
38
34
  def test_fork_safety_with_enabled_inherited_socket
@@ -59,7 +55,6 @@ class TestForkSafety < Test::Unit::TestCase
59
55
 
60
56
  rescue NotImplementedError => error
61
57
  raise unless error.message =~ /fork is not available/
62
- return skip(error.message)
63
58
  end
64
59
  end
65
60
  end
data/test/helper.rb CHANGED
@@ -1,62 +1,26 @@
1
- $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
- $:.unshift File.expand_path(File.dirname(__FILE__))
3
-
4
1
  require "test/unit"
2
+ require "mocha/test_unit"
5
3
  require "logger"
6
4
  require "stringio"
7
5
 
8
- (class Random; def self.rand(*args) super end; end) unless defined?(Random)
9
-
10
- begin
11
- require "ruby-debug"
12
- rescue LoadError
13
- end
14
-
15
6
  $VERBOSE = true
16
7
 
17
- ENV["conn"] ||= "ruby"
8
+ ENV["DRIVER"] ||= "ruby"
18
9
 
19
- require "redis"
20
- require "redis/distributed"
21
- require "redis/connection/#{ENV["conn"]}"
10
+ require_relative "../lib/redis"
11
+ require_relative "../lib/redis/distributed"
12
+ require_relative "../lib/redis/connection/#{ENV["DRIVER"]}"
22
13
 
23
- require "support/redis_mock"
24
- require "support/connection/#{ENV["conn"]}"
14
+ require_relative "support/redis_mock"
15
+ require_relative "support/connection/#{ENV["DRIVER"]}"
16
+ require_relative 'support/cluster/orchestrator'
25
17
 
26
18
  PORT = 6381
27
19
  OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
28
20
  NODES = ["redis://127.0.0.1:#{PORT}/15"]
29
21
 
30
- def init(redis)
31
- begin
32
- redis.select 14
33
- redis.flushdb
34
- redis.select 15
35
- redis.flushdb
36
- redis
37
- rescue Redis::CannotConnectError
38
- puts <<-EOS
39
-
40
- Cannot connect to Redis.
41
-
42
- Make sure Redis is running on localhost, port #{PORT}.
43
- This testing suite connects to the database 15.
44
-
45
- Try this once:
46
-
47
- $ rake clean
48
-
49
- Then run the build again:
50
-
51
- $ rake
52
-
53
- EOS
54
- exit 1
55
- end
56
- end
57
-
58
22
  def driver(*drivers, &blk)
59
- if drivers.map(&:to_s).include?(ENV["conn"])
23
+ if drivers.map(&:to_s).include?(ENV["DRIVER"])
60
24
  class_eval(&blk)
61
25
  end
62
26
  end
@@ -92,14 +56,6 @@ module Helper
92
56
  end
93
57
  end
94
58
 
95
- def try_encoding(encoding, &block)
96
- if defined?(Encoding)
97
- with_external_encoding(encoding, &block)
98
- else
99
- yield
100
- end
101
- end
102
-
103
59
  class Version
104
60
 
105
61
  include Comparable
@@ -151,6 +107,32 @@ module Helper
151
107
  @redis.quit if @redis
152
108
  end
153
109
 
110
+ def init(redis)
111
+ redis.select 14
112
+ redis.flushdb
113
+ redis.select 15
114
+ redis.flushdb
115
+ redis
116
+ rescue Redis::CannotConnectError
117
+ puts <<-MSG
118
+
119
+ Cannot connect to Redis.
120
+
121
+ Make sure Redis is running on localhost, port #{PORT}.
122
+ This testing suite connects to the database 15.
123
+
124
+ Try this once:
125
+
126
+ $ make clean
127
+
128
+ Then run the build again:
129
+
130
+ $ make
131
+
132
+ MSG
133
+ exit 1
134
+ end
135
+
154
136
  def redis_mock(commands, options = {}, &blk)
155
137
  RedisMock.start(commands, options) do |port|
156
138
  yield _new_client(options.merge(:port => port))
@@ -174,16 +156,16 @@ module Helper
174
156
  yield
175
157
  end
176
158
  end
159
+
160
+ def version
161
+ Version.new(redis.info['redis_version'])
162
+ end
177
163
  end
178
164
 
179
165
  module Client
180
166
 
181
167
  include Generic
182
168
 
183
- def version
184
- Version.new(redis.info["redis_version"])
185
- end
186
-
187
169
  private
188
170
 
189
171
  def _format_options(options)
@@ -191,7 +173,7 @@ module Helper
191
173
  end
192
174
 
193
175
  def _new_client(options = {})
194
- Redis.new(_format_options(options).merge(:driver => ENV["conn"]))
176
+ Redis.new(_format_options(options).merge(:driver => ENV["DRIVER"]))
195
177
  end
196
178
  end
197
179
 
@@ -217,16 +199,147 @@ module Helper
217
199
  end
218
200
  end
219
201
 
220
- # Basic support for `skip` in 1.8.x
221
- # Note: YOU MUST use `return skip(message)` in order to appropriately bail
222
- # from a running test.
223
- module Skipable
224
- Skipped = Class.new(RuntimeError)
202
+ module Cluster
203
+ include Generic
204
+
205
+ DEFAULT_HOST = '127.0.0.1'
206
+ DEFAULT_PORTS = (7000..7005).freeze
207
+
208
+ ClusterSlotsRawReply = lambda { |host, port|
209
+ # @see https://redis.io/topics/protocol
210
+ <<-REPLY.delete(' ')
211
+ *1\r
212
+ *4\r
213
+ :0\r
214
+ :16383\r
215
+ *3\r
216
+ $#{host.size}\r
217
+ #{host}\r
218
+ :#{port}\r
219
+ $40\r
220
+ 649fa246273043021a05f547a79478597d3f1dc5\r
221
+ *3\r
222
+ $#{host.size}\r
223
+ #{host}\r
224
+ :#{port}\r
225
+ $40\r
226
+ 649fa246273043021a05f547a79478597d3f1dc5\r
227
+ REPLY
228
+ }
229
+
230
+ ClusterNodesRawReply = lambda { |host, port|
231
+ line = "649fa246273043021a05f547a79478597d3f1dc5 #{host}:#{port}@17000 "\
232
+ 'myself,master - 0 1530797742000 1 connected 0-16383'
233
+ "$#{line.size}\r\n#{line}\r\n"
234
+ }
235
+
236
+ def init(redis)
237
+ redis.flushall
238
+ redis
239
+ rescue Redis::CannotConnectError
240
+ puts <<-MSG
241
+
242
+ Cannot connect to Redis Cluster.
243
+
244
+ Make sure Redis is running on localhost, port #{DEFAULT_PORTS}.
245
+
246
+ Try this once:
247
+
248
+ $ make stop_cluster
249
+
250
+ Then run the build again:
251
+
252
+ $ make
253
+
254
+ MSG
255
+ exit 1
256
+ end
257
+
258
+ def build_another_client(options = {})
259
+ _new_client(options)
260
+ end
261
+
262
+ def redis_cluster_mock(commands, options = {})
263
+ host = DEFAULT_HOST
264
+ port = nil
265
+
266
+ cluster_subcommands = if commands.key?(:cluster)
267
+ commands.delete(:cluster)
268
+ .map { |k, v| [k.to_s.downcase, v] }
269
+ .to_h
270
+ else
271
+ {}
272
+ end
273
+
274
+ commands[:cluster] = lambda { |subcommand, *args|
275
+ if cluster_subcommands.key?(subcommand)
276
+ cluster_subcommands[subcommand].call(*args)
277
+ else
278
+ case subcommand
279
+ when 'slots' then ClusterSlotsRawReply.call(host, port)
280
+ when 'nodes' then ClusterNodesRawReply.call(host, port)
281
+ else '+OK'
282
+ end
283
+ end
284
+ }
285
+
286
+ commands[:command] = ->(*_) { "*0\r\n" }
287
+
288
+ RedisMock.start(commands, options) do |po|
289
+ port = po
290
+ scheme = options[:ssl] ? 'rediss' : 'redis'
291
+ nodes = %W[#{scheme}://#{host}:#{port}]
292
+ yield _new_client(options.merge(cluster: nodes))
293
+ end
294
+ end
225
295
 
226
- def skip(message = nil, bt = caller)
227
- return super if defined?(super)
296
+ def redis_cluster_down
297
+ trib = ClusterOrchestrator.new(_default_nodes)
298
+ trib.down
299
+ yield
300
+ ensure
301
+ trib.rebuild
302
+ trib.close
303
+ end
228
304
 
229
- $stderr.puts("SKIPPED: #{self} #{message || 'no reason given'}")
305
+ def redis_cluster_failover
306
+ trib = ClusterOrchestrator.new(_default_nodes)
307
+ trib.failover
308
+ yield
309
+ ensure
310
+ trib.rebuild
311
+ trib.close
312
+ end
313
+
314
+ # @param slot [Integer]
315
+ # @param src [String] <ip>:<port>
316
+ # @param dest [String] <ip>:<port>
317
+ def redis_cluster_resharding(slot, src:, dest:)
318
+ trib = ClusterOrchestrator.new(_default_nodes)
319
+ trib.start_resharding(slot, src, dest)
320
+ yield
321
+ trib.finish_resharding(slot, dest)
322
+ ensure
323
+ trib.rebuild
324
+ trib.close
325
+ end
326
+
327
+ private
328
+
329
+ def _default_nodes(host: DEFAULT_HOST, ports: DEFAULT_PORTS)
330
+ ports.map { |port| "redis://#{host}:#{port}" }
331
+ end
332
+
333
+ def _format_options(options)
334
+ {
335
+ timeout: OPTIONS[:timeout],
336
+ logger: ::Logger.new(@log),
337
+ cluster: _default_nodes
338
+ }.merge(options)
339
+ end
340
+
341
+ def _new_client(options = {})
342
+ Redis.new(_format_options(options).merge(driver: ENV['DRIVER']))
230
343
  end
231
344
  end
232
345
  end
data/test/helper_test.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestHelper < Test::Unit::TestCase
6
4
 
@@ -1,11 +1,8 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestInternals < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
- include Helper::Skipable
9
6
 
10
7
  def test_logger
11
8
  r.ping
@@ -45,23 +42,23 @@ class TestInternals < Test::Unit::TestCase
45
42
  end
46
43
 
47
44
  def test_redis_current
48
- assert_equal "127.0.0.1", Redis.current.client.host
49
- assert_equal 6379, Redis.current.client.port
50
- assert_equal 0, Redis.current.client.db
45
+ assert_equal "127.0.0.1", Redis.current._client.host
46
+ assert_equal 6379, Redis.current._client.port
47
+ assert_equal 0, Redis.current._client.db
51
48
 
52
49
  Redis.current = Redis.new(OPTIONS.merge(:port => 6380, :db => 1))
53
50
 
54
51
  t = Thread.new do
55
- assert_equal "127.0.0.1", Redis.current.client.host
56
- assert_equal 6380, Redis.current.client.port
57
- assert_equal 1, Redis.current.client.db
52
+ assert_equal "127.0.0.1", Redis.current._client.host
53
+ assert_equal 6380, Redis.current._client.port
54
+ assert_equal 1, Redis.current._client.db
58
55
  end
59
56
 
60
57
  t.join
61
58
 
62
- assert_equal "127.0.0.1", Redis.current.client.host
63
- assert_equal 6380, Redis.current.client.port
64
- assert_equal 1, Redis.current.client.db
59
+ assert_equal "127.0.0.1", Redis.current._client.host
60
+ assert_equal 6380, Redis.current._client.port
61
+ assert_equal 1, Redis.current._client.db
65
62
  end
66
63
 
67
64
  def test_redis_connected?
@@ -88,7 +85,7 @@ class TestInternals < Test::Unit::TestCase
88
85
  redis = Redis.new(OPTIONS.merge(:tcp_keepalive => keepalive))
89
86
  redis.ping
90
87
 
91
- connection = redis.client.connection
88
+ connection = redis._client.connection
92
89
  actual_keepalive = connection.get_tcp_keepalive
93
90
 
94
91
  [:time, :intvl, :probes].each do |key|
@@ -121,22 +118,10 @@ class TestInternals < Test::Unit::TestCase
121
118
  assert (Time.now - start_time) <= opts[:timeout]
122
119
  end
123
120
 
124
- driver(:ruby) do
125
- def test_write_timeout
126
- return skip("Relies on buffer sizes, might be unreliable")
127
-
128
- server = TCPServer.new("127.0.0.1", 0)
129
- port = server.addr[1]
130
-
131
- # Hacky, but we need the buffer size
132
- val = TCPSocket.new("127.0.0.1", port).getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).unpack("i")[0]
133
-
134
- assert_raise(Redis::TimeoutError) do
135
- Timeout.timeout(1) do
136
- redis = Redis.new(:port => port, :timeout => 5, :write_timeout => 0.1)
137
- redis.set("foo", "1" * val*2)
138
- end
139
- end
121
+ def test_missing_socket
122
+ opts = { :path => '/missing.sock' }
123
+ assert_raise Redis::CannotConnectError do
124
+ Redis.new(opts).ping
140
125
  end
141
126
  end
142
127
 
@@ -197,7 +182,7 @@ class TestInternals < Test::Unit::TestCase
197
182
  redis.ping
198
183
  end
199
184
 
200
- assert !redis.client.connected?
185
+ assert !redis._client.connected?
201
186
  end
202
187
  end
203
188
 
@@ -213,7 +198,20 @@ class TestInternals < Test::Unit::TestCase
213
198
  redis.ping
214
199
  end
215
200
 
216
- assert !redis.client.connected?
201
+ assert !redis._client.connected?
202
+ end
203
+ end
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
217
215
  end
218
216
  end
219
217
 
@@ -226,7 +224,7 @@ class TestInternals < Test::Unit::TestCase
226
224
  end
227
225
  end
228
226
 
229
- assert !redis.client.connected?
227
+ assert !redis._client.connected?
230
228
  end
231
229
  end
232
230
 
@@ -267,14 +265,14 @@ class TestInternals < Test::Unit::TestCase
267
265
 
268
266
  def test_retry_on_write_error_by_default
269
267
  close_on_connection([0]) do |redis|
270
- assert_equal "1", redis.client.call(["x" * 128 * 1024])
268
+ assert_equal "1", redis._client.call(["x" * 128 * 1024])
271
269
  end
272
270
  end
273
271
 
274
272
  def test_retry_on_write_error_when_wrapped_in_with_reconnect_true
275
273
  close_on_connection([0]) do |redis|
276
274
  redis.with_reconnect(true) do
277
- assert_equal "1", redis.client.call(["x" * 128 * 1024])
275
+ assert_equal "1", redis._client.call(["x" * 128 * 1024])
278
276
  end
279
277
  end
280
278
  end
@@ -283,7 +281,7 @@ class TestInternals < Test::Unit::TestCase
283
281
  close_on_connection([0]) do |redis|
284
282
  assert_raise Redis::ConnectionError do
285
283
  redis.with_reconnect(false) do
286
- redis.client.call(["x" * 128 * 1024])
284
+ redis._client.call(["x" * 128 * 1024])
287
285
  end
288
286
  end
289
287
  end
@@ -293,7 +291,7 @@ class TestInternals < Test::Unit::TestCase
293
291
  close_on_connection([0]) do |redis|
294
292
  assert_raise Redis::ConnectionError do
295
293
  redis.without_reconnect do
296
- redis.client.call(["x" * 128 * 1024])
294
+ redis._client.call(["x" * 128 * 1024])
297
295
  end
298
296
  end
299
297
  end
@@ -301,7 +299,7 @@ class TestInternals < Test::Unit::TestCase
301
299
 
302
300
  def test_connecting_to_unix_domain_socket
303
301
  assert_nothing_raised do
304
- Redis.new(OPTIONS.merge(:path => "./test/db/redis.sock")).ping
302
+ Redis.new(OPTIONS.merge(:path => ENV.fetch("SOCKET_PATH"))).ping
305
303
  end
306
304
  end
307
305
 
@@ -323,23 +321,10 @@ class TestInternals < Test::Unit::TestCase
323
321
  def test_client_options
324
322
  redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
325
323
 
326
- assert_equal "host", redis.client.options[:host]
327
- assert_equal 1234, redis.client.options[:port]
328
- assert_equal 1, redis.client.options[:db]
329
- assert_equal "foo", redis.client.options[:scheme]
330
- end
331
-
332
- def test_does_not_change_self_client_options
333
- redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
334
- options = redis.client.options
335
-
336
- options[:host] << "new_host"
337
- options[:scheme] << "bar"
338
- options.merge!(:db => 0)
339
-
340
- assert_equal "host", redis.client.options[:host]
341
- assert_equal 1, redis.client.options[:db]
342
- assert_equal "foo", redis.client.options[:scheme]
324
+ assert_equal "host", redis._client.options[:host]
325
+ assert_equal 1234, redis._client.options[:port]
326
+ assert_equal 1, redis._client.options[:db]
327
+ assert_equal "foo", redis._client.options[:scheme]
343
328
  end
344
329
 
345
330
  def test_resolves_localhost
@@ -362,7 +347,13 @@ class TestInternals < Test::Unit::TestCase
362
347
  begin
363
348
  sa = Socket.pack_sockaddr_in(1024 + Random.rand(63076), hosts[af])
364
349
  s.bind(sa)
365
- rescue Errno::EADDRINUSE
350
+ rescue Errno::EADDRINUSE => e
351
+ # On JRuby (9.1.15.0), if IPv6 is globally disabled on the system,
352
+ # we get an EADDRINUSE with belows message.
353
+ if e.message =~ /Protocol family unavailable/
354
+ return
355
+ end
356
+
366
357
  tries -= 1
367
358
  retry if tries > 0
368
359
 
@@ -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|