gorsuch-redis 3.0.0.rc1
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/.gitignore +10 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +113 -0
- data/LICENSE +20 -0
- data/README.md +214 -0
- data/Rakefile +260 -0
- data/TODO.md +4 -0
- data/benchmarking/logging.rb +62 -0
- data/benchmarking/pipeline.rb +51 -0
- data/benchmarking/speed.rb +21 -0
- data/benchmarking/suite.rb +24 -0
- data/benchmarking/thread_safety.rb +38 -0
- data/benchmarking/worker.rb +71 -0
- data/examples/basic.rb +15 -0
- data/examples/dist_redis.rb +43 -0
- data/examples/incr-decr.rb +17 -0
- data/examples/list.rb +26 -0
- data/examples/pubsub.rb +31 -0
- data/examples/sets.rb +36 -0
- data/examples/unicorn/config.ru +3 -0
- data/examples/unicorn/unicorn.rb +20 -0
- data/lib/redis/client.rb +303 -0
- data/lib/redis/connection/command_helper.rb +44 -0
- data/lib/redis/connection/hiredis.rb +52 -0
- data/lib/redis/connection/registry.rb +12 -0
- data/lib/redis/connection/ruby.rb +136 -0
- data/lib/redis/connection/synchrony.rb +131 -0
- data/lib/redis/connection.rb +9 -0
- data/lib/redis/distributed.rb +696 -0
- data/lib/redis/errors.rb +38 -0
- data/lib/redis/hash_ring.rb +131 -0
- data/lib/redis/pipeline.rb +106 -0
- data/lib/redis/subscribe.rb +79 -0
- data/lib/redis/version.rb +3 -0
- data/lib/redis.rb +1724 -0
- data/redis.gemspec +43 -0
- data/test/command_map_test.rb +29 -0
- data/test/commands_on_hashes_test.rb +20 -0
- data/test/commands_on_lists_test.rb +60 -0
- data/test/commands_on_sets_test.rb +76 -0
- data/test/commands_on_sorted_sets_test.rb +108 -0
- data/test/commands_on_strings_test.rb +80 -0
- data/test/commands_on_value_types_test.rb +87 -0
- data/test/connection_handling_test.rb +204 -0
- data/test/db/.gitignore +1 -0
- data/test/distributed_blocking_commands_test.rb +53 -0
- data/test/distributed_commands_on_hashes_test.rb +11 -0
- data/test/distributed_commands_on_lists_test.rb +23 -0
- data/test/distributed_commands_on_sets_test.rb +84 -0
- data/test/distributed_commands_on_sorted_sets_test.rb +19 -0
- data/test/distributed_commands_on_strings_test.rb +49 -0
- data/test/distributed_commands_on_value_types_test.rb +72 -0
- data/test/distributed_commands_requiring_clustering_test.rb +148 -0
- data/test/distributed_connection_handling_test.rb +24 -0
- data/test/distributed_internals_test.rb +27 -0
- data/test/distributed_key_tags_test.rb +52 -0
- data/test/distributed_persistence_control_commands_test.rb +23 -0
- data/test/distributed_publish_subscribe_test.rb +100 -0
- data/test/distributed_remote_server_control_commands_test.rb +42 -0
- data/test/distributed_sorting_test.rb +21 -0
- data/test/distributed_test.rb +59 -0
- data/test/distributed_transactions_test.rb +33 -0
- data/test/encoding_test.rb +15 -0
- data/test/error_replies_test.rb +53 -0
- data/test/helper.rb +155 -0
- data/test/helper_test.rb +8 -0
- data/test/internals_test.rb +152 -0
- data/test/lint/hashes.rb +140 -0
- data/test/lint/internals.rb +36 -0
- data/test/lint/lists.rb +107 -0
- data/test/lint/sets.rb +90 -0
- data/test/lint/sorted_sets.rb +196 -0
- data/test/lint/strings.rb +133 -0
- data/test/lint/value_types.rb +81 -0
- data/test/persistence_control_commands_test.rb +21 -0
- data/test/pipelining_commands_test.rb +186 -0
- data/test/publish_subscribe_test.rb +158 -0
- data/test/redis_mock.rb +89 -0
- data/test/remote_server_control_commands_test.rb +88 -0
- data/test/sorting_test.rb +43 -0
- data/test/synchrony_driver.rb +57 -0
- data/test/test.conf +9 -0
- data/test/thread_safety_test.rb +30 -0
- data/test/transactions_test.rb +173 -0
- data/test/unknown_commands_test.rb +13 -0
- data/test/url_param_test.rb +59 -0
- metadata +236 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path("../redis_mock", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
include RedisMock::Helper
|
4
|
+
|
5
|
+
test "SET and GET" do |r|
|
6
|
+
r.set("foo", "s1")
|
7
|
+
|
8
|
+
assert "s1" == r.get("foo")
|
9
|
+
end
|
10
|
+
|
11
|
+
test "SET and GET with brackets" do |r|
|
12
|
+
r["foo"] = "s1"
|
13
|
+
|
14
|
+
assert "s1" == r["foo"]
|
15
|
+
end
|
16
|
+
|
17
|
+
test "SET and GET with brackets and symbol" do |r|
|
18
|
+
r[:foo] = "s1"
|
19
|
+
|
20
|
+
assert "s1" == r[:foo]
|
21
|
+
end
|
22
|
+
|
23
|
+
test "SET and GET with newline characters" do |r|
|
24
|
+
r.set("foo", "1\n")
|
25
|
+
|
26
|
+
assert "1\n" == r.get("foo")
|
27
|
+
end
|
28
|
+
|
29
|
+
test "SET and GET with ASCII characters" do |r|
|
30
|
+
with_external_encoding("ASCII-8BIT") do
|
31
|
+
(0..255).each do |i|
|
32
|
+
str = "#{i.chr}---#{i.chr}"
|
33
|
+
r.set("foo", str)
|
34
|
+
|
35
|
+
assert str == r.get("foo")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end if defined?(Encoding)
|
39
|
+
|
40
|
+
test "SETEX" do
|
41
|
+
redis_mock(:setex => lambda { |*args| "+#{args.join(" ")}" }) do
|
42
|
+
r = Redis.new(OPTIONS.merge(:port => 6380))
|
43
|
+
|
44
|
+
assert_equal "foo 1 s1", r.setex("foo", 1, "s1")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
test "GETSET" do |r|
|
49
|
+
r.set("foo", "bar")
|
50
|
+
|
51
|
+
assert "bar" == r.getset("foo", "baz")
|
52
|
+
assert "baz" == r.get("foo")
|
53
|
+
end
|
54
|
+
|
55
|
+
test "SETNX" do |r|
|
56
|
+
r.set("foo", "s1")
|
57
|
+
|
58
|
+
assert "s1" == r.get("foo")
|
59
|
+
|
60
|
+
r.setnx("foo", "s2")
|
61
|
+
|
62
|
+
assert "s1" == r.get("foo")
|
63
|
+
end
|
64
|
+
|
65
|
+
test "INCR" do |r|
|
66
|
+
assert 1 == r.incr("foo")
|
67
|
+
assert 2 == r.incr("foo")
|
68
|
+
assert 3 == r.incr("foo")
|
69
|
+
end
|
70
|
+
|
71
|
+
test "INCRBY" do |r|
|
72
|
+
assert 1 == r.incrby("foo", 1)
|
73
|
+
assert 3 == r.incrby("foo", 2)
|
74
|
+
assert 6 == r.incrby("foo", 3)
|
75
|
+
end
|
76
|
+
|
77
|
+
test "DECR" do |r|
|
78
|
+
r.set("foo", 3)
|
79
|
+
|
80
|
+
assert 2 == r.decr("foo")
|
81
|
+
assert 1 == r.decr("foo")
|
82
|
+
assert 0 == r.decr("foo")
|
83
|
+
end
|
84
|
+
|
85
|
+
test "DECRBY" do |r|
|
86
|
+
r.set("foo", 6)
|
87
|
+
|
88
|
+
assert 3 == r.decrby("foo", 3)
|
89
|
+
assert 1 == r.decrby("foo", 2)
|
90
|
+
assert 0 == r.decrby("foo", 1)
|
91
|
+
end
|
92
|
+
|
93
|
+
test "APPEND" do |r|
|
94
|
+
r.set "foo", "s"
|
95
|
+
r.append "foo", "1"
|
96
|
+
|
97
|
+
assert "s1" == r.get("foo")
|
98
|
+
end
|
99
|
+
|
100
|
+
test "GETBIT" do |r|
|
101
|
+
r.set("foo", "a")
|
102
|
+
|
103
|
+
assert_equal 1, r.getbit("foo", 1)
|
104
|
+
assert_equal 1, r.getbit("foo", 2)
|
105
|
+
assert_equal 0, r.getbit("foo", 3)
|
106
|
+
assert_equal 0, r.getbit("foo", 4)
|
107
|
+
assert_equal 0, r.getbit("foo", 5)
|
108
|
+
assert_equal 0, r.getbit("foo", 6)
|
109
|
+
assert_equal 1, r.getbit("foo", 7)
|
110
|
+
end
|
111
|
+
|
112
|
+
test "SETBIT" do |r|
|
113
|
+
r.set("foo", "a")
|
114
|
+
|
115
|
+
r.setbit("foo", 6, 1)
|
116
|
+
|
117
|
+
assert_equal "c", r.get("foo")
|
118
|
+
end
|
119
|
+
|
120
|
+
test "GETRANGE" do |r|
|
121
|
+
r.set("foo", "abcde")
|
122
|
+
|
123
|
+
assert_equal "bcd", r.getrange("foo", 1, 3)
|
124
|
+
assert_equal "abcde", r.getrange("foo", 0, -1)
|
125
|
+
end
|
126
|
+
|
127
|
+
test "SETRANGE" do |r|
|
128
|
+
r.set("foo", "abcde")
|
129
|
+
|
130
|
+
r.setrange("foo", 1, "bar")
|
131
|
+
|
132
|
+
assert_equal "abare", r.get("foo")
|
133
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path("../redis_mock", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
include RedisMock::Helper
|
4
|
+
|
5
|
+
test "EXISTS" do |r|
|
6
|
+
assert false == r.exists("foo")
|
7
|
+
|
8
|
+
r.set("foo", "s1")
|
9
|
+
|
10
|
+
assert true == r.exists("foo")
|
11
|
+
end
|
12
|
+
|
13
|
+
test "TYPE" do |r|
|
14
|
+
assert "none" == r.type("foo")
|
15
|
+
|
16
|
+
r.set("foo", "s1")
|
17
|
+
|
18
|
+
assert "string" == r.type("foo")
|
19
|
+
end
|
20
|
+
|
21
|
+
test "KEYS" do |r|
|
22
|
+
r.set("f", "s1")
|
23
|
+
r.set("fo", "s2")
|
24
|
+
r.set("foo", "s3")
|
25
|
+
|
26
|
+
assert ["f","fo", "foo"] == r.keys("f*").sort
|
27
|
+
end
|
28
|
+
|
29
|
+
test "EXPIRE" do |r|
|
30
|
+
redis_mock(:expire => lambda { |*args| args == ["foo", "1"] ? ":1" : ":0" }) do
|
31
|
+
r = Redis.new(OPTIONS.merge(:port => 6380))
|
32
|
+
|
33
|
+
assert r.expire("foo", 1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
test "EXPIREAT" do |r|
|
38
|
+
redis_mock(:expireat => lambda { |*args| args == ["foo", "1328236326"] ? ":1" : ":0" }) do
|
39
|
+
r = Redis.new(OPTIONS.merge(:port => 6380))
|
40
|
+
|
41
|
+
assert r.expireat("foo", 1328236326)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
test "PERSIST" do |r|
|
46
|
+
r.set("foo", "s1")
|
47
|
+
r.expire("foo", 1)
|
48
|
+
r.persist("foo")
|
49
|
+
|
50
|
+
assert(-1 == r.ttl("foo"))
|
51
|
+
end
|
52
|
+
|
53
|
+
test "TTL" do |r|
|
54
|
+
r.set("foo", "s1")
|
55
|
+
r.expire("foo", 1)
|
56
|
+
|
57
|
+
assert 1 == r.ttl("foo")
|
58
|
+
end
|
59
|
+
|
60
|
+
test "MOVE" do |r|
|
61
|
+
r.select 14
|
62
|
+
r.flushdb
|
63
|
+
|
64
|
+
r.set "bar", "s3"
|
65
|
+
|
66
|
+
r.select 15
|
67
|
+
|
68
|
+
r.set "foo", "s1"
|
69
|
+
r.set "bar", "s2"
|
70
|
+
|
71
|
+
assert r.move("foo", 14)
|
72
|
+
assert nil == r.get("foo")
|
73
|
+
|
74
|
+
assert !r.move("bar", 14)
|
75
|
+
assert "s2" == r.get("bar")
|
76
|
+
|
77
|
+
r.select 14
|
78
|
+
|
79
|
+
assert "s1" == r.get("foo")
|
80
|
+
assert "s3" == r.get("bar")
|
81
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
setup do
|
6
|
+
init Redis.new(OPTIONS)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "SAVE and BGSAVE" do |r|
|
10
|
+
assert_nothing_raised do
|
11
|
+
r.save
|
12
|
+
end
|
13
|
+
|
14
|
+
assert_nothing_raised do
|
15
|
+
r.bgsave
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test "LASTSAVE" do |r|
|
20
|
+
assert Time.at(r.lastsave) <= Time.now
|
21
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
setup do
|
6
|
+
init Redis.new(OPTIONS)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "BULK commands" do |r|
|
10
|
+
r.pipelined do
|
11
|
+
r.lpush "foo", "s1"
|
12
|
+
r.lpush "foo", "s2"
|
13
|
+
end
|
14
|
+
|
15
|
+
assert 2 == r.llen("foo")
|
16
|
+
assert "s2" == r.lpop("foo")
|
17
|
+
assert "s1" == r.lpop("foo")
|
18
|
+
end
|
19
|
+
|
20
|
+
test "MULTI_BULK commands" do |r|
|
21
|
+
r.pipelined do
|
22
|
+
r.mset("foo", "s1", "bar", "s2")
|
23
|
+
r.mset("baz", "s3", "qux", "s4")
|
24
|
+
end
|
25
|
+
|
26
|
+
assert "s1" == r.get("foo")
|
27
|
+
assert "s2" == r.get("bar")
|
28
|
+
assert "s3" == r.get("baz")
|
29
|
+
assert "s4" == r.get("qux")
|
30
|
+
end
|
31
|
+
|
32
|
+
test "BULK and MULTI_BULK commands mixed" do |r|
|
33
|
+
r.pipelined do
|
34
|
+
r.lpush "foo", "s1"
|
35
|
+
r.lpush "foo", "s2"
|
36
|
+
r.mset("baz", "s3", "qux", "s4")
|
37
|
+
end
|
38
|
+
|
39
|
+
assert 2 == r.llen("foo")
|
40
|
+
assert "s2" == r.lpop("foo")
|
41
|
+
assert "s1" == r.lpop("foo")
|
42
|
+
assert "s3" == r.get("baz")
|
43
|
+
assert "s4" == r.get("qux")
|
44
|
+
end
|
45
|
+
|
46
|
+
test "MULTI_BULK and BULK commands mixed" do |r|
|
47
|
+
r.pipelined do
|
48
|
+
r.mset("baz", "s3", "qux", "s4")
|
49
|
+
r.lpush "foo", "s1"
|
50
|
+
r.lpush "foo", "s2"
|
51
|
+
end
|
52
|
+
|
53
|
+
assert 2 == r.llen("foo")
|
54
|
+
assert "s2" == r.lpop("foo")
|
55
|
+
assert "s1" == r.lpop("foo")
|
56
|
+
assert "s3" == r.get("baz")
|
57
|
+
assert "s4" == r.get("qux")
|
58
|
+
end
|
59
|
+
|
60
|
+
test "Pipelined with an empty block" do |r|
|
61
|
+
assert_nothing_raised do
|
62
|
+
r.pipelined do
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
assert 0 == r.dbsize
|
67
|
+
end
|
68
|
+
|
69
|
+
test "Returning the result of a pipeline" do |r|
|
70
|
+
result = r.pipelined do
|
71
|
+
r.set "foo", "bar"
|
72
|
+
r.get "foo"
|
73
|
+
r.get "bar"
|
74
|
+
end
|
75
|
+
|
76
|
+
assert ["OK", "bar", nil] == result
|
77
|
+
end
|
78
|
+
|
79
|
+
test "Assignment of results inside the block" do |r|
|
80
|
+
r.pipelined do
|
81
|
+
@first = r.sadd("foo", 1)
|
82
|
+
@second = r.sadd("foo", 1)
|
83
|
+
end
|
84
|
+
|
85
|
+
assert_equal true, @first.value
|
86
|
+
assert_equal false, @second.value
|
87
|
+
end
|
88
|
+
|
89
|
+
# Although we could support accessing the values in these futures,
|
90
|
+
# it doesn't make a lot of sense.
|
91
|
+
test "Assignment of results inside the block with errors" do |r|
|
92
|
+
assert_raise do
|
93
|
+
r.pipelined do
|
94
|
+
r.doesnt_exist
|
95
|
+
@first = r.sadd("foo", 1)
|
96
|
+
r.doesnt_exist
|
97
|
+
@second = r.sadd("foo", 1)
|
98
|
+
r.doesnt_exist
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
assert_raise(Redis::FutureNotReady) { @first.value }
|
103
|
+
assert_raise(Redis::FutureNotReady) { @second.value }
|
104
|
+
end
|
105
|
+
|
106
|
+
test "Assignment of results inside a nested block" do |r|
|
107
|
+
r.pipelined do
|
108
|
+
@first = r.sadd("foo", 1)
|
109
|
+
|
110
|
+
r.pipelined do
|
111
|
+
@second = r.sadd("foo", 1)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
assert_equal true, @first.value
|
116
|
+
assert_equal false, @second.value
|
117
|
+
end
|
118
|
+
|
119
|
+
test "Futures raise when confused with something else" do |r|
|
120
|
+
r.pipelined do
|
121
|
+
@result = r.sadd("foo", 1)
|
122
|
+
end
|
123
|
+
|
124
|
+
assert_raise(NoMethodError) { @result.to_s }
|
125
|
+
end
|
126
|
+
|
127
|
+
test "Futures raise when trying to access their values too early" do |r|
|
128
|
+
r.pipelined do
|
129
|
+
assert_raise(Redis::FutureNotReady) do
|
130
|
+
r.sadd("foo", 1).value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
test "Returning the result of an empty pipeline" do |r|
|
136
|
+
result = r.pipelined do
|
137
|
+
end
|
138
|
+
|
139
|
+
assert [] == result
|
140
|
+
end
|
141
|
+
|
142
|
+
test "Nesting pipeline blocks" do |r|
|
143
|
+
r.pipelined do
|
144
|
+
r.set("foo", "s1")
|
145
|
+
r.pipelined do
|
146
|
+
r.set("bar", "s2")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
assert "s1" == r.get("foo")
|
151
|
+
assert "s2" == r.get("bar")
|
152
|
+
end
|
153
|
+
|
154
|
+
test "INFO in a pipeline returns hash" do |r|
|
155
|
+
result = r.pipelined do
|
156
|
+
r.info
|
157
|
+
end
|
158
|
+
|
159
|
+
assert result.first.kind_of?(Hash)
|
160
|
+
end
|
161
|
+
|
162
|
+
test "CONFIG GET in a pipeline returns hash" do |r|
|
163
|
+
result = r.pipelined do
|
164
|
+
r.config(:get, "*")
|
165
|
+
end
|
166
|
+
|
167
|
+
assert result.first.kind_of?(Hash)
|
168
|
+
end
|
169
|
+
|
170
|
+
test "HGETALL in a pipeline returns hash" do |r|
|
171
|
+
r.hmset("hash", "field", "value")
|
172
|
+
result = r.pipelined do
|
173
|
+
r.hgetall("hash")
|
174
|
+
end
|
175
|
+
|
176
|
+
assert result.first == { "field" => "value" }
|
177
|
+
end
|
178
|
+
|
179
|
+
test "KEYS in a pipeline" do |r|
|
180
|
+
r.set("key", "value")
|
181
|
+
result = r.pipelined do
|
182
|
+
r.keys("*")
|
183
|
+
end
|
184
|
+
|
185
|
+
assert ["key"] == result.first
|
186
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
setup do
|
6
|
+
init Redis.new(OPTIONS)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "SUBSCRIBE and UNSUBSCRIBE" do |r|
|
10
|
+
listening = false
|
11
|
+
|
12
|
+
wire = Wire.new do
|
13
|
+
r.subscribe("foo") do |on|
|
14
|
+
on.subscribe do |channel, total|
|
15
|
+
@subscribed = true
|
16
|
+
@t1 = total
|
17
|
+
end
|
18
|
+
|
19
|
+
on.message do |channel, message|
|
20
|
+
if message == "s1"
|
21
|
+
r.unsubscribe
|
22
|
+
@message = message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
on.unsubscribe do |channel, total|
|
27
|
+
@unsubscribed = true
|
28
|
+
@t2 = total
|
29
|
+
end
|
30
|
+
|
31
|
+
listening = true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Wire.pass while !listening
|
36
|
+
|
37
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
38
|
+
|
39
|
+
wire.join
|
40
|
+
|
41
|
+
assert @subscribed
|
42
|
+
assert 1 == @t1
|
43
|
+
assert @unsubscribed
|
44
|
+
assert 0 == @t2
|
45
|
+
assert "s1" == @message
|
46
|
+
end
|
47
|
+
|
48
|
+
test "PSUBSCRIBE and PUNSUBSCRIBE" do |r|
|
49
|
+
listening = false
|
50
|
+
|
51
|
+
wire = Wire.new do
|
52
|
+
r.psubscribe("f*") do |on|
|
53
|
+
on.psubscribe do |pattern, total|
|
54
|
+
@subscribed = true
|
55
|
+
@t1 = total
|
56
|
+
end
|
57
|
+
|
58
|
+
on.pmessage do |pattern, channel, message|
|
59
|
+
if message == "s1"
|
60
|
+
r.punsubscribe
|
61
|
+
@message = message
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
on.punsubscribe do |pattern, total|
|
66
|
+
@unsubscribed = true
|
67
|
+
@t2 = total
|
68
|
+
end
|
69
|
+
|
70
|
+
listening = true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Wire.pass while !listening
|
75
|
+
|
76
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
77
|
+
|
78
|
+
wire.join
|
79
|
+
|
80
|
+
assert @subscribed
|
81
|
+
assert 1 == @t1
|
82
|
+
assert @unsubscribed
|
83
|
+
assert 0 == @t2
|
84
|
+
assert "s1" == @message
|
85
|
+
end
|
86
|
+
|
87
|
+
test "SUBSCRIBE within SUBSCRIBE" do |r|
|
88
|
+
listening = false
|
89
|
+
|
90
|
+
@channels = []
|
91
|
+
|
92
|
+
wire = Wire.new do
|
93
|
+
r.subscribe("foo") do |on|
|
94
|
+
on.subscribe do |channel, total|
|
95
|
+
@channels << channel
|
96
|
+
|
97
|
+
r.subscribe("bar") if channel == "foo"
|
98
|
+
r.unsubscribe if channel == "bar"
|
99
|
+
end
|
100
|
+
|
101
|
+
listening = true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
Wire.pass while !listening
|
106
|
+
|
107
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
108
|
+
|
109
|
+
wire.join
|
110
|
+
|
111
|
+
assert ["foo", "bar"] == @channels
|
112
|
+
end
|
113
|
+
|
114
|
+
test "other commands within a SUBSCRIBE" do |r|
|
115
|
+
assert_raise Redis::CommandError do
|
116
|
+
r.subscribe("foo") do |on|
|
117
|
+
on.subscribe do |channel, total|
|
118
|
+
r.set("bar", "s2")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
test "SUBSCRIBE without a block" do |r|
|
125
|
+
assert_raise LocalJumpError do
|
126
|
+
r.subscribe("foo")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
test "UNSUBSCRIBE without a SUBSCRIBE" do |r|
|
131
|
+
assert_raise RuntimeError do
|
132
|
+
r.unsubscribe
|
133
|
+
end
|
134
|
+
|
135
|
+
assert_raise RuntimeError do
|
136
|
+
r.punsubscribe
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
test "SUBSCRIBE past a timeout" do |r|
|
141
|
+
# For some reason, a thread here doesn't reproduce the issue.
|
142
|
+
sleep = %{sleep #{OPTIONS[:timeout] + 1}}
|
143
|
+
publish = %{echo "publish foo bar\r\n" | nc localhost #{OPTIONS[:port]}}
|
144
|
+
cmd = [sleep, publish].join("; ")
|
145
|
+
|
146
|
+
IO.popen(cmd, "r+") do |pipe|
|
147
|
+
received = false
|
148
|
+
|
149
|
+
r.subscribe "foo" do |on|
|
150
|
+
on.message do |channel, message|
|
151
|
+
received = true
|
152
|
+
r.unsubscribe
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
assert received
|
157
|
+
end
|
158
|
+
end
|