redis 3.3.5 → 4.0.0

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +36 -52
  3. data/.travis/Gemfile +3 -1
  4. data/CHANGELOG.md +8 -6
  5. data/Gemfile +0 -1
  6. data/README.md +31 -75
  7. data/benchmarking/logging.rb +1 -1
  8. data/bors.toml +14 -0
  9. data/lib/redis.rb +68 -41
  10. data/lib/redis/client.rb +12 -8
  11. data/lib/redis/connection.rb +2 -2
  12. data/lib/redis/connection/command_helper.rb +2 -8
  13. data/lib/redis/connection/hiredis.rb +2 -2
  14. data/lib/redis/connection/ruby.rb +8 -28
  15. data/lib/redis/connection/synchrony.rb +12 -4
  16. data/lib/redis/distributed.rb +3 -3
  17. data/lib/redis/hash_ring.rb +20 -64
  18. data/lib/redis/pipeline.rb +0 -6
  19. data/lib/redis/version.rb +1 -1
  20. data/makefile +42 -0
  21. data/redis.gemspec +7 -9
  22. data/test/bitpos_test.rb +13 -19
  23. data/test/blocking_commands_test.rb +3 -5
  24. data/test/client_test.rb +1 -1
  25. data/test/command_map_test.rb +3 -5
  26. data/test/commands_on_hashes_test.rb +2 -4
  27. data/test/commands_on_hyper_log_log_test.rb +3 -5
  28. data/test/commands_on_lists_test.rb +2 -4
  29. data/test/commands_on_sets_test.rb +2 -4
  30. data/test/commands_on_sorted_sets_test.rb +17 -4
  31. data/test/commands_on_strings_test.rb +3 -5
  32. data/test/commands_on_value_types_test.rb +4 -6
  33. data/test/connection_handling_test.rb +5 -7
  34. data/test/distributed_blocking_commands_test.rb +2 -4
  35. data/test/distributed_commands_on_hashes_test.rb +2 -4
  36. data/test/distributed_commands_on_hyper_log_log_test.rb +2 -4
  37. data/test/distributed_commands_on_lists_test.rb +2 -4
  38. data/test/distributed_commands_on_sets_test.rb +2 -4
  39. data/test/distributed_commands_on_sorted_sets_test.rb +2 -4
  40. data/test/distributed_commands_on_strings_test.rb +2 -4
  41. data/test/distributed_commands_on_value_types_test.rb +2 -4
  42. data/test/distributed_commands_requiring_clustering_test.rb +1 -3
  43. data/test/distributed_connection_handling_test.rb +1 -3
  44. data/test/distributed_internals_test.rb +8 -19
  45. data/test/distributed_key_tags_test.rb +4 -6
  46. data/test/distributed_persistence_control_commands_test.rb +1 -3
  47. data/test/distributed_publish_subscribe_test.rb +1 -3
  48. data/test/distributed_remote_server_control_commands_test.rb +1 -3
  49. data/test/distributed_scripting_test.rb +1 -3
  50. data/test/distributed_sorting_test.rb +1 -3
  51. data/test/distributed_test.rb +12 -14
  52. data/test/distributed_transactions_test.rb +1 -3
  53. data/test/encoding_test.rb +4 -8
  54. data/test/error_replies_test.rb +2 -4
  55. data/test/fork_safety_test.rb +1 -6
  56. data/test/helper.rb +10 -41
  57. data/test/helper_test.rb +1 -3
  58. data/test/internals_test.rb +67 -55
  59. data/test/lint/strings.rb +6 -20
  60. data/test/lint/value_types.rb +8 -0
  61. data/test/persistence_control_commands_test.rb +1 -3
  62. data/test/pipelining_commands_test.rb +4 -8
  63. data/test/publish_subscribe_test.rb +1 -3
  64. data/test/remote_server_control_commands_test.rb +60 -3
  65. data/test/scanning_test.rb +1 -7
  66. data/test/scripting_test.rb +1 -3
  67. data/test/sentinel_command_test.rb +1 -3
  68. data/test/sentinel_test.rb +1 -3
  69. data/test/sorting_test.rb +1 -3
  70. data/test/ssl_test.rb +45 -49
  71. data/test/support/connection/hiredis.rb +1 -1
  72. data/test/support/connection/ruby.rb +1 -1
  73. data/test/support/connection/synchrony.rb +1 -1
  74. data/test/synchrony_driver.rb +6 -9
  75. data/test/thread_safety_test.rb +1 -3
  76. data/test/transactions_test.rb +1 -3
  77. data/test/unknown_commands_test.rb +1 -3
  78. data/test/url_param_test.rb +44 -46
  79. metadata +30 -18
  80. data/Rakefile +0 -87
  81. data/test/connection_test.rb +0 -57
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestDistributedSorting < Test::Unit::TestCase
6
4
 
