redis 3.0.0.rc1 → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.travis.yml +50 -0
  2. data/.travis/Gemfile +11 -0
  3. data/CHANGELOG.md +47 -19
  4. data/README.md +160 -149
  5. data/Rakefile +15 -50
  6. data/examples/pubsub.rb +1 -1
  7. data/examples/unicorn/config.ru +1 -1
  8. data/examples/unicorn/unicorn.rb +1 -1
  9. data/lib/redis.rb +790 -390
  10. data/lib/redis/client.rb +137 -49
  11. data/lib/redis/connection/hiredis.rb +26 -15
  12. data/lib/redis/connection/ruby.rb +170 -53
  13. data/lib/redis/connection/synchrony.rb +23 -35
  14. data/lib/redis/distributed.rb +92 -32
  15. data/lib/redis/errors.rb +4 -2
  16. data/lib/redis/pipeline.rb +17 -6
  17. data/lib/redis/version.rb +1 -1
  18. data/redis.gemspec +4 -6
  19. data/test/blocking_commands_test.rb +42 -0
  20. data/test/command_map_test.rb +18 -17
  21. data/test/commands_on_hashes_test.rb +13 -12
  22. data/test/commands_on_lists_test.rb +35 -45
  23. data/test/commands_on_sets_test.rb +55 -54
  24. data/test/commands_on_sorted_sets_test.rb +106 -105
  25. data/test/commands_on_strings_test.rb +64 -55
  26. data/test/commands_on_value_types_test.rb +66 -54
  27. data/test/connection_handling_test.rb +136 -151
  28. data/test/distributed_blocking_commands_test.rb +33 -40
  29. data/test/distributed_commands_on_hashes_test.rb +6 -7
  30. data/test/distributed_commands_on_lists_test.rb +13 -14
  31. data/test/distributed_commands_on_sets_test.rb +57 -58
  32. data/test/distributed_commands_on_sorted_sets_test.rb +11 -12
  33. data/test/distributed_commands_on_strings_test.rb +31 -32
  34. data/test/distributed_commands_on_value_types_test.rb +61 -46
  35. data/test/distributed_commands_requiring_clustering_test.rb +108 -108
  36. data/test/distributed_connection_handling_test.rb +14 -15
  37. data/test/distributed_internals_test.rb +7 -19
  38. data/test/distributed_key_tags_test.rb +36 -36
  39. data/test/distributed_persistence_control_commands_test.rb +17 -14
  40. data/test/distributed_publish_subscribe_test.rb +61 -69
  41. data/test/distributed_remote_server_control_commands_test.rb +39 -28
  42. data/test/distributed_sorting_test.rb +12 -13
  43. data/test/distributed_test.rb +40 -41
  44. data/test/distributed_transactions_test.rb +20 -21
  45. data/test/encoding_test.rb +12 -9
  46. data/test/error_replies_test.rb +42 -36
  47. data/test/helper.rb +118 -85
  48. data/test/helper_test.rb +20 -6
  49. data/test/internals_test.rb +167 -103
  50. data/test/lint/blocking_commands.rb +124 -0
  51. data/test/lint/hashes.rb +115 -93
  52. data/test/lint/lists.rb +86 -80
  53. data/test/lint/sets.rb +68 -62
  54. data/test/lint/sorted_sets.rb +200 -195
  55. data/test/lint/strings.rb +112 -94
  56. data/test/lint/value_types.rb +76 -55
  57. data/test/persistence_control_commands_test.rb +17 -12
  58. data/test/pipelining_commands_test.rb +135 -126
  59. data/test/publish_subscribe_test.rb +105 -110
  60. data/test/remote_server_control_commands_test.rb +74 -58
  61. data/test/sorting_test.rb +31 -29
  62. data/test/support/connection/hiredis.rb +1 -0
  63. data/test/support/connection/ruby.rb +1 -0
  64. data/test/support/connection/synchrony.rb +17 -0
  65. data/test/{redis_mock.rb → support/redis_mock.rb} +24 -21
  66. data/test/support/wire/synchrony.rb +24 -0
  67. data/test/support/wire/thread.rb +5 -0
  68. data/test/synchrony_driver.rb +9 -9
  69. data/test/test.conf +1 -1
  70. data/test/thread_safety_test.rb +21 -19
  71. data/test/transactions_test.rb +189 -118
  72. data/test/unknown_commands_test.rb +9 -8
  73. data/test/url_param_test.rb +46 -41
  74. metadata +28 -43
  75. data/TODO.md +0 -4
  76. data/benchmarking/thread_safety.rb +0 -38
  77. data/test/lint/internals.rb +0 -36
