redis 3.0.6 → 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/.travis.yml +8 -5
- data/CHANGELOG.md +10 -0
- data/README.md +17 -1
- data/lib/redis.rb +6 -1
- data/lib/redis/client.rb +15 -3
- data/lib/redis/connection/ruby.rb +36 -5
- data/lib/redis/distributed.rb +8 -3
- data/lib/redis/pipeline.rb +1 -1
- data/lib/redis/subscribe.rb +2 -1
- data/lib/redis/version.rb +1 -1
- data/redis.gemspec +2 -0
- data/test/commands_on_strings_test.rb +14 -12
- data/test/commands_on_value_types_test.rb +4 -4
- data/test/connection_handling_test.rb +1 -1
- data/test/distributed_internals_test.rb +37 -8
- data/test/distributed_key_tags_test.rb +6 -6
- data/test/distributed_test.rb +3 -3
- data/test/helper.rb +14 -3
- data/test/internals_test.rb +87 -0
- data/test/pipelining_commands_test.rb +0 -2
- data/test/publish_subscribe_test.rb +60 -1
- data/test/support/redis_mock.rb +6 -6
- data/test/transactions_test.rb +0 -2
- metadata +14 -71
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
NTZjYTMwZjU5ZWMwZDI0ZWM4OTZmZGU3YmMzMGJlZmZjMDUxNjUwMzNhZGMy
|
10
|
-
OTZkOWJmNTM5NTQzMWUyZTRjZmMzNWQ5MDY1NDljNzJiNWMzMGE4NGZjMDI0
|
11
|
-
YzM4YTE5MGM5MWVmN2YyYTI3YTViMzljMDg2YzQyYTZlY2M0OTE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Mzk0NmVkMmEwYjc1MzIzOTU4MDEwN2QwNmRhZThkMzA2NzIyOTU5YjlmMzMz
|
14
|
-
Y2NkZjUyZTE5YmI2MjFiZTA4YjNkOWMzZWEwYWRkMjZlNDgzNTc3NDViOTRl
|
15
|
-
ZDMyZDlhYThhZjMxOGM5YzE1NjNkZDQzNjAwODEyNjM3ZmQ3OWE=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f19cb52776a7c819c4e77758ef023e958a9929f8
|
4
|
+
data.tar.gz: 38c26138524df7d89fe8c876d23d22d424cbeace
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d448483ee949db61aafe63bfa1a81ca0eba4ebf3310303d06642a48bb806736219d39e16a739cba2ebdd080270e93307c46a07ee5caa1e390ba11f7e3ca7f66f
|
7
|
+
data.tar.gz: c2bc48a670e248fa68b8bb149d73bac42e060212019f8ae7cbc0c14555040b9616e3673ca809bfa97f8038a10e02c94a49d1211a6300c323d83bc3742c8b1a68
|
data/.travis.yml
CHANGED
@@ -16,11 +16,14 @@ gemfile:
|
|
16
16
|
- .travis/Gemfile
|
17
17
|
|
18
18
|
env:
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
global:
|
20
|
+
- TIMEOUT=1
|
21
|
+
matrix:
|
22
|
+
- conn=ruby REDIS_BRANCH=2.6
|
23
|
+
- conn=hiredis REDIS_BRANCH=2.6
|
24
|
+
- conn=synchrony REDIS_BRANCH=2.6
|
25
|
+
- conn=ruby REDIS_BRANCH=2.8
|
26
|
+
- conn=ruby REDIS_BRANCH=unstable
|
24
27
|
|
25
28
|
matrix:
|
26
29
|
exclude:
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -38,15 +38,31 @@ listening on `localhost`, port 6379. If you need to connect to a remote
|
|
38
38
|
server or a different port, try:
|
39
39
|
|
40
40
|
```ruby
|
41
|
-
redis = Redis.new(:host => "10.0.1.1", :port => 6380)
|
41
|
+
redis = Redis.new(:host => "10.0.1.1", :port => 6380, :db => 15)
|
42
42
|
```
|
43
43
|
|
44
|
+
You can also specify connection options as an URL:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
48
|
+
```
|
49
|
+
|
50
|
+
By default, the client will try to read the `REDIS_URL` environment variable
|
51
|
+
and use that as URL to connect to. The above statement is therefore equivalent
|
52
|
+
to setting this environment variable and calling `Redis.new` without arguments.
|
53
|
+
|
44
54
|
To connect to Redis listening on a Unix socket, try:
|
45
55
|
|
46
56
|
```ruby
|
47
57
|
redis = Redis.new(:path => "/tmp/redis.sock")
|
48
58
|
```
|
49
59
|
|
60
|
+
To connect to a password protected Redis instance, use:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
redis = Redis.new(:password => "mysecret")
|
64
|
+
```
|
65
|
+
|
50
66
|
The Redis class exports methods that are named identical to the commands
|
51
67
|
they execute. The arguments these methods accept are often identical to
|
52
68
|
the arguments specified on the [Redis website][redis-commands]. For
|
data/lib/redis.rb
CHANGED
@@ -27,6 +27,7 @@ class Redis
|
|
27
27
|
include MonitorMixin
|
28
28
|
|
29
29
|
def initialize(options = {})
|
30
|
+
@options = options.dup
|
30
31
|
@original_client = @client = Client.new(options)
|
31
32
|
|
32
33
|
super() # Monitor#initialize
|
@@ -128,7 +129,7 @@ class Redis
|
|
128
129
|
|
129
130
|
# Get or set server configuration parameters.
|
130
131
|
#
|
131
|
-
# @param [
|
132
|
+
# @param [Symbol] action e.g. `:get`, `:set`, `:resetstat`
|
132
133
|
# @return [String, Hash] string reply, or hash when retrieving more than one
|
133
134
|
# property with `CONFIG GET`
|
134
135
|
def config(action, *args)
|
@@ -2422,6 +2423,10 @@ class Redis
|
|
2422
2423
|
"#<Redis client v#{Redis::VERSION} for #{id}>"
|
2423
2424
|
end
|
2424
2425
|
|
2426
|
+
def dup
|
2427
|
+
self.class.new(@options)
|
2428
|
+
end
|
2429
|
+
|
2425
2430
|
def method_missing(command, *args)
|
2426
2431
|
synchronize do |client|
|
2427
2432
|
client.call([command] + args)
|
data/lib/redis/client.rb
CHANGED
@@ -19,6 +19,10 @@ class Redis
|
|
19
19
|
:tcp_keepalive => 0
|
20
20
|
}
|
21
21
|
|
22
|
+
def options
|
23
|
+
Marshal.load(Marshal.dump(@options))
|
24
|
+
end
|
25
|
+
|
22
26
|
def scheme
|
23
27
|
@options[:scheme]
|
24
28
|
end
|
@@ -51,6 +55,10 @@ class Redis
|
|
51
55
|
@options[:db] = db.to_i
|
52
56
|
end
|
53
57
|
|
58
|
+
def driver
|
59
|
+
@options[:driver]
|
60
|
+
end
|
61
|
+
|
54
62
|
attr_accessor :logger
|
55
63
|
attr_reader :connection
|
56
64
|
attr_reader :command_map
|
@@ -66,9 +74,13 @@ class Redis
|
|
66
74
|
def connect
|
67
75
|
@pid = Process.pid
|
68
76
|
|
69
|
-
|
70
|
-
|
71
|
-
|
77
|
+
# Don't try to reconnect when the connection is fresh
|
78
|
+
with_reconnect(false) do
|
79
|
+
establish_connection
|
80
|
+
call [:auth, password] if password
|
81
|
+
call [:select, db] if db != 0
|
82
|
+
end
|
83
|
+
|
72
84
|
self
|
73
85
|
end
|
74
86
|
|
@@ -114,11 +114,9 @@ class Redis
|
|
114
114
|
|
115
115
|
include SocketMixin
|
116
116
|
|
117
|
-
def self.
|
118
|
-
|
119
|
-
|
120
|
-
sock = new(::Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
121
|
-
sockaddr = ::Socket.pack_sockaddr_in(port, addr[0][3])
|
117
|
+
def self.connect_addrinfo(ai, port, timeout)
|
118
|
+
sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
|
119
|
+
sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
|
122
120
|
|
123
121
|
begin
|
124
122
|
sock.connect_nonblock(sockaddr)
|
@@ -135,6 +133,39 @@ class Redis
|
|
135
133
|
|
136
134
|
sock
|
137
135
|
end
|
136
|
+
|
137
|
+
def self.connect(host, port, timeout)
|
138
|
+
# Don't pass AI_ADDRCONFIG as flag to getaddrinfo(3)
|
139
|
+
#
|
140
|
+
# From the man page for getaddrinfo(3):
|
141
|
+
#
|
142
|
+
# If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4
|
143
|
+
# addresses are returned in the list pointed to by res only if the
|
144
|
+
# local system has at least one IPv4 address configured, and IPv6
|
145
|
+
# addresses are returned only if the local system has at least one
|
146
|
+
# IPv6 address configured. The loopback address is not considered
|
147
|
+
# for this case as valid as a configured address.
|
148
|
+
#
|
149
|
+
# We do want the IPv6 loopback address to be returned if applicable,
|
150
|
+
# even if it is the only configured IPv6 address on the machine.
|
151
|
+
# Also see: https://github.com/redis/redis-rb/pull/394.
|
152
|
+
addrinfo = ::Socket.getaddrinfo(host, nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
|
153
|
+
|
154
|
+
# From the man page for getaddrinfo(3):
|
155
|
+
#
|
156
|
+
# Normally, the application should try using the addresses in the
|
157
|
+
# order in which they are returned. The sorting function used
|
158
|
+
# within getaddrinfo() is defined in RFC 3484 [...].
|
159
|
+
#
|
160
|
+
addrinfo.each_with_index do |ai, i|
|
161
|
+
begin
|
162
|
+
return connect_addrinfo(ai, port, timeout)
|
163
|
+
rescue SystemCallError
|
164
|
+
# Raise if this was our last attempt.
|
165
|
+
raise if addrinfo.length == i+1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
138
169
|
end
|
139
170
|
|
140
171
|
class UNIXSocket < ::Socket
|
data/lib/redis/distributed.rb
CHANGED
@@ -16,9 +16,10 @@ class Redis
|
|
16
16
|
attr_reader :ring
|
17
17
|
|
18
18
|
def initialize(node_configs, options = {})
|
19
|
-
@tag = options
|
20
|
-
@ring = options
|
21
|
-
@
|
19
|
+
@tag = options[:tag] || /^\{(.+?)\}/
|
20
|
+
@ring = options[:ring] || HashRing.new
|
21
|
+
@node_configs = node_configs.dup
|
22
|
+
@default_options = options.dup
|
22
23
|
node_configs.each { |node_config| add_node(node_config) }
|
23
24
|
@subscribed_node = nil
|
24
25
|
end
|
@@ -807,6 +808,10 @@ class Redis
|
|
807
808
|
"#<Redis client v#{Redis::VERSION} for #{nodes.map(&:id).join(', ')}>"
|
808
809
|
end
|
809
810
|
|
811
|
+
def dup
|
812
|
+
self.class.new(@node_configs, @default_options)
|
813
|
+
end
|
814
|
+
|
810
815
|
protected
|
811
816
|
|
812
817
|
def on_each_node(command, *args)
|
data/lib/redis/pipeline.rb
CHANGED
data/lib/redis/subscribe.rb
CHANGED
data/lib/redis/version.rb
CHANGED
data/redis.gemspec
CHANGED
@@ -82,18 +82,20 @@ class TestCommandsOnStrings < Test::Unit::TestCase
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_bitop
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
85
|
+
try_encoding("UTF-8") do
|
86
|
+
target_version "2.5.10" do
|
87
|
+
r.set("foo", "a")
|
88
|
+
r.set("bar", "b")
|
89
|
+
|
90
|
+
r.bitop(:and, "foo&bar", "foo", "bar")
|
91
|
+
assert_equal "\x60", r.get("foo&bar")
|
92
|
+
r.bitop(:or, "foo|bar", "foo", "bar")
|
93
|
+
assert_equal "\x63", r.get("foo|bar")
|
94
|
+
r.bitop(:xor, "foo^bar", "foo", "bar")
|
95
|
+
assert_equal "\x03", r.get("foo^bar")
|
96
|
+
r.bitop(:not, "~foo", "foo")
|
97
|
+
assert_equal "\x9E", r.get("~foo")
|
98
|
+
end
|
97
99
|
end
|
98
100
|
end
|
99
101
|
end
|
@@ -99,7 +99,7 @@ class TestCommandsOnValueTypes < Test::Unit::TestCase
|
|
99
99
|
|
100
100
|
def test_migrate
|
101
101
|
redis_mock(:migrate => lambda { |*args| args }) do |redis|
|
102
|
-
options = { :host => "
|
102
|
+
options = { :host => "127.0.0.1", :port => 1234 }
|
103
103
|
|
104
104
|
assert_raise(RuntimeError, /host not specified/) do
|
105
105
|
redis.migrate("foo", options.reject { |key, _| key == :host })
|
@@ -114,17 +114,17 @@ class TestCommandsOnValueTypes < Test::Unit::TestCase
|
|
114
114
|
|
115
115
|
# Test defaults
|
116
116
|
actual = redis.migrate("foo", options)
|
117
|
-
expected = ["
|
117
|
+
expected = ["127.0.0.1", "1234", "foo", default_db.to_s, default_timeout.to_s]
|
118
118
|
assert_equal expected, actual
|
119
119
|
|
120
120
|
# Test db override
|
121
121
|
actual = redis.migrate("foo", options.merge(:db => default_db + 1))
|
122
|
-
expected = ["
|
122
|
+
expected = ["127.0.0.1", "1234", "foo", (default_db + 1).to_s, default_timeout.to_s]
|
123
123
|
assert_equal expected, actual
|
124
124
|
|
125
125
|
# Test timeout override
|
126
126
|
actual = redis.migrate("foo", options.merge(:timeout => default_timeout + 1))
|
127
|
-
expected = ["
|
127
|
+
expected = ["127.0.0.1", "1234", "foo", default_db.to_s, (default_timeout + 1).to_s]
|
128
128
|
assert_equal expected, actual
|
129
129
|
end
|
130
130
|
end
|
@@ -157,7 +157,7 @@ class TestConnectionHandling < Test::Unit::TestCase
|
|
157
157
|
|
158
158
|
def test_slaveof
|
159
159
|
redis_mock(:slaveof => lambda { |host, port| "+SLAVEOF #{host} #{port}" }) do |redis|
|
160
|
-
assert_equal "SLAVEOF
|
160
|
+
assert_equal "SLAVEOF somehost 6381", redis.slaveof("somehost", 6381)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
@@ -7,35 +7,64 @@ class TestDistributedInternals < Test::Unit::TestCase
|
|
7
7
|
include Helper::Distributed
|
8
8
|
|
9
9
|
def test_provides_a_meaningful_inspect
|
10
|
-
nodes = ["redis://
|
10
|
+
nodes = ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
11
11
|
redis = Redis::Distributed.new nodes
|
12
12
|
|
13
13
|
assert_equal "#<Redis client v#{Redis::VERSION} for #{redis.nodes.map(&:id).join(', ')}>", redis.inspect
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_default_as_urls
|
17
|
-
nodes = ["redis://
|
17
|
+
nodes = ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
18
18
|
redis = Redis::Distributed.new nodes
|
19
|
-
assert_equal ["redis://
|
19
|
+
assert_equal ["redis://127.0.0.1:#{PORT}/15", *NODES], redis.nodes.map { |node| node.client.id}
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_default_as_config_hashes
|
23
|
-
nodes = [OPTIONS.merge(:host => '
|
23
|
+
nodes = [OPTIONS.merge(:host => '127.0.0.1'), OPTIONS.merge(:host => 'somehost', :port => PORT.next)]
|
24
24
|
redis = Redis::Distributed.new nodes
|
25
|
-
assert_equal ["redis://
|
25
|
+
assert_equal ["redis://127.0.0.1:#{PORT}/15","redis://somehost:#{PORT.next}/15"], redis.nodes.map { |node| node.client.id }
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_as_mix_and_match
|
29
|
-
nodes = ["redis://
|
29
|
+
nodes = ["redis://127.0.0.1:7389/15", OPTIONS.merge(:host => 'somehost'), OPTIONS.merge(:host => 'somehost', :port => PORT.next)]
|
30
30
|
redis = Redis::Distributed.new nodes
|
31
|
-
assert_equal ["redis://
|
31
|
+
assert_equal ["redis://127.0.0.1:7389/15", "redis://somehost:#{PORT}/15", "redis://somehost:#{PORT.next}/15"], redis.nodes.map { |node| node.client.id }
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_override_id
|
35
|
-
nodes = [OPTIONS.merge(:host => '
|
35
|
+
nodes = [OPTIONS.merge(:host => '127.0.0.1', :id => "test"), OPTIONS.merge( :host => 'somehost', :port => PORT.next, :id => "test1")]
|
36
36
|
redis = Redis::Distributed.new nodes
|
37
37
|
assert_equal redis.nodes.first.client.id, "test"
|
38
38
|
assert_equal redis.nodes.last.client.id, "test1"
|
39
39
|
assert_equal "#<Redis client v#{Redis::VERSION} for #{redis.nodes.map(&:id).join(', ')}>", redis.inspect
|
40
40
|
end
|
41
|
+
|
42
|
+
def test_can_be_duped_to_create_a_new_connection
|
43
|
+
redis = Redis::Distributed.new(NODES)
|
44
|
+
|
45
|
+
clients = redis.info[0]["connected_clients"].to_i
|
46
|
+
|
47
|
+
r2 = redis.dup
|
48
|
+
r2.ping
|
49
|
+
|
50
|
+
assert_equal clients + 1, redis.info[0]["connected_clients"].to_i
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_keeps_options_after_dup
|
54
|
+
r1 = Redis::Distributed.new(NODES, :tag => /^(\w+):/)
|
55
|
+
|
56
|
+
assert_raise(Redis::Distributed::CannotDistribute) do
|
57
|
+
r1.sinter("foo", "bar")
|
58
|
+
end
|
59
|
+
|
60
|
+
assert_equal [], r1.sinter("baz:foo", "baz:bar")
|
61
|
+
|
62
|
+
r2 = r1.dup
|
63
|
+
|
64
|
+
assert_raise(Redis::Distributed::CannotDistribute) do
|
65
|
+
r2.sinter("foo", "bar")
|
66
|
+
end
|
67
|
+
|
68
|
+
assert_equal [], r2.sinter("baz:foo", "baz:bar")
|
69
|
+
end
|
41
70
|
end
|
@@ -8,9 +8,9 @@ class TestDistributedKeyTags < Test::Unit::TestCase
|
|
8
8
|
include Helper::Distributed
|
9
9
|
|
10
10
|
def test_hashes_consistently
|
11
|
-
r1 = Redis::Distributed.new ["redis://
|
12
|
-
r2 = Redis::Distributed.new ["redis://
|
13
|
-
r3 = Redis::Distributed.new ["redis://
|
11
|
+
r1 = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
12
|
+
r2 = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
13
|
+
r3 = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
14
14
|
|
15
15
|
assert_equal r1.node_for("foo").id, r2.node_for("foo").id
|
16
16
|
assert_equal r1.node_for("foo").id, r3.node_for("foo").id
|
@@ -18,7 +18,7 @@ class TestDistributedKeyTags < Test::Unit::TestCase
|
|
18
18
|
|
19
19
|
def test_allows_clustering_of_keys
|
20
20
|
r = Redis::Distributed.new(NODES)
|
21
|
-
r.add_node("redis://
|
21
|
+
r.add_node("redis://127.0.0.1:#{PORT}/14")
|
22
22
|
r.flushdb
|
23
23
|
|
24
24
|
100.times do |i|
|
@@ -29,7 +29,7 @@ class TestDistributedKeyTags < Test::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_distributes_keys_if_no_clustering_is_used
|
32
|
-
r.add_node("redis://
|
32
|
+
r.add_node("redis://127.0.0.1:#{PORT}/14")
|
33
33
|
r.flushdb
|
34
34
|
|
35
35
|
r.set "users:1", 1
|
@@ -40,7 +40,7 @@ class TestDistributedKeyTags < Test::Unit::TestCase
|
|
40
40
|
|
41
41
|
def test_allows_passing_a_custom_tag_extractor
|
42
42
|
r = Redis::Distributed.new(NODES, :tag => /^(.+?):/)
|
43
|
-
r.add_node("redis://
|
43
|
+
r.add_node("redis://127.0.0.1:#{PORT}/14")
|
44
44
|
r.flushdb
|
45
45
|
|
46
46
|
100.times do |i|
|
data/test/distributed_test.rb
CHANGED
@@ -7,7 +7,7 @@ class TestDistributed < Test::Unit::TestCase
|
|
7
7
|
include Helper::Distributed
|
8
8
|
|
9
9
|
def test_handle_multiple_servers
|
10
|
-
@r = Redis::Distributed.new ["redis://
|
10
|
+
@r = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
|
11
11
|
|
12
12
|
100.times do |idx|
|
13
13
|
@r.set(idx.to_s, "foo#{idx}")
|
@@ -32,9 +32,9 @@ class TestDistributed < Test::Unit::TestCase
|
|
32
32
|
assert_equal 10, @r.nodes[0].client.timeout
|
33
33
|
assert_equal logger, @r.nodes[0].client.logger
|
34
34
|
|
35
|
-
@r.add_node("redis://
|
35
|
+
@r.add_node("redis://127.0.0.1:6380/14")
|
36
36
|
|
37
|
-
assert_equal "
|
37
|
+
assert_equal "127.0.0.1", @r.nodes[1].client.host
|
38
38
|
assert_equal 6380, @r.nodes[1].client.port
|
39
39
|
assert_equal 14, @r.nodes[1].client.db
|
40
40
|
assert_equal 10, @r.nodes[1].client.timeout
|
data/test/helper.rb
CHANGED
@@ -22,7 +22,7 @@ require "support/redis_mock"
|
|
22
22
|
require "support/connection/#{ENV["conn"]}"
|
23
23
|
|
24
24
|
PORT = 6381
|
25
|
-
OPTIONS = {:port => PORT, :db => 15, :timeout => 0.1}
|
25
|
+
OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
|
26
26
|
NODES = ["redis://127.0.0.1:#{PORT}/15"]
|
27
27
|
|
28
28
|
def init(redis)
|
@@ -91,6 +91,14 @@ module Helper
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
def try_encoding(encoding, &block)
|
95
|
+
if defined?(Encoding)
|
96
|
+
with_external_encoding(encoding, &block)
|
97
|
+
else
|
98
|
+
yield
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
94
102
|
class Version
|
95
103
|
|
96
104
|
include Comparable
|
@@ -133,6 +141,9 @@ module Helper
|
|
133
141
|
def setup
|
134
142
|
@log = StringIO.new
|
135
143
|
@redis = init _new_client
|
144
|
+
|
145
|
+
# Run GC to make sure orphaned connections are closed.
|
146
|
+
GC.start
|
136
147
|
end
|
137
148
|
|
138
149
|
def teardown
|
@@ -140,13 +151,13 @@ module Helper
|
|
140
151
|
end
|
141
152
|
|
142
153
|
def redis_mock(commands, options = {}, &blk)
|
143
|
-
RedisMock.start(commands) do |port|
|
154
|
+
RedisMock.start(commands, options) do |port|
|
144
155
|
yield _new_client(options.merge(:port => port))
|
145
156
|
end
|
146
157
|
end
|
147
158
|
|
148
159
|
def redis_mock_with_handler(handler, options = {}, &blk)
|
149
|
-
RedisMock.start_with_handler(handler) do |port|
|
160
|
+
RedisMock.start_with_handler(handler, options) do |port|
|
150
161
|
yield _new_client(options.merge(:port => port))
|
151
162
|
end
|
152
163
|
end
|
data/test/internals_test.rb
CHANGED
@@ -320,4 +320,91 @@ class TestInternals < Test::Unit::TestCase
|
|
320
320
|
serv.close if serv
|
321
321
|
end
|
322
322
|
end
|
323
|
+
|
324
|
+
def test_client_options
|
325
|
+
redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
|
326
|
+
|
327
|
+
assert_equal "host", redis.client.options[:host]
|
328
|
+
assert_equal 1234, redis.client.options[:port]
|
329
|
+
assert_equal 1, redis.client.options[:db]
|
330
|
+
assert_equal "foo", redis.client.options[:scheme]
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_does_not_change_self_client_options
|
334
|
+
redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
|
335
|
+
options = redis.client.options
|
336
|
+
|
337
|
+
options[:host] << "new_host"
|
338
|
+
options[:scheme] << "bar"
|
339
|
+
options.merge!(:db => 0)
|
340
|
+
|
341
|
+
assert_equal "host", redis.client.options[:host]
|
342
|
+
assert_equal 1, redis.client.options[:db]
|
343
|
+
assert_equal "foo", redis.client.options[:scheme]
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_resolves_localhost
|
347
|
+
assert_nothing_raised do
|
348
|
+
Redis.new(OPTIONS.merge(:host => 'localhost')).ping
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
class << self
|
353
|
+
def af_family_supported(af)
|
354
|
+
hosts = {
|
355
|
+
Socket::AF_INET => "127.0.0.1",
|
356
|
+
Socket::AF_INET6 => "::1",
|
357
|
+
}
|
358
|
+
|
359
|
+
begin
|
360
|
+
s = Socket.new(af, Socket::SOCK_STREAM, 0)
|
361
|
+
begin
|
362
|
+
sa = Socket.pack_sockaddr_in(9999, hosts[af])
|
363
|
+
s.bind(sa)
|
364
|
+
yield
|
365
|
+
rescue Errno::EADDRNOTAVAIL
|
366
|
+
ensure
|
367
|
+
s.close
|
368
|
+
end
|
369
|
+
rescue Errno::ESOCKTNOSUPPORT
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def af_test(host)
|
375
|
+
commands = {
|
376
|
+
:ping => lambda { |*_| "+pong" },
|
377
|
+
}
|
378
|
+
|
379
|
+
redis_mock(commands, :host => host) do |redis|
|
380
|
+
assert_nothing_raised do
|
381
|
+
redis.ping
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
driver(:ruby) do
|
387
|
+
af_family_supported(Socket::AF_INET) do
|
388
|
+
def test_connect_ipv4
|
389
|
+
af_test("127.0.0.1")
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
driver(:ruby) do
|
395
|
+
af_family_supported(Socket::AF_INET6) do
|
396
|
+
def test_connect_ipv6
|
397
|
+
af_test("::1")
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_can_be_duped_to_create_a_new_connection
|
403
|
+
clients = r.info["connected_clients"].to_i
|
404
|
+
|
405
|
+
r2 = r.dup
|
406
|
+
r2.ping
|
407
|
+
|
408
|
+
assert_equal clients + 1, r.info["connected_clients"].to_i
|
409
|
+
end
|
323
410
|
end
|
@@ -6,6 +6,9 @@ class TestPublishSubscribe < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
include Helper::Client
|
8
8
|
|
9
|
+
class TestError < StandardError
|
10
|
+
end
|
11
|
+
|
9
12
|
def test_subscribe_and_unsubscribe
|
10
13
|
@subscribed = false
|
11
14
|
@unsubscribed = false
|
@@ -84,6 +87,62 @@ class TestPublishSubscribe < Test::Unit::TestCase
|
|
84
87
|
assert_equal "s1", @message
|
85
88
|
end
|
86
89
|
|
90
|
+
def test_subscribe_connection_usable_after_raise
|
91
|
+
@subscribed = false
|
92
|
+
|
93
|
+
wire = Wire.new do
|
94
|
+
begin
|
95
|
+
r.subscribe("foo") do |on|
|
96
|
+
on.subscribe do |channel, total|
|
97
|
+
@subscribed = true
|
98
|
+
end
|
99
|
+
|
100
|
+
on.message do |channel, message|
|
101
|
+
raise TestError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
rescue TestError
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Wait until the subscription is active before publishing
|
109
|
+
Wire.pass while !@subscribed
|
110
|
+
|
111
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
112
|
+
|
113
|
+
wire.join
|
114
|
+
|
115
|
+
assert_equal "PONG", r.ping
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_psubscribe_connection_usable_after_raise
|
119
|
+
@subscribed = false
|
120
|
+
|
121
|
+
wire = Wire.new do
|
122
|
+
begin
|
123
|
+
r.psubscribe("f*") do |on|
|
124
|
+
on.psubscribe do |pattern, total|
|
125
|
+
@subscribed = true
|
126
|
+
end
|
127
|
+
|
128
|
+
on.pmessage do |pattern, channel, message|
|
129
|
+
raise TestError
|
130
|
+
end
|
131
|
+
end
|
132
|
+
rescue TestError
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Wait until the subscription is active before publishing
|
137
|
+
Wire.pass while !@subscribed
|
138
|
+
|
139
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
140
|
+
|
141
|
+
wire.join
|
142
|
+
|
143
|
+
assert_equal "PONG", r.ping
|
144
|
+
end
|
145
|
+
|
87
146
|
def test_subscribe_within_subscribe
|
88
147
|
@channels = []
|
89
148
|
|
@@ -132,7 +191,7 @@ class TestPublishSubscribe < Test::Unit::TestCase
|
|
132
191
|
def test_subscribe_past_a_timeout
|
133
192
|
# For some reason, a thread here doesn't reproduce the issue.
|
134
193
|
sleep = %{sleep #{OPTIONS[:timeout] * 2}}
|
135
|
-
publish = %{echo "publish foo bar\r\n" | nc
|
194
|
+
publish = %{echo "publish foo bar\r\n" | nc 127.0.0.1 #{OPTIONS[:port]}}
|
136
195
|
cmd = [sleep, publish].join("; ")
|
137
196
|
|
138
197
|
IO.popen(cmd, "r+") do |pipe|
|
data/test/support/redis_mock.rb
CHANGED
@@ -4,8 +4,8 @@ module RedisMock
|
|
4
4
|
class Server
|
5
5
|
VERBOSE = false
|
6
6
|
|
7
|
-
def initialize(port, &block)
|
8
|
-
@server = TCPServer.new("127.0.0.1", port)
|
7
|
+
def initialize(port, options = {}, &block)
|
8
|
+
@server = TCPServer.new(options[:host] || "127.0.0.1", port)
|
9
9
|
@server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
10
10
|
end
|
11
11
|
|
@@ -53,8 +53,8 @@ module RedisMock
|
|
53
53
|
# # Every connection will be closed immediately
|
54
54
|
# end
|
55
55
|
#
|
56
|
-
def self.start_with_handler(blk)
|
57
|
-
server = Server.new(MOCK_PORT)
|
56
|
+
def self.start_with_handler(blk, options = {})
|
57
|
+
server = Server.new(MOCK_PORT, options)
|
58
58
|
|
59
59
|
begin
|
60
60
|
server.start(&blk)
|
@@ -75,7 +75,7 @@ module RedisMock
|
|
75
75
|
# assert_equal "PONG", Redis.new(:port => MOCK_PORT).ping
|
76
76
|
# end
|
77
77
|
#
|
78
|
-
def self.start(commands = {}, &blk)
|
78
|
+
def self.start(commands, options = {}, &blk)
|
79
79
|
handler = lambda do |session|
|
80
80
|
while line = session.gets
|
81
81
|
argv = Array.new(line[1..-3].to_i) do
|
@@ -110,6 +110,6 @@ module RedisMock
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
start_with_handler(handler, &blk)
|
113
|
+
start_with_handler(handler, options, &blk)
|
114
114
|
end
|
115
115
|
end
|
data/test/transactions_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -16,25 +16,26 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date:
|
19
|
+
date: 2014-01-21 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: rake
|
23
23
|
requirement: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - '>='
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
type: :development
|
29
29
|
prerelease: false
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
|
-
description:
|
36
|
-
|
37
|
-
|
35
|
+
description: |2
|
36
|
+
A Ruby client that tries to match Redis' API one-to-one, while still
|
37
|
+
providing an idiomatic interface. It features thread-safety,
|
38
|
+
client-side sharding, pipelining, and an obsession for performance.
|
38
39
|
email:
|
39
40
|
- redis-db@googlegroups.com
|
40
41
|
executables: []
|
@@ -138,7 +139,8 @@ files:
|
|
138
139
|
- test/unknown_commands_test.rb
|
139
140
|
- test/url_param_test.rb
|
140
141
|
homepage: https://github.com/redis/redis-rb
|
141
|
-
licenses:
|
142
|
+
licenses:
|
143
|
+
- MIT
|
142
144
|
metadata: {}
|
143
145
|
post_install_message:
|
144
146
|
rdoc_options: []
|
@@ -146,77 +148,18 @@ require_paths:
|
|
146
148
|
- lib
|
147
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
148
150
|
requirements:
|
149
|
-
- -
|
151
|
+
- - '>='
|
150
152
|
- !ruby/object:Gem::Version
|
151
153
|
version: '0'
|
152
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
155
|
requirements:
|
154
|
-
- -
|
156
|
+
- - '>='
|
155
157
|
- !ruby/object:Gem::Version
|
156
158
|
version: '0'
|
157
159
|
requirements: []
|
158
160
|
rubyforge_project:
|
159
|
-
rubygems_version: 2.0.
|
161
|
+
rubygems_version: 2.0.14
|
160
162
|
signing_key:
|
161
163
|
specification_version: 4
|
162
164
|
summary: A Ruby client library for Redis
|
163
|
-
test_files:
|
164
|
-
- test/blocking_commands_test.rb
|
165
|
-
- test/command_map_test.rb
|
166
|
-
- test/commands_on_hashes_test.rb
|
167
|
-
- test/commands_on_lists_test.rb
|
168
|
-
- test/commands_on_sets_test.rb
|
169
|
-
- test/commands_on_sorted_sets_test.rb
|
170
|
-
- test/commands_on_strings_test.rb
|
171
|
-
- test/commands_on_value_types_test.rb
|
172
|
-
- test/connection_handling_test.rb
|
173
|
-
- test/db/.gitkeep
|
174
|
-
- test/distributed_blocking_commands_test.rb
|
175
|
-
- test/distributed_commands_on_hashes_test.rb
|
176
|
-
- test/distributed_commands_on_lists_test.rb
|
177
|
-
- test/distributed_commands_on_sets_test.rb
|
178
|
-
- test/distributed_commands_on_sorted_sets_test.rb
|
179
|
-
- test/distributed_commands_on_strings_test.rb
|
180
|
-
- test/distributed_commands_on_value_types_test.rb
|
181
|
-
- test/distributed_commands_requiring_clustering_test.rb
|
182
|
-
- test/distributed_connection_handling_test.rb
|
183
|
-
- test/distributed_internals_test.rb
|
184
|
-
- test/distributed_key_tags_test.rb
|
185
|
-
- test/distributed_persistence_control_commands_test.rb
|
186
|
-
- test/distributed_publish_subscribe_test.rb
|
187
|
-
- test/distributed_remote_server_control_commands_test.rb
|
188
|
-
- test/distributed_scripting_test.rb
|
189
|
-
- test/distributed_sorting_test.rb
|
190
|
-
- test/distributed_test.rb
|
191
|
-
- test/distributed_transactions_test.rb
|
192
|
-
- test/encoding_test.rb
|
193
|
-
- test/error_replies_test.rb
|
194
|
-
- test/helper.rb
|
195
|
-
- test/helper_test.rb
|
196
|
-
- test/internals_test.rb
|
197
|
-
- test/lint/blocking_commands.rb
|
198
|
-
- test/lint/hashes.rb
|
199
|
-
- test/lint/lists.rb
|
200
|
-
- test/lint/sets.rb
|
201
|
-
- test/lint/sorted_sets.rb
|
202
|
-
- test/lint/strings.rb
|
203
|
-
- test/lint/value_types.rb
|
204
|
-
- test/persistence_control_commands_test.rb
|
205
|
-
- test/pipelining_commands_test.rb
|
206
|
-
- test/publish_subscribe_test.rb
|
207
|
-
- test/remote_server_control_commands_test.rb
|
208
|
-
- test/scanning_test.rb
|
209
|
-
- test/scripting_test.rb
|
210
|
-
- test/sorting_test.rb
|
211
|
-
- test/support/connection/hiredis.rb
|
212
|
-
- test/support/connection/ruby.rb
|
213
|
-
- test/support/connection/synchrony.rb
|
214
|
-
- test/support/redis_mock.rb
|
215
|
-
- test/support/wire/synchrony.rb
|
216
|
-
- test/support/wire/thread.rb
|
217
|
-
- test/synchrony_driver.rb
|
218
|
-
- test/test.conf
|
219
|
-
- test/thread_safety_test.rb
|
220
|
-
- test/transactions_test.rb
|
221
|
-
- test/unknown_commands_test.rb
|
222
|
-
- test/url_param_test.rb
|
165
|
+
test_files: []
|