@@ -1,13 +1,11 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestDistributed < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Distributed
8
6
 
9
7
  def test_handle_multiple_servers
10
- @r = Redis::Distributed.new ["redis://localhost:#{PORT}/15", *NODES]
8
+ @r = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
11
9
 
12
10
  100.times do |idx|
13
11
  @r.set(idx.to_s, "foo#{idx}")
@@ -26,19 +24,19 @@ class TestDistributed < Test::Unit::TestCase
26
24
 
27
25
  @r = Redis::Distributed.new NODES, :logger => logger, :timeout => 10
28
26
 
29
- assert_equal "127.0.0.1", @r.nodes[0].client.host
30
- assert_equal PORT, @r.nodes[0].client.port
31
- assert_equal 15, @r.nodes[0].client.db
32
- assert_equal 10, @r.nodes[0].client.timeout
33
- assert_equal logger, @r.nodes[0].client.logger
27
+ assert_equal "127.0.0.1", @r.nodes[0]._client.host
28
+ assert_equal PORT, @r.nodes[0]._client.port
29
+ assert_equal 15, @r.nodes[0]._client.db
30
+ assert_equal 10, @r.nodes[0]._client.timeout
31
+ assert_equal logger, @r.nodes[0]._client.logger
34
32
 
35
33
  @r.add_node("redis://127.0.0.1:6380/14")
36
34
 
37
- assert_equal "127.0.0.1", @r.nodes[1].client.host
38
- assert_equal 6380, @r.nodes[1].client.port
39
- assert_equal 14, @r.nodes[1].client.db
40
- assert_equal 10, @r.nodes[1].client.timeout
41
- assert_equal logger, @r.nodes[1].client.logger
35
+ assert_equal "127.0.0.1", @r.nodes[1]._client.host
36
+ assert_equal 6380, @r.nodes[1]._client.port
37
+ assert_equal 14, @r.nodes[1]._client.db
38
+ assert_equal 10, @r.nodes[1]._client.timeout
39
+ assert_equal logger, @r.nodes[1]._client.logger
42
40
  end
43
41
 
44
42
  def test_pipelining_commands_cannot_be_distributed
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestDistributedTransactions < Test::Unit::TestCase
6
4
 
@@ -1,18 +1,14 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestEncoding < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
6
 
9
7
  def test_returns_properly_encoded_strings
10
- if defined?(Encoding)
11
- with_external_encoding("UTF-8") do
12
- r.set "foo", "שלום"
8
+ with_external_encoding("UTF-8") do
9
+ r.set "foo", "שלום"
13
10
 
14
- assert_equal "Shalom שלום", "Shalom " + r.get("foo")
15
- end
11
+ assert_equal "Shalom שלום", "Shalom " + r.get("foo")
16
12
  end
17
13
  end
18
14
  end
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestErrorReplies < Test::Unit::TestCase
6
4
 
@@ -47,7 +45,7 @@ class TestErrorReplies < Test::Unit::TestCase
47
45
  def test_recover_from_raise_in__call_loop
48
46
  with_reconnection_check do
49
47
  begin
50
- r.client.call_loop([:invalid_monitor]) do
48
+ r._client.call_loop([:invalid_monitor]) do
51
49
  assert false # Should never be executed
52
50
  end
53
51
  rescue => ex
@@ -1,11 +1,8 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestForkSafety < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
- include Helper::Skipable
9
6
 
10
7
  driver(:ruby, :hiredis) do
11
8
  def test_fork_safety
@@ -32,7 +29,6 @@ class TestForkSafety < Test::Unit::TestCase
32
29
 
33
30
  rescue NotImplementedError => error
34
31
  raise unless error.message =~ /fork is not available/
35
- return skip(error.message)
36
32
  end
37
33
 
38
34
  def test_fork_safety_with_enabled_inherited_socket
