@@ -219,33 +219,6 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
219
219
} ) ;
220
220
} ) ;
221
221
222
- it ( "should handle StopStatement message with retries" , async ( ) => {
223
- // Mock the updateSqlv1Statement to fail with 409 twice then succeed
224
- ctx . flinkSqlStatementsApi . updateSqlv1Statement
225
- . onFirstCall ( )
226
- . rejects ( createResponseError ( 409 , "Conflict" , "{}" ) ) ;
227
- ctx . flinkSqlStatementsApi . updateSqlv1Statement
228
- . onSecondCall ( )
229
- . rejects ( createResponseError ( 409 , "Conflict" , "{}" ) ) ;
230
- ctx . flinkSqlStatementsApi . updateSqlv1Statement . onThirdCall ( ) . resolves ( ) ;
231
-
232
- await vm . stopStatement ( ) ;
233
-
234
- await eventually ( ( ) => {
235
- assert . equal ( ctx . flinkSqlStatementsApi . updateSqlv1Statement . callCount , 3 ) ;
236
- } ) ;
237
- } ) ;
238
-
239
- it ( "should handle StopStatement message with max retries exceeded" , async ( ) => {
240
- // Mock the updateSqlv1Statement to always fail with 409
241
- const responseError = createResponseError ( 409 , "Conflict" , "{}" ) ;
242
- ctx . flinkSqlStatementsApi . updateSqlv1Statement . rejects ( responseError ) ;
243
-
244
- // Call stop statement and expect it to throw after max retries
245
- await vm . stopStatement ( ) ;
246
- assert . equal ( ctx . flinkSqlStatementsApi . updateSqlv1Statement . callCount , 5 ) ;
247
- } ) ;
248
-
249
222
it ( "should stop polling when statement is not results viewable" , async ( ) => {
250
223
assert . ok ( ctx . manager [ "_pollingInterval" ] as NodeJS . Timeout ) ;
251
224
@@ -276,16 +249,57 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
276
249
} ) ;
277
250
278
251
describe ( "with fetchResults not running in a setInterval" , ( ) => {
252
+ let clock : sinon . SinonFakeTimers ;
253
+
279
254
beforeEach ( ( ) => {
280
255
clearInterval ( ctx . manager [ "_pollingInterval" ] ) ;
281
256
ctx . manager [ "_pollingInterval" ] = undefined ;
282
-
283
257
ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . resetHistory ( ) ;
258
+
259
+ // TODO: Eventually, the idea would be to move this fake timer up to
260
+ // the top-level describe's beforeEach.
261
+ // See https://github.com/confluentinc/vscode/issues/1807
262
+ clock = sinon . useFakeTimers ( { shouldClearNativeTimers : true } ) ;
284
263
} ) ;
285
264
286
- it ( "should abort in-flight get results when stopping statement" , async ( ) => {
287
- // Clear the polling interval so we can control when fetchResults is called
265
+ afterEach ( ( ) => {
266
+ clock . restore ( ) ;
267
+ } ) ;
268
+
269
+ it ( "should handle StopStatement message with retries" , async ( ) => {
270
+ // Mock the updateSqlv1Statement to fail with 409 twice then succeed
271
+ ctx . flinkSqlStatementsApi . updateSqlv1Statement
272
+ . onFirstCall ( )
273
+ . rejects ( createResponseError ( 409 , "Conflict" , "{}" ) ) ;
274
+ ctx . flinkSqlStatementsApi . updateSqlv1Statement
275
+ . onSecondCall ( )
276
+ . rejects ( createResponseError ( 409 , "Conflict" , "{}" ) ) ;
277
+ ctx . flinkSqlStatementsApi . updateSqlv1Statement . onThirdCall ( ) . resolves ( ) ;
278
+
279
+ const stopPromise = vm . stopStatement ( ) ;
280
+
281
+ await clock . tickAsync ( 3000 ) ;
282
+
283
+ await stopPromise ;
284
+
285
+ assert . equal ( ctx . flinkSqlStatementsApi . updateSqlv1Statement . callCount , 3 ) ;
286
+ } ) ;
287
+
288
+ it ( "should handle StopStatement message with max retries exceeded" , async ( ) => {
289
+ // Mock the updateSqlv1Statement to always fail with 409
290
+ const responseError = createResponseError ( 409 , "Conflict" , "{}" ) ;
291
+ ctx . flinkSqlStatementsApi . updateSqlv1Statement . rejects ( responseError ) ;
292
+
293
+ // Call stop statement and expect it to throw after max retries
294
+ const stopPromise = vm . stopStatement ( ) ;
295
+
296
+ await clock . tickAsync ( 61 * 500 ) ;
288
297
298
+ await stopPromise ;
299
+ assert . equal ( ctx . flinkSqlStatementsApi . updateSqlv1Statement . callCount , 60 ) ;
300
+ } ) ;
301
+
302
+ it ( "should abort in-flight get results when stopping statement" , async ( ) => {
289
303
// Create a promise that we can reject manually to simulate the aborted request
290
304
let rejectRequest : ( reason : Error ) => void ;
291
305
const requestPromise = new Promise < GetSqlv1StatementResult200Response > ( ( _resolve , reject ) => {
@@ -350,12 +364,17 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
350
364
} ) ;
351
365
352
366
// Trigger a fetch
353
- await ctx . manager . fetchResults ( ) ;
367
+ const fetchPromise = ctx . manager . fetchResults ( ) ;
368
+
369
+ // Advance time to trigger retries
370
+ await clock . tickAsync ( 500 ) ;
371
+ await clock . tickAsync ( 500 ) ;
372
+ await clock . tickAsync ( 500 ) ;
373
+
374
+ await fetchPromise ;
354
375
355
376
// Verify the request was made 3 times
356
- await eventually ( ( ) => {
357
- assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 3 ) ;
358
- } ) ;
377
+ assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 3 ) ;
359
378
} ) ;
360
379
361
380
it ( "should handle fetch results with max retries exceeded" , async ( ) => {
@@ -364,13 +383,16 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
364
383
ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . rejects ( responseError ) ;
365
384
366
385
// Trigger a fetch
367
- await ctx . manager . fetchResults ( ) ;
386
+ const fetchPromise = ctx . manager . fetchResults ( ) ;
368
387
369
- await eventually ( ( ) => {
370
- assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 5 ) ;
371
- // Verify error state is set
372
- assert . ok ( ctx . manager [ "_latestError" ] ( ) ) ;
373
- } ) ;
388
+ // Advance time to trigger all retries
389
+ await clock . tickAsync ( 61 * 500 ) ;
390
+
391
+ await fetchPromise ;
392
+
393
+ assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 60 ) ;
394
+ // Verify error state is set
395
+ assert . ok ( ctx . manager [ "_latestError" ] ( ) ) ;
374
396
} ) ;
375
397
376
398
it ( "should not retry on non-409 errors during fetch" , async ( ) => {
@@ -379,13 +401,16 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
379
401
ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . rejects ( responseError ) ;
380
402
381
403
// Trigger a fetch
382
- await ctx . manager . fetchResults ( ) ;
404
+ const fetchPromise = ctx . manager . fetchResults ( ) ;
383
405
384
- await eventually ( ( ) => {
385
- assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 1 ) ;
386
- // Verify error state is set
387
- assert . ok ( ctx . manager [ "_latestError" ] ( ) ) ;
388
- } ) ;
406
+ // Advance time to ensure no retries happen
407
+ await clock . tickAsync ( 1000 ) ;
408
+
409
+ await fetchPromise ;
410
+
411
+ assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 1 ) ;
412
+ // Verify error state is set
413
+ assert . ok ( ctx . manager [ "_latestError" ] ( ) ) ;
389
414
} ) ;
390
415
391
416
it ( "should only allow one instance of fetchResults to run at a time" , async ( ) => {
@@ -405,11 +430,10 @@ describe("FlinkStatementResultsViewModel and FlinkStatementResultsManager", () =
405
430
ctx . manager . fetchResults ( ) ,
406
431
ctx . manager . fetchResults ( ) ,
407
432
ctx . manager . fetchResults ( ) ,
408
- ctx . manager . fetchResults ( ) ,
409
433
] ;
410
434
411
- // Wait a bit to ensure all calls have started
412
- await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
435
+ // Advance time to ensure all calls have started
436
+ await clock . tickAsync ( 50 ) ;
413
437
414
438
// Verify only one API call was made
415
439
assert . equal ( ctx . flinkSqlStatementResultsApi . getSqlv1StatementResult . callCount , 1 ) ;
0 commit comments