@@ -614,3 +614,49 @@ async def test_dns_resolver_manager_multiple_event_loops(
614
614
# Verify resolver cleanup
615
615
resolver1 .cancel .assert_called_once ()
616
616
resolver2 .cancel .assert_called_once ()
617
+
618
+
619
+ @pytest .mark .skipif (not getaddrinfo , reason = "aiodns >=3.2.0 required" )
620
+ async def test_dns_resolver_manager_weakref_garbage_collection () -> None :
621
+ """Test that release_resolver handles None resolver due to weakref garbage collection."""
622
+ manager = _DNSResolverManager ()
623
+
624
+ # Create a mock resolver that will be None when accessed
625
+ mock_resolver = Mock ()
626
+ mock_resolver .cancel = Mock ()
627
+
628
+ with patch ("aiodns.DNSResolver" , return_value = mock_resolver ):
629
+ # Create an AsyncResolver to get a resolver from the manager
630
+ resolver = AsyncResolver ()
631
+ loop = asyncio .get_running_loop ()
632
+
633
+ # Manually corrupt the data to simulate garbage collection
634
+ # by setting the resolver to None
635
+ manager ._loop_data [loop ] = (None , manager ._loop_data [loop ][1 ]) # type: ignore[assignment]
636
+
637
+ # This should not raise an AttributeError: 'NoneType' object has no attribute 'cancel'
638
+ await resolver .close ()
639
+
640
+ # Verify no exception was raised and the loop data was cleaned up properly
641
+ # Since we set resolver to None and there was one client, the entry should be removed
642
+ assert loop not in manager ._loop_data
643
+
644
+
645
+ @pytest .mark .skipif (not getaddrinfo , reason = "aiodns >=3.2.0 required" )
646
+ async def test_dns_resolver_manager_missing_loop_data () -> None :
647
+ """Test that release_resolver handles missing loop data gracefully."""
648
+ manager = _DNSResolverManager ()
649
+
650
+ with patch ("aiodns.DNSResolver" ):
651
+ # Create an AsyncResolver
652
+ resolver = AsyncResolver ()
653
+ loop = asyncio .get_running_loop ()
654
+
655
+ # Manually remove the loop data to simulate race condition
656
+ manager ._loop_data .clear ()
657
+
658
+ # This should not raise a KeyError
659
+ await resolver .close ()
660
+
661
+ # Verify no exception was raised
662
+ assert loop not in manager ._loop_data
0 commit comments