@@ -59,7 +55,6 @@ class TestForkSafety < Test::Unit::TestCase
59
55
 
60
56
  rescue NotImplementedError => error
61
57
  raise unless error.message =~ /fork is not available/
62
- return skip(error.message)
63
58
  end
64
59
  end
65
60
  end
data/test/helper.rb CHANGED
@@ -1,27 +1,17 @@
1
- $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
- $:.unshift File.expand_path(File.dirname(__FILE__))
3
-
4
1
  require "test/unit"
5
2
  require "logger"
6
3
  require "stringio"
7
4
 
8
- (class Random; def self.rand(*args) super end; end) unless defined?(Random)
9
-
10
- begin
11
- require "ruby-debug"
12
- rescue LoadError
13
- end
14
-
15
5
  $VERBOSE = true
16
6
 
17
- ENV["conn"] ||= "ruby"
7
+ ENV["DRIVER"] ||= "ruby"
18
8
 
19
- require "redis"
20
- require "redis/distributed"
21
- require "redis/connection/#{ENV["conn"]}"
9
+ require_relative "../lib/redis"
10
+ require_relative "../lib/redis/distributed"
11
+ require_relative "../lib/redis/connection/#{ENV["DRIVER"]}"
22
12
 
23
- require "support/redis_mock"
24
- require "support/connection/#{ENV["conn"]}"
13
+ require_relative "support/redis_mock"
14
+ require_relative "support/connection/#{ENV["DRIVER"]}"
25
15
 
26
16
  PORT = 6381
27
17
  OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
@@ -44,11 +34,11 @@ def init(redis)
44
34
 
45
35
  Try this once:
46
36
 
47
- $ rake clean
37
+ $ make clean
48
38
 
49
39
  Then run the build again:
50
40
 
51
- $ rake
41
+ $ make
52
42
 
53
43
  EOS
54
44
  exit 1
@@ -56,7 +46,7 @@ def init(redis)
56
46
  end
57
47
 
58
48
  def driver(*drivers, &blk)
59
- if drivers.map(&:to_s).include?(ENV["conn"])
49
+ if drivers.map(&:to_s).include?(ENV["DRIVER"])
60
50
  class_eval(&blk)
61
51
  end
62
52
  end
@@ -92,14 +82,6 @@ module Helper
92
82
  end
93
83
  end
94
84
 
95
- def try_encoding(encoding, &block)
96
- if defined?(Encoding)
97
- with_external_encoding(encoding, &block)
98
- else
99
- yield
100
- end
101
- end
102
-
103
85
  class Version
104
86
 
105
87
  include Comparable
@@ -191,7 +173,7 @@ module Helper
191
173
  end
192
174
 
193
175
  def _new_client(options = {})
194
- Redis.new(_format_options(options).merge(:driver => ENV["conn"]))
176
+ Redis.new(_format_options(options).merge(:driver => ENV["DRIVER"]))
195
177
  end
196
178
  end
197
179
 
@@ -216,17 +198,4 @@ module Helper
216
198
  Redis::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
217
199
  end
218
200
  end
219
-
220
- # Basic support for `skip` in 1.8.x
221
- # Note: YOU MUST use `return skip(message)` in order to appropriately bail
222
- # from a running test.
223
- module Skipable
224
- Skipped = Class.new(RuntimeError)
225
-
226
- def skip(message = nil, bt = caller)
227
- return super if defined?(super)
228
-
229
- $stderr.puts("SKIPPED: #{self} #{message || 'no reason given'}")
230
- end
231
- end
232
201
  end
data/test/helper_test.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestHelper < Test::Unit::TestCase
6
4
 
@@ -1,11 +1,8 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestInternals < Test::Unit::TestCase
6
4
 
7
5
  include Helper::Client
8
- include Helper::Skipable
9
6
 
10
7
  def test_logger
11
8
  r.ping
@@ -44,24 +41,28 @@ class TestInternals < Test::Unit::TestCase
44
41
  end
45
42
  end
46
43
 
44
+ def test_provides_a_meaningful_inspect
45
+ assert_equal "#<Redis client v#{Redis::VERSION} for redis://127.0.0.1:#{PORT}/15>", r.inspect
46
+ end
47
+
47
48
  def test_redis_current
