@@ -272,10 +272,11 @@ public async Task WorkerProcess_WaitForExit_NotStarted_Throws()
272272 public async Task WorkerProcess_WaitForExit_Success_TaskCompletes ( )
273273 {
274274 // arrange
275- using Process process = GetProcess ( exitCode : 0 ) ;
276- _hostProcessMonitorMock . Setup ( m => m . RegisterChildProcess ( process ) ) ;
277- _hostProcessMonitorMock . Setup ( m => m . UnregisterChildProcess ( process ) ) ;
278- _workerProcessFactory . Setup ( m => m . CreateWorkerProcess ( It . IsNotNull < WorkerContext > ( ) ) ) . Returns ( process ) ;
275+ await using ProcessWrapper wrapper = new ( exitCode : 0 ) ;
276+ _hostProcessMonitorMock . Setup ( m => m . RegisterChildProcess ( wrapper . Process ) ) ;
277+ _hostProcessMonitorMock . Setup ( m => m . UnregisterChildProcess ( wrapper . Process ) ) ;
278+ _workerProcessFactory . Setup ( m => m . CreateWorkerProcess ( It . IsNotNull < WorkerContext > ( ) ) )
279+ . Returns ( wrapper . Process ) ;
279280 using var rpcWorkerProcess = GetRpcWorkerConfigProcess (
280281 TestHelpers . GetTestWorkerConfigsWithExecutableWorkingDirectory ( ) . ElementAt ( 0 ) ) ;
281282
@@ -290,10 +291,11 @@ public async Task WorkerProcess_WaitForExit_Success_TaskCompletes()
290291 public async Task WorkerProcess_WaitForExit_Error_Rethrows ( )
291292 {
292293 // arrange
293- using Process process = GetProcess ( exitCode : - 1 ) ;
294- _hostProcessMonitorMock . Setup ( m => m . RegisterChildProcess ( process ) ) ;
295- _hostProcessMonitorMock . Setup ( m => m . UnregisterChildProcess ( process ) ) ;
296- _workerProcessFactory . Setup ( m => m . CreateWorkerProcess ( It . IsNotNull < WorkerContext > ( ) ) ) . Returns ( process ) ;
294+ await using ProcessWrapper wrapper = new ( exitCode : - 1 ) ;
295+ _hostProcessMonitorMock . Setup ( m => m . RegisterChildProcess ( wrapper . Process ) ) ;
296+ _hostProcessMonitorMock . Setup ( m => m . UnregisterChildProcess ( wrapper . Process ) ) ;
297+ _workerProcessFactory . Setup ( m => m . CreateWorkerProcess ( It . IsNotNull < WorkerContext > ( ) ) )
298+ . Returns ( wrapper . Process ) ;
297299 using var rpcWorkerProcess = GetRpcWorkerConfigProcess (
298300 TestHelpers . GetTestWorkerConfigsWithExecutableWorkingDirectory ( ) . ElementAt ( 0 ) ) ;
299301
@@ -310,13 +312,33 @@ private static Process GetProcess(int exitCode)
310312 {
311313 StartInfo = new ( )
312314 {
313- WindowStyle = ProcessWindowStyle . Hidden ,
314315 FileName = OperatingSystem . IsWindows ( ) ? "cmd" : "bash" ,
315316 Arguments = OperatingSystem . IsWindows ( ) ? $ "/C exit { exitCode } " : $ "-c \" exit { exitCode } \" ",
316317 RedirectStandardError = true ,
317318 RedirectStandardOutput = true ,
319+ CreateNoWindow = true ,
320+ ErrorDialog = false ,
321+ UseShellExecute = false
318322 }
319323 } ;
320324 }
325+
326+ private class ProcessWrapper ( int exitCode ) : IAsyncDisposable
327+ {
328+ public Process Process { get ; } = GetProcess ( exitCode ) ;
329+
330+ public async ValueTask DisposeAsync ( )
331+ {
332+ if ( ! Process . HasExited )
333+ {
334+ // We need to kill the entire process tree to ensure
335+ // CI tests don't hang due to child processes lingering around.
336+ Process . Kill ( entireProcessTree : true ) ;
337+ await Process . WaitForExitAsync ( ) ;
338+ }
339+
340+ Process . Dispose ( ) ;
341+ }
342+ }
321343 }
322344}
0 commit comments