@@ -1,53 +1,59 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
3
+ require "helper"
4
4
 
5
- setup do
6
- init Redis.new(OPTIONS)
7
- end
5
+ class TestErrorReplies < Test::Unit::TestCase
6
+
7
+ include Helper::Client
8
8
 
9
- # Every test shouldn't disconnect from the server. Also, when error replies are
10
- # in play, the protocol should never get into an invalid state where there are
11
- # pending replies in the connection. Calling INFO after every test ensures that
12
- # the protocol is still in a valid state.
13
- def test_with_reconnection_check(title)
14
- test(title) do |r|
9
+ # Every test shouldn't disconnect from the server. Also, when error replies are
10
+ # in play, the protocol should never get into an invalid state where there are
11
+ # pending replies in the connection. Calling INFO after every test ensures that
12
+ # the protocol is still in a valid state.
13
+ def with_reconnection_check
15
14
  before = r.info["total_connections_received"]
16
15
  yield(r)
17
16
  after = r.info["total_connections_received"]
18
- assert before == after
17
+ ensure
18
+ assert_equal before, after
19
19
  end
20
- end
21
20
 
22
- test_with_reconnection_check "Error reply for single command" do |r|
23
- begin
24
- r.unknown_command
25
- rescue => ex
26
- ensure
27
- assert ex.message =~ /unknown command/i
21
+ def test_error_reply_for_single_command
22
+ with_reconnection_check do
23
+ begin
24
+ r.unknown_command
25
+ rescue => ex
26
+ ensure
27
+ assert ex.message =~ /unknown command/i
28
+ end
29
+ end
28
30
  end
29
- end
30
31
 
31
- test_with_reconnection_check "Raise first error reply in pipeline" do |r|
32
- begin
33
- r.pipelined do
34
- r.set("foo", "s1")
35
- r.incr("foo") # not an integer
36
- r.lpush("foo", "value") # wrong kind of value
32
+ def test_raise_first_error_reply_in_pipeline
33
+ with_reconnection_check do
34
+ begin
35
+ r.pipelined do
36
+ r.set("foo", "s1")
37
+ r.incr("foo") # not an integer
38
+ r.lpush("foo", "value") # wrong kind of value
39
+ end
40
+ rescue => ex
41
+ ensure
42
+ assert ex.message =~ /not an integer/i
43
+ end
37
44
  end
38
- rescue => ex
39
- ensure
40
- assert ex.message =~ /not an integer/i
41
45
  end
42
- end
43
46
 
44
- test_with_reconnection_check "Recover from raise in #call_loop" do |r|
45
- begin
46
- r.client.call_loop([:invalid_monitor]) do
47
- assert false # Should never be executed
47
+ def test_recover_from_raise_in__call_loop
48
+ with_reconnection_check do
49
+ begin
50
+ r.client.call_loop([:invalid_monitor]) do
51
+ assert false # Should never be executed
52
+ end
53
+ rescue => ex
54
+ ensure
55
+ assert ex.message =~ /unknown command/i
56
+ end
48
57
  end
49
- rescue => ex
50
- ensure
51
- assert ex.message =~ /unknown command/i
52
58
  end
53
59
  end
@@ -1,6 +1,6 @@
1
1
  $:.unshift File.expand_path('../lib', File.dirname(__FILE__))
2
2
 
3
- #require "cutest"
3
+ require "test/unit"
4
4
  require "logger"