48
- assert_equal "127.0.0.1", Redis.current.client.host
49
- assert_equal 6379, Redis.current.client.port
50
- assert_equal 0, Redis.current.client.db
49
+ assert_equal "127.0.0.1", Redis.current._client.host
50
+ assert_equal 6379, Redis.current._client.port
51
+ assert_equal 0, Redis.current._client.db
51
52
 
52
53
  Redis.current = Redis.new(OPTIONS.merge(:port => 6380, :db => 1))
53
54
 
54
55
  t = Thread.new do
55
- assert_equal "127.0.0.1", Redis.current.client.host
56
- assert_equal 6380, Redis.current.client.port
57
- assert_equal 1, Redis.current.client.db
56
+ assert_equal "127.0.0.1", Redis.current._client.host
57
+ assert_equal 6380, Redis.current._client.port
58
+ assert_equal 1, Redis.current._client.db
58
59
  end
59
60
 
60
61
  t.join
61
62
 
62
- assert_equal "127.0.0.1", Redis.current.client.host
63
- assert_equal 6380, Redis.current.client.port
64
- assert_equal 1, Redis.current.client.db
63
+ assert_equal "127.0.0.1", Redis.current._client.host
64
+ assert_equal 6380, Redis.current._client.port
65
+ assert_equal 1, Redis.current._client.db
65
66
  end
66
67
 
67
68
  def test_redis_connected?
@@ -75,12 +76,48 @@ class TestInternals < Test::Unit::TestCase
75
76
  assert !fresh_client.connected?
76
77
  end
77
78
 
79
+ def test_default_id_with_host_and_port
80
+ redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
81
+ assert_equal "redis://host:1234/0", redis._client.id
82
+ end
83
+
84
+ def test_default_id_with_host_and_port_and_explicit_scheme
85
+ redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0, :scheme => "foo"))
86
+ assert_equal "redis://host:1234/0", redis._client.id
87
+ end
88
+
89
+ def test_default_id_with_path
90
+ redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0))
91
+ assert_equal "redis:///tmp/redis.sock/0", redis._client.id
92
+ end
93
+
94
+ def test_default_id_with_path_and_explicit_scheme
95
+ redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0, :scheme => "foo"))
96
+ assert_equal "redis:///tmp/redis.sock/0", redis._client.id
97
+ end
98
+
99
+ def test_override_id
100
+ redis = Redis.new(OPTIONS.merge(:id => "test"))
101
+ assert_equal redis._client.id, "test"
102
+ end
103
+
78
104
  def test_timeout
79
105
  assert_nothing_raised do
80
106
  Redis.new(OPTIONS.merge(:timeout => 0))
81
107
  end
82
108
  end
83
109
 
110
+ def test_id_inside_multi
111
+ redis = Redis.new(OPTIONS)
112
+ id = nil
113
+
114
+ redis.multi do
115
+ id = redis.id
116
+ end
117
+
118
+ assert_equal id, "redis://127.0.0.1:6381/15"
119
+ end
120
+
84
121
  driver(:ruby) do
85
122
  def test_tcp_keepalive
86
123
  keepalive = {:time => 20, :intvl => 10, :probes => 5}
@@ -88,7 +125,7 @@ class TestInternals < Test::Unit::TestCase
88
125
  redis = Redis.new(OPTIONS.merge(:tcp_keepalive => keepalive))
89
126
  redis.ping
90
127
 
91
- connection = redis.client.connection
128
+ connection = redis._client.connection
92
129
  actual_keepalive = connection.get_tcp_keepalive
93
130
 
94
131
  [:time, :intvl, :probes].each do |key|
@@ -121,22 +158,10 @@ class TestInternals < Test::Unit::TestCase
121
158
  assert (Time.now - start_time) <= opts[:timeout]
122
159
  end
123
160
 
124
- driver(:ruby) do
125
- def test_write_timeout
126
- return skip("Relies on buffer sizes, might be unreliable")
127
-
128
- server = TCPServer.new("127.0.0.1", 0)
129
- port = server.addr[1]
130
-
131
- # Hacky, but we need the buffer size
132
- val = TCPSocket.new("127.0.0.1", port).getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).unpack("i")[0]
133
-
134
- assert_raise(Redis::TimeoutError) do
135
- Timeout.timeout(1) do
136
- redis = Redis.new(:port => port, :timeout => 5, :write_timeout => 0.1)
137
- redis.set("foo", "1" * val*2)
138
- end
139
- end
161
+ def test_missing_socket
162
+ opts = { :path => '/missing.sock' }
163
+ assert_raise Redis::CannotConnectError do
164
+ Redis.new(opts).ping
140
165
  end
