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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MWU4NjJlZTMzODJmNjI0MTk5ZWQ4Yzk1OGIxNGUwYmQzNzcwZGM0Zg==
5
- data.tar.gz: !binary |-
6
- ZmQzMjMxMmU2NWRhY2E3NGE1N2I1OWExMjQxMzQ2YmY1MzcxOTM2Mw==
7
- !binary "U0hBNTEy":
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
@@ -16,11 +16,14 @@ gemfile:
16
16
  - .travis/Gemfile
17
17
 
18
18
  env:
19
- - conn=ruby REDIS_BRANCH=2.6
20
- - conn=hiredis REDIS_BRANCH=2.6
21
- - conn=synchrony REDIS_BRANCH=2.6
22
- - conn=ruby REDIS_BRANCH=2.8
23
- - conn=ruby REDIS_BRANCH=unstable
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:
@@ -1,3 +1,13 @@
1
+ # (unreleased)
2
+
3
+ ...
4
+
5
+ # 3.0.7
6
+
7
+ * Added method `Redis#dup` to duplicate a Redis connection.
8
+
9
+ * IPv6 support.
10
+
1
11
  # 3.0.6
2
12
 
3
13
  * Added support for `SCAN` and variants.
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
@@ -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 [String] action e.g. `get`, `set`, `resetstat`
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)
@@ -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
- establish_connection
70
- call [:auth, password] if password
71
- call [:select, db] if db != 0
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.connect(host, port, timeout)
118
- # Limit lookup to IPv4, as Redis doesn't yet do IPv6...
119
- addr = ::Socket.getaddrinfo(host, nil, Socket::AF_INET)
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
@@ -16,9 +16,10 @@ class Redis
16
16
  attr_reader :ring
17
17
 
18
18
  def initialize(node_configs, options = {})
19
- @tag = options.delete(:tag) || /^\{(.+?)\}/
20
- @ring = options.delete(:ring) || HashRing.new
21
- @default_options = options
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)
@@ -78,7 +78,7 @@ class Redis
78
78
  # EXEC command failed.
79
79
  raise exec if exec.is_a?(CommandError)
80
80
 
81
- if exec.size < futures.size - 2
81
+ if exec.size < futures.size
82
82
  # Some command wasn't recognized by Redis.
83
83
  raise replies.detect { |r| r.is_a?(CommandError) }
84
84
  end
@@ -39,7 +39,8 @@ class Redis
39
39
  break if unsubscribed
40
40
  end
41
41
  ensure
42
- send(stop) if !unsubscribed
42
+ # No need to unsubscribe here. The real client closes the connection
43
+ # whenever an exception is raised (see #ensure_connected).
43
44
  end
44
45
  end
45
46
  end
@@ -1,3 +1,3 @@
1
1
  class Redis
2
- VERSION = "3.0.6"
2
+ VERSION = "3.0.7"
3
3
  end
@@ -19,6 +19,8 @@ Gem::Specification.new do |s|
19
19
  client-side sharding, pipelining, and an obsession for performance.
20
20
  EOS
21
21
 
22
+ s.license = "MIT"
23
+
22
24
  s.authors = [
23
25
  "Ezra Zygmuntowicz",
24
26
  "Taylor Weibley",
@@ -82,18 +82,20 @@ class TestCommandsOnStrings < Test::Unit::TestCase
82
82
  end
83
83
 
84
84
  def test_bitop
85
- target_version "2.5.10" do
86
- r.set("foo", "a")
87
- r.set("bar", "b")
88
-
89
- r.bitop(:and, "foo&bar", "foo", "bar")
90
- assert_equal "\x60", r.get("foo&bar")
91
- r.bitop(:or, "foo|bar", "foo", "bar")
92
- assert_equal "\x63", r.get("foo|bar")
93
- r.bitop(:xor, "foo^bar", "foo", "bar")
94
- assert_equal "\x03", r.get("foo^bar")
95
- r.bitop(:not, "~foo", "foo")
96
- assert_equal "\x9E", r.get("~foo")
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 => "localhost", :port => 1234 }
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 = ["localhost", "1234", "foo", default_db.to_s, default_timeout.to_s]
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 = ["localhost", "1234", "foo", (default_db + 1).to_s, default_timeout.to_s]
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 = ["localhost", "1234", "foo", default_db.to_s, (default_timeout + 1).to_s]
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 localhost 6381", redis.slaveof("localhost", 6381)
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://localhost:#{PORT}/15", *NODES]
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://localhost:#{PORT}/15", *NODES]
17
+ nodes = ["redis://127.0.0.1:#{PORT}/15", *NODES]
18
18
  redis = Redis::Distributed.new nodes
19
- assert_equal ["redis://localhost:#{PORT}/15", *NODES], redis.nodes.map { |node| node.client.id}
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 => 'localhost'), OPTIONS.merge(:host => 'localhost', :port => PORT.next)]
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://localhost:#{PORT}/15","redis://localhost:#{PORT.next}/15"], redis.nodes.map { |node| node.client.id }
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://localhost:7389/15", OPTIONS.merge(:host => 'localhost'), OPTIONS.merge(:host => 'localhost', :port => PORT.next)]
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://localhost:7389/15", "redis://localhost:#{PORT}/15", "redis://localhost:#{PORT.next}/15"], redis.nodes.map { |node| node.client.id }
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 => 'localhost', :id => "test"), OPTIONS.merge( :host => 'localhost', :port => PORT.next, :id => "test1")]
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://localhost:#{PORT}/15", *NODES]
12
- r2 = Redis::Distributed.new ["redis://localhost:#{PORT}/15", *NODES]
13
- r3 = Redis::Distributed.new ["redis://localhost:#{PORT}/15", *NODES]
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://localhost:#{PORT}/14")
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://localhost:#{PORT}/14")
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://localhost:#{PORT}/14")
43
+ r.add_node("redis://127.0.0.1:#{PORT}/14")
44
44
  r.flushdb
45
45
 
46
46
  100.times do |i|
@@ -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://localhost:#{PORT}/15", *NODES]
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://localhost:6380/14")
35
+ @r.add_node("redis://127.0.0.1:6380/14")
36
36
 
37
- assert_equal "localhost", @r.nodes[1].client.host
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
@@ -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
@@ -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
@@ -93,9 +93,7 @@ class TestPipeliningCommands < Test::Unit::TestCase
93
93
  r.pipelined do
94
94
  r.doesnt_exist
95
95
  @first = r.sadd("foo", 1)
96
- r.doesnt_exist
97
96
  @second = r.sadd("foo", 1)
98
- r.doesnt_exist
99
97
  end
100
98
  end
101
99
 
@@ -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 localhost #{OPTIONS[:port]}}
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|
@@ -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
@@ -67,9 +67,7 @@ class TestTransactions < Test::Unit::TestCase
67
67
  r.multi do |m|
68
68
  m.doesnt_exist
69
69
  @first = m.sadd("foo", 1)
70
- m.doesnt_exist
71
70
  @second = m.sadd("foo", 1)
72
- m.doesnt_exist
73
71
  end
74
72
  end
75
73
 
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.6
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: 2013-11-07 00:00:00.000000000 Z
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: ! " A Ruby client that tries to match Redis' API one-to-one, while
36
- still\n providing an idiomatic interface. It features thread-safety,\n client-side
37
- sharding, pipelining, and an obsession for performance.\n"
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.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: []