@@ -24,18 +24,30 @@ async def asyncTearDown(self):
2424
2525 async def test_slow_reader (self ):
2626 a , b = self .socketpair ()
27+ first_recv = asyncio .Future ()
28+
2729 def recv ():
28- b .recv (100 )
30+ msg = b .recv (100 )
31+ if not first_recv .done ():
32+ first_recv .set_result (msg )
33+
2934 mock_recv = mock .MagicMock (wraps = recv )
3035 # make sure select is only called once when
3136 # event loop thread is slow to consume events
3237 a .sendall (b"msg" )
3338 with mock .patch ("select.select" , wraps = select .select ) as mock_select :
3439 self .selector_thread .add_reader (b , mock_recv )
40+ # ready event, but main event loop is blocked for some time
3541 time .sleep (0.1 )
36- self .assertEqual (mock_select .call_count , 1 )
37- await asyncio .sleep (0.1 )
42+ recvd = await asyncio .wait_for (first_recv , timeout = 10 )
43+ self .assertEqual (recvd , b"msg" )
44+ # make sure recv wasn't scheduled more than once
3845 self .assertEqual (mock_recv .call_count , 1 )
46+ # 1 for add_reader
47+ # 1 for finishing reader callback
48+ # up to 2 more for wake FD calls if CI is slow
49+ # this would be thousands if select is busy-looping while the main thread blocks
50+ self .assertLessEqual (mock_select .call_count , 5 )
3951
4052 async def test_reader_error (self ):
4153 # test error handling in callbacks doesn't break handling
@@ -44,10 +56,12 @@ async def test_reader_error(self):
4456
4557 selector_thread = self .selector_thread
4658
47- # make sure it's called a few
59+ # make sure it's called a few times,
60+ # and errors don't prevent rescheduling
4861 n_failures = 5
4962 counter = 0
5063 bad_recv_done = asyncio .Future ()
64+
5165 def bad_recv (sock ):
5266 # fail the first n_failures calls, then succeed
5367 nonlocal counter
@@ -67,7 +81,9 @@ def bad_recv(sock):
6781
6882 # make sure start_select is called
6983 # even when recv callback errors,
70- with mock .patch .object (selector_thread , "_start_select" , wraps = selector_thread ._start_select ) as start_select :
84+ with mock .patch .object (
85+ selector_thread , "_start_select" , wraps = selector_thread ._start_select
86+ ) as start_select :
7187 await asyncio .wait_for (bad_recv_done , timeout = 10 )
7288
7389 # make sure recv is called N + 1 times,
0 commit comments