gorsuch-redis 3.0.0.rc1
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.
- 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
|