redis 3.0.6 → 3.0.7
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 +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: []
|