@@ -125,8 +125,12 @@ async def main(srv):
125125class TestServer2 (unittest .IsolatedAsyncioTestCase ):
126126
127127 async def test_wait_closed_basic (self ):
128- async def serve (* args ):
129- pass
128+ async def serve (rd , wr ):
129+ try :
130+ await rd .read ()
131+ finally :
132+ wr .close ()
133+ await wr .wait_closed ()
130134
131135 srv = await asyncio .start_server (serve , socket_helper .HOSTv4 , 0 )
132136 self .addCleanup (srv .close )
@@ -137,7 +141,8 @@ async def serve(*args):
137141 self .assertFalse (task1 .done ())
138142
139143 # active count != 0, not closed: should block
140- srv ._attach ()
144+ addr = srv .sockets [0 ].getsockname ()
145+ (rd , wr ) = await asyncio .open_connection (addr [0 ], addr [1 ])
141146 task2 = asyncio .create_task (srv .wait_closed ())
142147 await asyncio .sleep (0 )
143148 self .assertFalse (task1 .done ())
@@ -152,7 +157,8 @@ async def serve(*args):
152157 self .assertFalse (task2 .done ())
153158 self .assertFalse (task3 .done ())
154159
155- srv ._detach ()
160+ wr .close ()
161+ await wr .wait_closed ()
156162 # active count == 0, closed: should unblock
157163 await task1
158164 await task2
@@ -161,22 +167,96 @@ async def serve(*args):
161167
162168 async def test_wait_closed_race (self ):
163169 # Test a regression in 3.12.0, should be fixed in 3.12.1
164- async def serve (* args ):
165- pass
170+ async def serve (rd , wr ):
171+ try :
172+ await rd .read ()
173+ finally :
174+ wr .close ()
175+ await wr .wait_closed ()
166176
167177 srv = await asyncio .start_server (serve , socket_helper .HOSTv4 , 0 )
168178 self .addCleanup (srv .close )
169179
170180 task = asyncio .create_task (srv .wait_closed ())
171181 await asyncio .sleep (0 )
172182 self .assertFalse (task .done ())
173- srv ._attach ()
183+ addr = srv .sockets [0 ].getsockname ()
184+ (rd , wr ) = await asyncio .open_connection (addr [0 ], addr [1 ])
174185 loop = asyncio .get_running_loop ()
175186 loop .call_soon (srv .close )
176- loop .call_soon (srv . _detach )
187+ loop .call_soon (wr . close )
177188 await srv .wait_closed ()
178189
190+ async def test_close_clients (self ):
191+ async def serve (rd , wr ):
192+ try :
193+ await rd .read ()
194+ finally :
195+ wr .close ()
196+ await wr .wait_closed ()
197+
198+ srv = await asyncio .start_server (serve , socket_helper .HOSTv4 , 0 )
199+ self .addCleanup (srv .close )
200+
201+ addr = srv .sockets [0 ].getsockname ()
202+ (rd , wr ) = await asyncio .open_connection (addr [0 ], addr [1 ])
203+ self .addCleanup (wr .close )
204+
205+ task = asyncio .create_task (srv .wait_closed ())
206+ await asyncio .sleep (0 )
207+ self .assertFalse (task .done ())
208+
209+ srv .close ()
210+ srv .close_clients ()
211+ await asyncio .sleep (0 )
212+ await asyncio .sleep (0 )
213+ self .assertTrue (task .done ())
214+
215+ async def test_abort_clients (self ):
216+ async def serve (rd , wr ):
217+ nonlocal s_rd , s_wr
218+ s_rd = rd
219+ s_wr = wr
220+ await wr .wait_closed ()
221+
222+ s_rd = s_wr = None
223+ srv = await asyncio .start_server (serve , socket_helper .HOSTv4 , 0 )
224+ self .addCleanup (srv .close )
225+
226+ addr = srv .sockets [0 ].getsockname ()
227+ (c_rd , c_wr ) = await asyncio .open_connection (addr [0 ], addr [1 ], limit = 4096 )
228+ self .addCleanup (c_wr .close )
229+
230+ # Limit the socket buffers so we can reliably overfill them
231+ s_sock = s_wr .get_extra_info ('socket' )
232+ s_sock .setsockopt (socket .SOL_SOCKET , socket .SO_SNDBUF , 65536 )
233+ c_sock = c_wr .get_extra_info ('socket' )
234+ c_sock .setsockopt (socket .SOL_SOCKET , socket .SO_RCVBUF , 65536 )
235+
236+ # Get the reader in to a paused state by sending more than twice
237+ # the configured limit
238+ s_wr .write (b'a' * 4096 )
239+ s_wr .write (b'a' * 4096 )
240+ s_wr .write (b'a' * 4096 )
241+ while c_wr .transport .is_reading ():
242+ await asyncio .sleep (0 )
243+
244+ # Get the writer in a waiting state by sending data until the
245+ # socket buffers are full on both server and client sockets and
246+ # the kernel stops accepting more data
247+ s_wr .write (b'a' * c_sock .getsockopt (socket .SOL_SOCKET , socket .SO_RCVBUF ))
248+ s_wr .write (b'a' * s_sock .getsockopt (socket .SOL_SOCKET , socket .SO_SNDBUF ))
249+ self .assertNotEqual (s_wr .transport .get_write_buffer_size (), 0 )
250+
251+ task = asyncio .create_task (srv .wait_closed ())
252+ await asyncio .sleep (0 )
253+ self .assertFalse (task .done ())
179254
255+ srv .close ()
256+ srv .abort_clients ()
257+ await asyncio .sleep (0 )
258+ await asyncio .sleep (0 )
259+ self .assertTrue (task .done ())
180260
181261
182262# Test the various corner cases of Unix server socket removal
0 commit comments