@@ -660,3 +660,40 @@ async def test_dns_resolver_manager_missing_loop_data() -> None:
660
660
661
661
# Verify no exception was raised
662
662
assert loop not in manager ._loop_data
663
+
664
+
665
+ @pytest .mark .skipif (not getaddrinfo , reason = "aiodns >=3.2.0 required" )
666
+ @pytest .mark .usefixtures ("check_no_lingering_resolvers" )
667
+ async def test_async_resolver_close_multiple_times () -> None :
668
+ """Test that AsyncResolver.close() can be called multiple times without error."""
669
+ with patch ("aiodns.DNSResolver" ) as mock_dns_resolver :
670
+ mock_resolver = Mock ()
671
+ mock_resolver .cancel = Mock ()
672
+ mock_dns_resolver .return_value = mock_resolver
673
+
674
+ # Create a resolver with custom args (dedicated resolver)
675
+ resolver = AsyncResolver (nameservers = ["8.8.8.8" ])
676
+
677
+ # Close it once
678
+ await resolver .close ()
679
+ mock_resolver .cancel .assert_called_once ()
680
+
681
+ # Close it again - should not raise AttributeError
682
+ await resolver .close ()
683
+ # cancel should still only be called once
684
+ mock_resolver .cancel .assert_called_once ()
685
+
686
+
687
+ @pytest .mark .skipif (not getaddrinfo , reason = "aiodns >=3.2.0 required" )
688
+ @pytest .mark .usefixtures ("check_no_lingering_resolvers" )
689
+ async def test_async_resolver_close_with_none_resolver () -> None :
690
+ """Test that AsyncResolver.close() handles None resolver gracefully."""
691
+ with patch ("aiodns.DNSResolver" ):
692
+ # Create a resolver with custom args (dedicated resolver)
693
+ resolver = AsyncResolver (nameservers = ["8.8.8.8" ])
694
+
695
+ # Manually set resolver to None to simulate edge case
696
+ resolver ._resolver = None # type: ignore[assignment]
697
+
698
+ # This should not raise AttributeError
699
+ await resolver .close ()
0 commit comments