@@ -62,3 +62,48 @@ async def retrieve(_request):
6262 finally :
6363 await provider .aclose ()
6464 await runner .cleanup ()
65+
66+
67+ @pytest .mark .asyncio
68+ @pytest .mark .parametrize ("status" , [408 , 500 , 502 , 503 , 504 , 400 ])
69+ async def test_http_gateway_failures_follow_retry_contract (monkeypatch , status ):
70+ from ifixai .providers .base import ProviderOverloadedError , is_fatal_provider_error
71+
72+ seen = []
73+ async def chat (request ):
74+ seen .append (await request .json ())
75+ if len (seen ) == 1 :
76+ return aiohttp .web .json_response ({"error" : {"message" : "owned gateway unavailable" }}, status = status )
77+ return aiohttp .web .json_response ({"choices" : [{"message" : {"content" : "recovered reply" }}]})
78+
79+ async def no_delay (_seconds ):
80+ pass
81+
82+ monkeypatch .setattr ("ifixai.providers.http.asyncio.sleep" , no_delay )
83+ app = aiohttp .web .Application ()
84+ app .router .add_post ("/v1/chat/completions" , chat )
85+ runner = aiohttp .web .AppRunner (app )
86+ await runner .setup ()
87+ site = aiohttp .web .TCPSite (runner , "127.0.0.1" , 0 )
88+ await site .start ()
89+ url = f"http://127.0.0.1:{ site ._server .sockets [0 ].getsockname ()[1 ]} /v1"
90+ provider = HttpProvider ()
91+ try :
92+ config = ProviderConfig (provider = "http" , endpoint = url , max_retries = 1 )
93+ if status == 400 :
94+ with pytest .raises (ProviderResponseError ):
95+ await provider .send_message ([ChatMessage (content = "hello" )], config )
96+ assert len (seen ) == 1
97+ else :
98+ assert await provider .send_message ([ChatMessage (content = "hello" )], config ) == "recovered reply"
99+ assert len (seen ) == 2
100+ seen .clear ()
101+ config .max_retries = 0
102+ expected = ProviderResponseError if status == 400 else ProviderOverloadedError
103+ with pytest .raises (expected ) as caught :
104+ await provider .send_message ([ChatMessage (content = "hello" )], config )
105+ assert not is_fatal_provider_error (caught .value )
106+ assert len (seen ) == 1
107+ finally :
108+ await provider .aclose ()
109+ await runner .cleanup ()
0 commit comments