@@ -205,19 +205,22 @@ def test_other_commands_within_a_subscribe
205205 end
206206
207207 def test_subscribe_without_a_block
208- assert_raises LocalJumpError do
208+ error = assert_raises Redis :: SubscriptionError do
209209 r . subscribe ( channel_name )
210210 end
211+ assert_includes "This client is not subscribed" , error . message
211212 end
212213
213214 def test_unsubscribe_without_a_subscribe
214- assert_raises RuntimeError do
215+ error = assert_raises Redis :: SubscriptionError do
215216 r . unsubscribe
216217 end
218+ assert_includes "This client is not subscribed" , error . message
217219
218- assert_raises RuntimeError do
220+ error = assert_raises Redis :: SubscriptionError do
219221 r . punsubscribe
220222 end
223+ assert_includes "This client is not subscribed" , error . message
221224 end
222225
223226 def test_subscribe_past_a_timeout
@@ -264,12 +267,87 @@ def test_psubscribe_with_timeout
264267 refute received
265268 end
266269
270+ def test_unsubscribe_from_another_thread
271+ @unsubscribed = @subscribed = false
272+ @subscribed_redis = nil
273+ @messages = [ ]
274+ @messages_count = 0
275+ thread = new_thread do |r |
276+ @subscribed_redis = r
277+ r . subscribe ( channel_name ) do |on |
278+ on . subscribe do |_channel , _total |
279+ @subscribed = true
280+ end
281+
282+ on . message do |channel , message |
283+ @messages << [ channel , message ]
284+ @messages_count += 1
285+ end
286+
287+ on . unsubscribe do |_channel , _total |
288+ @unsubscribed = true
289+ end
290+ end
291+ end
292+
293+ Thread . pass until @subscribed
294+
295+ redis . publish ( channel_name , "test" )
296+ Thread . pass until @messages_count == 1
297+ assert_equal [ channel_name , "test" ] , @messages . last
298+
299+ @subscribed_redis . unsubscribe # this shouldn't block
300+ refute_nil thread . join ( 2 )
301+ assert_equal true , @unsubscribed
302+ end
303+
304+ def test_subscribe_from_another_thread
305+ @events = [ ]
306+ @subscribed_redis = nil
307+ thread = new_thread do |r |
308+ r . subscribe ( channel_name ) do |on |
309+ @subscribed_redis = r
310+ on . subscribe do |channel , _total |
311+ @events << [ "subscribed" , channel ]
312+ end
313+
314+ on . message do |channel , message |
315+ @events << [ "message" , channel , message ]
316+ end
317+
318+ on . unsubscribe do |channel , _total |
319+ @events << [ "unsubscribed" , channel ]
320+ end
321+ end
322+ end
323+
324+ Thread . pass until @subscribed_redis &.subscribed?
325+
326+ redis . publish ( channel_name , "test" )
327+ @subscribed_redis . subscribe ( "#{ channel_name } :2" )
328+ redis . publish ( "#{ channel_name } :2" , "test-2" )
329+
330+ @subscribed_redis . unsubscribe ( channel_name )
331+ @subscribed_redis . unsubscribe # this shouldn't block
332+
333+ refute_nil thread . join ( 2 )
334+ expected = [
335+ [ "subscribed" , channel_name ] ,
336+ [ "message" , channel_name , "test" ] ,
337+ [ "subscribed" , "#{ channel_name } :2" ] ,
338+ [ "message" , "#{ channel_name } :2" , "test-2" ] ,
339+ [ "unsubscribed" , channel_name ] ,
340+ [ "unsubscribed" , "#{ channel_name } :2" ]
341+ ]
342+ assert_equal expected , @events
343+ end
344+
267345 private
268346
269347 def new_thread ( &block )
270348 redis = Redis . new ( OPTIONS )
271349 thread = Thread . new ( redis , &block )
272- thread . report_on_exception = false
350+ thread . report_on_exception = true
273351 @threads [ thread ] = redis
274352 thread
275353 end
0 commit comments