2
2
import functools
3
3
import sys
4
4
from typing import Optional
5
+ from unittest .mock import patch
5
6
6
7
import async_timeout
7
8
import pytest
@@ -773,20 +774,52 @@ def callback(message):
773
774
}
774
775
775
776
776
- @pytest .mark .skipif (sys .version_info < (3 , 8 ), reason = "requires python 3.8 or higher" )
777
777
@pytest .mark .onlynoncluster
778
- async def test_outer_timeout (r : redis .Redis ):
779
- """
780
- Using asyncio_timeout manually outside the inner method timeouts works.
781
- This works on Python versions 3.8 and greater, at which time asyncio.CancelledError became a BaseException
782
- instead of an Exception before.
783
- """
784
- pubsub = r .pubsub ()
785
- await pubsub .subscribe ("foo" )
786
- assert pubsub .connection .is_connected
787
-
788
- async def get_msg_or_timeout (timeout = 0.1 ):
789
- async with async_timeout .timeout (timeout ):
778
+ class TestBaseException :
779
+ @pytest .mark .skipif (
780
+ sys .version_info < (3 , 8 ), reason = "requires python 3.8 or higher"
781
+ )
782
+ async def test_outer_timeout (self , r : redis .Redis ):
783
+ """
784
+ Using asyncio_timeout manually outside the inner method timeouts works.
785
+ This works on Python versions 3.8 and greater, at which time asyncio.CancelledError
786
+ became a BaseException instead of an Exception before.
787
+ """
788
+ pubsub = r .pubsub ()
789
+ await pubsub .subscribe ("foo" )
790
+ assert pubsub .connection .is_connected
791
+
792
+ async def get_msg_or_timeout (timeout = 0.1 ):
793
+ async with async_timeout .timeout (timeout ):
794
+ # blocking method to return messages
795
+ while True :
796
+ response = await pubsub .parse_response (block = True )
797
+ message = await pubsub .handle_message (
798
+ response , ignore_subscribe_messages = False
799
+ )
800
+ if message is not None :
801
+ return message
802
+
803
+ # get subscribe message
804
+ msg = await get_msg_or_timeout (10 )
805
+ assert msg is not None
806
+ # timeout waiting for another message which never arrives
807
+ assert pubsub .connection .is_connected
808
+ with pytest .raises (asyncio .TimeoutError ):
809
+ await get_msg_or_timeout ()
810
+ # the timeout on the read should not cause disconnect
811
+ assert pubsub .connection .is_connected
812
+
813
+ async def test_base_exception (self , r : redis .Redis ):
814
+ """
815
+ Manually trigger a BaseException inside the parser's .read_response method
816
+ and verify that it isn't caught
817
+ """
818
+ pubsub = r .pubsub ()
819
+ await pubsub .subscribe ("foo" )
820
+ assert pubsub .connection .is_connected
821
+
822
+ async def get_msg ():
790
823
# blocking method to return messages
791
824
while True :
792
825
response = await pubsub .parse_response (block = True )
@@ -796,12 +829,18 @@ async def get_msg_or_timeout(timeout=0.1):
796
829
if message is not None :
797
830
return message
798
831
799
- # get subscribe message
800
- msg = await get_msg_or_timeout (10 )
801
- assert msg is not None
802
- # timeout waiting for another message which never arrives
803
- assert pubsub .connection .is_connected
804
- with pytest .raises (asyncio .TimeoutError ):
805
- await get_msg_or_timeout ()
806
- # the timeout on the read should not cause disconnect
807
- assert pubsub .connection .is_connected
832
+ # get subscribe message
833
+ msg = await get_msg ()
834
+ assert msg is not None
835
+ # timeout waiting for another message which never arrives
836
+ assert pubsub .connection .is_connected
837
+ with patch ("redis.asyncio.connection.PythonParser.read_response" ) as mock1 :
838
+ mock1 .side_effect = BaseException ("boom" )
839
+ with patch ("redis.asyncio.connection.HiredisParser.read_response" ) as mock2 :
840
+ mock2 .side_effect = BaseException ("boom" )
841
+
842
+ with pytest .raises (BaseException ):
843
+ await get_msg ()
844
+
845
+ # the timeout on the read should not cause disconnect
846
+ assert pubsub .connection .is_connected
0 commit comments