5
5
  require "stringio"
6
6
 
@@ -9,23 +9,34 @@ begin
9
9
  rescue LoadError
10
10
  end
11
11
 
12
- PORT = 6379
13
- OPTIONS = {:port => PORT, :db => 15, :timeout => 3}
14
- NODES = ["redis://127.0.0.1:6379/15"]
12
+ $VERBOSE = true
13
+
14
+ ENV["conn"] ||= "ruby"
15
+
16
+ require "redis"
17
+ require "redis/distributed"
18
+ require "redis/connection/#{ENV["conn"]}"
19
+
20
+ require "support/redis_mock"
21
+ require "support/connection/#{ENV["conn"]}"
22
+
23
+ PORT = 6381
24
+ OPTIONS = {:port => PORT, :db => 15, :timeout => 0.1}
25
+ NODES = ["redis://127.0.0.1:#{PORT}/15"]
15
26
 
16
27
  def init(redis)
17
28
  begin
18
- redis.flushdb
19
29
  redis.select 14
20
30
  redis.flushdb
21
31
  redis.select 15
32
+ redis.flushdb
22
33
  redis
23
34
  rescue Redis::CannotConnectError
24
35
  puts <<-EOS
25
36
 
26
37
  Cannot connect to Redis.
27
38
 
28
- Make sure Redis is running on localhost, port 6379.
39
+ Make sure Redis is running on localhost, port #{PORT}.
29
40
  This testing suite connects to the database 15.
30
41
 
31
42
  To install redis:
@@ -42,114 +53,136 @@ def init(redis)
42
53
  end
43
54
  end
44
55
 
45
- $VERBOSE = true
56
+ def driver(*drivers, &blk)
57
+ if drivers.map(&:to_s).include?(ENV["conn"])
58
+ class_eval(&blk)
59
+ end
60
+ end
46
61
 
47
- require "redis/connection/%s" % (ENV["REDIS_CONNECTION_DRIVER"] || "ruby")
48
- require "redis"
62
+ module Helper
49
63
 
50
- def driver
51
- Redis::Connection.drivers.last.to_s.split("::").last.downcase.to_sym
52
- end
64
+ def run(runner)
65
+ if respond_to?(:around)
66
+ around { super(runner) }
67
+ else
68
+ super
69
+ end
70
+ end
53
71
 
54
- if driver == :synchrony
55
- # Make cutest fiber + eventmachine aware if the synchrony driver is used.
56
- undef test if defined? test
57
- def test(name = nil, &block)
58
- cutest[:test] = name
72
+ def silent
73
+ verbose, $VERBOSE = $VERBOSE, false
59
74
 
60
- blk = Proc.new do
61
- prepare.each { |blk| blk.call }
62
- block.call(setup && setup.call)
75
+ begin
76
+ yield
77
+ ensure
78
+ $VERBOSE = verbose
63
79
  end
80
+ end
64
81
 
65
- t = Thread.current[:cutest]
66
- if defined? EventMachine
67
- EM.synchrony do
68
- Thread.current[:cutest] = t
69
- blk.call
70
- EM.stop
71
- end
72
- else
73
- blk.call
82
+ def with_external_encoding(encoding)
83
+ original_encoding = Encoding.default_external
84
+
85
+ begin
86
+ silent { Encoding.default_external = Encoding.find(encoding) }
87
+ yield
88
+ ensure
89
+ silent { Encoding.default_external = original_encoding }
74
90
  end
75
91
  end
76
92
 
77
- class Wire < Fiber
78
- # We cannot run this fiber explicitly because EM schedules it. Resuming the
79
- # current fiber on the next tick to let the reactor do work.
80
- def self.pass
81
- f = Fiber.current
82
- EM.next_tick { f.resume }
83
- Fiber.yield
93
+ class Version
94
+
95
+ include Comparable
96
+
97
+ attr :parts
98
+
99
+ def initialize(v)
100
+ case v
101
+ when Version
102
+ @parts = v.parts
103
+ else
104
+ @parts = v.to_s.split(".")
105
+ end
84
106
  end
