Skip to content

Commit d4ee8a9

Browse files
committed
add test_datagram_write_error_close_from_callback
1 parent b52b945 commit d4ee8a9

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

Lib/test/test_asyncio/test_events.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,47 @@ def connection_lost(self, exc):
18091809
loop.run_until_complete(asyncio.wait_for(protocol.lost, 10))
18101810
self.assertTrue(protocol.errors)
18111811

1812+
def test_datagram_write_error_close_from_callback(self):
1813+
# See https://github.com/python/cpython/issues/156920: an
1814+
# error_received() callback that closes the transport must still
1815+
# result in connection_lost() being called eventually, instead of
1816+
# leaving the transport hanging forever. Two failing writes are
1817+
# used so that the first failure's error_received() call closes
1818+
# the transport while the second is still queued (close() defers
1819+
# to the write loop), and the second failure then empties the
1820+
# buffer with self._closing already True and no write in flight
1821+
# -- exercising the `self._closing` half of the
1822+
# `if self._buffer or self._closing:` condition in _loop_writing.
1823+
loop = self.loop
1824+
1825+
class Protocol(asyncio.DatagramProtocol):
1826+
def connection_made(self, transport):
1827+
self.transport = transport
1828+
self.errors = []
1829+
self.lost = loop.create_future()
1830+
1831+
def error_received(self, exc):
1832+
self.errors.append(exc)
1833+
self.transport.close()
1834+
1835+
def connection_lost(self, exc):
1836+
if not self.lost.done():
1837+
self.lost.set_result(exc)
1838+
1839+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1840+
sock.setblocking(False)
1841+
sock.bind(('127.0.0.1', 0))
1842+
transport, protocol = loop.run_until_complete(
1843+
loop.create_datagram_endpoint(Protocol, sock=sock))
1844+
addr = sock.getsockname()
1845+
1846+
oversized = b'\x00' * 70000
1847+
transport.sendto(oversized, addr)
1848+
transport.sendto(oversized, addr)
1849+
1850+
loop.run_until_complete(asyncio.wait_for(protocol.lost, 10))
1851+
self.assertEqual(len(protocol.errors), 2)
1852+
18121853
def test_datagram_recvfrom_connection_reset_recovers(self):
18131854
# gh-127057: a UDP socket that sent a datagram to an address that
18141855
# wasn't listening can raise ConnectionResetError on a later

0 commit comments

Comments
 (0)