11import pytest
22import trio
3+ import trio .testing
34from trio import DTLSEndpoint
45import random
56import attr
67from async_generator import asynccontextmanager
78from itertools import count
8- import ipaddress
9- import warnings
109
1110import trustme
1211from OpenSSL import SSL
@@ -699,9 +698,13 @@ def route_packet(packet):
699698async def test_system_task_cleaned_up_on_gc ():
700699 before_tasks = trio .lowlevel .current_statistics ().tasks_living
701700
702- e = endpoint ()
701+ # We put this into a sub-function so that everything automatically becomes garbage
702+ # when the frame exits. For some reason just doing 'del e' wasn't enough on pypy
703+ # with coverage enabled -- I think we were hitting this bug:
704+ # https://foss.heptapod.net/pypy/pypy/-/issues/3656
705+ async def start_and_forget_endpoint ():
706+ e = endpoint ()
703707
704- async def force_receive_loop_to_start ():
705708 # This connection/handshake attempt can't succeed. The only purpose is to force
706709 # the endpoint to set up a receive loop.
707710 with trio .socket .socket (type = trio .socket .SOCK_DGRAM ) as s :
@@ -712,12 +715,12 @@ async def force_receive_loop_to_start():
712715 await trio .testing .wait_all_tasks_blocked ()
713716 nursery .cancel_scope .cancel ()
714717
715- await force_receive_loop_to_start ()
716-
717- during_tasks = trio .lowlevel .current_statistics ().tasks_living
718+ during_tasks = trio .lowlevel .current_statistics ().tasks_living
719+ return during_tasks
718720
719721 with pytest .warns (ResourceWarning ):
720- del e
722+ during_tasks = await start_and_forget_endpoint ()
723+ await trio .testing .wait_all_tasks_blocked ()
721724 gc_collect_harder ()
722725
723726 await trio .testing .wait_all_tasks_blocked ()
@@ -745,6 +748,7 @@ async def test_gc_as_packet_received():
745748
746749 e = endpoint ()
747750 await e .socket .bind (("127.0.0.1" , 0 ))
751+ e ._ensure_receive_loop ()
748752
749753 await trio .testing .wait_all_tasks_blocked ()
750754
@@ -761,6 +765,12 @@ async def test_gc_as_packet_received():
761765@pytest .mark .filterwarnings ("always:unclosed DTLS:ResourceWarning" )
762766def test_gc_after_trio_exits ():
763767 async def main ():
768+ # We use fakenet just to make sure no real sockets can leak out of the test
769+ # case - on pypy somehow the socket was outliving the gc_collect_harder call
770+ # below. Since the test is just making sure DTLSEndpoint.__del__ doesn't explode
771+ # when called after trio exits, it doesn't need a real socket.
772+ fn = FakeNet ()
773+ fn .enable ()
764774 return endpoint ()
765775
766776 e = trio .run (main )
0 commit comments