redis 3.3.5 → 4.0.3
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis/Gemfile +8 -1
- data/.travis.yml +34 -62
- data/CHANGELOG.md +45 -2
- data/Gemfile +5 -1
- data/README.md +32 -76
- data/benchmarking/logging.rb +1 -1
- data/bin/build +71 -0
- data/bors.toml +14 -0
- data/lib/redis/client.rb +38 -20
- data/lib/redis/cluster/command.rb +81 -0
- data/lib/redis/cluster/command_loader.rb +32 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +104 -0
- data/lib/redis/cluster/node_key.rb +35 -0
- data/lib/redis/cluster/node_loader.rb +35 -0
- data/lib/redis/cluster/option.rb +76 -0
- data/lib/redis/cluster/slot.rb +69 -0
- data/lib/redis/cluster/slot_loader.rb +47 -0
- data/lib/redis/cluster.rb +285 -0
- data/lib/redis/connection/command_helper.rb +2 -8
- data/lib/redis/connection/hiredis.rb +2 -2
- data/lib/redis/connection/ruby.rb +13 -30
- data/lib/redis/connection/synchrony.rb +12 -4
- data/lib/redis/connection.rb +2 -2
- data/lib/redis/distributed.rb +29 -8
- data/lib/redis/errors.rb +46 -0
- data/lib/redis/hash_ring.rb +20 -64
- data/lib/redis/pipeline.rb +9 -7
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +287 -52
- data/makefile +74 -0
- data/redis.gemspec +9 -10
- data/test/bitpos_test.rb +13 -19
- data/test/blocking_commands_test.rb +3 -5
- data/test/client_test.rb +18 -1
- data/test/cluster_abnormal_state_test.rb +38 -0
- data/test/cluster_blocking_commands_test.rb +15 -0
- data/test/cluster_client_internals_test.rb +77 -0
- data/test/cluster_client_key_hash_tags_test.rb +88 -0
- data/test/cluster_client_options_test.rb +147 -0
- data/test/cluster_client_pipelining_test.rb +59 -0
- data/test/cluster_client_replicas_test.rb +36 -0
- data/test/cluster_client_slots_test.rb +94 -0
- data/test/cluster_client_transactions_test.rb +71 -0
- data/test/cluster_commands_on_cluster_test.rb +165 -0
- data/test/cluster_commands_on_connection_test.rb +40 -0
- data/test/cluster_commands_on_geo_test.rb +74 -0
- data/test/cluster_commands_on_hashes_test.rb +11 -0
- data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
- data/test/cluster_commands_on_keys_test.rb +134 -0
- data/test/cluster_commands_on_lists_test.rb +15 -0
- data/test/cluster_commands_on_pub_sub_test.rb +101 -0
- data/test/cluster_commands_on_scripting_test.rb +56 -0
- data/test/cluster_commands_on_server_test.rb +221 -0
- data/test/cluster_commands_on_sets_test.rb +39 -0
- data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
- data/test/cluster_commands_on_streams_test.rb +196 -0
- data/test/cluster_commands_on_strings_test.rb +15 -0
- data/test/cluster_commands_on_transactions_test.rb +41 -0
- data/test/cluster_commands_on_value_types_test.rb +14 -0
- data/test/command_map_test.rb +3 -5
- data/test/commands_on_geo_test.rb +116 -0
- data/test/commands_on_hashes_test.rb +2 -16
- data/test/commands_on_hyper_log_log_test.rb +3 -17
- data/test/commands_on_lists_test.rb +2 -15
- data/test/commands_on_sets_test.rb +2 -72
- data/test/commands_on_sorted_sets_test.rb +2 -132
- data/test/commands_on_strings_test.rb +2 -96
- data/test/commands_on_value_types_test.rb +80 -6
- data/test/connection_handling_test.rb +5 -7
- data/test/distributed_blocking_commands_test.rb +10 -4
- data/test/distributed_commands_on_hashes_test.rb +16 -5
- data/test/distributed_commands_on_hyper_log_log_test.rb +8 -15
- data/test/distributed_commands_on_lists_test.rb +4 -7
- data/test/distributed_commands_on_sets_test.rb +58 -36
- data/test/distributed_commands_on_sorted_sets_test.rb +51 -10
- data/test/distributed_commands_on_strings_test.rb +30 -10
- data/test/distributed_commands_on_value_types_test.rb +38 -4
- data/test/distributed_commands_requiring_clustering_test.rb +1 -3
- data/test/distributed_connection_handling_test.rb +1 -3
- data/test/distributed_internals_test.rb +8 -19
- data/test/distributed_key_tags_test.rb +4 -6
- data/test/distributed_persistence_control_commands_test.rb +1 -3
- data/test/distributed_publish_subscribe_test.rb +1 -3
- data/test/distributed_remote_server_control_commands_test.rb +1 -3
- data/test/distributed_scripting_test.rb +1 -3
- data/test/distributed_sorting_test.rb +1 -3
- data/test/distributed_test.rb +12 -14
- data/test/distributed_transactions_test.rb +1 -3
- data/test/encoding_test.rb +4 -8
- data/test/error_replies_test.rb +2 -4
- data/test/fork_safety_test.rb +1 -6
- data/test/helper.rb +179 -66
- data/test/helper_test.rb +1 -3
- data/test/internals_test.rb +47 -56
- data/test/lint/blocking_commands.rb +40 -16
- data/test/lint/hashes.rb +41 -0
- data/test/lint/hyper_log_log.rb +15 -1
- data/test/lint/lists.rb +16 -0
- data/test/lint/sets.rb +142 -0
- data/test/lint/sorted_sets.rb +183 -2
- data/test/lint/strings.rb +108 -20
- data/test/lint/value_types.rb +8 -0
- data/test/persistence_control_commands_test.rb +1 -3
- data/test/pipelining_commands_test.rb +12 -8
- data/test/publish_subscribe_test.rb +1 -3
- data/test/remote_server_control_commands_test.rb +60 -3
- data/test/scanning_test.rb +1 -7
- data/test/scripting_test.rb +1 -3
- data/test/sentinel_command_test.rb +1 -3
- data/test/sentinel_test.rb +1 -3
- data/test/sorting_test.rb +1 -3
- data/test/ssl_test.rb +45 -49
- data/test/support/cluster/orchestrator.rb +199 -0
- data/test/support/connection/hiredis.rb +1 -1
- data/test/support/connection/ruby.rb +1 -1
- data/test/support/connection/synchrony.rb +1 -1
- data/test/support/redis_mock.rb +1 -1
- data/test/synchrony_driver.rb +6 -9
- data/test/thread_safety_test.rb +1 -3
- data/test/transactions_test.rb +11 -3
- data/test/unknown_commands_test.rb +1 -3
- data/test/url_param_test.rb +44 -46
- metadata +109 -16
- data/Rakefile +0 -87
data/test/encoding_test.rb
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
|
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
|
-
|
11
|
-
|
12
|
-
r.set "foo", "שלום"
|
8
|
+
with_external_encoding("UTF-8") do
|
9
|
+
r.set "foo", "שלום"
|
13
10
|
|
14
|
-
|
15
|
-
end
|
11
|
+
assert_equal "Shalom שלום", "Shalom " + r.get("foo")
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
data/test/error_replies_test.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
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.
|
48
|
+
r._client.call_loop([:invalid_monitor]) do
|
51
49
|
assert false # Should never be executed
|
52
50
|
end
|
53
51
|
rescue => ex
|
data/test/fork_safety_test.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
|
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["
|
8
|
+
ENV["DRIVER"] ||= "ruby"
|
18
9
|
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
require_relative "../lib/redis"
|
11
|
+
require_relative "../lib/redis/distributed"
|
12
|
+
require_relative "../lib/redis/connection/#{ENV["DRIVER"]}"
|
22
13
|
|
23
|
-
|
24
|
-
|
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["
|
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["
|
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
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
227
|
-
|
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
|
-
|
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
data/test/internals_test.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
|
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.
|
49
|
-
assert_equal 6379, Redis.current.
|
50
|
-
assert_equal 0, Redis.current.
|
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.
|
56
|
-
assert_equal 6380, Redis.current.
|
57
|
-
assert_equal 1, Redis.current.
|
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.
|
63
|
-
assert_equal 6380, Redis.current.
|
64
|
-
assert_equal 1, Redis.current.
|
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.
|
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
|
-
|
125
|
-
|
126
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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 =>
|
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.
|
327
|
-
assert_equal 1234, redis.
|
328
|
-
assert_equal 1, redis.
|
329
|
-
assert_equal "foo", redis.
|
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(
|
9
|
-
r.rpush(
|
10
|
-
r.rpush(
|
11
|
-
r.rpush(
|
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
|
-
|
22
|
+
raise
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
def mock(options = {}, &blk)
|
26
|
-
commands =
|
27
|
-
|
28
|
-
|
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
|
-
:
|
32
|
-
sleep options[:delay] if options.
|
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
|
-
:
|
36
|
-
sleep options[:delay] if options.
|
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|
|