141
166
  end
142
167
 
@@ -197,7 +222,7 @@ class TestInternals < Test::Unit::TestCase
197
222
  redis.ping
198
223
  end
199
224
 
200
- assert !redis.client.connected?
225
+ assert !redis._client.connected?
201
226
  end
202
227
  end
203
228
 
@@ -213,7 +238,7 @@ class TestInternals < Test::Unit::TestCase
213
238
  redis.ping
214
239
  end
215
240
 
216
- assert !redis.client.connected?
241
+ assert !redis._client.connected?
217
242
  end
218
243
  end
219
244
 
@@ -226,7 +251,7 @@ class TestInternals < Test::Unit::TestCase
226
251
  end
227
252
  end
228
253
 
229
- assert !redis.client.connected?
254
+ assert !redis._client.connected?
230
255
  end
231
256
  end
232
257
 
@@ -267,14 +292,14 @@ class TestInternals < Test::Unit::TestCase
267
292
 
268
293
  def test_retry_on_write_error_by_default
269
294
  close_on_connection([0]) do |redis|
270
- assert_equal "1", redis.client.call(["x" * 128 * 1024])
295
+ assert_equal "1", redis._client.call(["x" * 128 * 1024])
271
296
  end
272
297
  end
273
298
 
274
299
  def test_retry_on_write_error_when_wrapped_in_with_reconnect_true
275
300
  close_on_connection([0]) do |redis|
276
301
  redis.with_reconnect(true) do
277
- assert_equal "1", redis.client.call(["x" * 128 * 1024])
302
+ assert_equal "1", redis._client.call(["x" * 128 * 1024])
278
303
  end
279
304
  end
280
305
  end
@@ -283,7 +308,7 @@ class TestInternals < Test::Unit::TestCase
283
308
  close_on_connection([0]) do |redis|
284
309
  assert_raise Redis::ConnectionError do
285
310
  redis.with_reconnect(false) do
286
- redis.client.call(["x" * 128 * 1024])
311
+ redis._client.call(["x" * 128 * 1024])
287
312
  end
288
313
  end
289
314
  end
@@ -293,7 +318,7 @@ class TestInternals < Test::Unit::TestCase
293
318
  close_on_connection([0]) do |redis|
294
319
  assert_raise Redis::ConnectionError do
295
320
  redis.without_reconnect do
296
- redis.client.call(["x" * 128 * 1024])
321
+ redis._client.call(["x" * 128 * 1024])
297
322
  end
298
323
  end
299
324
  end
@@ -301,7 +326,7 @@ class TestInternals < Test::Unit::TestCase
301
326
 
302
327
  def test_connecting_to_unix_domain_socket
303
328
  assert_nothing_raised do
304
- Redis.new(OPTIONS.merge(:path => "./test/db/redis.sock")).ping
329
+ Redis.new(OPTIONS.merge(:path => ENV.fetch("SOCKET_PATH"))).ping
305
330
  end
306
331
  end
307
332
 
@@ -323,23 +348,10 @@ class TestInternals < Test::Unit::TestCase
323
348
  def test_client_options
324
349
  redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
325
350
 
326
- assert_equal "host", redis.client.options[:host]
327
- assert_equal 1234, redis.client.options[:port]
328
- assert_equal 1, redis.client.options[:db]
329
- assert_equal "foo", redis.client.options[:scheme]
330
- end
331
-
332
- def test_does_not_change_self_client_options
333
- redis = Redis.new(OPTIONS.merge(:host => "host", :port => 1234, :db => 1, :scheme => "foo"))
334
- options = redis.client.options
335
-
336
- options[:host] << "new_host"
337
- options[:scheme] << "bar"
338
- options.merge!(:db => 0)
339
-
340
- assert_equal "host", redis.client.options[:host]
341
- assert_equal 1, redis.client.options[:db]
342
- assert_equal "foo", redis.client.options[:scheme]
351
+ assert_equal "host", redis._client.options[:host]
352
+ assert_equal 1234, redis._client.options[:port]
353
+ assert_equal 1, redis._client.options[:db]
354
+ assert_equal "foo", redis._client.options[:scheme]
343
355
  end
344
356
 
345
357
  def test_resolves_localhost