redis 3.0.0.rc1 → 3.0.0.rc2
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/.travis.yml +50 -0
- data/.travis/Gemfile +11 -0
- data/CHANGELOG.md +47 -19
- data/README.md +160 -149
- data/Rakefile +15 -50
- data/examples/pubsub.rb +1 -1
- data/examples/unicorn/config.ru +1 -1
- data/examples/unicorn/unicorn.rb +1 -1
- data/lib/redis.rb +790 -390
- data/lib/redis/client.rb +137 -49
- data/lib/redis/connection/hiredis.rb +26 -15
- data/lib/redis/connection/ruby.rb +170 -53
- data/lib/redis/connection/synchrony.rb +23 -35
- data/lib/redis/distributed.rb +92 -32
- data/lib/redis/errors.rb +4 -2
- data/lib/redis/pipeline.rb +17 -6
- data/lib/redis/version.rb +1 -1
- data/redis.gemspec +4 -6
- data/test/blocking_commands_test.rb +42 -0
- data/test/command_map_test.rb +18 -17
- data/test/commands_on_hashes_test.rb +13 -12
- data/test/commands_on_lists_test.rb +35 -45
- data/test/commands_on_sets_test.rb +55 -54
- data/test/commands_on_sorted_sets_test.rb +106 -105
- data/test/commands_on_strings_test.rb +64 -55
- data/test/commands_on_value_types_test.rb +66 -54
- data/test/connection_handling_test.rb +136 -151
- data/test/distributed_blocking_commands_test.rb +33 -40
- data/test/distributed_commands_on_hashes_test.rb +6 -7
- data/test/distributed_commands_on_lists_test.rb +13 -14
- data/test/distributed_commands_on_sets_test.rb +57 -58
- data/test/distributed_commands_on_sorted_sets_test.rb +11 -12
- data/test/distributed_commands_on_strings_test.rb +31 -32
- data/test/distributed_commands_on_value_types_test.rb +61 -46
- data/test/distributed_commands_requiring_clustering_test.rb +108 -108
- data/test/distributed_connection_handling_test.rb +14 -15
- data/test/distributed_internals_test.rb +7 -19
- data/test/distributed_key_tags_test.rb +36 -36
- data/test/distributed_persistence_control_commands_test.rb +17 -14
- data/test/distributed_publish_subscribe_test.rb +61 -69
- data/test/distributed_remote_server_control_commands_test.rb +39 -28
- data/test/distributed_sorting_test.rb +12 -13
- data/test/distributed_test.rb +40 -41
- data/test/distributed_transactions_test.rb +20 -21
- data/test/encoding_test.rb +12 -9
- data/test/error_replies_test.rb +42 -36
- data/test/helper.rb +118 -85
- data/test/helper_test.rb +20 -6
- data/test/internals_test.rb +167 -103
- data/test/lint/blocking_commands.rb +124 -0
- data/test/lint/hashes.rb +115 -93
- data/test/lint/lists.rb +86 -80
- data/test/lint/sets.rb +68 -62
- data/test/lint/sorted_sets.rb +200 -195
- data/test/lint/strings.rb +112 -94
- data/test/lint/value_types.rb +76 -55
- data/test/persistence_control_commands_test.rb +17 -12
- data/test/pipelining_commands_test.rb +135 -126
- data/test/publish_subscribe_test.rb +105 -110
- data/test/remote_server_control_commands_test.rb +74 -58
- data/test/sorting_test.rb +31 -29
- data/test/support/connection/hiredis.rb +1 -0
- data/test/support/connection/ruby.rb +1 -0
- data/test/support/connection/synchrony.rb +17 -0
- data/test/{redis_mock.rb → support/redis_mock.rb} +24 -21
- data/test/support/wire/synchrony.rb +24 -0
- data/test/support/wire/thread.rb +5 -0
- data/test/synchrony_driver.rb +9 -9
- data/test/test.conf +1 -1
- data/test/thread_safety_test.rb +21 -19
- data/test/transactions_test.rb +189 -118
- data/test/unknown_commands_test.rb +9 -8
- data/test/url_param_test.rb +46 -41
- metadata +28 -43
- data/TODO.md +0 -4
- data/benchmarking/thread_safety.rb +0 -38
- data/test/lint/internals.rb +0 -36
@@ -1,158 +1,153 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require
|
3
|
+
require "helper"
|
4
4
|
|
5
|
-
|
6
|
-
init Redis.new(OPTIONS)
|
7
|
-
end
|
5
|
+
class TestPublishSubscribe < Test::Unit::TestCase
|
8
6
|
|
9
|
-
|
10
|
-
listening = false
|
7
|
+
include Helper::Client
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@subscribed = true
|
16
|
-
@t1 = total
|
17
|
-
end
|
9
|
+
def test_subscribe_and_unsubscribe
|
10
|
+
@subscribed = false
|
11
|
+
@unsubscribed = false
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@
|
13
|
+
wire = Wire.new do
|
14
|
+
r.subscribe("foo") do |on|
|
15
|
+
on.subscribe do |channel, total|
|
16
|
+
@subscribed = true
|
17
|
+
@t1 = total
|
23
18
|
end
|
24
|
-
end
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
on.message do |channel, message|
|
21
|
+
if message == "s1"
|
22
|
+
r.unsubscribe
|
23
|
+
@message = message
|
24
|
+
end
|
25
|
+
end
|
30
26
|
|
31
|
-
|
27
|
+
on.unsubscribe do |channel, total|
|
28
|
+
@unsubscribed = true
|
29
|
+
@t2 = total
|
30
|
+
end
|
31
|
+
end
|
32
32
|
end
|
33
|
-
end
|
34
33
|
|
35
|
-
|
34
|
+
# Wait until the subscription is active before publishing
|
35
|
+
Wire.pass while !@subscribed
|
36
36
|
|
37
|
-
|
37
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
38
38
|
|
39
|
-
|
39
|
+
wire.join
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
41
|
+
assert @subscribed
|
42
|
+
assert_equal 1, @t1
|
43
|
+
assert @unsubscribed
|
44
|
+
assert_equal 0, @t2
|
45
|
+
assert_equal "s1", @message
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
def test_psubscribe_and_punsubscribe
|
49
|
+
@subscribed = false
|
50
|
+
@unsubscribed = false
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
wire = Wire.new do
|
53
|
+
r.psubscribe("f*") do |on|
|
54
|
+
on.psubscribe do |pattern, total|
|
55
|
+
@subscribed = true
|
56
|
+
@t1 = total
|
57
|
+
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
on.pmessage do |pattern, channel, message|
|
60
|
+
if message == "s1"
|
61
|
+
r.punsubscribe
|
62
|
+
@message = message
|
63
|
+
end
|
62
64
|
end
|
63
|
-
end
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
on.punsubscribe do |pattern, total|
|
67
|
+
@unsubscribed = true
|
68
|
+
@t2 = total
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
+
listening = true
|
72
|
+
end
|
71
73
|
end
|
72
|
-
end
|
73
74
|
|
74
|
-
|
75
|
+
# Wait until the subscription is active before publishing
|
76
|
+
Wire.pass while !@subscribed
|
75
77
|
|
76
|
-
|
78
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
assert @subscribed
|
81
|
-
assert 1 == @t1
|
82
|
-
assert @unsubscribed
|
83
|
-
assert 0 == @t2
|
84
|
-
assert "s1" == @message
|
85
|
-
end
|
80
|
+
wire.join
|
86
81
|
|
87
|
-
|
88
|
-
|
82
|
+
assert @subscribed
|
83
|
+
assert_equal 1, @t1
|
84
|
+
assert @unsubscribed
|
85
|
+
assert_equal 0, @t2
|
86
|
+
assert_equal "s1", @message
|
87
|
+
end
|
89
88
|
|
90
|
-
|
89
|
+
def test_subscribe_within_subscribe
|
90
|
+
@channels = []
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
wire = Wire.new do
|
93
|
+
r.subscribe("foo") do |on|
|
94
|
+
on.subscribe do |channel, total|
|
95
|
+
@channels << channel
|
96
96
|
|
97
|
-
|
98
|
-
|
97
|
+
r.subscribe("bar") if channel == "foo"
|
98
|
+
r.unsubscribe if channel == "bar"
|
99
|
+
end
|
99
100
|
end
|
100
|
-
|
101
|
-
listening = true
|
102
101
|
end
|
103
|
-
end
|
104
|
-
|
105
|
-
Wire.pass while !listening
|
106
102
|
|
107
|
-
|
103
|
+
wire.join
|
108
104
|
|
109
|
-
|
110
|
-
|
111
|
-
assert ["foo", "bar"] == @channels
|
112
|
-
end
|
105
|
+
assert_equal ["foo", "bar"], @channels
|
106
|
+
end
|
113
107
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
108
|
+
def test_other_commands_within_a_subscribe
|
109
|
+
assert_raise Redis::CommandError do
|
110
|
+
r.subscribe("foo") do |on|
|
111
|
+
on.subscribe do |channel, total|
|
112
|
+
r.set("bar", "s2")
|
113
|
+
end
|
119
114
|
end
|
120
115
|
end
|
121
116
|
end
|
122
|
-
end
|
123
117
|
|
124
|
-
|
125
|
-
|
126
|
-
|
118
|
+
def test_subscribe_without_a_block
|
119
|
+
assert_raise LocalJumpError do
|
120
|
+
r.subscribe("foo")
|
121
|
+
end
|
127
122
|
end
|
128
|
-
end
|
129
123
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
124
|
+
def test_unsubscribe_without_a_subscribe
|
125
|
+
assert_raise RuntimeError do
|
126
|
+
r.unsubscribe
|
127
|
+
end
|
134
128
|
|
135
|
-
|
136
|
-
|
129
|
+
assert_raise RuntimeError do
|
130
|
+
r.punsubscribe
|
131
|
+
end
|
137
132
|
end
|
138
|
-
end
|
139
133
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
134
|
+
def test_subscribe_past_a_timeout
|
135
|
+
# For some reason, a thread here doesn't reproduce the issue.
|
136
|
+
sleep = %{sleep #{OPTIONS[:timeout] * 2}}
|
137
|
+
publish = %{echo "publish foo bar\r\n" | nc localhost #{OPTIONS[:port]}}
|
138
|
+
cmd = [sleep, publish].join("; ")
|
145
139
|
|
146
|
-
|
147
|
-
|
140
|
+
IO.popen(cmd, "r+") do |pipe|
|
141
|
+
received = false
|
148
142
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
143
|
+
r.subscribe "foo" do |on|
|
144
|
+
on.message do |channel, message|
|
145
|
+
received = true
|
146
|
+
r.unsubscribe
|
147
|
+
end
|
153
148
|
end
|
154
|
-
end
|
155
149
|
|
156
|
-
|
150
|
+
assert received
|
151
|
+
end
|
157
152
|
end
|
158
153
|
end
|
@@ -1,88 +1,104 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require
|
4
|
-
require File.expand_path("./redis_mock", File.dirname(__FILE__))
|
3
|
+
require "helper"
|
5
4
|
|
6
|
-
|
5
|
+
class TestRemoteServerControlCommands < Test::Unit::TestCase
|
7
6
|
|
8
|
-
|
9
|
-
init Redis.new(OPTIONS)
|
10
|
-
end
|
7
|
+
include Helper::Client
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def test_info
|
10
|
+
%w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
|
11
|
+
assert r.info.keys.include?(x)
|
12
|
+
end
|
15
13
|
end
|
16
|
-
end
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
next if version(r) < 209000
|
15
|
+
def test_info_commandstats
|
16
|
+
return if version < "2.9.0"
|
21
17
|
|
22
|
-
|
23
|
-
|
18
|
+
r.config(:resetstat)
|
19
|
+
r.ping
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
21
|
+
result = r.info(:commandstats)
|
22
|
+
assert_equal "1", result["ping"]["calls"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_monitor_redis_lt_2_5_0
|
26
|
+
return unless version < "2.5.0"
|
28
27
|
|
29
|
-
|
30
|
-
log = []
|
28
|
+
log = []
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
wire = Wire.new do
|
31
|
+
Redis.new(OPTIONS).monitor do |line|
|
32
|
+
log << line
|
33
|
+
break if log.size == 3
|
34
|
+
end
|
36
35
|
end
|
36
|
+
|
37
|
+
Wire.pass while log.empty? # Faster than sleep
|
38
|
+
|
39
|
+
r.set "foo", "s1"
|
40
|
+
|
41
|
+
wire.join
|
42
|
+
|
43
|
+
assert log[-1][%q{(db 15) "set" "foo" "s1"}]
|
37
44
|
end
|
38
45
|
|
39
|
-
|
46
|
+
def test_monitor_redis_gte_2_5_0
|
47
|
+
return unless version >= "2.5.0"
|
40
48
|
|
41
|
-
|
49
|
+
log = []
|
42
50
|
|
43
|
-
|
51
|
+
wire = Wire.new do
|
52
|
+
Redis.new(OPTIONS).monitor do |line|
|
53
|
+
log << line
|
54
|
+
break if line =~ /set/
|
55
|
+
end
|
56
|
+
end
|
44
57
|
|
45
|
-
|
46
|
-
end
|
58
|
+
Wire.pass while log.empty? # Faster than sleep
|
47
59
|
|
48
|
-
|
49
|
-
result = r.monitor do |line|
|
50
|
-
break line
|
51
|
-
end
|
60
|
+
r.set "foo", "s1"
|
52
61
|
|
53
|
-
|
54
|
-
end
|
62
|
+
wire.join
|
55
63
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
64
|
+
assert log[-1] =~ /\b15\b.* "set" "foo" "s1"/
|
65
|
+
end
|
59
66
|
|
60
|
-
|
61
|
-
|
67
|
+
def test_monitor_returns_value_for_break
|
68
|
+
result = r.monitor do |line|
|
69
|
+
break line
|
70
|
+
end
|
62
71
|
|
63
|
-
|
64
|
-
end
|
72
|
+
assert_equal result, "OK"
|
73
|
+
end
|
65
74
|
|
66
|
-
|
67
|
-
|
75
|
+
def test_echo
|
76
|
+
assert_equal "foo bar baz\n", r.echo("foo bar baz\n")
|
77
|
+
end
|
68
78
|
|
69
|
-
|
70
|
-
|
71
|
-
assert r.object(:idletime, "list").kind_of?(Fixnum)
|
72
|
-
end
|
79
|
+
def test_debug
|
80
|
+
r.set "foo", "s1"
|
73
81
|
|
74
|
-
|
75
|
-
|
82
|
+
assert r.debug(:object, "foo").kind_of?(String)
|
83
|
+
end
|
76
84
|
|
77
|
-
|
78
|
-
|
85
|
+
def test_object
|
86
|
+
r.lpush "list", "value"
|
79
87
|
|
80
|
-
|
88
|
+
assert_equal r.object(:refcount, "list"), 1
|
89
|
+
assert_equal r.object(:encoding, "list"), "ziplist"
|
90
|
+
assert r.object(:idletime, "list").kind_of?(Fixnum)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_sync
|
94
|
+
redis_mock(:sync => lambda { "+OK" }) do |redis|
|
95
|
+
assert_equal "OK", redis.sync
|
96
|
+
end
|
81
97
|
end
|
82
|
-
end
|
83
98
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
99
|
+
def test_slowlog
|
100
|
+
r.slowlog(:reset)
|
101
|
+
result = r.slowlog(:len)
|
102
|
+
assert_equal result, 0
|
103
|
+
end
|
88
104
|
end
|
data/test/sorting_test.rb
CHANGED
@@ -1,43 +1,45 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require
|
3
|
+
require "helper"
|
4
4
|
|
5
|
-
|
6
|
-
init Redis.new(OPTIONS)
|
7
|
-
end
|
5
|
+
class TestSorting < Test::Unit::TestCase
|
8
6
|
|
9
|
-
|
10
|
-
r.set("foo:1", "s1")
|
11
|
-
r.set("foo:2", "s2")
|
7
|
+
include Helper::Client
|
12
8
|
|
13
|
-
|
14
|
-
|
9
|
+
def test_sort
|
10
|
+
r.set("foo:1", "s1")
|
11
|
+
r.set("foo:2", "s2")
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
13
|
+
r.rpush("bar", "1")
|
14
|
+
r.rpush("bar", "2")
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
assert_equal ["s1"], r.sort("bar", :get => "foo:*", :limit => [0, 1])
|
17
|
+
assert_equal ["s2"], r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
|
18
|
+
end
|
23
19
|
|
24
|
-
|
25
|
-
|
20
|
+
def test_sort_with_an_array_of_gets
|
21
|
+
r.set("foo:1:a", "s1a")
|
22
|
+
r.set("foo:1:b", "s1b")
|
26
23
|
|
27
|
-
|
28
|
-
|
24
|
+
r.set("foo:2:a", "s2a")
|
25
|
+
r.set("foo:2:b", "s2b")
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
r.rpush("bar", "1")
|
28
|
+
r.rpush("bar", "2")
|
29
|
+
|
30
|
+
assert_equal [["s1a", "s1b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
|
31
|
+
assert_equal [["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
|
32
|
+
assert_equal [["s1a", "s1b"], ["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"])
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def test_sort_with_store
|
36
|
+
r.set("foo:1", "s1")
|
37
|
+
r.set("foo:2", "s2")
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
r.rpush("bar", "1")
|
40
|
+
r.rpush("bar", "2")
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
r.sort("bar", :get => "foo:*", :store => "baz")
|
43
|
+
assert_equal ["s1", "s2"], r.lrange("baz", 0, -1)
|
44
|
+
end
|
43
45
|
end
|