@@ -157,6 +157,91 @@ describe("provider-catalog-live-runtime", () => {
157157 expect ( fetchGuardMock ) . toHaveBeenCalledTimes ( 1 ) ;
158158 } ) ;
159159
160+ it ( "bounds an unbounded live catalog success stream and cancels the body" , async ( ) => {
161+ const encoder = new TextEncoder ( ) ;
162+ let pullCount = 0 ;
163+ let cancelled = false ;
164+ const release = vi . fn ( async ( ) => undefined ) ;
165+ const fetchGuardMock : MockedFunction < LiveModelCatalogFetchGuard > = vi . fn ( async ( ) => ( {
166+ response : new Response (
167+ new ReadableStream < Uint8Array > ( {
168+ pull ( controller ) {
169+ pullCount += 1 ;
170+ // Stream a JSON array prefix followed by an effectively endless run of
171+ // padding so the body never terminates under its own power.
172+ if ( pullCount === 1 ) {
173+ controller . enqueue ( encoder . encode ( '[{"id":"model-a","object":"model"},' ) ) ;
174+ return ;
175+ }
176+ controller . enqueue ( encoder . encode ( "0" . repeat ( 1024 * 1024 ) ) ) ;
177+ } ,
178+ cancel ( ) {
179+ cancelled = true ;
180+ } ,
181+ } ) ,
182+ { headers : { "content-type" : "application/json" } } ,
183+ ) ,
184+ finalUrl : "https://provider.example.test/v1/models" ,
185+ release,
186+ } ) ) ;
187+
188+ const error = await fetchLiveProviderModelIds ( {
189+ providerId : "provider" ,
190+ endpoint : "https://provider.example.test/v1/models" ,
191+ fetchGuard : fetchGuardMock ,
192+ } ) . catch ( ( err : unknown ) => err ) ;
193+
194+ expect ( error ) . toBeInstanceOf ( Error ) ;
195+ expect ( ( error as Error ) . message ) . toMatch ( / L i v e m o d e l c a t a l o g r e s p o n s e e x c e e d e d \d + b y t e s / ) ;
196+ expect ( cancelled ) . toBe ( true ) ;
197+ expect ( release ) . toHaveBeenCalledTimes ( 1 ) ;
198+ } ) ;
199+
200+ it ( "aborts a stalled live catalog success stream" , async ( ) => {
201+ vi . useFakeTimers ( ) ;
202+ try {
203+ const encoder = new TextEncoder ( ) ;
204+ let cancelReason : unknown ;
205+ const release = vi . fn ( async ( ) => undefined ) ;
206+ const fetchGuardMock : MockedFunction < LiveModelCatalogFetchGuard > = vi . fn ( async ( ) => ( {
207+ response : new Response (
208+ new ReadableStream < Uint8Array > ( {
209+ start ( controller ) {
210+ // Emit a partial JSON prefix and then idle forever without closing.
211+ controller . enqueue ( encoder . encode ( '[{"id":"model-a",' ) ) ;
212+ } ,
213+ cancel ( reason ) {
214+ cancelReason = reason ;
215+ } ,
216+ } ) ,
217+ { headers : { "content-type" : "application/json" } } ,
218+ ) ,
219+ finalUrl : "https://provider.example.test/v1/models" ,
220+ release,
221+ } ) ) ;
222+
223+ const resultPromise = fetchLiveProviderModelIds ( {
224+ providerId : "provider" ,
225+ endpoint : "https://provider.example.test/v1/models" ,
226+ fetchGuard : fetchGuardMock ,
227+ timeoutMs : 1234 ,
228+ } ) . catch ( ( err : unknown ) => err ) ;
229+
230+ await vi . advanceTimersByTimeAsync ( 0 ) ;
231+ await vi . advanceTimersByTimeAsync ( 1234 ) ;
232+ const error = await resultPromise ;
233+
234+ expect ( error ) . toBeInstanceOf ( Error ) ;
235+ expect ( ( error as Error ) . message ) . toBe (
236+ "Live model catalog response stalled: no data received for 1234ms" ,
237+ ) ;
238+ expect ( cancelReason ) . toBeInstanceOf ( Error ) ;
239+ expect ( release ) . toHaveBeenCalledTimes ( 1 ) ;
240+ } finally {
241+ vi . useRealTimers ( ) ;
242+ }
243+ } ) ;
244+
160245 it ( "throws structured HTTP errors after releasing guarded fetches" , async ( ) => {
161246 const release = vi . fn ( async ( ) => undefined ) ;
162247 const response = new Response ( "{}" , { status : 401 } ) ;
0 commit comments