redis 3.0.1 → 3.0.2
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.
- data/CHANGELOG.md +21 -0
- data/README.md +3 -3
- data/examples/pubsub.rb +18 -12
- data/lib/redis.rb +165 -164
- data/lib/redis/client.rb +46 -6
- data/lib/redis/connection/ruby.rb +44 -12
- data/lib/redis/connection/synchrony.rb +11 -6
- data/lib/redis/distributed.rb +7 -4
- data/lib/redis/pipeline.rb +9 -4
- data/lib/redis/subscribe.rb +2 -2
- data/lib/redis/version.rb +1 -1
- data/test/distributed_internals_test.rb +26 -0
- data/test/distributed_remote_server_control_commands_test.rb +1 -1
- data/test/internals_test.rb +18 -0
- data/test/lint/sorted_sets.rb +37 -0
- data/test/lint/value_types.rb +12 -12
- data/test/remote_server_control_commands_test.rb +1 -1
- data/test/synchrony_driver.rb +32 -1
- data/test/transactions_test.rb +21 -5
- data/test/url_param_test.rb +68 -0
- metadata +2 -2
data/lib/redis/client.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require "redis/errors"
|
2
|
+
require "socket"
|
3
|
+
require "cgi"
|
2
4
|
|
3
5
|
class Redis
|
4
6
|
class Client
|
5
7
|
|
6
8
|
DEFAULTS = {
|
9
|
+
:url => lambda { ENV["REDIS_URL"] },
|
7
10
|
:scheme => "redis",
|
8
11
|
:host => "127.0.0.1",
|
9
12
|
:port => 6379,
|
@@ -11,6 +14,9 @@ class Redis
|
|
11
14
|
:timeout => 5.0,
|
12
15
|
:password => nil,
|
13
16
|
:db => 0,
|
17
|
+
:driver => nil,
|
18
|
+
:id => nil,
|
19
|
+
:tcp_keepalive => 0
|
14
20
|
}
|
15
21
|
|
16
22
|
def scheme
|
@@ -45,9 +51,9 @@ class Redis
|
|
45
51
|
@options[:db] = db.to_i
|
46
52
|
end
|
47
53
|
|
48
|
-
|
49
|
-
|
50
|
-
|
54
|
+
attr_accessor :logger
|
55
|
+
attr_reader :connection
|
56
|
+
attr_reader :command_map
|
51
57
|
|
52
58
|
def initialize(options = {})
|
53
59
|
@options = _parse_options(options)
|
@@ -295,8 +301,19 @@ class Redis
|
|
295
301
|
|
296
302
|
def _parse_options(options)
|
297
303
|
defaults = DEFAULTS.dup
|
304
|
+
options = options.dup
|
298
305
|
|
299
|
-
|
306
|
+
defaults.keys.each do |key|
|
307
|
+
# Fill in defaults if needed
|
308
|
+
if defaults[key].respond_to?(:call)
|
309
|
+
defaults[key] = defaults[key].call
|
310
|
+
end
|
311
|
+
|
312
|
+
# Symbolize only keys that are needed
|
313
|
+
options[key] = options[key.to_s] if options.has_key?(key.to_s)
|
314
|
+
end
|
315
|
+
|
316
|
+
url = options[:url] || defaults[:url]
|
300
317
|
|
301
318
|
# Override defaults from URL if given
|
302
319
|
if url
|
@@ -313,12 +330,15 @@ class Redis
|
|
313
330
|
defaults[:scheme] = uri.scheme
|
314
331
|
defaults[:host] = uri.host
|
315
332
|
defaults[:port] = uri.port if uri.port
|
316
|
-
defaults[:password] = uri.password if uri.password
|
333
|
+
defaults[:password] = CGI.unescape(uri.password) if uri.password
|
317
334
|
defaults[:db] = uri.path[1..-1].to_i if uri.path
|
318
335
|
end
|
319
336
|
end
|
320
337
|
|
321
|
-
|
338
|
+
# Use default when option is not specified or nil
|
339
|
+
defaults.keys.each do |key|
|
340
|
+
options[key] ||= defaults[key]
|
341
|
+
end
|
322
342
|
|
323
343
|
if options[:path]
|
324
344
|
options[:scheme] = "unix"
|
@@ -333,6 +353,26 @@ class Redis
|
|
333
353
|
options[:db] = options[:db].to_i
|
334
354
|
options[:driver] = _parse_driver(options[:driver]) || Connection.drivers.last
|
335
355
|
|
356
|
+
case options[:tcp_keepalive]
|
357
|
+
when Hash
|
358
|
+
[:time, :intvl, :probes].each do |key|
|
359
|
+
unless options[:tcp_keepalive][key].is_a?(Fixnum)
|
360
|
+
raise "Expected the #{key.inspect} key in :tcp_keepalive to be a Fixnum"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
when Fixnum
|
365
|
+
if options[:tcp_keepalive] >= 60
|
366
|
+
options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 20, :intvl => 10, :probes => 2}
|
367
|
+
|
368
|
+
elsif options[:tcp_keepalive] >= 30
|
369
|
+
options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 10, :intvl => 5, :probes => 2}
|
370
|
+
|
371
|
+
elsif options[:tcp_keepalive] >= 5
|
372
|
+
options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 2, :intvl => 2, :probes => 1}
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
336
376
|
options
|
337
377
|
end
|
338
378
|
|
@@ -79,22 +79,26 @@ class Redis
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
82
|
+
if defined?(::UNIXSocket)
|
83
83
|
|
84
|
-
|
85
|
-
# Errno::EAGAIN on #read_nonblock even when IO.select says it is
|
86
|
-
# readable. This behavior shows in 1.6.6 in both 1.8 and 1.9 mode.
|
87
|
-
# Therefore, fall back on the default Unix socket implementation,
|
88
|
-
# without timeouts.
|
84
|
+
class UNIXSocket < ::UNIXSocket
|
89
85
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
86
|
+
# This class doesn't include the mixin, because JRuby raises
|
87
|
+
# Errno::EAGAIN on #read_nonblock even when IO.select says it is
|
88
|
+
# readable. This behavior shows in 1.6.6 in both 1.8 and 1.9 mode.
|
89
|
+
# Therefore, fall back on the default Unix socket implementation,
|
90
|
+
# without timeouts.
|
91
|
+
|
92
|
+
def self.connect(path, timeout)
|
93
|
+
Timeout.timeout(timeout) do
|
94
|
+
sock = new(path)
|
95
|
+
sock
|
96
|
+
end
|
97
|
+
rescue Timeout::Error
|
98
|
+
raise TimeoutError
|
94
99
|
end
|
95
|
-
rescue Timeout::Error
|
96
|
-
raise TimeoutError
|
97
100
|
end
|
101
|
+
|
98
102
|
end
|
99
103
|
|
100
104
|
else
|
@@ -172,9 +176,37 @@ class Redis
|
|
172
176
|
|
173
177
|
instance = new(sock)
|
174
178
|
instance.timeout = config[:timeout]
|
179
|
+
instance.set_tcp_keepalive config[:tcp_keepalive]
|
175
180
|
instance
|
176
181
|
end
|
177
182
|
|
183
|
+
if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
|
184
|
+
def set_tcp_keepalive(keepalive)
|
185
|
+
return unless keepalive.is_a?(Hash)
|
186
|
+
|
187
|
+
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
188
|
+
@sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, keepalive[:time])
|
189
|
+
@sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, keepalive[:intvl])
|
190
|
+
@sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, keepalive[:probes])
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_tcp_keepalive
|
194
|
+
{
|
195
|
+
:time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
|
196
|
+
:intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
|
197
|
+
:probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
|
198
|
+
}
|
199
|
+
end
|
200
|
+
else
|
201
|
+
def set_tcp_keepalive(keepalive)
|
202
|
+
end
|
203
|
+
|
204
|
+
def get_tcp_keepalive
|
205
|
+
{
|
206
|
+
}
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
178
210
|
def initialize(sock)
|
179
211
|
@sock = sock
|
180
212
|
end
|
@@ -27,13 +27,18 @@ class Redis
|
|
27
27
|
def receive_data(data)
|
28
28
|
@reader.feed(data)
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
reply =
|
33
|
-
|
30
|
+
loop do
|
31
|
+
begin
|
32
|
+
reply = @reader.gets
|
33
|
+
rescue RuntimeError => err
|
34
|
+
@req.fail [:error, ProtocolError.new(err.message)]
|
35
|
+
break
|
34
36
|
end
|
35
|
-
|
36
|
-
|
37
|
+
|
38
|
+
break if reply == false
|
39
|
+
|
40
|
+
reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
|
41
|
+
@req.succeed [:reply, reply]
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
data/lib/redis/distributed.rb
CHANGED
@@ -15,10 +15,11 @@ class Redis
|
|
15
15
|
|
16
16
|
attr_reader :ring
|
17
17
|
|
18
|
-
def initialize(
|
18
|
+
def initialize(node_configs, options = {})
|
19
19
|
@tag = options.delete(:tag) || /^\{(.+?)\}/
|
20
20
|
@default_options = options
|
21
|
-
@ring = HashRing.new
|
21
|
+
@ring = HashRing.new
|
22
|
+
node_configs.each { |node_config| add_node(node_config) }
|
22
23
|
@subscribed_node = nil
|
23
24
|
end
|
24
25
|
|
@@ -30,8 +31,10 @@ class Redis
|
|
30
31
|
@ring.nodes
|
31
32
|
end
|
32
33
|
|
33
|
-
def add_node(
|
34
|
-
|
34
|
+
def add_node(options)
|
35
|
+
options = { :url => options } if options.is_a?(String)
|
36
|
+
options = @default_options.merge(options)
|
37
|
+
@ring.add_node Redis.new( options )
|
35
38
|
end
|
36
39
|
|
37
40
|
# Change the selected database for the current connection.
|
data/lib/redis/pipeline.rb
CHANGED
@@ -68,14 +68,19 @@ class Redis
|
|
68
68
|
|
69
69
|
class Multi < self
|
70
70
|
def finish(replies)
|
71
|
-
|
71
|
+
exec = replies.last
|
72
72
|
|
73
|
-
if
|
73
|
+
return if exec.nil? # The transaction failed because of WATCH.
|
74
|
+
|
75
|
+
# EXEC command failed.
|
76
|
+
raise exec if exec.is_a?(CommandError)
|
77
|
+
|
78
|
+
if exec.size < futures.size - 2
|
74
79
|
# Some command wasn't recognized by Redis.
|
75
|
-
raise replies.detect { |r| r.
|
80
|
+
raise replies.detect { |r| r.is_a?(CommandError) }
|
76
81
|
end
|
77
82
|
|
78
|
-
super(
|
83
|
+
super(exec) do |reply|
|
79
84
|
# Because an EXEC returns nested replies, hiredis won't be able to
|
80
85
|
# convert an error reply to a CommandError instance itself. This is
|
81
86
|
# specific to MULTI/EXEC, so we solve this here.
|
data/lib/redis/subscribe.rb
CHANGED
@@ -17,11 +17,11 @@ class Redis
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def unsubscribe(*channels)
|
20
|
-
call
|
20
|
+
call([:unsubscribe, *channels])
|
21
21
|
end
|
22
22
|
|
23
23
|
def punsubscribe(*channels)
|
24
|
-
call
|
24
|
+
call([:punsubscribe, *channels])
|
25
25
|
end
|
26
26
|
|
27
27
|
protected
|
data/lib/redis/version.rb
CHANGED
@@ -12,4 +12,30 @@ class TestDistributedInternals < Test::Unit::TestCase
|
|
12
12
|
|
13
13
|
assert_equal "#<Redis client v#{Redis::VERSION} for #{redis.nodes.map(&:id).join(', ')}>", redis.inspect
|
14
14
|
end
|
15
|
+
|
16
|
+
def test_default_as_urls
|
17
|
+
nodes = ["redis://localhost:#{PORT}/15", *NODES]
|
18
|
+
redis = Redis::Distributed.new nodes
|
19
|
+
assert_equal ["redis://localhost:#{PORT}/15", *NODES], redis.nodes.map { |node| node.client.id}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_default_as_config_hashes
|
23
|
+
nodes = [OPTIONS.merge(:host => 'localhost'), OPTIONS.merge(:host => 'localhost', :port => PORT.next)]
|
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 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_as_mix_and_match
|
29
|
+
nodes = ["redis://localhost:7389/15", OPTIONS.merge(:host => 'localhost'), OPTIONS.merge(:host => 'localhost', :port => PORT.next)]
|
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 }
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_override_id
|
35
|
+
nodes = [OPTIONS.merge(:host => 'localhost', :id => "test"), OPTIONS.merge( :host => 'localhost', :port => PORT.next, :id => "test1")]
|
36
|
+
redis = Redis::Distributed.new nodes
|
37
|
+
assert_equal redis.nodes.first.client.id, "test"
|
38
|
+
assert_equal redis.nodes.last.client.id, "test1"
|
39
|
+
assert_equal "#<Redis client v#{Redis::VERSION} for #{redis.nodes.map(&:id).join(', ')}>", redis.inspect
|
40
|
+
end
|
15
41
|
end
|
data/test/internals_test.rb
CHANGED
@@ -98,6 +98,24 @@ class TestInternals < Test::Unit::TestCase
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
driver(:ruby) do
|
102
|
+
def test_tcp_keepalive
|
103
|
+
keepalive = {:time => 20, :intvl => 10, :probes => 5}
|
104
|
+
|
105
|
+
redis = Redis.new(OPTIONS.merge(:tcp_keepalive => keepalive))
|
106
|
+
redis.ping
|
107
|
+
|
108
|
+
connection = redis.client.connection
|
109
|
+
actual_keepalive = connection.get_tcp_keepalive
|
110
|
+
|
111
|
+
[:time, :intvl, :probes].each do |key|
|
112
|
+
if actual_keepalive.has_key?(key)
|
113
|
+
assert_equal actual_keepalive[key], keepalive[key]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
101
119
|
def test_time
|
102
120
|
return if version < "2.5.4"
|
103
121
|
|
data/test/lint/sorted_sets.rb
CHANGED
@@ -2,6 +2,8 @@ module Lint
|
|
2
2
|
|
3
3
|
module SortedSets
|
4
4
|
|
5
|
+
Infinity = 1.0/0.0
|
6
|
+
|
5
7
|
def test_zadd
|
6
8
|
assert_equal 0, r.zcard("foo")
|
7
9
|
assert_equal true, r.zadd("foo", 1, "s1")
|
@@ -61,6 +63,12 @@ module Lint
|
|
61
63
|
|
62
64
|
rv = r.zincrby "foo", 10, "s1"
|
63
65
|
assert_equal 11.0, rv
|
66
|
+
|
67
|
+
rv = r.zincrby "bar", "-inf", "s1"
|
68
|
+
assert_equal(-Infinity, rv)
|
69
|
+
|
70
|
+
rv = r.zincrby "bar", "+inf", "s2"
|
71
|
+
assert_equal(+Infinity, rv)
|
64
72
|
end
|
65
73
|
|
66
74
|
def test_zrank
|
@@ -87,6 +95,11 @@ module Lint
|
|
87
95
|
assert_equal ["s1", "s2"], r.zrange("foo", 0, 1)
|
88
96
|
assert_equal [["s1", 1.0], ["s2", 2.0]], r.zrange("foo", 0, 1, :with_scores => true)
|
89
97
|
assert_equal [["s1", 1.0], ["s2", 2.0]], r.zrange("foo", 0, 1, :withscores => true)
|
98
|
+
|
99
|
+
r.zadd "bar", "-inf", "s1"
|
100
|
+
r.zadd "bar", "+inf", "s2"
|
101
|
+
assert_equal [["s1", -Infinity], ["s2", +Infinity]], r.zrange("bar", 0, 1, :with_scores => true)
|
102
|
+
assert_equal [["s1", -Infinity], ["s2", +Infinity]], r.zrange("bar", 0, 1, :withscores => true)
|
90
103
|
end
|
91
104
|
|
92
105
|
def test_zrevrange
|
@@ -97,6 +110,11 @@ module Lint
|
|
97
110
|
assert_equal ["s3", "s2"], r.zrevrange("foo", 0, 1)
|
98
111
|
assert_equal [["s3", 3.0], ["s2", 2.0]], r.zrevrange("foo", 0, 1, :with_scores => true)
|
99
112
|
assert_equal [["s3", 3.0], ["s2", 2.0]], r.zrevrange("foo", 0, 1, :withscores => true)
|
113
|
+
|
114
|
+
r.zadd "bar", "-inf", "s1"
|
115
|
+
r.zadd "bar", "+inf", "s2"
|
116
|
+
assert_equal [["s2", +Infinity], ["s1", -Infinity]], r.zrevrange("bar", 0, 1, :with_scores => true)
|
117
|
+
assert_equal [["s2", +Infinity], ["s1", -Infinity]], r.zrevrange("bar", 0, 1, :withscores => true)
|
100
118
|
end
|
101
119
|
|
102
120
|
def test_zrangebyscore
|
@@ -147,6 +165,13 @@ module Lint
|
|
147
165
|
assert_equal [["s3", 3.0]], r.zrangebyscore("foo", 2, 4, :limit => [1, 1], :with_scores => true)
|
148
166
|
assert_equal [["s2", 2.0]], r.zrangebyscore("foo", 2, 4, :limit => [0, 1], :withscores => true)
|
149
167
|
assert_equal [["s3", 3.0]], r.zrangebyscore("foo", 2, 4, :limit => [1, 1], :withscores => true)
|
168
|
+
|
169
|
+
r.zadd "bar", "-inf", "s1"
|
170
|
+
r.zadd "bar", "+inf", "s2"
|
171
|
+
assert_equal [["s1", -Infinity]], r.zrangebyscore("bar", -Infinity, +Infinity, :limit => [0, 1], :with_scores => true)
|
172
|
+
assert_equal [["s2", +Infinity]], r.zrangebyscore("bar", -Infinity, +Infinity, :limit => [1, 1], :with_scores => true)
|
173
|
+
assert_equal [["s1", -Infinity]], r.zrangebyscore("bar", -Infinity, +Infinity, :limit => [0, 1], :withscores => true)
|
174
|
+
assert_equal [["s2", +Infinity]], r.zrangebyscore("bar", -Infinity, +Infinity, :limit => [1, 1], :withscores => true)
|
150
175
|
end
|
151
176
|
|
152
177
|
def test_zrevrangebyscore_with_withscores
|
@@ -159,6 +184,13 @@ module Lint
|
|
159
184
|
assert_equal [["s3", 3.0]], r.zrevrangebyscore("foo", 4, 2, :limit => [1, 1], :with_scores => true)
|
160
185
|
assert_equal [["s4", 4.0]], r.zrevrangebyscore("foo", 4, 2, :limit => [0, 1], :withscores => true)
|
161
186
|
assert_equal [["s3", 3.0]], r.zrevrangebyscore("foo", 4, 2, :limit => [1, 1], :withscores => true)
|
187
|
+
|
188
|
+
r.zadd "bar", "-inf", "s1"
|
189
|
+
r.zadd "bar", "+inf", "s2"
|
190
|
+
assert_equal [["s2", +Infinity]], r.zrevrangebyscore("bar", +Infinity, -Infinity, :limit => [0, 1], :with_scores => true)
|
191
|
+
assert_equal [["s1", -Infinity]], r.zrevrangebyscore("bar", +Infinity, -Infinity, :limit => [1, 1], :with_scores => true)
|
192
|
+
assert_equal [["s2", +Infinity]], r.zrevrangebyscore("bar", +Infinity, -Infinity, :limit => [0, 1], :withscores => true)
|
193
|
+
assert_equal [["s1", -Infinity]], r.zrevrangebyscore("bar", +Infinity, -Infinity, :limit => [1, 1], :withscores => true)
|
162
194
|
end
|
163
195
|
|
164
196
|
def test_zcard
|
@@ -176,6 +208,11 @@ module Lint
|
|
176
208
|
|
177
209
|
assert_equal nil, r.zscore("foo", "s2")
|
178
210
|
assert_equal nil, r.zscore("bar", "s1")
|
211
|
+
|
212
|
+
r.zadd "bar", "-inf", "s1"
|
213
|
+
r.zadd "bar", "+inf", "s2"
|
214
|
+
assert_equal(-Infinity, r.zscore("bar", "s1"))
|
215
|
+
assert_equal(+Infinity, r.zscore("bar", "s2"))
|
179
216
|
end
|
180
217
|
|
181
218
|
def test_zremrangebyrank
|
data/test/lint/value_types.rb
CHANGED
@@ -32,30 +32,30 @@ module Lint
|
|
32
32
|
|
33
33
|
def test_expire
|
34
34
|
r.set("foo", "s1")
|
35
|
-
assert r.expire("foo",
|
36
|
-
assert_in_range 0..
|
35
|
+
assert r.expire("foo", 2)
|
36
|
+
assert_in_range 0..2, r.ttl("foo")
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_pexpire
|
40
40
|
return if version < "2.5.4"
|
41
41
|
|
42
42
|
r.set("foo", "s1")
|
43
|
-
assert r.pexpire("foo",
|
44
|
-
assert_in_range 0..
|
43
|
+
assert r.pexpire("foo", 2000)
|
44
|
+
assert_in_range 0..2, r.ttl("foo")
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_expireat
|
48
48
|
r.set("foo", "s1")
|
49
|
-
assert r.expireat("foo", (Time.now +
|
50
|
-
assert_in_range 0..
|
49
|
+
assert r.expireat("foo", (Time.now + 2).to_i)
|
50
|
+
assert_in_range 0..2, r.ttl("foo")
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_pexpireat
|
54
54
|
return if version < "2.5.4"
|
55
55
|
|
56
56
|
r.set("foo", "s1")
|
57
|
-
assert r.pexpireat("foo", (Time.now +
|
58
|
-
assert_in_range 0..
|
57
|
+
assert r.pexpireat("foo", (Time.now + 2).to_i * 1_000)
|
58
|
+
assert_in_range 0..2, r.ttl("foo")
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_persist
|
@@ -68,16 +68,16 @@ module Lint
|
|
68
68
|
|
69
69
|
def test_ttl
|
70
70
|
r.set("foo", "s1")
|
71
|
-
r.expire("foo",
|
72
|
-
assert_in_range 0..
|
71
|
+
r.expire("foo", 2)
|
72
|
+
assert_in_range 0..2, r.ttl("foo")
|
73
73
|
end
|
74
74
|
|
75
75
|
def test_pttl
|
76
76
|
return if version < "2.5.4"
|
77
77
|
|
78
78
|
r.set("foo", "s1")
|
79
|
-
r.expire("foo",
|
80
|
-
assert_in_range 1..
|
79
|
+
r.expire("foo", 2)
|
80
|
+
assert_in_range 1..2000, r.pttl("foo")
|
81
81
|
end
|
82
82
|
|
83
83
|
def test_move
|