85
107
 
86
- def self.sleep(sec)
87
- EM::Synchrony.sleep(sec)
108
+ def <=>(other)
109
+ other = Version.new(other)
110
+ length = [self.parts.length, other.parts.length].max
111
+ length.times do |i|
112
+ a, b = self.parts[i], other.parts[i]
113
+
114
+ return -1 if a.nil?
115
+ return +1 if b.nil?
116
+ return a <=> b if a != b
117
+ end
118
+
119
+ 0
88
120
  end
121
+ end
89
122
 
90
- def initialize(&blk)
91
- super
123
+ module Generic
124
+
125
+ include Helper
92
126
 
93
- # Schedule run in next tick
94
- EM.next_tick { resume }
127
+ attr_reader :log
128
+ attr_reader :redis
129
+
130
+ alias :r :redis
131
+
132
+ def setup
133
+ @log = StringIO.new
134
+ @redis = init _new_client
95
135
  end
96
136
 
97
- def join
98
- self.class.pass while alive?
137
+ def teardown
138
+ @redis.quit if @redis
99
139
  end
100
- end
101
- else
102
- class Wire < Thread
103
- def self.sleep(sec)
104
- Kernel.sleep(sec)
140
+
141
+ def redis_mock(commands, options = {}, &blk)
142
+ RedisMock.start(commands) do |port|
143
+ yield _new_client(options.merge(:port => port))
144
+ end
105
145
  end
106
146
  end
107
- end
108
147
 
109
- def capture_stderr
110
- stderr = $stderr
111
- $stderr = StringIO.new
148
+ module Client
112
149
 
113
- yield
150
+ include Generic
114
151
 
115
- $stderr = stderr
116
- end
152
+ def version
153
+ Version.new(redis.info["redis_version"])
154
+ end
117
155
 
118
- def silent
119
- verbose, $VERBOSE = $VERBOSE, false
156
+ private
120
157
 
121
- begin
122
- yield
123
- ensure
124
- $VERBOSE = verbose
158
+ def _format_options(options)
159
+ OPTIONS.merge(:logger => ::Logger.new(@log)).merge(options)
160
+ end
161
+
162
+ def _new_client(options = {})
163
+ Redis.new(_format_options(options))
164
+ end
125
165
  end
126
- end
127
166
 
128
- def version(r)
129
- info = r.info
130
- info = info.first unless info.is_a?(Hash)
131
- version_str_to_i info["redis_version"]
132
- end
167
+ module Distributed
133
168
 
134
- def version_str_to_i(version_str)
135
- version_str.split(".").map{ |v| v.ljust(2, '0') }.join.to_i
136
- end
169
+ include Generic
137
170
 
138
- def with_external_encoding(encoding)
139
- original_encoding = Encoding.default_external
171
+ def version
172
+ Version.new(redis.info.first["redis_version"])
173
+ end
140
174
 
141
- begin
142
- silent { Encoding.default_external = Encoding.find(encoding) }
143
- yield
144
- ensure
145
- silent { Encoding.default_external = original_encoding }
146
- end
147
- end
175
+ private
148
176
 
149
- def assert_nothing_raised(*exceptions)
150
- begin
151
- yield
152
- rescue *exceptions
153
- flunk(caller[1])
177
+ def _format_options(options)
178
+ {
179
+ :timeout => OPTIONS[:timeout],
180
+ :logger => ::Logger.new(@log),
181
+ }.merge(options)
182
+ end
183
+
184
+ def _new_client(options = {})
185
+ Redis::Distributed.new(NODES, _format_options(options))
186
+ end
154
187
  end
155
188
  end
@@ -1,8 +1,22 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ # encoding: UTF-8
2
2
 
