4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Net . Http ;
7
+ using System . Runtime . CompilerServices ;
7
8
using System . Threading ;
8
9
using System . Threading . Tasks ;
9
10
using Microsoft . Extensions . DependencyInjection ;
@@ -356,6 +357,40 @@ public async Task Factory_CleanupCycle_DisposesEligibleHandler()
356
357
EnableCleanupTimer = true ,
357
358
} ;
358
359
360
+ var cleanupEntry = await SimulateClientUse_Factory_CleanupCycle_DisposesEligibleHandler ( factory ) ;
361
+
362
+ // Being pretty conservative here because we want this test to be reliable,
363
+ // and it depends on the GC and timing.
364
+ for ( var i = 0 ; i < 3 ; i ++ )
365
+ {
366
+ GC . Collect ( ) ;
367
+ GC . WaitForPendingFinalizers ( ) ;
368
+ GC . Collect ( ) ;
369
+
370
+ if ( cleanupEntry . CanDispose )
371
+ {
372
+ break ;
373
+ }
374
+
375
+ await Task . Delay ( TimeSpan . FromSeconds ( 1 ) ) ;
376
+ }
377
+
378
+ Assert . True ( cleanupEntry . CanDispose , "Cleanup entry disposable" ) ;
379
+
380
+ // Act
381
+ factory . CleanupTimer_Tick ( ) ;
382
+
383
+ // Assert
384
+ Assert . Empty ( factory . _expiredHandlers ) ;
385
+ Assert . Equal ( 1 , disposeHandler . DisposeCount ) ;
386
+ Assert . False ( factory . CleanupTimerStarted . IsSet , "Cleanup timer not started" ) ;
387
+ }
388
+
389
+ // Seprate to avoid the HttpClient getting its lifetime extended by
390
+ // the state machine of the test.
391
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
392
+ private async Task < ExpiredHandlerTrackingEntry > SimulateClientUse_Factory_CleanupCycle_DisposesEligibleHandler ( TestHttpClientFactory factory )
393
+ {
359
394
// Create a handler and move it to the expired state
360
395
var client1 = factory . CreateClient ( "github" ) ;
361
396
@@ -372,19 +407,8 @@ public async Task Factory_CleanupCycle_DisposesEligibleHandler()
372
407
// the factory isn't keeping any references.
373
408
kvp = default ;
374
409
client1 = null ;
375
- GC . Collect ( ) ;
376
- GC . WaitForPendingFinalizers ( ) ;
377
- GC . Collect ( ) ;
378
410
379
- Assert . True ( cleanupEntry . CanDispose , "Cleanup entry disposable" ) ;
380
-
381
- // Act
382
- factory . CleanupTimer_Tick ( ) ;
383
-
384
- // Assert
385
- Assert . Empty ( factory . _expiredHandlers ) ;
386
- Assert . Equal ( 1 , disposeHandler . DisposeCount ) ;
387
- Assert . False ( factory . CleanupTimerStarted . IsSet , "Cleanup timer not started" ) ;
411
+ return cleanupEntry ;
388
412
}
389
413
390
414
[ Fact ]
@@ -403,7 +427,7 @@ public async Task Factory_CleanupCycle_DisposesLiveHandler()
403
427
EnableCleanupTimer = true ,
404
428
} ;
405
429
406
- var cleanupEntry = await SimulateClientUse ( factory , disposeHandler ) ;
430
+ var cleanupEntry = await SimulateClientUse_Factory_CleanupCycle_DisposesLiveHandler ( factory , disposeHandler ) ;
407
431
408
432
// Being pretty conservative here because we want this test to be reliable,
409
433
// and it depends on the GC and timing.
@@ -432,7 +456,10 @@ public async Task Factory_CleanupCycle_DisposesLiveHandler()
432
456
Assert . False ( factory . CleanupTimerStarted . IsSet , "Cleanup timer not started" ) ;
433
457
}
434
458
435
- private async Task < ExpiredHandlerTrackingEntry > SimulateClientUse (
459
+ // Seprate to avoid the HttpClient getting its lifetime extended by
460
+ // the state machine of the test.
461
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
462
+ private async Task < ExpiredHandlerTrackingEntry > SimulateClientUse_Factory_CleanupCycle_DisposesLiveHandler (
436
463
TestHttpClientFactory factory ,
437
464
DisposeTrackingHandler disposeHandler )
438
465
{
0 commit comments