@@ -687,6 +687,82 @@ async def test_connection_pool_closed_while_request_in_flight():
687
687
await response .aread ()
688
688
689
689
690
+ @pytest .mark .anyio
691
+ async def test_connection_pool_with_idle_broken_connection ():
692
+ """
693
+ Pool gives a new connection when an idle connection gets readable (ie broken) while in the pool.
694
+ """
695
+
696
+ class MockStream (httpcore .AsyncMockStream ):
697
+ def __init__ (self , buffer : typing .List [bytes ]):
698
+ super ().__init__ (buffer )
699
+ self .mock_is_readable = False
700
+
701
+ def get_extra_info (self , info : str ) -> typing .Any :
702
+ if info == "is_readable" :
703
+ return self .mock_is_readable
704
+ return super ().get_extra_info (info ) # pragma: nocover
705
+
706
+ streams = [
707
+ MockStream (
708
+ [
709
+ b"HTTP/1.1 200 OK\r \n " ,
710
+ b"Content-Type: plain/text\r \n " ,
711
+ b"Content-Length: 15\r \n " ,
712
+ b"\r \n " ,
713
+ b"Hello, world 1!" ,
714
+ b"HTTP/1.1 200 OK\r \n " ,
715
+ b"Content-Type: plain/text\r \n " ,
716
+ b"Content-Length: 15\r \n " ,
717
+ b"\r \n " ,
718
+ b"Hello, world 2!" ,
719
+ ]
720
+ ),
721
+ MockStream (
722
+ [
723
+ b"HTTP/1.1 200 OK\r \n " ,
724
+ b"Content-Type: plain/text\r \n " ,
725
+ b"Content-Length: 29\r \n " ,
726
+ b"\r \n " ,
727
+ b"Hello, world from new stream!" ,
728
+ ]
729
+ ),
730
+ ]
731
+
732
+ class MockBackend (httpcore .AsyncMockBackend ):
733
+ async def connect_tcp (
734
+ self , * args : typing .Any , ** kwargs : typing .Any
735
+ ) -> MockStream :
736
+ return streams .pop (0 )
737
+
738
+ async with httpcore .AsyncConnectionPool (
739
+ network_backend = MockBackend ([]), max_connections = 1
740
+ ) as pool :
741
+ res = await pool .request ("GET" , "https://example.com/" )
742
+ assert (await res .aread ()) == b"Hello, world 1!"
743
+
744
+ assert len (pool .connections ) == 1
745
+ conn = pool .connections [0 ]
746
+
747
+ res = await pool .request ("GET" , "https://example.com/" )
748
+ assert (await res .aread ()) == b"Hello, world 2!"
749
+
750
+ assert len (pool .connections ) == 1
751
+ assert conn is pool .connections [0 ], "Should reuse connection"
752
+
753
+ # Simulate network breakage
754
+ assert conn .is_idle ()
755
+ conn ._connection ._network_stream .mock_is_readable = True # type: ignore[attr-defined]
756
+
757
+ res = await pool .request ("GET" , "https://example.com/" )
758
+ assert (await res .aread ()) == b"Hello, world from new stream!"
759
+
760
+ assert len (pool .connections ) == 1
761
+ new_conn = pool .connections [0 ]
762
+ assert new_conn is not conn , "Should be a new connection"
763
+ assert not new_conn ._connection ._network_stream .mock_is_readable # type: ignore[attr-defined]
764
+
765
+
690
766
@pytest .mark .anyio
691
767
async def test_connection_pool_timeout ():
692
768
"""
0 commit comments