3
- test "version_str_to_i" do
4
- assert_equal 200000, version_str_to_i('2.0.0')
5
- assert_equal 202020, version_str_to_i('2.2.2')
6
- assert_equal 202022, version_str_to_i('2.2.22')
7
- assert_equal 222222, version_str_to_i('22.22.22')
3
+ require "helper"
4
+
5
+ class TestHelper < Test::Unit::TestCase
6
+
7
+ include Helper
8
+
9
+ def test_version_comparison
10
+ v = Version.new("2.0.0")
11
+
12
+ assert v < "3"
13
+ assert v > "1"
14
+ assert v > "2"
15
+
16
+ assert v < "2.1"
17
+ assert v < "2.0.1"
18
+ assert v < "2.0.0.1"
19
+
20
+ assert v == "2.0.0"
21
+ end
8
22
  end
@@ -1,152 +1,216 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
- require File.expand_path("./redis_mock", File.dirname(__FILE__))
3
+ require "helper"
5
4
 
6
- include RedisMock::Helper
5
+ class TestInternals < Test::Unit::TestCase
7
6
 
8
- setup do
9
- log = StringIO.new
7
+ include Helper::Client
10
8
 
11
- [Redis.new(OPTIONS.merge(:logger => ::Logger.new(log))), log]
12
- end
9
+ def test_logger
10
+ r.ping
13
11
 
14
- $TEST_PIPELINING = true
12
+ assert log.string =~ /Redis >> PING/
13
+ assert log.string =~ /Redis >> \d+\.\d+ms/
14
+ end
15
15
 
16
- load File.expand_path("./lint/internals.rb", File.dirname(__FILE__))
16
+ def test_logger_with_pipelining
17
+ r.pipelined do
18
+ r.set "foo", "bar"
19
+ r.get "foo"
20
+ end
17
21
 
18
- test "provides a meaningful inspect" do |r, _|
19
- assert "#<Redis client v#{Redis::VERSION} connected to redis://127.0.0.1:6379/15 (Redis v#{r.info["redis_version"]})>" == r.inspect
20
- end
22
+ assert log.string["SET foo bar"]
23
+ assert log.string["GET foo"]
24
+ end
21
25
 
22
- test "Redis.current" do
23
- Redis.current.set("foo", "bar")
26
+ def test_recovers_from_failed_commands
27
+ # See https://github.com/redis/redis-rb/issues#issue/28
24
28
 
25
- assert "bar" == Redis.current.get("foo")
29
+ assert_raise(Redis::CommandError) do
30
+ r.command_that_doesnt_exist
31
+ end
26
32
 
27
- Redis.current = Redis.new(OPTIONS.merge(:db => 14))
33
+ assert_nothing_raised do
34
+ r.info
35
+ end
36
+ end
28
37
 
29
- assert Redis.current.get("foo").nil?
30
- end
38
+ def test_raises_on_protocol_errors
39
+ redis_mock(:ping => lambda { |*_| "foo" }) do |redis|
40
+ assert_raise(Redis::ProtocolError) do
41
+ redis.ping
42
+ end
43
+ end
44
+ end
31
45
 
32
- test "Timeout" do
33
- assert_nothing_raised do
34
- Redis.new(OPTIONS.merge(:timeout => 0))
46
+ def test_provides_a_meaningful_inspect
47
+ assert_equal "#<Redis client v#{Redis::VERSION} for redis://127.0.0.1:#{PORT}/15>", r.inspect
35
48
  end
36
- end
37
49
 
38
- test "Connection timeout" do
39
- next if driver == :synchrony
50
+ def test_redis_current
51
+ assert_equal "127.0.0.1", Redis.current.client.host
52
+ assert_equal 6379, Redis.current.client.port
53
+ assert_equal 0, Redis.current.client.db
54
+
55
+ Redis.current = Redis.new(OPTIONS.merge(:port => 6380, :db => 1))
56
+
57
+ t = Thread.new do
58
+ assert_equal "127.0.0.1", Redis.current.client.host
59
+ assert_equal 6380, Redis.current.client.port
60
+ assert_equal 1, Redis.current.client.db
61
+ end
62
+
63
+ t.join
40
64
 
