@@ -2283,6 +2283,44 @@ public async Task HttpSemaphore_RangeStrategy_HeldThroughProcessPartAsync()
22832283
22842284 #region Semaphore Release Error Path Tests
22852285
2286+ [ TestMethod ]
2287+ public async Task StartDownloadAsync_WaitForCapacityFails_DoesNotReleaseHttpSemaphore ( )
2288+ {
2289+ // Arrange - Test that semaphore is NOT released when it was never acquired
2290+ var httpThrottler = new SemaphoreSlim ( 2 , 2 ) ;
2291+ var initialCount = httpThrottler . CurrentCount ;
2292+
2293+ var mockDataHandler = new Mock < IPartDataHandler > ( ) ;
2294+
2295+ // WaitForCapacityAsync fails BEFORE HTTP semaphore is acquired
2296+ mockDataHandler
2297+ . Setup ( x => x . WaitForCapacityAsync ( It . IsAny < CancellationToken > ( ) ) )
2298+ . ThrowsAsync ( new InvalidOperationException ( "Simulated capacity wait failure" ) ) ;
2299+
2300+ var mockClient = MultipartDownloadTestHelpers . CreateMockS3Client ( ) ;
2301+ var request = MultipartDownloadTestHelpers . CreateOpenStreamRequest ( ) ;
2302+ var config = MultipartDownloadTestHelpers . CreateBufferedDownloadConfiguration ( ) ;
2303+ var coordinator = new MultipartDownloadManager (
2304+ mockClient . Object , request , config , mockDataHandler . Object , null , httpThrottler ) ;
2305+
2306+ // Act & Assert
2307+ try
2308+ {
2309+ await coordinator . StartDownloadAsync ( null , CancellationToken . None ) ;
2310+ Assert . Fail ( "Expected InvalidOperationException to be thrown" ) ;
2311+ }
2312+ catch ( InvalidOperationException ex )
2313+ {
2314+ Assert . AreEqual ( "Simulated capacity wait failure" , ex . Message ) ;
2315+ }
2316+
2317+ // Assert - Semaphore should NOT be released (it was never acquired)
2318+ Assert . AreEqual ( initialCount , httpThrottler . CurrentCount ,
2319+ "HTTP semaphore should NOT be released when it was never acquired (failed before WaitAsync)" ) ;
2320+
2321+ // Cleanup
2322+ httpThrottler . Dispose ( ) ;
2323+ }
22862324
22872325
22882326 [ TestMethod ]
0 commit comments