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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +278 -15
- data/README.md +260 -76
- data/lib/redis/client.rb +239 -115
- data/lib/redis/cluster/command.rb +79 -0
- data/lib/redis/cluster/command_loader.rb +33 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +120 -0
- data/lib/redis/cluster/node_key.rb +31 -0
- data/lib/redis/cluster/node_loader.rb +37 -0
- data/lib/redis/cluster/option.rb +93 -0
- data/lib/redis/cluster/slot.rb +86 -0
- data/lib/redis/cluster/slot_loader.rb +49 -0
- data/lib/redis/cluster.rb +315 -0
- data/lib/redis/commands/bitmaps.rb +63 -0
- data/lib/redis/commands/cluster.rb +45 -0
- data/lib/redis/commands/connection.rb +58 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +251 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +411 -0
- data/lib/redis/commands/lists.rb +289 -0
- data/lib/redis/commands/pubsub.rb +72 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +207 -0
- data/lib/redis/commands/sorted_sets.rb +804 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +92 -0
- data/lib/redis/commands.rb +242 -0
- data/lib/redis/connection/command_helper.rb +7 -10
- data/lib/redis/connection/hiredis.rb +11 -6
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +173 -64
- data/lib/redis/connection/synchrony.rb +32 -8
- data/lib/redis/connection.rb +3 -1
- data/lib/redis/distributed.rb +233 -74
- data/lib/redis/errors.rb +48 -0
- data/lib/redis/hash_ring.rb +30 -72
- data/lib/redis/pipeline.rb +145 -12
- data/lib/redis/subscribe.rb +20 -13
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +171 -2476
- metadata +71 -165
- data/.gitignore +0 -15
- data/.travis/Gemfile +0 -11
- data/.travis.yml +0 -54
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -68
- data/benchmarking/logging.rb +0 -71
- data/benchmarking/pipeline.rb +0 -51
- data/benchmarking/speed.rb +0 -21
- data/benchmarking/suite.rb +0 -24
- data/benchmarking/worker.rb +0 -71
- data/examples/basic.rb +0 -15
- data/examples/consistency.rb +0 -114
- data/examples/dist_redis.rb +0 -43
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sentinel.rb +0 -41
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/redis.gemspec +0 -43
- data/test/bitpos_test.rb +0 -69
- data/test/blocking_commands_test.rb +0 -42
- data/test/command_map_test.rb +0 -30
- data/test/commands_on_hashes_test.rb +0 -21
- data/test/commands_on_hyper_log_log_test.rb +0 -21
- data/test/commands_on_lists_test.rb +0 -20
- data/test/commands_on_sets_test.rb +0 -77
- data/test/commands_on_sorted_sets_test.rb +0 -123
- data/test/commands_on_strings_test.rb +0 -101
- data/test/commands_on_value_types_test.rb +0 -131
- data/test/connection_handling_test.rb +0 -189
- data/test/db/.gitkeep +0 -0
- data/test/distributed_blocking_commands_test.rb +0 -46
- data/test/distributed_commands_on_hashes_test.rb +0 -10
- data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
- data/test/distributed_commands_on_lists_test.rb +0 -22
- data/test/distributed_commands_on_sets_test.rb +0 -83
- data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
- data/test/distributed_commands_on_strings_test.rb +0 -59
- data/test/distributed_commands_on_value_types_test.rb +0 -95
- data/test/distributed_commands_requiring_clustering_test.rb +0 -164
- data/test/distributed_connection_handling_test.rb +0 -23
- data/test/distributed_internals_test.rb +0 -70
- data/test/distributed_key_tags_test.rb +0 -52
- data/test/distributed_persistence_control_commands_test.rb +0 -26
- data/test/distributed_publish_subscribe_test.rb +0 -92
- data/test/distributed_remote_server_control_commands_test.rb +0 -66
- data/test/distributed_scripting_test.rb +0 -102
- data/test/distributed_sorting_test.rb +0 -20
- data/test/distributed_test.rb +0 -58
- data/test/distributed_transactions_test.rb +0 -32
- data/test/encoding_test.rb +0 -18
- data/test/error_replies_test.rb +0 -59
- data/test/fork_safety_test.rb +0 -65
- data/test/helper.rb +0 -232
- data/test/helper_test.rb +0 -24
- data/test/internals_test.rb +0 -434
- data/test/lint/blocking_commands.rb +0 -150
- data/test/lint/hashes.rb +0 -162
- data/test/lint/hyper_log_log.rb +0 -60
- data/test/lint/lists.rb +0 -143
- data/test/lint/sets.rb +0 -125
- data/test/lint/sorted_sets.rb +0 -238
- data/test/lint/strings.rb +0 -260
- data/test/lint/value_types.rb +0 -122
- data/test/persistence_control_commands_test.rb +0 -26
- data/test/pipelining_commands_test.rb +0 -242
- data/test/publish_subscribe_test.rb +0 -210
- data/test/remote_server_control_commands_test.rb +0 -117
- data/test/scanning_test.rb +0 -413
- data/test/scripting_test.rb +0 -78
- data/test/sorting_test.rb +0 -59
- data/test/support/connection/hiredis.rb +0 -1
- data/test/support/connection/ruby.rb +0 -1
- data/test/support/connection/synchrony.rb +0 -17
- data/test/support/redis_mock.rb +0 -115
- data/test/support/wire/synchrony.rb +0 -24
- data/test/support/wire/thread.rb +0 -5
- data/test/synchrony_driver.rb +0 -88
- data/test/test.conf +0 -9
- data/test/thread_safety_test.rb +0 -32
- data/test/transactions_test.rb +0 -264
- data/test/unknown_commands_test.rb +0 -14
- data/test/url_param_test.rb +0 -132
data/test/helper.rb
DELETED
@@ -1,232 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
|
2
|
-
$:.unshift File.expand_path(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
require "test/unit"
|
5
|
-
require "logger"
|
6
|
-
require "stringio"
|
7
|
-
|
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
|
-
$VERBOSE = true
|
16
|
-
|
17
|
-
ENV["conn"] ||= "ruby"
|
18
|
-
|
19
|
-
require "redis"
|
20
|
-
require "redis/distributed"
|
21
|
-
require "redis/connection/#{ENV["conn"]}"
|
22
|
-
|
23
|
-
require "support/redis_mock"
|
24
|
-
require "support/connection/#{ENV["conn"]}"
|
25
|
-
|
26
|
-
PORT = 6381
|
27
|
-
OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
|
28
|
-
NODES = ["redis://127.0.0.1:#{PORT}/15"]
|
29
|
-
|
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
|
-
def driver(*drivers, &blk)
|
59
|
-
if drivers.map(&:to_s).include?(ENV["conn"])
|
60
|
-
class_eval(&blk)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
module Helper
|
65
|
-
|
66
|
-
def run(runner)
|
67
|
-
if respond_to?(:around)
|
68
|
-
around { super(runner) }
|
69
|
-
else
|
70
|
-
super
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def silent
|
75
|
-
verbose, $VERBOSE = $VERBOSE, false
|
76
|
-
|
77
|
-
begin
|
78
|
-
yield
|
79
|
-
ensure
|
80
|
-
$VERBOSE = verbose
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def with_external_encoding(encoding)
|
85
|
-
original_encoding = Encoding.default_external
|
86
|
-
|
87
|
-
begin
|
88
|
-
silent { Encoding.default_external = Encoding.find(encoding) }
|
89
|
-
yield
|
90
|
-
ensure
|
91
|
-
silent { Encoding.default_external = original_encoding }
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
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
|
-
class Version
|
104
|
-
|
105
|
-
include Comparable
|
106
|
-
|
107
|
-
attr :parts
|
108
|
-
|
109
|
-
def initialize(v)
|
110
|
-
case v
|
111
|
-
when Version
|
112
|
-
@parts = v.parts
|
113
|
-
else
|
114
|
-
@parts = v.to_s.split(".")
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def <=>(other)
|
119
|
-
other = Version.new(other)
|
120
|
-
length = [self.parts.length, other.parts.length].max
|
121
|
-
length.times do |i|
|
122
|
-
a, b = self.parts[i], other.parts[i]
|
123
|
-
|
124
|
-
return -1 if a.nil?
|
125
|
-
return +1 if b.nil?
|
126
|
-
return a.to_i <=> b.to_i if a != b
|
127
|
-
end
|
128
|
-
|
129
|
-
0
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
module Generic
|
134
|
-
|
135
|
-
include Helper
|
136
|
-
|
137
|
-
attr_reader :log
|
138
|
-
attr_reader :redis
|
139
|
-
|
140
|
-
alias :r :redis
|
141
|
-
|
142
|
-
def setup
|
143
|
-
@log = StringIO.new
|
144
|
-
@redis = init _new_client
|
145
|
-
|
146
|
-
# Run GC to make sure orphaned connections are closed.
|
147
|
-
GC.start
|
148
|
-
end
|
149
|
-
|
150
|
-
def teardown
|
151
|
-
@redis.quit if @redis
|
152
|
-
end
|
153
|
-
|
154
|
-
def redis_mock(commands, options = {}, &blk)
|
155
|
-
RedisMock.start(commands, options) do |port|
|
156
|
-
yield _new_client(options.merge(:port => port))
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def redis_mock_with_handler(handler, options = {}, &blk)
|
161
|
-
RedisMock.start_with_handler(handler, options) do |port|
|
162
|
-
yield _new_client(options.merge(:port => port))
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def assert_in_range(range, value)
|
167
|
-
assert range.include?(value), "expected #{value} to be in #{range.inspect}"
|
168
|
-
end
|
169
|
-
|
170
|
-
def target_version(target)
|
171
|
-
if version < target
|
172
|
-
skip("Requires Redis > #{target}") if respond_to?(:skip)
|
173
|
-
else
|
174
|
-
yield
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
module Client
|
180
|
-
|
181
|
-
include Generic
|
182
|
-
|
183
|
-
def version
|
184
|
-
Version.new(redis.info["redis_version"])
|
185
|
-
end
|
186
|
-
|
187
|
-
private
|
188
|
-
|
189
|
-
def _format_options(options)
|
190
|
-
OPTIONS.merge(:logger => ::Logger.new(@log)).merge(options)
|
191
|
-
end
|
192
|
-
|
193
|
-
def _new_client(options = {})
|
194
|
-
Redis.new(_format_options(options).merge(:driver => ENV["conn"]))
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
module Distributed
|
199
|
-
|
200
|
-
include Generic
|
201
|
-
|
202
|
-
def version
|
203
|
-
Version.new(redis.info.first["redis_version"])
|
204
|
-
end
|
205
|
-
|
206
|
-
private
|
207
|
-
|
208
|
-
def _format_options(options)
|
209
|
-
{
|
210
|
-
:timeout => OPTIONS[:timeout],
|
211
|
-
:logger => ::Logger.new(@log),
|
212
|
-
}.merge(options)
|
213
|
-
end
|
214
|
-
|
215
|
-
def _new_client(options = {})
|
216
|
-
Redis::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
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)
|
225
|
-
|
226
|
-
def skip(message = nil, bt = caller)
|
227
|
-
return super if defined?(super)
|
228
|
-
|
229
|
-
$stderr.puts("SKIPPED: #{self} #{message || 'no reason given'}")
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
data/test/helper_test.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
-
|
5
|
-
class TestHelper < Test::Unit::TestCase
|
6
|
-
|
7
|
-
include Helper
|
8
|
-
|
9
|
-
def test_version_comparison
|
10
|
-
v = Version.new("2.0.1")
|
11
|
-
|
12
|
-
assert v > "1"
|
13
|
-
assert v > "2"
|
14
|
-
assert v < "3"
|
15
|
-
assert v < "10"
|
16
|
-
|
17
|
-
assert v < "2.1"
|
18
|
-
assert v < "2.0.2"
|
19
|
-
assert v < "2.0.1.1"
|
20
|
-
assert v < "2.0.10"
|
21
|
-
|
22
|
-
assert v == "2.0.1"
|
23
|
-
end
|
24
|
-
end
|
data/test/internals_test.rb
DELETED
@@ -1,434 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
-
|
5
|
-
class TestInternals < Test::Unit::TestCase
|
6
|
-
|
7
|
-
include Helper::Client
|
8
|
-
|
9
|
-
def test_logger
|
10
|
-
r.ping
|
11
|
-
|
12
|
-
assert log.string["[Redis] command=PING"]
|
13
|
-
assert log.string =~ /\[Redis\] call_time=\d+\.\d+ ms/
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_logger_with_pipelining
|
17
|
-
r.pipelined do
|
18
|
-
r.set "foo", "bar"
|
19
|
-
r.get "foo"
|
20
|
-
end
|
21
|
-
|
22
|
-
assert log.string[" command=SET args=\"foo\" \"bar\""]
|
23
|
-
assert log.string[" command=GET args=\"foo\""]
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_recovers_from_failed_commands
|
27
|
-
# See https://github.com/redis/redis-rb/issues#issue/28
|
28
|
-
|
29
|
-
assert_raise(Redis::CommandError) do
|
30
|
-
r.command_that_doesnt_exist
|
31
|
-
end
|
32
|
-
|
33
|
-
assert_nothing_raised do
|
34
|
-
r.info
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_raises_on_protocol_errors
|
39
|
-
redis_mock(:ping => lambda { |*_| "foo" }) do |redis|
|
40
|
-
assert_raise(Redis::ProtocolError) do
|
41
|
-
redis.ping
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_provides_a_meaningful_inspect
|
47
|
-
assert_equal "#<Redis client v#{Redis::VERSION} for redis://127.0.0.1:#{PORT}/15>", r.inspect
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_redis_current
|
51
|
-
assert_equal "127.0.0.1", Redis.current.client.host
|
52
|
-
assert_equal 6379, Redis.current.client.port
|
53
|
-
assert_equal 0, Redis.current.client.db
|
54
|
-
|
55
|
-
Redis.current = Redis.new(OPTIONS.merge(:port => 6380, :db => 1))
|
56
|
-
|
57
|
-
t = Thread.new do
|
58
|
-
assert_equal "127.0.0.1", Redis.current.client.host
|
59
|
-
assert_equal 6380, Redis.current.client.port
|
60
|
-
assert_equal 1, Redis.current.client.db
|
61
|
-
end
|
62
|
-
|
63
|
-
t.join
|
64
|
-
|
65
|
-
assert_equal "127.0.0.1", Redis.current.client.host
|
66
|
-
assert_equal 6380, Redis.current.client.port
|
67
|
-
assert_equal 1, Redis.current.client.db
|
68
|
-
end
|
69
|
-
|
70
|
-
def test_redis_connected?
|
71
|
-
fresh_client = _new_client
|
72
|
-
assert !fresh_client.connected?
|
73
|
-
|
74
|
-
fresh_client.ping
|
75
|
-
assert fresh_client.connected?
|
76
|
-
|
77
|
-
fresh_client.quit
|
78
|
-
assert !fresh_client.connected?
|
79
|
-
end
|
80
|
-
|
81
|
-
def test_default_id_with_host_and_port
|
82
|
-
redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
|
83
|
-
assert_equal "redis://host:1234/0", redis.client.id
|
84
|
-
end
|
85
|
-
|
86
|
-
def test_default_id_with_host_and_port_and_explicit_scheme
|
87
|
-
redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0, :scheme => "foo"))
|
88
|
-
assert_equal "redis://host:1234/0", redis.client.id
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_default_id_with_path
|
92
|
-
redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0))
|
93
|
-
assert_equal "redis:///tmp/redis.sock/0", redis.client.id
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_default_id_with_path_and_explicit_scheme
|
97
|
-
redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0, :scheme => "foo"))
|
98
|
-
assert_equal "redis:///tmp/redis.sock/0", redis.client.id
|
99
|
-
end
|
100
|
-
|
101
|
-
def test_override_id
|
102
|
-
redis = Redis.new(OPTIONS.merge(:id => "test"))
|
103
|
-
assert_equal redis.client.id, "test"
|
104
|
-
end
|
105
|
-
|
106
|
-
def test_timeout
|
107
|
-
assert_nothing_raised do
|
108
|
-
Redis.new(OPTIONS.merge(:timeout => 0))
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_id_inside_multi
|
113
|
-
redis = Redis.new(OPTIONS)
|
114
|
-
id = nil
|
115
|
-
|
116
|
-
redis.multi do
|
117
|
-
id = redis.id
|
118
|
-
end
|
119
|
-
|
120
|
-
assert_equal id, "redis://127.0.0.1:6381/15"
|
121
|
-
end
|
122
|
-
|
123
|
-
driver(:ruby) do
|
124
|
-
def test_tcp_keepalive
|
125
|
-
keepalive = {:time => 20, :intvl => 10, :probes => 5}
|
126
|
-
|
127
|
-
redis = Redis.new(OPTIONS.merge(:tcp_keepalive => keepalive))
|
128
|
-
redis.ping
|
129
|
-
|
130
|
-
connection = redis.client.connection
|
131
|
-
actual_keepalive = connection.get_tcp_keepalive
|
132
|
-
|
133
|
-
[:time, :intvl, :probes].each do |key|
|
134
|
-
if actual_keepalive.has_key?(key)
|
135
|
-
assert_equal actual_keepalive[key], keepalive[key]
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_time
|
142
|
-
target_version "2.5.4" do
|
143
|
-
# Test that the difference between the time that Ruby reports and the time
|
144
|
-
# that Redis reports is minimal (prevents the test from being racy).
|
145
|
-
rv = r.time
|
146
|
-
|
147
|
-
redis_usec = rv[0] * 1_000_000 + rv[1]
|
148
|
-
ruby_usec = Integer(Time.now.to_f * 1_000_000)
|
149
|
-
|
150
|
-
assert 500_000 > (ruby_usec - redis_usec).abs
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def test_connection_timeout
|
155
|
-
assert_raise Redis::CannotConnectError do
|
156
|
-
Redis.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def close_on_ping(seq, options = {})
|
161
|
-
$request = 0
|
162
|
-
|
163
|
-
command = lambda do
|
164
|
-
idx = $request
|
165
|
-
$request += 1
|
166
|
-
|
167
|
-
rv = "+%d" % idx
|
168
|
-
rv = nil if seq.include?(idx)
|
169
|
-
rv
|
170
|
-
end
|
171
|
-
|
172
|
-
redis_mock({:ping => command}, {:timeout => 0.1}.merge(options)) do |redis|
|
173
|
-
yield(redis)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def test_retry_by_default
|
178
|
-
close_on_ping([0]) do |redis|
|
179
|
-
assert_equal "1", redis.ping
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def test_retry_when_wrapped_in_with_reconnect_true
|
184
|
-
close_on_ping([0]) do |redis|
|
185
|
-
redis.with_reconnect(true) do
|
186
|
-
assert_equal "1", redis.ping
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_dont_retry_when_wrapped_in_with_reconnect_false
|
192
|
-
close_on_ping([0]) do |redis|
|
193
|
-
assert_raise Redis::ConnectionError do
|
194
|
-
redis.with_reconnect(false) do
|
195
|
-
redis.ping
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def test_dont_retry_when_wrapped_in_without_reconnect
|
202
|
-
close_on_ping([0]) do |redis|
|
203
|
-
assert_raise Redis::ConnectionError do
|
204
|
-
redis.without_reconnect do
|
205
|
-
redis.ping
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def test_retry_only_once_when_read_raises_econnreset
|
212
|
-
close_on_ping([0, 1]) do |redis|
|
213
|
-
assert_raise Redis::ConnectionError do
|
214
|
-
redis.ping
|
215
|
-
end
|
216
|
-
|
217
|
-
assert !redis.client.connected?
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def test_retry_with_custom_reconnect_attempts
|
222
|
-
close_on_ping([0, 1], :reconnect_attempts => 2) do |redis|
|
223
|
-
assert_equal "2", redis.ping
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def test_retry_with_custom_reconnect_attempts_can_still_fail
|
228
|
-
close_on_ping([0, 1, 2], :reconnect_attempts => 2) do |redis|
|
229
|
-
assert_raise Redis::ConnectionError do
|
230
|
-
redis.ping
|
231
|
-
end
|
232
|
-
|
233
|
-
assert !redis.client.connected?
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
|
238
|
-
close_on_ping([1]) do |redis|
|
239
|
-
assert_raise Redis::ConnectionError do
|
240
|
-
redis.pipelined do
|
241
|
-
redis.ping
|
242
|
-
redis.ping # Second #read times out
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
assert !redis.client.connected?
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def close_on_connection(seq)
|
251
|
-
$n = 0
|
252
|
-
|
253
|
-
read_command = lambda do |session|
|
254
|
-
Array.new(session.gets[1..-3].to_i) do
|
255
|
-
bytes = session.gets[1..-3].to_i
|
256
|
-
arg = session.read(bytes)
|
257
|
-
session.read(2) # Discard \r\n
|
258
|
-
arg
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
handler = lambda do |session|
|
263
|
-
n = $n
|
264
|
-
$n += 1
|
265
|
-
|
266
|
-
select = read_command.call(session)
|
267
|
-
if select[0].downcase == "select"
|
268
|
-
session.write("+OK\r\n")
|
269
|
-
else
|
270
|
-
raise "Expected SELECT"
|
271
|
-
end
|
272
|
-
|
273
|
-
if !seq.include?(n)
|
274
|
-
while read_command.call(session)
|
275
|
-
session.write("+#{n}\r\n")
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
redis_mock_with_handler(handler) do |redis|
|
281
|
-
yield(redis)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
def test_retry_on_write_error_by_default
|
286
|
-
close_on_connection([0]) do |redis|
|
287
|
-
assert_equal "1", redis.client.call(["x" * 128 * 1024])
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
def test_retry_on_write_error_when_wrapped_in_with_reconnect_true
|
292
|
-
close_on_connection([0]) do |redis|
|
293
|
-
redis.with_reconnect(true) do
|
294
|
-
assert_equal "1", redis.client.call(["x" * 128 * 1024])
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def test_dont_retry_on_write_error_when_wrapped_in_with_reconnect_false
|
300
|
-
close_on_connection([0]) do |redis|
|
301
|
-
assert_raise Redis::ConnectionError do
|
302
|
-
redis.with_reconnect(false) do
|
303
|
-
redis.client.call(["x" * 128 * 1024])
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def test_dont_retry_on_write_error_when_wrapped_in_without_reconnect
|
310
|
-
close_on_connection([0]) do |redis|
|
311
|
-
assert_raise Redis::ConnectionError do
|
312
|
-
redis.without_reconnect do
|
313
|
-
redis.client.call(["x" * 128 * 1024])
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def test_connecting_to_unix_domain_socket
|
320
|
-
assert_nothing_raised do
|
321
|
-
Redis.new(OPTIONS.merge(:path => "./test/db/redis.sock")).ping
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
driver(:ruby, :hiredis) do
|
326
|
-
def test_bubble_timeout_without_retrying
|
327
|
-
serv = TCPServer.new(6380)
|
328
|
-
|
329
|
-
redis = Redis.new(:port => 6380, :timeout => 0.1)
|
330
|
-
|
331
|
-
assert_raise(Redis::TimeoutError) do
|
332
|
-
redis.ping
|
333
|
-
end
|
334
|
-
|
335
|
-
ensure
|
336
|
-
serv.close if serv
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
def test_client_options
|
341
|
-
redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
|
342
|
-
|
343
|
-
assert_equal "host", redis.client.options[:host]
|
344
|
-
assert_equal 1234, redis.client.options[:port]
|
345
|
-
assert_equal 1, redis.client.options[:db]
|
346
|
-
assert_equal "foo", redis.client.options[:scheme]
|
347
|
-
end
|
348
|
-
|
349
|
-
def test_does_not_change_self_client_options
|
350
|
-
redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
|
351
|
-
options = redis.client.options
|
352
|
-
|
353
|
-
options[:host] << "new_host"
|
354
|
-
options[:scheme] << "bar"
|
355
|
-
options.merge!(:db => 0)
|
356
|
-
|
357
|
-
assert_equal "host", redis.client.options[:host]
|
358
|
-
assert_equal 1, redis.client.options[:db]
|
359
|
-
assert_equal "foo", redis.client.options[:scheme]
|
360
|
-
end
|
361
|
-
|
362
|
-
def test_resolves_localhost
|
363
|
-
assert_nothing_raised do
|
364
|
-
Redis.new(OPTIONS.merge(:host => 'localhost')).ping
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
class << self
|
369
|
-
def af_family_supported(af)
|
370
|
-
hosts = {
|
371
|
-
Socket::AF_INET => "127.0.0.1",
|
372
|
-
Socket::AF_INET6 => "::1",
|
373
|
-
}
|
374
|
-
|
375
|
-
begin
|
376
|
-
s = Socket.new(af, Socket::SOCK_STREAM, 0)
|
377
|
-
begin
|
378
|
-
tries = 5
|
379
|
-
begin
|
380
|
-
sa = Socket.pack_sockaddr_in(1024 + Random.rand(63076), hosts[af])
|
381
|
-
s.bind(sa)
|
382
|
-
rescue Errno::EADDRINUSE
|
383
|
-
tries -= 1
|
384
|
-
retry if tries > 0
|
385
|
-
|
386
|
-
raise
|
387
|
-
end
|
388
|
-
yield
|
389
|
-
rescue Errno::EADDRNOTAVAIL
|
390
|
-
ensure
|
391
|
-
s.close
|
392
|
-
end
|
393
|
-
rescue Errno::ESOCKTNOSUPPORT
|
394
|
-
end
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
def af_test(host)
|
399
|
-
commands = {
|
400
|
-
:ping => lambda { |*_| "+pong" },
|
401
|
-
}
|
402
|
-
|
403
|
-
redis_mock(commands, :host => host) do |redis|
|
404
|
-
assert_nothing_raised do
|
405
|
-
redis.ping
|
406
|
-
end
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
|
-
driver(:ruby) do
|
411
|
-
af_family_supported(Socket::AF_INET) do
|
412
|
-
def test_connect_ipv4
|
413
|
-
af_test("127.0.0.1")
|
414
|
-
end
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
driver(:ruby) do
|
419
|
-
af_family_supported(Socket::AF_INET6) do
|
420
|
-
def test_connect_ipv6
|
421
|
-
af_test("::1")
|
422
|
-
end
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
def test_can_be_duped_to_create_a_new_connection
|
427
|
-
clients = r.info["connected_clients"].to_i
|
428
|
-
|
429
|
-
r2 = r.dup
|
430
|
-
r2.ping
|
431
|
-
|
432
|
-
assert_equal clients + 1, r.info["connected_clients"].to_i
|
433
|
-
end
|
434
|
-
end
|