41
- assert_raise Redis::CannotConnectError do
42
- Redis.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
65
+ assert_equal "127.0.0.1", Redis.current.client.host
66
+ assert_equal 6380, Redis.current.client.port
67
+ assert_equal 1, Redis.current.client.db
68
+ end
69
+
70
+ def test_default_id_with_host_and_port
71
+ redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
72
+ assert_equal "redis://host:1234/0", redis.client.id
43
73
  end
44
- end
45
74
 
46
- test "Retry when first read raises ECONNRESET" do
47
- $request = 0
75
+ def test_default_id_with_host_and_port_and_explicit_scheme
76
+ redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0, :scheme => "foo"))
77
+ assert_equal "redis://host:1234/0", redis.client.id
78
+ end
48
79
 
49
- command = lambda do
50
- case ($request += 1)
51
- when 1; nil # Close on first command
52
- else "+%d" % $request
53
- end
80
+ def test_default_id_with_path
81
+ redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0))
82
+ assert_equal "redis:///tmp/redis.sock/0", redis.client.id
54
83
  end
55
84
 
56
- redis_mock(:ping => command) do
57
- redis = Redis.connect(:port => 6380, :timeout => 0.1)
58
- assert "2" == redis.ping
85
+ def test_default_id_with_path_and_explicit_scheme
86
+ redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0, :scheme => "foo"))
87
+ assert_equal "redis:///tmp/redis.sock/0", redis.client.id
59
88
  end
60
- end
61
89
 
62
- test "Don't retry when wrapped inside #without_reconnect" do
63
- $request = 0
90
+ def test_override_id
91
+ redis = Redis.new(OPTIONS.merge(:id => "test"))
92
+ assert_equal redis.client.id, "test"
93
+ end
64
94
 
65
- command = lambda do
66
- case ($request += 1)
67
- when 1; nil # Close on first command
68
- else "+%d" % $request
95
+ def test_timeout
96
+ assert_nothing_raised do
97
+ Redis.new(OPTIONS.merge(:timeout => 0))
69
98
  end
70
99
  end
71
100
 
72
- redis_mock(:ping => command) do
73
- redis = Redis.connect(:port => 6380, :timeout => 0.1)
74
- assert_raise Redis::ConnectionError do
75
- redis.without_reconnect do
76
- redis.ping
101
+ def test_time
102
+ return if version < "2.5.4"
103
+
104
+ # Test that the difference between the time that Ruby reports and the time
105
+ # that Redis reports is minimal (prevents the test from being racy).
106
+ rv = r.time
107
+
108
+ redis_usec = rv[0] * 1_000_000 + rv[1]
109
+ ruby_usec = Integer(Time.now.to_f * 1_000_000)
110
+
111
+ assert 500_000 > (ruby_usec - redis_usec).abs
112
+ end
113
+
114
+ def test_connection_timeout
115
+ assert_raise Redis::CannotConnectError do
116
+ Redis.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
117
+ end
118
+ end
119
+
120
+ def test_retry_when_first_read_raises_econnreset
121
+ $request = 0
122
+
123
+ command = lambda do
124
+ case ($request += 1)
125
+ when 1; nil # Close on first command
126
+ else "+%d" % $request
77
127
  end
78
128
  end
79
129
 
80
- assert !redis.client.connected?
130
+ redis_mock(:ping => command, :timeout => 0.1) do |redis|
131
+ assert_equal "2", redis.ping
132
+ end
81
133
  end
82
- end
83
134
 
84
- test "Retry only once when read raises ECONNRESET" do
85
- $request = 0
135
+ def test_don_t_retry_when_wrapped_inside__without_reconnect
136
+ $request = 0
137
+
138
+ command = lambda do
139
+ case ($request += 1)
140
+ when 1; nil # Close on first command
141
+ else "+%d" % $request
142
+ end
143
+ end
144
+
145
+ redis_mock(:ping => command, :timeout => 0.1) do |redis|
146
+ assert_raise Redis::ConnectionError do
147
+ redis.without_reconnect do
148
+ redis.ping
149
+ end
150
+ end
86
151
 
