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