redis2-namespaced 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.order +170 -0
  4. data/.travis/Gemfile +11 -0
  5. data/.travis.yml +55 -0
  6. data/.yardopts +3 -0
  7. data/CHANGELOG.md +285 -0
  8. data/LICENSE +20 -0
  9. data/README.md +251 -0
  10. data/Rakefile +403 -0
  11. data/benchmarking/logging.rb +71 -0
  12. data/benchmarking/pipeline.rb +51 -0
  13. data/benchmarking/speed.rb +21 -0
  14. data/benchmarking/suite.rb +24 -0
  15. data/benchmarking/worker.rb +71 -0
  16. data/examples/basic.rb +15 -0
  17. data/examples/dist_redis.rb +43 -0
  18. data/examples/incr-decr.rb +17 -0
  19. data/examples/list.rb +26 -0
  20. data/examples/pubsub.rb +37 -0
  21. data/examples/sets.rb +36 -0
  22. data/examples/unicorn/config.ru +3 -0
  23. data/examples/unicorn/unicorn.rb +20 -0
  24. data/lib/redis2/client.rb +419 -0
  25. data/lib/redis2/connection/command_helper.rb +44 -0
  26. data/lib/redis2/connection/hiredis.rb +63 -0
  27. data/lib/redis2/connection/registry.rb +12 -0
  28. data/lib/redis2/connection/ruby.rb +322 -0
  29. data/lib/redis2/connection/synchrony.rb +124 -0
  30. data/lib/redis2/connection.rb +9 -0
  31. data/lib/redis2/distributed.rb +853 -0
  32. data/lib/redis2/errors.rb +40 -0
  33. data/lib/redis2/hash_ring.rb +131 -0
  34. data/lib/redis2/pipeline.rb +141 -0
  35. data/lib/redis2/subscribe.rb +83 -0
  36. data/lib/redis2/version.rb +3 -0
  37. data/lib/redis2.rb +2533 -0
  38. data/redis.gemspec +43 -0
  39. data/test/bitpos_test.rb +69 -0
  40. data/test/blocking_commands_test.rb +42 -0
  41. data/test/command_map_test.rb +30 -0
  42. data/test/commands_on_hashes_test.rb +21 -0
  43. data/test/commands_on_lists_test.rb +20 -0
  44. data/test/commands_on_sets_test.rb +77 -0
  45. data/test/commands_on_sorted_sets_test.rb +109 -0
  46. data/test/commands_on_strings_test.rb +101 -0
  47. data/test/commands_on_value_types_test.rb +131 -0
  48. data/test/connection_handling_test.rb +189 -0
  49. data/test/db/.gitkeep +0 -0
  50. data/test/distributed_blocking_commands_test.rb +46 -0
  51. data/test/distributed_commands_on_hashes_test.rb +10 -0
  52. data/test/distributed_commands_on_lists_test.rb +22 -0
  53. data/test/distributed_commands_on_sets_test.rb +83 -0
  54. data/test/distributed_commands_on_sorted_sets_test.rb +18 -0
  55. data/test/distributed_commands_on_strings_test.rb +59 -0
  56. data/test/distributed_commands_on_value_types_test.rb +95 -0
  57. data/test/distributed_commands_requiring_clustering_test.rb +164 -0
  58. data/test/distributed_connection_handling_test.rb +23 -0
  59. data/test/distributed_internals_test.rb +70 -0
  60. data/test/distributed_key_tags_test.rb +52 -0
  61. data/test/distributed_persistence_control_commands_test.rb +26 -0
  62. data/test/distributed_publish_subscribe_test.rb +92 -0
  63. data/test/distributed_remote_server_control_commands_test.rb +66 -0
  64. data/test/distributed_scripting_test.rb +102 -0
  65. data/test/distributed_sorting_test.rb +20 -0
  66. data/test/distributed_test.rb +58 -0
  67. data/test/distributed_transactions_test.rb +32 -0
  68. data/test/encoding_test.rb +18 -0
  69. data/test/error_replies_test.rb +59 -0
  70. data/test/helper.rb +218 -0
  71. data/test/helper_test.rb +24 -0
  72. data/test/internals_test.rb +410 -0
  73. data/test/lint/blocking_commands.rb +150 -0
  74. data/test/lint/hashes.rb +162 -0
  75. data/test/lint/lists.rb +143 -0
  76. data/test/lint/sets.rb +125 -0
  77. data/test/lint/sorted_sets.rb +238 -0
  78. data/test/lint/strings.rb +260 -0
  79. data/test/lint/value_types.rb +122 -0
  80. data/test/persistence_control_commands_test.rb +26 -0
  81. data/test/pipelining_commands_test.rb +242 -0
  82. data/test/publish_subscribe_test.rb +210 -0
  83. data/test/remote_server_control_commands_test.rb +117 -0
  84. data/test/scanning_test.rb +413 -0
  85. data/test/scripting_test.rb +78 -0
  86. data/test/sorting_test.rb +59 -0
  87. data/test/support/connection/hiredis.rb +1 -0
  88. data/test/support/connection/ruby.rb +1 -0
  89. data/test/support/connection/synchrony.rb +17 -0
  90. data/test/support/redis_mock.rb +115 -0
  91. data/test/support/wire/synchrony.rb +24 -0
  92. data/test/support/wire/thread.rb +5 -0
  93. data/test/synchrony_driver.rb +88 -0
  94. data/test/test.conf +9 -0
  95. data/test/thread_safety_test.rb +32 -0
  96. data/test/transactions_test.rb +264 -0
  97. data/test/unknown_commands_test.rb +14 -0
  98. data/test/url_param_test.rb +132 -0
  99. metadata +226 -0
