gorsuch-redis 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +113 -0
- data/LICENSE +20 -0
- data/README.md +214 -0
- data/Rakefile +260 -0
- data/TODO.md +4 -0
- data/benchmarking/logging.rb +62 -0
- data/benchmarking/pipeline.rb +51 -0
- data/benchmarking/speed.rb +21 -0
- data/benchmarking/suite.rb +24 -0
- data/benchmarking/thread_safety.rb +38 -0
- data/benchmarking/worker.rb +71 -0
- data/examples/basic.rb +15 -0
- data/examples/dist_redis.rb +43 -0
- data/examples/incr-decr.rb +17 -0
- data/examples/list.rb +26 -0
- data/examples/pubsub.rb +31 -0
- data/examples/sets.rb +36 -0
- data/examples/unicorn/config.ru +3 -0
- data/examples/unicorn/unicorn.rb +20 -0
- data/lib/redis/client.rb +303 -0
- data/lib/redis/connection/command_helper.rb +44 -0
- data/lib/redis/connection/hiredis.rb +52 -0
- data/lib/redis/connection/registry.rb +12 -0
- data/lib/redis/connection/ruby.rb +136 -0
- data/lib/redis/connection/synchrony.rb +131 -0
- data/lib/redis/connection.rb +9 -0
- data/lib/redis/distributed.rb +696 -0
- data/lib/redis/errors.rb +38 -0
- data/lib/redis/hash_ring.rb +131 -0
- data/lib/redis/pipeline.rb +106 -0
- data/lib/redis/subscribe.rb +79 -0
- data/lib/redis/version.rb +3 -0
- data/lib/redis.rb +1724 -0
- data/redis.gemspec +43 -0
- data/test/command_map_test.rb +29 -0
- data/test/commands_on_hashes_test.rb +20 -0
- data/test/commands_on_lists_test.rb +60 -0
- data/test/commands_on_sets_test.rb +76 -0
- data/test/commands_on_sorted_sets_test.rb +108 -0
- data/test/commands_on_strings_test.rb +80 -0
- data/test/commands_on_value_types_test.rb +87 -0
- data/test/connection_handling_test.rb +204 -0
- data/test/db/.gitignore +1 -0
- data/test/distributed_blocking_commands_test.rb +53 -0
- data/test/distributed_commands_on_hashes_test.rb +11 -0
- data/test/distributed_commands_on_lists_test.rb +23 -0
- data/test/distributed_commands_on_sets_test.rb +84 -0
- data/test/distributed_commands_on_sorted_sets_test.rb +19 -0
- data/test/distributed_commands_on_strings_test.rb +49 -0
- data/test/distributed_commands_on_value_types_test.rb +72 -0
- data/test/distributed_commands_requiring_clustering_test.rb +148 -0
- data/test/distributed_connection_handling_test.rb +24 -0
- data/test/distributed_internals_test.rb +27 -0
- data/test/distributed_key_tags_test.rb +52 -0
- data/test/distributed_persistence_control_commands_test.rb +23 -0
- data/test/distributed_publish_subscribe_test.rb +100 -0
- data/test/distributed_remote_server_control_commands_test.rb +42 -0
- data/test/distributed_sorting_test.rb +21 -0
- data/test/distributed_test.rb +59 -0
- data/test/distributed_transactions_test.rb +33 -0
- data/test/encoding_test.rb +15 -0
- data/test/error_replies_test.rb +53 -0
- data/test/helper.rb +155 -0
- data/test/helper_test.rb +8 -0
- data/test/internals_test.rb +152 -0
- data/test/lint/hashes.rb +140 -0
- data/test/lint/internals.rb +36 -0
- data/test/lint/lists.rb +107 -0
- data/test/lint/sets.rb +90 -0
- data/test/lint/sorted_sets.rb +196 -0
- data/test/lint/strings.rb +133 -0
- data/test/lint/value_types.rb +81 -0
- data/test/persistence_control_commands_test.rb +21 -0
- data/test/pipelining_commands_test.rb +186 -0
- data/test/publish_subscribe_test.rb +158 -0
- data/test/redis_mock.rb +89 -0
- data/test/remote_server_control_commands_test.rb +88 -0
- data/test/sorting_test.rb +43 -0
- data/test/synchrony_driver.rb +57 -0
- data/test/test.conf +9 -0
- data/test/thread_safety_test.rb +30 -0
- data/test/transactions_test.rb +173 -0
- data/test/unknown_commands_test.rb +13 -0
- data/test/url_param_test.rb +59 -0
- metadata +236 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
require "redis/distributed"
|
5
|
+
|
6
|
+
setup do
|
7
|
+
log = StringIO.new
|
8
|
+
init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
|
9
|
+
end
|
10
|
+
|
11
|
+
test "INFO" do |r|
|
12
|
+
%w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
|
13
|
+
r.info.each do |info|
|
14
|
+
assert info.keys.include?(x)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test "INFO COMMANDSTATS" do |r|
|
20
|
+
# Only available on Redis >= 2.9.0
|
21
|
+
next if version(r) < 209000
|
22
|
+
|
23
|
+
r.nodes.each { |n| n.config(:resetstat) }
|
24
|
+
r.ping # Executed on every node
|
25
|
+
|
26
|
+
r.info(:commandstats).each do |info|
|
27
|
+
assert "1" == info["ping"]["calls"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test "MONITOR" do |r|
|
32
|
+
begin
|
33
|
+
r.monitor
|
34
|
+
rescue Exception => ex
|
35
|
+
ensure
|
36
|
+
assert ex.kind_of?(NotImplementedError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
test "ECHO" do |r|
|
41
|
+
assert ["foo bar baz\n"] == r.echo("foo bar baz\n")
|
42
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
require "redis/distributed"
|
5
|
+
|
6
|
+
setup do
|
7
|
+
log = StringIO.new
|
8
|
+
init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
|
9
|
+
end
|
10
|
+
|
11
|
+
test "SORT" do |r|
|
12
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
13
|
+
r.set("foo:1", "s1")
|
14
|
+
r.set("foo:2", "s2")
|
15
|
+
|
16
|
+
r.rpush("bar", "1")
|
17
|
+
r.rpush("bar", "2")
|
18
|
+
|
19
|
+
r.sort("bar", :get => "foo:*", :limit => [0, 1])
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
require "redis/distributed"
|
5
|
+
|
6
|
+
setup do
|
7
|
+
log = StringIO.new
|
8
|
+
init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
|
9
|
+
end
|
10
|
+
|
11
|
+
test "handle multiple servers" do
|
12
|
+
@r = Redis::Distributed.new ["redis://localhost:6379/15", *NODES]
|
13
|
+
|
14
|
+
100.times do |idx|
|
15
|
+
@r.set(idx.to_s, "foo#{idx}")
|
16
|
+
end
|
17
|
+
|
18
|
+
100.times do |idx|
|
19
|
+
assert "foo#{idx}" == @r.get(idx.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
assert "0" == @r.keys("*").sort.first
|
23
|
+
assert "string" == @r.type("1")
|
24
|
+
end
|
25
|
+
|
26
|
+
test "add nodes" do
|
27
|
+
logger = Logger.new("/dev/null")
|
28
|
+
|
29
|
+
@r = Redis::Distributed.new NODES, :logger => logger, :timeout => 10
|
30
|
+
|
31
|
+
assert "127.0.0.1" == @r.nodes[0].client.host
|
32
|
+
assert 6379 == @r.nodes[0].client.port
|
33
|
+
assert 15 == @r.nodes[0].client.db
|
34
|
+
assert 10 == @r.nodes[0].client.timeout
|
35
|
+
assert logger == @r.nodes[0].client.logger
|
36
|
+
|
37
|
+
@r.add_node("redis://localhost:6380/14")
|
38
|
+
|
39
|
+
assert "localhost" == @r.nodes[1].client.host
|
40
|
+
assert 6380 == @r.nodes[1].client.port
|
41
|
+
assert 14 == @r.nodes[1].client.db
|
42
|
+
assert 10 == @r.nodes[1].client.timeout
|
43
|
+
assert logger == @r.nodes[1].client.logger
|
44
|
+
end
|
45
|
+
|
46
|
+
test "Pipelining commands cannot be distributed" do |r|
|
47
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
48
|
+
r.pipelined do
|
49
|
+
r.lpush "foo", "s1"
|
50
|
+
r.lpush "foo", "s2"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
test "Unknown commands does not work by default" do |r|
|
56
|
+
assert_raise NoMethodError do
|
57
|
+
r.not_yet_implemented_command
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
require "redis/distributed"
|
5
|
+
|
6
|
+
setup do
|
7
|
+
log = StringIO.new
|
8
|
+
init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
|
9
|
+
end
|
10
|
+
|
11
|
+
test "MULTI/DISCARD" do |r|
|
12
|
+
@foo = nil
|
13
|
+
|
14
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
15
|
+
r.multi { @foo = 1 }
|
16
|
+
end
|
17
|
+
|
18
|
+
assert nil == @foo
|
19
|
+
|
20
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
21
|
+
r.discard
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
test "WATCH/UNWATCH" do |r|
|
26
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
27
|
+
r.watch("foo")
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
31
|
+
r.unwatch
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
setup do
|
6
|
+
init Redis.new(OPTIONS)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "returns properly encoded strings" do |r|
|
10
|
+
with_external_encoding("UTF-8") do
|
11
|
+
r.set "foo", "שלום"
|
12
|
+
|
13
|
+
assert "Shalom שלום" == "Shalom " + r.get("foo")
|
14
|
+
end
|
15
|
+
end if defined?(Encoding)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
setup do
|
6
|
+
init Redis.new(OPTIONS)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Every test shouldn't disconnect from the server. Also, when error replies are
|
10
|
+
# in play, the protocol should never get into an invalid state where there are
|
11
|
+
# pending replies in the connection. Calling INFO after every test ensures that
|
12
|
+
# the protocol is still in a valid state.
|
13
|
+
def test_with_reconnection_check(title)
|
14
|
+
test(title) do |r|
|
15
|
+
before = r.info["total_connections_received"]
|
16
|
+
yield(r)
|
17
|
+
after = r.info["total_connections_received"]
|
18
|
+
assert before == after
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
test_with_reconnection_check "Error reply for single command" do |r|
|
23
|
+
begin
|
24
|
+
r.unknown_command
|
25
|
+
rescue => ex
|
26
|
+
ensure
|
27
|
+
assert ex.message =~ /unknown command/i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test_with_reconnection_check "Raise first error reply in pipeline" do |r|
|
32
|
+
begin
|
33
|
+
r.pipelined do
|
34
|
+
r.set("foo", "s1")
|
35
|
+
r.incr("foo") # not an integer
|
36
|
+
r.lpush("foo", "value") # wrong kind of value
|
37
|
+
end
|
38
|
+
rescue => ex
|
39
|
+
ensure
|
40
|
+
assert ex.message =~ /not an integer/i
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
test_with_reconnection_check "Recover from raise in #call_loop" do |r|
|
45
|
+
begin
|
46
|
+
r.client.call_loop([:invalid_monitor]) do
|
47
|
+
assert false # Should never be executed
|
48
|
+
end
|
49
|
+
rescue => ex
|
50
|
+
ensure
|
51
|
+
assert ex.message =~ /unknown command/i
|
52
|
+
end
|
53
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
#require "cutest"
|
4
|
+
require "logger"
|
5
|
+
require "stringio"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "ruby-debug"
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
12
|
+
PORT = 6379
|
13
|
+
OPTIONS = {:port => PORT, :db => 15, :timeout => 3}
|
14
|
+
NODES = ["redis://127.0.0.1:6379/15"]
|
15
|
+
|
16
|
+
def init(redis)
|
17
|
+
begin
|
18
|
+
redis.flushdb
|
19
|
+
redis.select 14
|
20
|
+
redis.flushdb
|
21
|
+
redis.select 15
|
22
|
+
redis
|
23
|
+
rescue Redis::CannotConnectError
|
24
|
+
puts <<-EOS
|
25
|
+
|
26
|
+
Cannot connect to Redis.
|
27
|
+
|
28
|
+
Make sure Redis is running on localhost, port 6379.
|
29
|
+
This testing suite connects to the database 15.
|
30
|
+
|
31
|
+
To install redis:
|
32
|
+
visit <http://redis.io/download/>.
|
33
|
+
|
34
|
+
To start the server:
|
35
|
+
rake start
|
36
|
+
|
37
|
+
To stop the server:
|
38
|
+
rake stop
|
39
|
+
|
40
|
+
EOS
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
$VERBOSE = true
|
46
|
+
|
47
|
+
require "redis/connection/%s" % (ENV["REDIS_CONNECTION_DRIVER"] || "ruby")
|
48
|
+
require "redis"
|
49
|
+
|
50
|
+
def driver
|
51
|
+
Redis::Connection.drivers.last.to_s.split("::").last.downcase.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
if driver == :synchrony
|
55
|
+
# Make cutest fiber + eventmachine aware if the synchrony driver is used.
|
56
|
+
undef test if defined? test
|
57
|
+
def test(name = nil, &block)
|
58
|
+
cutest[:test] = name
|
59
|
+
|
60
|
+
blk = Proc.new do
|
61
|
+
prepare.each { |blk| blk.call }
|
62
|
+
block.call(setup && setup.call)
|
63
|
+
end
|
64
|
+
|
65
|
+
t = Thread.current[:cutest]
|
66
|
+
if defined? EventMachine
|
67
|
+
EM.synchrony do
|
68
|
+
Thread.current[:cutest] = t
|
69
|
+
blk.call
|
70
|
+
EM.stop
|
71
|
+
end
|
72
|
+
else
|
73
|
+
blk.call
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Wire < Fiber
|
78
|
+
# We cannot run this fiber explicitly because EM schedules it. Resuming the
|
79
|
+
# current fiber on the next tick to let the reactor do work.
|
80
|
+
def self.pass
|
81
|
+
f = Fiber.current
|
82
|
+
EM.next_tick { f.resume }
|
83
|
+
Fiber.yield
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.sleep(sec)
|
87
|
+
EM::Synchrony.sleep(sec)
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize(&blk)
|
91
|
+
super
|
92
|
+
|
93
|
+
# Schedule run in next tick
|
94
|
+
EM.next_tick { resume }
|
95
|
+
end
|
96
|
+
|
97
|
+
def join
|
98
|
+
self.class.pass while alive?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
class Wire < Thread
|
103
|
+
def self.sleep(sec)
|
104
|
+
Kernel.sleep(sec)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def capture_stderr
|
110
|
+
stderr = $stderr
|
111
|
+
$stderr = StringIO.new
|
112
|
+
|
113
|
+
yield
|
114
|
+
|
115
|
+
$stderr = stderr
|
116
|
+
end
|
117
|
+
|
118
|
+
def silent
|
119
|
+
verbose, $VERBOSE = $VERBOSE, false
|
120
|
+
|
121
|
+
begin
|
122
|
+
yield
|
123
|
+
ensure
|
124
|
+
$VERBOSE = verbose
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def version(r)
|
129
|
+
info = r.info
|
130
|
+
info = info.first unless info.is_a?(Hash)
|
131
|
+
version_str_to_i info["redis_version"]
|
132
|
+
end
|
133
|
+
|
134
|
+
def version_str_to_i(version_str)
|
135
|
+
version_str.split(".").map{ |v| v.ljust(2, '0') }.join.to_i
|
136
|
+
end
|
137
|
+
|
138
|
+
def with_external_encoding(encoding)
|
139
|
+
original_encoding = Encoding.default_external
|
140
|
+
|
141
|
+
begin
|
142
|
+
silent { Encoding.default_external = Encoding.find(encoding) }
|
143
|
+
yield
|
144
|
+
ensure
|
145
|
+
silent { Encoding.default_external = original_encoding }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def assert_nothing_raised(*exceptions)
|
150
|
+
begin
|
151
|
+
yield
|
152
|
+
rescue *exceptions
|
153
|
+
flunk(caller[1])
|
154
|
+
end
|
155
|
+
end
|
data/test/helper_test.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
test "version_str_to_i" do
|
4
|
+
assert_equal 200000, version_str_to_i('2.0.0')
|
5
|
+
assert_equal 202020, version_str_to_i('2.2.2')
|
6
|
+
assert_equal 202022, version_str_to_i('2.2.22')
|
7
|
+
assert_equal 222222, version_str_to_i('22.22.22')
|
8
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
require File.expand_path("./redis_mock", File.dirname(__FILE__))
|
5
|
+
|
6
|
+
include RedisMock::Helper
|
7
|
+
|
8
|
+
setup do
|
9
|
+
log = StringIO.new
|
10
|
+
|
11
|
+
[Redis.new(OPTIONS.merge(:logger => ::Logger.new(log))), log]
|
12
|
+
end
|
13
|
+
|
14
|
+
$TEST_PIPELINING = true
|
15
|
+
|
16
|
+
load File.expand_path("./lint/internals.rb", File.dirname(__FILE__))
|
17
|
+
|
18
|
+
test "provides a meaningful inspect" do |r, _|
|
19
|
+
assert "#<Redis client v#{Redis::VERSION} connected to redis://127.0.0.1:6379/15 (Redis v#{r.info["redis_version"]})>" == r.inspect
|
20
|
+
end
|
21
|
+
|
22
|
+
test "Redis.current" do
|
23
|
+
Redis.current.set("foo", "bar")
|
24
|
+
|
25
|
+
assert "bar" == Redis.current.get("foo")
|
26
|
+
|
27
|
+
Redis.current = Redis.new(OPTIONS.merge(:db => 14))
|
28
|
+
|
29
|
+
assert Redis.current.get("foo").nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
test "Timeout" do
|
33
|
+
assert_nothing_raised do
|
34
|
+
Redis.new(OPTIONS.merge(:timeout => 0))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
test "Connection timeout" do
|
39
|
+
next if driver == :synchrony
|
40
|
+
|
41
|
+
assert_raise Redis::CannotConnectError do
|
42
|
+
Redis.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
test "Retry when first read raises ECONNRESET" do
|
47
|
+
$request = 0
|
48
|
+
|
49
|
+
command = lambda do
|
50
|
+
case ($request += 1)
|
51
|
+
when 1; nil # Close on first command
|
52
|
+
else "+%d" % $request
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
redis_mock(:ping => command) do
|
57
|
+
redis = Redis.connect(:port => 6380, :timeout => 0.1)
|
58
|
+
assert "2" == redis.ping
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
test "Don't retry when wrapped inside #without_reconnect" do
|
63
|
+
$request = 0
|
64
|
+
|
65
|
+
command = lambda do
|
66
|
+
case ($request += 1)
|
67
|
+
when 1; nil # Close on first command
|
68
|
+
else "+%d" % $request
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
redis_mock(:ping => command) do
|
73
|
+
redis = Redis.connect(:port => 6380, :timeout => 0.1)
|
74
|
+
assert_raise Redis::ConnectionError do
|
75
|
+
redis.without_reconnect do
|
76
|
+
redis.ping
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
assert !redis.client.connected?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
test "Retry only once when read raises ECONNRESET" do
|
85
|
+
$request = 0
|
86
|
+
|
87
|
+
command = lambda do
|
88
|
+
case ($request += 1)
|
89
|
+
when 1; nil # Close on first command
|
90
|
+
when 2; nil # Close on second command
|
91
|
+
else "+%d" % $request
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
redis_mock(:ping => command) do
|
96
|
+
redis = Redis.connect(:port => 6380, :timeout => 0.1)
|
97
|
+
assert_raise Redis::ConnectionError do
|
98
|
+
redis.ping
|
99
|
+
end
|
100
|
+
|
101
|
+
assert !redis.client.connected?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
test "Don't retry when second read in pipeline raises ECONNRESET" do
|
106
|
+
$request = 0
|
107
|
+
|
108
|
+
command = lambda do
|
109
|
+
case ($request += 1)
|
110
|
+
when 2; nil # Close on second command
|
111
|
+
else "+%d" % $request
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
redis_mock(:ping => command) do
|
116
|
+
redis = Redis.connect(:port => 6380, :timeout => 0.1)
|
117
|
+
assert_raise Redis::ConnectionError do
|
118
|
+
redis.pipelined do
|
119
|
+
redis.ping
|
120
|
+
redis.ping # Second #read times out
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
test "Connecting to UNIX domain socket" do
|
127
|
+
assert_nothing_raised do
|
128
|
+
Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock")).ping
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# if driver == :ruby || driver == :hiredis
|
133
|
+
# # Using a mock server in a thread doesn't work here (possibly because blocking
|
134
|
+
# # socket ops, raw socket timeouts and Ruby's thread scheduling don't mix).
|
135
|
+
# test "Bubble EAGAIN without retrying" do
|
136
|
+
# cmd = %{(sleep 0.3; echo "+PONG\r\n") | nc -l 6380}
|
137
|
+
# IO.popen(cmd) do |_|
|
138
|
+
# sleep 0.1 # Give nc a little time to start listening
|
139
|
+
# redis = Redis.connect(:port => 6380, :timeout => 0.1)
|
140
|
+
#
|
141
|
+
# begin
|
142
|
+
# assert_raise(Errno::EAGAIN) { redis.ping }
|
143
|
+
# ensure
|
144
|
+
# # Explicitly close connection so nc can quit
|
145
|
+
# redis.client.disconnect
|
146
|
+
#
|
147
|
+
# # Make the reactor loop do a tick to really close
|
148
|
+
# EM::Synchrony.sleep(0) if driver == :synchrony
|
149
|
+
# end
|
150
|
+
# end
|
151
|
+
# end
|
152
|
+
# end
|