discourse-redis 3.2.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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +59 -0
- data/.travis/Gemfile +11 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +349 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +328 -0
- data/Rakefile +87 -0
- data/benchmarking/logging.rb +71 -0
- data/benchmarking/pipeline.rb +51 -0
- data/benchmarking/speed.rb +21 -0
- data/benchmarking/suite.rb +24 -0
- data/benchmarking/worker.rb +71 -0
- data/examples/basic.rb +15 -0
- data/examples/consistency.rb +114 -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 +37 -0
- data/examples/sentinel.rb +41 -0
- data/examples/sentinel/start +49 -0
- data/examples/sets.rb +36 -0
- data/examples/unicorn/config.ru +3 -0
- data/examples/unicorn/unicorn.rb +20 -0
- data/lib/redis.rb +2731 -0
- data/lib/redis/client.rb +575 -0
- data/lib/redis/connection.rb +9 -0
- data/lib/redis/connection/command_helper.rb +44 -0
- data/lib/redis/connection/hiredis.rb +64 -0
- data/lib/redis/connection/registry.rb +12 -0
- data/lib/redis/connection/ruby.rb +322 -0
- data/lib/redis/connection/synchrony.rb +124 -0
- data/lib/redis/distributed.rb +873 -0
- data/lib/redis/errors.rb +40 -0
- data/lib/redis/hash_ring.rb +132 -0
- data/lib/redis/pipeline.rb +141 -0
- data/lib/redis/subscribe.rb +83 -0
- data/lib/redis/version.rb +3 -0
- data/redis.gemspec +34 -0
- data/test/bitpos_test.rb +69 -0
- data/test/blocking_commands_test.rb +42 -0
- data/test/command_map_test.rb +30 -0
- data/test/commands_on_hashes_test.rb +21 -0
- data/test/commands_on_hyper_log_log_test.rb +21 -0
- data/test/commands_on_lists_test.rb +20 -0
- data/test/commands_on_sets_test.rb +77 -0
- data/test/commands_on_sorted_sets_test.rb +137 -0
- data/test/commands_on_strings_test.rb +101 -0
- data/test/commands_on_value_types_test.rb +133 -0
- data/test/connection_handling_test.rb +250 -0
- data/test/distributed_blocking_commands_test.rb +46 -0
- data/test/distributed_commands_on_hashes_test.rb +10 -0
- data/test/distributed_commands_on_hyper_log_log_test.rb +33 -0
- data/test/distributed_commands_on_lists_test.rb +22 -0
- data/test/distributed_commands_on_sets_test.rb +83 -0
- data/test/distributed_commands_on_sorted_sets_test.rb +18 -0
- data/test/distributed_commands_on_strings_test.rb +59 -0
- data/test/distributed_commands_on_value_types_test.rb +95 -0
- data/test/distributed_commands_requiring_clustering_test.rb +164 -0
- data/test/distributed_connection_handling_test.rb +23 -0
- data/test/distributed_internals_test.rb +79 -0
- data/test/distributed_key_tags_test.rb +52 -0
- data/test/distributed_persistence_control_commands_test.rb +26 -0
- data/test/distributed_publish_subscribe_test.rb +92 -0
- data/test/distributed_remote_server_control_commands_test.rb +66 -0
- data/test/distributed_scripting_test.rb +102 -0
- data/test/distributed_sorting_test.rb +20 -0
- data/test/distributed_test.rb +58 -0
- data/test/distributed_transactions_test.rb +32 -0
- data/test/encoding_test.rb +18 -0
- data/test/error_replies_test.rb +59 -0
- data/test/fork_safety_test.rb +65 -0
- data/test/helper.rb +232 -0
- data/test/helper_test.rb +24 -0
- data/test/internals_test.rb +437 -0
- data/test/lint/blocking_commands.rb +150 -0
- data/test/lint/hashes.rb +162 -0
- data/test/lint/hyper_log_log.rb +60 -0
- data/test/lint/lists.rb +143 -0
- data/test/lint/sets.rb +125 -0
- data/test/lint/sorted_sets.rb +316 -0
- data/test/lint/strings.rb +260 -0
- data/test/lint/value_types.rb +122 -0
- data/test/persistence_control_commands_test.rb +26 -0
- data/test/pipelining_commands_test.rb +242 -0
- data/test/publish_subscribe_test.rb +254 -0
- data/test/remote_server_control_commands_test.rb +118 -0
- data/test/scanning_test.rb +413 -0
- data/test/scripting_test.rb +78 -0
- data/test/sentinel_command_test.rb +80 -0
- data/test/sentinel_test.rb +255 -0
- data/test/sorting_test.rb +59 -0
- 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/support/redis_mock.rb +119 -0
- data/test/support/wire/synchrony.rb +24 -0
- data/test/support/wire/thread.rb +5 -0
- data/test/synchrony_driver.rb +88 -0
- data/test/test.conf.erb +9 -0
- data/test/thread_safety_test.rb +32 -0
- data/test/transactions_test.rb +264 -0
- data/test/unknown_commands_test.rb +14 -0
- data/test/url_param_test.rb +138 -0
- metadata +182 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
module Lint
|
2
|
+
|
3
|
+
module ValueTypes
|
4
|
+
|
5
|
+
def test_exists
|
6
|
+
assert_equal false, r.exists("foo")
|
7
|
+
|
8
|
+
r.set("foo", "s1")
|
9
|
+
|
10
|
+
assert_equal true, r.exists("foo")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_type
|
14
|
+
assert_equal "none", r.type("foo")
|
15
|
+
|
16
|
+
r.set("foo", "s1")
|
17
|
+
|
18
|
+
assert_equal "string", r.type("foo")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_keys
|
22
|
+
r.set("f", "s1")
|
23
|
+
r.set("fo", "s2")
|
24
|
+
r.set("foo", "s3")
|
25
|
+
|
26
|
+
assert_equal ["f","fo", "foo"], r.keys("f*").sort
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_expire
|
30
|
+
r.set("foo", "s1")
|
31
|
+
assert r.expire("foo", 2)
|
32
|
+
assert_in_range 0..2, r.ttl("foo")
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_pexpire
|
36
|
+
target_version "2.5.4" do
|
37
|
+
r.set("foo", "s1")
|
38
|
+
assert r.pexpire("foo", 2000)
|
39
|
+
assert_in_range 0..2, r.ttl("foo")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_expireat
|
44
|
+
r.set("foo", "s1")
|
45
|
+
assert r.expireat("foo", (Time.now + 2).to_i)
|
46
|
+
assert_in_range 0..2, r.ttl("foo")
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_pexpireat
|
50
|
+
target_version "2.5.4" do
|
51
|
+
r.set("foo", "s1")
|
52
|
+
assert r.pexpireat("foo", (Time.now + 2).to_i * 1_000)
|
53
|
+
assert_in_range 0..2, r.ttl("foo")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_persist
|
58
|
+
r.set("foo", "s1")
|
59
|
+
r.expire("foo", 1)
|
60
|
+
r.persist("foo")
|
61
|
+
|
62
|
+
assert(-1 == r.ttl("foo"))
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_ttl
|
66
|
+
r.set("foo", "s1")
|
67
|
+
r.expire("foo", 2)
|
68
|
+
assert_in_range 0..2, r.ttl("foo")
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_pttl
|
72
|
+
target_version "2.5.4" do
|
73
|
+
r.set("foo", "s1")
|
74
|
+
r.expire("foo", 2)
|
75
|
+
assert_in_range 1..2000, r.pttl("foo")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_dump_and_restore
|
80
|
+
target_version "2.5.7" do
|
81
|
+
r.set("foo", "a")
|
82
|
+
v = r.dump("foo")
|
83
|
+
r.del("foo")
|
84
|
+
|
85
|
+
assert r.restore("foo", 1000, v)
|
86
|
+
assert_equal "a", r.get("foo")
|
87
|
+
assert [0, 1].include? r.ttl("foo")
|
88
|
+
|
89
|
+
r.rpush("bar", ["b", "c", "d"])
|
90
|
+
w = r.dump("bar")
|
91
|
+
r.del("bar")
|
92
|
+
|
93
|
+
assert r.restore("bar", 1000, w)
|
94
|
+
assert_equal ["b", "c", "d"], r.lrange("bar", 0, -1)
|
95
|
+
assert [0, 1].include? r.ttl("bar")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_move
|
100
|
+
r.select 14
|
101
|
+
r.flushdb
|
102
|
+
|
103
|
+
r.set "bar", "s3"
|
104
|
+
|
105
|
+
r.select 15
|
106
|
+
|
107
|
+
r.set "foo", "s1"
|
108
|
+
r.set "bar", "s2"
|
109
|
+
|
110
|
+
assert r.move("foo", 14)
|
111
|
+
assert_equal nil, r.get("foo")
|
112
|
+
|
113
|
+
assert !r.move("bar", 14)
|
114
|
+
assert_equal "s2", r.get("bar")
|
115
|
+
|
116
|
+
r.select 14
|
117
|
+
|
118
|
+
assert_equal "s1", r.get("foo")
|
119
|
+
assert_equal "s3", r.get("bar")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class TestPersistenceControlCommands < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Helper::Client
|
8
|
+
|
9
|
+
def test_save
|
10
|
+
redis_mock(:save => lambda { "+SAVE" }) do |redis|
|
11
|
+
assert_equal "SAVE", redis.save
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_bgsave
|
16
|
+
redis_mock(:bgsave => lambda { "+BGSAVE" }) do |redis|
|
17
|
+
assert_equal "BGSAVE", redis.bgsave
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_lastsave
|
22
|
+
redis_mock(:lastsave => lambda { "+LASTSAVE" }) do |redis|
|
23
|
+
assert_equal "LASTSAVE", redis.lastsave
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class TestPipeliningCommands < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Helper::Client
|
8
|
+
|
9
|
+
def test_bulk_commands
|
10
|
+
r.pipelined do
|
11
|
+
r.lpush "foo", "s1"
|
12
|
+
r.lpush "foo", "s2"
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_equal 2, r.llen("foo")
|
16
|
+
assert_equal "s2", r.lpop("foo")
|
17
|
+
assert_equal "s1", r.lpop("foo")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_multi_bulk_commands
|
21
|
+
r.pipelined do
|
22
|
+
r.mset("foo", "s1", "bar", "s2")
|
23
|
+
r.mset("baz", "s3", "qux", "s4")
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_equal "s1", r.get("foo")
|
27
|
+
assert_equal "s2", r.get("bar")
|
28
|
+
assert_equal "s3", r.get("baz")
|
29
|
+
assert_equal "s4", r.get("qux")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_bulk_and_multi_bulk_commands_mixed
|
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_equal 2, r.llen("foo")
|
40
|
+
assert_equal "s2", r.lpop("foo")
|
41
|
+
assert_equal "s1", r.lpop("foo")
|
42
|
+
assert_equal "s3", r.get("baz")
|
43
|
+
assert_equal "s4", r.get("qux")
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_multi_bulk_and_bulk_commands_mixed
|
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_equal 2, r.llen("foo")
|
54
|
+
assert_equal "s2", r.lpop("foo")
|
55
|
+
assert_equal "s1", r.lpop("foo")
|
56
|
+
assert_equal "s3", r.get("baz")
|
57
|
+
assert_equal "s4", r.get("qux")
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_pipelined_with_an_empty_block
|
61
|
+
assert_nothing_raised do
|
62
|
+
r.pipelined do
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
assert_equal 0, r.dbsize
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_returning_the_result_of_a_pipeline
|
70
|
+
result = r.pipelined do
|
71
|
+
r.set "foo", "bar"
|
72
|
+
r.get "foo"
|
73
|
+
r.get "bar"
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_equal ["OK", "bar", nil], result
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_assignment_of_results_inside_the_block
|
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
|
+
def test_assignment_of_results_inside_the_block_with_errors
|
92
|
+
assert_raise(Redis::CommandError) do
|
93
|
+
r.pipelined do
|
94
|
+
r.doesnt_exist
|
95
|
+
@first = r.sadd("foo", 1)
|
96
|
+
@second = r.sadd("foo", 1)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
assert_raise(Redis::FutureNotReady) { @first.value }
|
101
|
+
assert_raise(Redis::FutureNotReady) { @second.value }
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_assignment_of_results_inside_a_nested_block
|
105
|
+
r.pipelined do
|
106
|
+
@first = r.sadd("foo", 1)
|
107
|
+
|
108
|
+
r.pipelined do
|
109
|
+
@second = r.sadd("foo", 1)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
assert_equal true, @first.value
|
114
|
+
assert_equal false, @second.value
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_futures_raise_when_confused_with_something_else
|
118
|
+
r.pipelined do
|
119
|
+
@result = r.sadd("foo", 1)
|
120
|
+
end
|
121
|
+
|
122
|
+
assert_raise(NoMethodError) { @result.to_s }
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_futures_raise_when_trying_to_access_their_values_too_early
|
126
|
+
r.pipelined do
|
127
|
+
assert_raise(Redis::FutureNotReady) do
|
128
|
+
r.sadd("foo", 1).value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_futures_can_be_identified
|
134
|
+
r.pipelined do
|
135
|
+
@result = r.sadd("foo", 1)
|
136
|
+
end
|
137
|
+
|
138
|
+
assert_equal true, @result.is_a?(Redis::Future)
|
139
|
+
if defined?(::BasicObject)
|
140
|
+
assert_equal true, @result.is_a?(::BasicObject)
|
141
|
+
end
|
142
|
+
assert_equal Redis::Future, @result.class
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_returning_the_result_of_an_empty_pipeline
|
146
|
+
result = r.pipelined do
|
147
|
+
end
|
148
|
+
|
149
|
+
assert_equal [], result
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_nesting_pipeline_blocks
|
153
|
+
r.pipelined do
|
154
|
+
r.set("foo", "s1")
|
155
|
+
r.pipelined do
|
156
|
+
r.set("bar", "s2")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
assert_equal "s1", r.get("foo")
|
161
|
+
assert_equal "s2", r.get("bar")
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_info_in_a_pipeline_returns_hash
|
165
|
+
result = r.pipelined do
|
166
|
+
r.info
|
167
|
+
end
|
168
|
+
|
169
|
+
assert result.first.kind_of?(Hash)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_config_get_in_a_pipeline_returns_hash
|
173
|
+
result = r.pipelined do
|
174
|
+
r.config(:get, "*")
|
175
|
+
end
|
176
|
+
|
177
|
+
assert result.first.kind_of?(Hash)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_hgetall_in_a_pipeline_returns_hash
|
181
|
+
r.hmset("hash", "field", "value")
|
182
|
+
result = r.pipelined do
|
183
|
+
r.hgetall("hash")
|
184
|
+
end
|
185
|
+
|
186
|
+
assert_equal result.first, { "field" => "value" }
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_keys_in_a_pipeline
|
190
|
+
r.set("key", "value")
|
191
|
+
result = r.pipelined do
|
192
|
+
r.keys("*")
|
193
|
+
end
|
194
|
+
|
195
|
+
assert_equal ["key"], result.first
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_pipeline_yields_a_connection
|
199
|
+
r.pipelined do |p|
|
200
|
+
p.set("foo", "bar")
|
201
|
+
end
|
202
|
+
|
203
|
+
assert_equal "bar", r.get("foo")
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_pipeline_select
|
207
|
+
r.select 1
|
208
|
+
r.set("db", "1")
|
209
|
+
|
210
|
+
r.pipelined do |p|
|
211
|
+
p.select 2
|
212
|
+
p.set("db", "2")
|
213
|
+
end
|
214
|
+
|
215
|
+
r.select 1
|
216
|
+
assert_equal "1", r.get("db")
|
217
|
+
|
218
|
+
r.select 2
|
219
|
+
assert_equal "2", r.get("db")
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_pipeline_select_client_db
|
223
|
+
r.select 1
|
224
|
+
r.pipelined do |p2|
|
225
|
+
p2.select 2
|
226
|
+
end
|
227
|
+
|
228
|
+
assert_equal 2, r.client.db
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_nested_pipeline_select_client_db
|
232
|
+
r.select 1
|
233
|
+
r.pipelined do |p2|
|
234
|
+
p2.select 2
|
235
|
+
p2.pipelined do |p3|
|
236
|
+
p3.select 3
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
assert_equal 3, r.client.db
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class TestPublishSubscribe < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Helper::Client
|
8
|
+
|
9
|
+
class TestError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_subscribe_and_unsubscribe
|
13
|
+
@subscribed = false
|
14
|
+
@unsubscribed = false
|
15
|
+
|
16
|
+
wire = Wire.new do
|
17
|
+
r.subscribe("foo") do |on|
|
18
|
+
on.subscribe do |channel, total|
|
19
|
+
@subscribed = true
|
20
|
+
@t1 = total
|
21
|
+
end
|
22
|
+
|
23
|
+
on.message do |channel, message|
|
24
|
+
if message == "s1"
|
25
|
+
r.unsubscribe
|
26
|
+
@message = message
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
on.unsubscribe do |channel, total|
|
31
|
+
@unsubscribed = true
|
32
|
+
@t2 = total
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Wait until the subscription is active before publishing
|
38
|
+
Wire.pass while !@subscribed
|
39
|
+
|
40
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
41
|
+
|
42
|
+
wire.join
|
43
|
+
|
44
|
+
assert @subscribed
|
45
|
+
assert_equal 1, @t1
|
46
|
+
assert @unsubscribed
|
47
|
+
assert_equal 0, @t2
|
48
|
+
assert_equal "s1", @message
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_psubscribe_and_punsubscribe
|
52
|
+
@subscribed = false
|
53
|
+
@unsubscribed = false
|
54
|
+
|
55
|
+
wire = Wire.new do
|
56
|
+
r.psubscribe("f*") do |on|
|
57
|
+
on.psubscribe do |pattern, total|
|
58
|
+
@subscribed = true
|
59
|
+
@t1 = total
|
60
|
+
end
|
61
|
+
|
62
|
+
on.pmessage do |pattern, channel, message|
|
63
|
+
if message == "s1"
|
64
|
+
r.punsubscribe
|
65
|
+
@message = message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
on.punsubscribe do |pattern, total|
|
70
|
+
@unsubscribed = true
|
71
|
+
@t2 = total
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Wait until the subscription is active before publishing
|
77
|
+
Wire.pass while !@subscribed
|
78
|
+
|
79
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
80
|
+
|
81
|
+
wire.join
|
82
|
+
|
83
|
+
assert @subscribed
|
84
|
+
assert_equal 1, @t1
|
85
|
+
assert @unsubscribed
|
86
|
+
assert_equal 0, @t2
|
87
|
+
assert_equal "s1", @message
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_pubsub_with_numpat_subcommand
|
91
|
+
target_version("2.8.0") do
|
92
|
+
@subscribed = false
|
93
|
+
wire = Wire.new do
|
94
|
+
r.psubscribe("f*") do |on|
|
95
|
+
on.psubscribe { |channel, total| @subscribed = true }
|
96
|
+
on.pmessage { |pattern, channel, message| r.punsubscribe }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
Wire.pass while !@subscribed
|
100
|
+
redis = Redis.new(OPTIONS)
|
101
|
+
numpat_result = redis.pubsub(:numpat)
|
102
|
+
|
103
|
+
redis.publish("foo", "s1")
|
104
|
+
wire.join
|
105
|
+
|
106
|
+
assert_equal redis.pubsub(:numpat), 0
|
107
|
+
assert_equal numpat_result, 1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def test_pubsub_with_channels_and_numsub_subcommnads
|
113
|
+
target_version("2.8.0") do
|
114
|
+
@subscribed = false
|
115
|
+
wire = Wire.new do
|
116
|
+
r.subscribe("foo") do |on|
|
117
|
+
on.subscribe { |channel, total| @subscribed = true }
|
118
|
+
on.message { |channel, message| r.unsubscribe }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
Wire.pass while !@subscribed
|
122
|
+
redis = Redis.new(OPTIONS)
|
123
|
+
channels_result = redis.pubsub(:channels)
|
124
|
+
numsub_result = redis.pubsub(:numsub, 'foo', 'boo')
|
125
|
+
|
126
|
+
redis.publish("foo", "s1")
|
127
|
+
wire.join
|
128
|
+
|
129
|
+
assert_equal channels_result, ['foo']
|
130
|
+
assert_equal numsub_result, ['foo', 1, 'boo', 0]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_subscribe_connection_usable_after_raise
|
135
|
+
@subscribed = false
|
136
|
+
|
137
|
+
wire = Wire.new do
|
138
|
+
begin
|
139
|
+
r.subscribe("foo") do |on|
|
140
|
+
on.subscribe do |channel, total|
|
141
|
+
@subscribed = true
|
142
|
+
end
|
143
|
+
|
144
|
+
on.message do |channel, message|
|
145
|
+
raise TestError
|
146
|
+
end
|
147
|
+
end
|
148
|
+
rescue TestError
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Wait until the subscription is active before publishing
|
153
|
+
Wire.pass while !@subscribed
|
154
|
+
|
155
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
156
|
+
|
157
|
+
wire.join
|
158
|
+
|
159
|
+
assert_equal "PONG", r.ping
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_psubscribe_connection_usable_after_raise
|
163
|
+
@subscribed = false
|
164
|
+
|
165
|
+
wire = Wire.new do
|
166
|
+
begin
|
167
|
+
r.psubscribe("f*") do |on|
|
168
|
+
on.psubscribe do |pattern, total|
|
169
|
+
@subscribed = true
|
170
|
+
end
|
171
|
+
|
172
|
+
on.pmessage do |pattern, channel, message|
|
173
|
+
raise TestError
|
174
|
+
end
|
175
|
+
end
|
176
|
+
rescue TestError
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Wait until the subscription is active before publishing
|
181
|
+
Wire.pass while !@subscribed
|
182
|
+
|
183
|
+
Redis.new(OPTIONS).publish("foo", "s1")
|
184
|
+
|
185
|
+
wire.join
|
186
|
+
|
187
|
+
assert_equal "PONG", r.ping
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_subscribe_within_subscribe
|
191
|
+
@channels = []
|
192
|
+
|
193
|
+
wire = Wire.new do
|
194
|
+
r.subscribe("foo") do |on|
|
195
|
+
on.subscribe do |channel, total|
|
196
|
+
@channels << channel
|
197
|
+
|
198
|
+
r.subscribe("bar") if channel == "foo"
|
199
|
+
r.unsubscribe if channel == "bar"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
wire.join
|
205
|
+
|
206
|
+
assert_equal ["foo", "bar"], @channels
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_other_commands_within_a_subscribe
|
210
|
+
assert_raise Redis::CommandError do
|
211
|
+
r.subscribe("foo") do |on|
|
212
|
+
on.subscribe do |channel, total|
|
213
|
+
r.set("bar", "s2")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_subscribe_without_a_block
|
220
|
+
assert_raise LocalJumpError do
|
221
|
+
r.subscribe("foo")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_unsubscribe_without_a_subscribe
|
226
|
+
assert_raise RuntimeError do
|
227
|
+
r.unsubscribe
|
228
|
+
end
|
229
|
+
|
230
|
+
assert_raise RuntimeError do
|
231
|
+
r.punsubscribe
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_subscribe_past_a_timeout
|
236
|
+
# For some reason, a thread here doesn't reproduce the issue.
|
237
|
+
sleep = %{sleep #{OPTIONS[:timeout] * 2}}
|
238
|
+
publish = %{ruby -rsocket -e 't=TCPSocket.new("127.0.0.1",#{OPTIONS[:port]});t.write("publish foo bar\\r\\n");t.read(4);t.close'}
|
239
|
+
cmd = [sleep, publish].join("; ")
|
240
|
+
|
241
|
+
IO.popen(cmd, "r+") do |pipe|
|
242
|
+
received = false
|
243
|
+
|
244
|
+
r.subscribe "foo" do |on|
|
245
|
+
on.message do |channel, message|
|
246
|
+
received = true
|
247
|
+
r.unsubscribe
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
assert received
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|