data/test/helper.rb ADDED
@@ -0,0 +1,218 @@
1
+ $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+ $:.unshift File.expand_path(File.dirname(__FILE__))
3
+
4
+ require "test/unit"
5
+ require "logger"
6
+ require "stringio"
7
+
8
+ begin
9
+ require "ruby-debug"
10
+ rescue LoadError
11
+ end
12
+
13
+ $VERBOSE = true
14
+
15
+ ENV["conn"] ||= "ruby"
16
+
17
+ require "redis"
18
+ require "redis2/distributed"
19
+ require "redis2/connection/#{ENV["conn"]}"
20
+
21
+ require "support/redis_mock"
22
+ require "support/connection/#{ENV["conn"]}"
23
+
24
+ PORT = 6381
25
+ OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
26
+ NODES = ["redis://127.0.0.1:#{PORT}/15"]
27
+
28
+ def init(redis)
29
+ begin
30
+ redis.select 14
31
+ redis.flushdb
32
+ redis.select 15
33
+ redis.flushdb
34
+ redis
35
+ rescue Redis2::CannotConnectError
36
+ puts <<-EOS
37
+
38
+ Cannot connect to Redis2.
39
+
40
+ Make sure Redis2 is running on localhost, port #{PORT}.
41
+ This testing suite connects to the database 15.
42
+
43
+ To install redis:
44
+ visit <http://redis.io/download/>.
45
+
46
+ To start the server:
47
+ rake start
48
+
49
+ To stop the server:
50
+ rake stop
51
+
52
+ EOS
53
+ exit 1
54
+ end
55
+ end
56
+
57
+ def driver(*drivers, &blk)
58
+ if drivers.map(&:to_s).include?(ENV["conn"])
59
+ class_eval(&blk)
60
+ end
61
+ end
62
+
63
+ module Helper
64
+
65
+ def run(runner)
66
+ if respond_to?(:around)
67
+ around { super(runner) }
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ def silent
74
+ verbose, $VERBOSE = $VERBOSE, false
75
+
76
+ begin
77
+ yield
78
+ ensure
79
+ $VERBOSE = verbose
80
+ end
81
+ end
82
+
83
+ def with_external_encoding(encoding)
84
+ original_encoding = Encoding.default_external
85
+
86
+ begin
87
+ silent { Encoding.default_external = Encoding.find(encoding) }
88
+ yield
89
+ ensure
90
+ silent { Encoding.default_external = original_encoding }
91
+ end
92
+ end
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
+
102
+ class Version
103
+
104
+ include Comparable
105
+
106
+ attr :parts
107
+
108
+ def initialize(v)
109
+ case v
110
+ when Version
111
+ @parts = v.parts
112
+ else
113
+ @parts = v.to_s.split(".")
114
+ end
115
+ end
116
+
117
+ def <=>(other)
118
+ other = Version.new(other)
119
+ length = [self.parts.length, other.parts.length].max
120
+ length.times do |i|
121
+ a, b = self.parts[i], other.parts[i]
122
+
123
+ return -1 if a.nil?
124
+ return +1 if b.nil?
125
+ return a.to_i <=> b.to_i if a != b
126
+ end
127
+
128
+ 0
129
+ end
130
+ end
131
+
132
+ module Generic
133
+
134
+ include Helper
135
+
136
+ attr_reader :log
137
+ attr_reader :redis
138
+
139
+ alias :r :redis
140
+
141
+ def setup
142
+ @log = StringIO.new
143
+ @redis = init _new_client
144
+
145
+ # Run GC to make sure orphaned connections are closed.
146
+ GC.start
147
+ end
148
+
149
+ def teardown
150
+ @redis.quit if @redis
151
+ end
152
+
153
+ def redis_mock(commands, options = {}, &blk)
154
+ Redis2Mock.start(commands, options) do |port|
155
+ yield _new_client(options.merge(:port => port))
156
+ end
157
+ end
158
+
159
+ def redis_mock_with_handler(handler, options = {}, &blk)
160
+ Redis2Mock.start_with_handler(handler, options) do |port|
161
+ yield _new_client(options.merge(:port => port))
162
+ end
163
+ end
164
+
165
+ def assert_in_range(range, value)
166
+ assert range.include?(value), "expected #{value} to be in #{range.inspect}"
167
+ end
168
+
169
+ def target_version(target)
170
+ if version < target
171
+ skip("Requires Redis2 > #{target}") if respond_to?(:skip)
172
+ else
173
+ yield
174
+ end
175
+ end
176
+ end
177
+
178
+ module Client
179
+
180
+ include Generic
181
+
182
+ def version
183
+ Version.new(redis.info["redis_version"])
184
+ end
185
+
186
+ private
187
+
188
+ def _format_options(options)
189
+ OPTIONS.merge(:logger => ::Logger.new(@log)).merge(options)
190
+ end
191
+
192
+ def _new_client(options = {})
193
+ Redis2.new(_format_options(options).merge(:driver => ENV["conn"]))
194
+ end
195
+ end
196
+
197
+ module Distributed
198
+
199
+ include Generic
200
+
201
+ def version
202
+ Version.new(redis.info.first["redis_version"])
203
+ end
204
+
205
+ private
206
+
207
+ def _format_options(options)
208
+ {
209
+ :timeout => OPTIONS[:timeout],
210
+ :logger => ::Logger.new(@log),
211
+ }.merge(options)
212
+ end
213
+
214
+ def _new_client(options = {})
215
+ Redis2::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+
5
+ class TestHelper < Test::Unit::TestCase
6
+
7
+ include Helper
8
+
9
+ def test_version_comparison
10
+ v = Version.new("2.0.1")
11
+
12
+ assert v > "1"
13
+ assert v > "2"
14
+ assert v < "3"
15
+ assert v < "10"
16
+
17
+ assert v < "2.1"
18
+ assert v < "2.0.2"
19
+ assert v < "2.0.1.1"
20
+ assert v < "2.0.10"
21
+
22
+ assert v == "2.0.1"
23
+ end
24
+ end
@@ -0,0 +1,410 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+
5
+ class TestInternals < Test::Unit::TestCase
6
+
7
+ include Helper::Client
8
+
9
+ def test_logger
10
+ r.ping
11
+
12
+ assert log.string =~ /Redis2 >> PING/
13
+ assert log.string =~ /Redis2 >> \d+\.\d+ms/
14
+ end
15
+
16
+ def test_logger_with_pipelining
17
+ r.pipelined do
18
+ r.set "foo", "bar"
19
+ r.get "foo"
20
+ end
21
+
22
+ assert log.string["SET foo bar"]
23
+ assert log.string["GET foo"]
24
+ end
25
+
26
+ def test_recovers_from_failed_commands
27
+ # See https://github.com/redis/redis-rb/issues#issue/28
28
+
29
+ assert_raise(Redis2::CommandError) do
30
+ r.command_that_doesnt_exist
31
+ end
32
+
33
+ assert_nothing_raised do
34
+ r.info
35
+ end
36
+ end
37
+
38
+ def test_raises_on_protocol_errors
39
+ redis_mock(:ping => lambda { |*_| "foo" }) do |redis|
40
+ assert_raise(Redis2::ProtocolError) do
41
+ redis.ping
42
+ end
43
+ end
44
+ end
45
+
46
+ def test_provides_a_meaningful_inspect
47
+ assert_equal "#<Redis2 client v#{Redis2::VERSION} for redis://127.0.0.1:#{PORT}/15>", r.inspect
48
+ end
49
+
50
+ def test_redis_current
51
+ assert_equal "127.0.0.1", Redis2.current.client.host
52
+ assert_equal 6379, Redis2.current.client.port
53
+ assert_equal 0, Redis2.current.client.db
54
+
55
+ Redis2.current = Redis2.new(OPTIONS.merge(:port => 6380, :db => 1))
56
+
57
+ t = Thread.new do
58
+ assert_equal "127.0.0.1", Redis2.current.client.host
59
+ assert_equal 6380, Redis2.current.client.port
60
+ assert_equal 1, Redis2.current.client.db
61
+ end
62
+
63
+ t.join
64
+
65
+ assert_equal "127.0.0.1", Redis2.current.client.host
66
+ assert_equal 6380, Redis2.current.client.port
67
+ assert_equal 1, Redis2.current.client.db
68
+ end
69
+
70
+ def test_redis_connected?
71
+ fresh_client = _new_client
72
+ assert !fresh_client.connected?
73
+
74
+ fresh_client.ping
75
+ assert fresh_client.connected?
76
+
77
+ fresh_client.quit
78
+ assert !fresh_client.connected?
79
+ end
80
+
81
+ def test_default_id_with_host_and_port
82
+ redis = Redis2.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
83
+ assert_equal "redis://host:1234/0", redis.client.id
84
+ end
85
+
86
+ def test_default_id_with_host_and_port_and_explicit_scheme
87
+ redis = Redis2.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0, :scheme => "foo"))
88
+ assert_equal "redis://host:1234/0", redis.client.id
89
+ end
90
+
91
+ def test_default_id_with_path
92
+ redis = Redis2.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0))
93
+ assert_equal "redis:///tmp/redis.sock/0", redis.client.id
94
+ end
95
+
96
+ def test_default_id_with_path_and_explicit_scheme
97
+ redis = Redis2.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0, :scheme => "foo"))
98
+ assert_equal "redis:///tmp/redis.sock/0", redis.client.id
99
+ end
100
+
101
+ def test_override_id
102
+ redis = Redis2.new(OPTIONS.merge(:id => "test"))
103
+ assert_equal redis.client.id, "test"
104
+ end
105
+
106
+ def test_timeout
107
+ assert_nothing_raised do
108
+ Redis2.new(OPTIONS.merge(:timeout => 0))
109
+ end
110
+ end
111
+
112
+ def test_id_inside_multi
113
+ redis = Redis2.new(OPTIONS)
114
+ id = nil
115
+
116
+ redis.multi do
117
+ id = redis.id
118
+ end
119
+
120
+ assert_equal id, "redis://127.0.0.1:6381/15"
121
+ end
122
+
123
+ driver(:ruby) do
124
+ def test_tcp_keepalive
125
+ keepalive = {:time => 20, :intvl => 10, :probes => 5}
126
+
127
+ redis = Redis2.new(OPTIONS.merge(:tcp_keepalive => keepalive))
128
+ redis.ping
129
+
130
+ connection = redis.client.connection
131
+ actual_keepalive = connection.get_tcp_keepalive
132
+
133
+ [:time, :intvl, :probes].each do |key|
134
+ if actual_keepalive.has_key?(key)
135
+ assert_equal actual_keepalive[key], keepalive[key]
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ def test_time
142
+ target_version "2.5.4" do
143
+ # Test that the difference between the time that Ruby reports and the time
144
+ # that Redis2 reports is minimal (prevents the test from being racy).
145
+ rv = r.time
146
+
147
+ redis_usec = rv[0] * 1_000_000 + rv[1]
148
+ ruby_usec = Integer(Time.now.to_f * 1_000_000)
149
+
150
+ assert 500_000 > (ruby_usec - redis_usec).abs
151
+ end
152
+ end
153
+
154
+ def test_connection_timeout
155
+ assert_raise Redis2::CannotConnectError do
156
+ Redis2.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
157
+ end
158
+ end
159
+
160
+ def close_on_ping(seq)
161
+ $request = 0
162
+
163
+ command = lambda do
164
+ idx = $request
165
+ $request += 1
166
+
167
+ rv = "+%d" % idx
168
+ rv = nil if seq.include?(idx)
169
+ rv
170
+ end
171
+
172
+ redis_mock(:ping => command, :timeout => 0.1) do |redis|
173
+ yield(redis)
174
+ end
175
+ end
176
+
177
+ def test_retry_by_default
178
+ close_on_ping([0]) do |redis|
179
+ assert_equal "1", redis.ping
180
+ end
181
+ end
182
+
183
+ def test_retry_when_wrapped_in_with_reconnect_true
184
+ close_on_ping([0]) do |redis|
185
+ redis.with_reconnect(true) do
186
+ assert_equal "1", redis.ping
187
+ end
188
+ end
189
+ end
190
+
191
+ def test_dont_retry_when_wrapped_in_with_reconnect_false
192
+ close_on_ping([0]) do |redis|
193
+ assert_raise Redis2::ConnectionError do
194
+ redis.with_reconnect(false) do
195
+ redis.ping
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ def test_dont_retry_when_wrapped_in_without_reconnect
202
+ close_on_ping([0]) do |redis|
203
+ assert_raise Redis2::ConnectionError do
204
+ redis.without_reconnect do
205
+ redis.ping
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ def test_retry_only_once_when_read_raises_econnreset
212
+ close_on_ping([0, 1]) do |redis|
213
+ assert_raise Redis2::ConnectionError do
214
+ redis.ping
215
+ end
216
+
217
+ assert !redis.client.connected?
218
+ end
219
+ end
220
+
221
+ def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
222
+ close_on_ping([1]) do |redis|
223
+ assert_raise Redis2::ConnectionError do
224
+ redis.pipelined do
225
+ redis.ping
226
+ redis.ping # Second #read times out
227
+ end
228
+ end
229
+
230
+ assert !redis.client.connected?
231
+ end
232
+ end
233
+
234
+ def close_on_connection(seq)
235
+ $n = 0
236
+
237
+ read_command = lambda do |session|
238
+ Array.new(session.gets[1..-3].to_i) do
239
+ bytes = session.gets[1..-3].to_i
240
+ arg = session.read(bytes)
241
+ session.read(2) # Discard \r\n
242
+ arg
243
+ end
244
+ end
245
+
246
+ handler = lambda do |session|
247
+ n = $n
248
+ $n += 1
249
+
250
+ select = read_command.call(session)
251
+ if select[0].downcase == "select"
252
+ session.write("+OK\r\n")
253
+ else
254
+ raise "Expected SELECT"
255
+ end
256
+
257
+ if !seq.include?(n)
258
+ while read_command.call(session)
259
+ session.write("+#{n}\r\n")
260
+ end
261
+ end
262
+ end
263
+
264
+ redis_mock_with_handler(handler) do |redis|
265
+ yield(redis)
266
+ end
267
+ end
268
+
269
+ def test_retry_on_write_error_by_default
270
+ close_on_connection([0]) do |redis|
271
+ assert_equal "1", redis.client.call(["x" * 128 * 1024])
272
+ end
273
+ end
274
+
275
+ def test_retry_on_write_error_when_wrapped_in_with_reconnect_true
276
+ close_on_connection([0]) do |redis|
277
+ redis.with_reconnect(true) do
278
+ assert_equal "1", redis.client.call(["x" * 128 * 1024])
279
+ end
280
+ end
281
+ end
282
+
283
+ def test_dont_retry_on_write_error_when_wrapped_in_with_reconnect_false
284
+ close_on_connection([0]) do |redis|
285
+ assert_raise Redis2::ConnectionError do
286
+ redis.with_reconnect(false) do
287
+ redis.client.call(["x" * 128 * 1024])
288
+ end
289
+ end
290
+ end
291
+ end
292
+
293
+ def test_dont_retry_on_write_error_when_wrapped_in_without_reconnect
294
+ close_on_connection([0]) do |redis|
295
+ assert_raise Redis2::ConnectionError do
296
+ redis.without_reconnect do
297
+ redis.client.call(["x" * 128 * 1024])
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ def test_connecting_to_unix_domain_socket
304
+ assert_nothing_raised do
305
+ Redis2.new(OPTIONS.merge(:path => "./test/db/redis.sock")).ping
306
+ end
307
+ end
308
+
309
+ driver(:ruby, :hiredis) do
310
+ def test_bubble_timeout_without_retrying
311
+ serv = TCPServer.new(6380)
312
+
313
+ redis = Redis2.new(:port => 6380, :timeout => 0.1)
314
+
315
+ assert_raise(Redis2::TimeoutError) do
316
+ redis.ping
317
+ end
318
+
319
+ ensure
320
+ serv.close if serv
321
+ end
322
+ end
323
+
324
+ def test_client_options
325
+ redis = Redis2.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 = Redis2.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
+ Redis2.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
410
+ end