87
- command = lambda do
88
- case ($request += 1)
89
- when 1; nil # Close on first command
90
- when 2; nil # Close on second command
91
- else "+%d" % $request
152
+ assert !redis.client.connected?
92
153
  end
93
154
  end
94
155
 
95
- redis_mock(:ping => command) do
96
- redis = Redis.connect(:port => 6380, :timeout => 0.1)
97
- assert_raise Redis::ConnectionError do
98
- redis.ping
156
+ def test_retry_only_once_when_read_raises_econnreset
157
+ $request = 0
158
+
159
+ command = lambda do
160
+ case ($request += 1)
161
+ when 1; nil # Close on first command
162
+ when 2; nil # Close on second command
163
+ else "+%d" % $request
164
+ end
99
165
  end
100
166
 
101
- assert !redis.client.connected?
167
+ redis_mock(:ping => command, :timeout => 0.1) do |redis|
168
+ assert_raise Redis::ConnectionError do
169
+ redis.ping
170
+ end
171
+
172
+ assert !redis.client.connected?
173
+ end
102
174
  end
103
- end
104
175
 
105
- test "Don't retry when second read in pipeline raises ECONNRESET" do
106
- $request = 0
176
+ def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
177
+ $request = 0
107
178
 
108
- command = lambda do
109
- case ($request += 1)
110
- when 2; nil # Close on second command
111
- else "+%d" % $request
179
+ command = lambda do
180
+ case ($request += 1)
181
+ when 2; nil # Close on second command
182
+ else "+%d" % $request
183
+ end
112
184
  end
113
- end
114
185
 
115
- redis_mock(:ping => command) do
116
- redis = Redis.connect(:port => 6380, :timeout => 0.1)
117
- assert_raise Redis::ConnectionError do
118
- redis.pipelined do
119
- redis.ping
120
- redis.ping # Second #read times out
186
+ redis_mock(:ping => command, :timeout => 0.1) do |redis|
187
+ assert_raise Redis::ConnectionError do
188
+ redis.pipelined do
189
+ redis.ping
190
+ redis.ping # Second #read times out
191
+ end
121
192
  end
122
193
  end
123
194
  end
124
- end
125
195
 
126
- test "Connecting to UNIX domain socket" do
127
- assert_nothing_raised do
128
- Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock")).ping
196
+ def test_connecting_to_unix_domain_socket
197
+ assert_nothing_raised do
198
+ Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock")).ping
199
+ end
129
200
  end
130
- end
131
201
 
132
- # if driver == :ruby || driver == :hiredis
133
- # # Using a mock server in a thread doesn't work here (possibly because blocking
134
- # # socket ops, raw socket timeouts and Ruby's thread scheduling don't mix).
135
- # test "Bubble EAGAIN without retrying" do
136
- # cmd = %{(sleep 0.3; echo "+PONG\r\n") | nc -l 6380}
137
- # IO.popen(cmd) do |_|
138
- # sleep 0.1 # Give nc a little time to start listening
139
- # redis = Redis.connect(:port => 6380, :timeout => 0.1)
140
- #
141
- # begin
142
- # assert_raise(Errno::EAGAIN) { redis.ping }
143
- # ensure
144
- # # Explicitly close connection so nc can quit
145
- # redis.client.disconnect
146
- #
147
- # # Make the reactor loop do a tick to really close
148
- # EM::Synchrony.sleep(0) if driver == :synchrony
149
- # end
150
- # end
151
- # end
152
- # end
202
+ driver(:ruby, :hiredis) do
203
+ def test_bubble_timeout_without_retrying
204
+ serv = TCPServer.new(6380)
205
+
206
+ redis = Redis.new(:port => 6380, :timeout => 0.1)
207
+
208
+ assert_raise(Redis::TimeoutError) do
209
+ redis.ping
210
+ end
211
+
212
+ ensure
213
+ serv.close if serv
214
+ end
215
+ end
216
+ end