redis 3.0.0.rc2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.order +169 -0
- data/CHANGELOG.md +79 -9
- data/README.md +7 -0
- data/Rakefile +167 -0
- data/lib/redis.rb +1265 -1148
- data/lib/redis/client.rb +11 -18
- data/lib/redis/distributed.rb +337 -280
- data/lib/redis/pipeline.rb +12 -4
- data/lib/redis/version.rb +1 -1
- data/redis.gemspec +1 -1
- data/test/commands_on_lists_test.rb +0 -30
- data/test/commands_on_strings_test.rb +0 -6
- data/test/distributed_scripting_test.rb +102 -0
- data/test/internals_test.rb +33 -35
- data/test/lint/lists.rb +42 -12
- data/test/lint/strings.rb +6 -0
- data/test/lint/value_types.rb +10 -6
- data/test/scripting_test.rb +78 -0
- metadata +12 -8
data/lib/redis/pipeline.rb
CHANGED
@@ -9,13 +9,17 @@ class Redis
|
|
9
9
|
attr :futures
|
10
10
|
|
11
11
|
def initialize
|
12
|
-
@
|
12
|
+
@with_reconnect = true
|
13
13
|
@shutdown = false
|
14
14
|
@futures = []
|
15
15
|
end
|
16
16
|
|
17
|
+
def with_reconnect?
|
18
|
+
@with_reconnect
|
19
|
+
end
|
20
|
+
|
17
21
|
def without_reconnect?
|
18
|
-
|
22
|
+
!@with_reconnect
|
19
23
|
end
|
20
24
|
|
21
25
|
def shutdown?
|
@@ -41,11 +45,15 @@ class Redis
|
|
41
45
|
@futures.map { |f| f._command }
|
42
46
|
end
|
43
47
|
|
44
|
-
def
|
45
|
-
@
|
48
|
+
def with_reconnect(val=true)
|
49
|
+
@with_reconnect = false unless val
|
46
50
|
yield
|
47
51
|
end
|
48
52
|
|
53
|
+
def without_reconnect(&blk)
|
54
|
+
with_reconnect(false, &blk)
|
55
|
+
end
|
56
|
+
|
49
57
|
def finish(replies, &blk)
|
50
58
|
if blk
|
51
59
|
futures.each_with_index.map do |future, i|
|
data/lib/redis/version.rb
CHANGED
data/redis.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
|
12
12
|
s.homepage = "https://github.com/redis/redis-rb"
|
13
13
|
|
14
|
-
s.summary = "A Ruby client library for
|
14
|
+
s.summary = "A Ruby client library for Redis"
|
15
15
|
|
16
16
|
s.description = <<-EOS
|
17
17
|
A Ruby client that tries to match Redis' API one-to-one, while still
|
@@ -8,36 +8,6 @@ class TestCommandsOnLists < Test::Unit::TestCase
|
|
8
8
|
include Helper::Client
|
9
9
|
include Lint::Lists
|
10
10
|
|
11
|
-
def test_rpushx
|
12
|
-
r.rpushx "foo", "s1"
|
13
|
-
r.rpush "foo", "s2"
|
14
|
-
r.rpushx "foo", "s3"
|
15
|
-
|
16
|
-
assert_equal 2, r.llen("foo")
|
17
|
-
assert_equal ["s2", "s3"], r.lrange("foo", 0, -1)
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_lpushx
|
21
|
-
r.lpushx "foo", "s1"
|
22
|
-
r.lpush "foo", "s2"
|
23
|
-
r.lpushx "foo", "s3"
|
24
|
-
|
25
|
-
assert_equal 2, r.llen("foo")
|
26
|
-
assert_equal ["s3", "s2"], r.lrange("foo", 0, -1)
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_linsert
|
30
|
-
r.rpush "foo", "s1"
|
31
|
-
r.rpush "foo", "s3"
|
32
|
-
r.linsert "foo", :before, "s3", "s2"
|
33
|
-
|
34
|
-
assert_equal ["s1", "s2", "s3"], r.lrange("foo", 0, -1)
|
35
|
-
|
36
|
-
assert_raise(Redis::CommandError) do
|
37
|
-
r.linsert "foo", :anywhere, "s3", "s2"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
11
|
def test_rpoplpush
|
42
12
|
r.rpush "foo", "s1"
|
43
13
|
r.rpush "foo", "s2"
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "helper"
|
4
|
+
|
5
|
+
class TestDistributedScripting < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Helper::Distributed
|
8
|
+
|
9
|
+
def to_sha(script)
|
10
|
+
r.script(:load, script).first
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_script_exists
|
14
|
+
return if version < "2.5.9" # 2.6-rc1
|
15
|
+
|
16
|
+
a = to_sha("return 1")
|
17
|
+
b = a.succ
|
18
|
+
|
19
|
+
assert_equal [true], r.script(:exists, a)
|
20
|
+
assert_equal [false], r.script(:exists, b)
|
21
|
+
assert_equal [[true]], r.script(:exists, [a])
|
22
|
+
assert_equal [[false]], r.script(:exists, [b])
|
23
|
+
assert_equal [[true, false]], r.script(:exists, [a, b])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_script_flush
|
27
|
+
return if version < "2.5.9" # 2.6-rc1
|
28
|
+
|
29
|
+
sha = to_sha("return 1")
|
30
|
+
assert r.script(:exists, sha).first
|
31
|
+
assert_equal ["OK"], r.script(:flush)
|
32
|
+
assert !r.script(:exists, sha).first
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_script_kill
|
36
|
+
return if version < "2.5.9" # 2.6-rc1
|
37
|
+
|
38
|
+
redis_mock(:script => lambda { |arg| "+#{arg.upcase}" }) do |redis|
|
39
|
+
assert_equal ["KILL"], redis.script(:kill)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_eval
|
44
|
+
return if version < "2.5.9" # 2.6-rc1
|
45
|
+
|
46
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
47
|
+
r.eval("return #KEYS")
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
51
|
+
r.eval("return KEYS", ["k1", "k2"])
|
52
|
+
end
|
53
|
+
|
54
|
+
assert_equal ["k1"], r.eval("return KEYS", ["k1"])
|
55
|
+
assert_equal ["a1", "a2"], r.eval("return ARGV", ["k1"], ["a1", "a2"])
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_eval_with_options_hash
|
59
|
+
return if version < "2.5.9" # 2.6-rc1
|
60
|
+
|
61
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
62
|
+
r.eval("return #KEYS", {})
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
66
|
+
r.eval("return KEYS", { :keys => ["k1", "k2"] })
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_equal ["k1"], r.eval("return KEYS", { :keys => ["k1"] })
|
70
|
+
assert_equal ["a1", "a2"], r.eval("return ARGV", { :keys => ["k1"], :argv => ["a1", "a2"] })
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_evalsha
|
74
|
+
return if version < "2.5.9" # 2.6-rc1
|
75
|
+
|
76
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
77
|
+
r.evalsha(to_sha("return #KEYS"))
|
78
|
+
end
|
79
|
+
|
80
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
81
|
+
r.evalsha(to_sha("return KEYS"), ["k1", "k2"])
|
82
|
+
end
|
83
|
+
|
84
|
+
assert_equal ["k1"], r.evalsha(to_sha("return KEYS"), ["k1"])
|
85
|
+
assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), ["k1"], ["a1", "a2"])
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_evalsha_with_options_hash
|
89
|
+
return if version < "2.5.9" # 2.6-rc1
|
90
|
+
|
91
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
92
|
+
r.evalsha(to_sha("return #KEYS"), {})
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_raises(Redis::Distributed::CannotDistribute) do
|
96
|
+
r.evalsha(to_sha("return KEYS"), { :keys => ["k1", "k2"] })
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal ["k1"], r.evalsha(to_sha("return KEYS"), { :keys => ["k1"] })
|
100
|
+
assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), { :keys => ["k1"], :argv => ["a1", "a2"] })
|
101
|
+
end
|
102
|
+
end
|
data/test/internals_test.rb
CHANGED
@@ -117,54 +117,59 @@ class TestInternals < Test::Unit::TestCase
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
def
|
120
|
+
def close_on_ping(seq)
|
121
121
|
$request = 0
|
122
122
|
|
123
123
|
command = lambda do
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
idx = $request
|
125
|
+
$request += 1
|
126
|
+
|
127
|
+
rv = "+%d" % idx
|
128
|
+
rv = nil if seq.include?(idx)
|
129
|
+
rv
|
128
130
|
end
|
129
131
|
|
130
132
|
redis_mock(:ping => command, :timeout => 0.1) do |redis|
|
131
|
-
|
133
|
+
yield(redis)
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
135
|
-
def
|
136
|
-
|
137
|
+
def test_retry_by_default
|
138
|
+
close_on_ping([0]) do |redis|
|
139
|
+
assert_equal "1", redis.ping
|
140
|
+
end
|
141
|
+
end
|
137
142
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
143
|
+
def test_retry_when_wrapped_in_with_reconnect_true
|
144
|
+
close_on_ping([0]) do |redis|
|
145
|
+
redis.with_reconnect(true) do
|
146
|
+
assert_equal "1", redis.ping
|
142
147
|
end
|
143
148
|
end
|
149
|
+
end
|
144
150
|
|
145
|
-
|
151
|
+
def test_dont_retry_when_wrapped_in_with_reconnect_false
|
152
|
+
close_on_ping([0]) do |redis|
|
146
153
|
assert_raise Redis::ConnectionError do
|
147
|
-
redis.
|
154
|
+
redis.with_reconnect(false) do
|
148
155
|
redis.ping
|
149
156
|
end
|
150
157
|
end
|
151
|
-
|
152
|
-
assert !redis.client.connected?
|
153
158
|
end
|
154
159
|
end
|
155
160
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
when 2; nil # Close on second command
|
163
|
-
else "+%d" % $request
|
161
|
+
def test_dont_retry_when_wrapped_in_without_reconnect
|
162
|
+
close_on_ping([0]) do |redis|
|
163
|
+
assert_raise Redis::ConnectionError do
|
164
|
+
redis.without_reconnect do
|
165
|
+
redis.ping
|
166
|
+
end
|
164
167
|
end
|
165
168
|
end
|
169
|
+
end
|
166
170
|
|
167
|
-
|
171
|
+
def test_retry_only_once_when_read_raises_econnreset
|
172
|
+
close_on_ping([0, 1]) do |redis|
|
168
173
|
assert_raise Redis::ConnectionError do
|
169
174
|
redis.ping
|
170
175
|
end
|
@@ -174,22 +179,15 @@ class TestInternals < Test::Unit::TestCase
|
|
174
179
|
end
|
175
180
|
|
176
181
|
def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
|
177
|
-
|
178
|
-
|
179
|
-
command = lambda do
|
180
|
-
case ($request += 1)
|
181
|
-
when 2; nil # Close on second command
|
182
|
-
else "+%d" % $request
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
redis_mock(:ping => command, :timeout => 0.1) do |redis|
|
182
|
+
close_on_ping([1]) do |redis|
|
187
183
|
assert_raise Redis::ConnectionError do
|
188
184
|
redis.pipelined do
|
189
185
|
redis.ping
|
190
186
|
redis.ping # Second #read times out
|
191
187
|
end
|
192
188
|
end
|
189
|
+
|
190
|
+
assert !redis.client.connected?
|
193
191
|
end
|
194
192
|
end
|
195
193
|
|
data/test/lint/lists.rb
CHANGED
@@ -2,6 +2,31 @@ module Lint
|
|
2
2
|
|
3
3
|
module Lists
|
4
4
|
|
5
|
+
def test_lpush
|
6
|
+
r.lpush "foo", "s1"
|
7
|
+
r.lpush "foo", "s2"
|
8
|
+
|
9
|
+
assert_equal 2, r.llen("foo")
|
10
|
+
assert_equal "s2", r.lpop("foo")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_variadic_lpush
|
14
|
+
return if version < "2.3.9" # 2.4-rc6
|
15
|
+
|
16
|
+
assert_equal 3, r.lpush("foo", ["s1", "s2", "s3"])
|
17
|
+
assert_equal 3, r.llen("foo")
|
18
|
+
assert_equal "s3", r.lpop("foo")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_lpushx
|
22
|
+
r.lpushx "foo", "s1"
|
23
|
+
r.lpush "foo", "s2"
|
24
|
+
r.lpushx "foo", "s3"
|
25
|
+
|
26
|
+
assert_equal 2, r.llen("foo")
|
27
|
+
assert_equal ["s3", "s2"], r.lrange("foo", 0, -1)
|
28
|
+
end
|
29
|
+
|
5
30
|
def test_rpush
|
6
31
|
r.rpush "foo", "s1"
|
7
32
|
r.rpush "foo", "s2"
|
@@ -18,20 +43,13 @@ module Lint
|
|
18
43
|
assert_equal "s3", r.rpop("foo")
|
19
44
|
end
|
20
45
|
|
21
|
-
def
|
22
|
-
r.
|
23
|
-
r.
|
46
|
+
def test_rpushx
|
47
|
+
r.rpushx "foo", "s1"
|
48
|
+
r.rpush "foo", "s2"
|
49
|
+
r.rpushx "foo", "s3"
|
24
50
|
|
25
51
|
assert_equal 2, r.llen("foo")
|
26
|
-
assert_equal "s2", r.
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_variadic_lpush
|
30
|
-
return if version < "2.3.9" # 2.4-rc6
|
31
|
-
|
32
|
-
assert_equal 3, r.lpush("foo", ["s1", "s2", "s3"])
|
33
|
-
assert_equal 3, r.llen("foo")
|
34
|
-
assert_equal "s3", r.lpop("foo")
|
52
|
+
assert_equal ["s2", "s3"], r.lrange("foo", 0, -1)
|
35
53
|
end
|
36
54
|
|
37
55
|
def test_llen
|
@@ -109,5 +127,17 @@ module Lint
|
|
109
127
|
assert_equal "s2", r.rpop("foo")
|
110
128
|
assert_equal 1, r.llen("foo")
|
111
129
|
end
|
130
|
+
|
131
|
+
def test_linsert
|
132
|
+
r.rpush "foo", "s1"
|
133
|
+
r.rpush "foo", "s3"
|
134
|
+
r.linsert "foo", :before, "s3", "s2"
|
135
|
+
|
136
|
+
assert_equal ["s1", "s2", "s3"], r.lrange("foo", 0, -1)
|
137
|
+
|
138
|
+
assert_raise(Redis::CommandError) do
|
139
|
+
r.linsert "foo", :anywhere, "s3", "s2"
|
140
|
+
end
|
141
|
+
end
|
112
142
|
end
|
113
143
|
end
|
data/test/lint/strings.rb
CHANGED
data/test/lint/value_types.rb
CHANGED
@@ -2,6 +2,10 @@ module Lint
|
|
2
2
|
|
3
3
|
module ValueTypes
|
4
4
|
|
5
|
+
def assert_in_range(range, value)
|
6
|
+
assert range.include?(value), "expected #{value} to be in #{range.inspect}"
|
7
|
+
end
|
8
|
+
|
5
9
|
def test_exists
|
6
10
|
assert_equal false, r.exists("foo")
|
7
11
|
|
@@ -29,7 +33,7 @@ module Lint
|
|
29
33
|
def test_expire
|
30
34
|
r.set("foo", "s1")
|
31
35
|
assert r.expire("foo", 1)
|
32
|
-
|
36
|
+
assert_in_range 0..1, r.ttl("foo")
|
33
37
|
end
|
34
38
|
|
35
39
|
def test_pexpire
|
@@ -37,13 +41,13 @@ module Lint
|
|
37
41
|
|
38
42
|
r.set("foo", "s1")
|
39
43
|
assert r.pexpire("foo", 1000)
|
40
|
-
|
44
|
+
assert_in_range 0..1, r.ttl("foo")
|
41
45
|
end
|
42
46
|
|
43
47
|
def test_expireat
|
44
48
|
r.set("foo", "s1")
|
45
49
|
assert r.expireat("foo", (Time.now + 1).to_i)
|
46
|
-
|
50
|
+
assert_in_range 0..1, r.ttl("foo")
|
47
51
|
end
|
48
52
|
|
49
53
|
def test_pexpireat
|
@@ -51,7 +55,7 @@ module Lint
|
|
51
55
|
|
52
56
|
r.set("foo", "s1")
|
53
57
|
assert r.pexpireat("foo", (Time.now + 1).to_i * 1_000)
|
54
|
-
|
58
|
+
assert_in_range 0..1, r.ttl("foo")
|
55
59
|
end
|
56
60
|
|
57
61
|
def test_persist
|
@@ -65,7 +69,7 @@ module Lint
|
|
65
69
|
def test_ttl
|
66
70
|
r.set("foo", "s1")
|
67
71
|
r.expire("foo", 1)
|
68
|
-
|
72
|
+
assert_in_range 0..1, r.ttl("foo")
|
69
73
|
end
|
70
74
|
|
71
75
|
def test_pttl
|
@@ -73,7 +77,7 @@ module Lint
|
|
73
77
|
|
74
78
|
r.set("foo", "s1")
|
75
79
|
r.expire("foo", 1)
|
76
|
-
|
80
|
+
assert_in_range 1..1000, r.pttl("foo")
|
77
81
|
end
|
78
82
|
|
79
83
|
def test_move
|