From e8af1141cb6d65b769cad14d3706bd75c0acb006 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 16 Jan 2018 13:57:09 -0800 Subject: [PATCH] Attempt to fix Razor CI flakiness We're seeing some test failures on the CI where the build has no output. Sure enough, using Process.Exited is trap. It doesn't guarantee that all of the output has been written when it's trigger. This is a different approach that shouldn't suffer from the same problem. --- .../IntegrationTests/MSBuildProcessManager.cs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildProcessManager.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildProcessManager.cs index fa3e1e11f3..7d63028cf5 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildProcessManager.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildProcessManager.cs @@ -48,11 +48,9 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests StartInfo = processStartInfo, EnableRaisingEvents = true, }; - - var completionSource = new TaskCompletionSource(); + var output = new StringBuilder(); - - process.Exited += Process_Exited; + process.ErrorDataReceived += Process_ErrorDataReceived; process.OutputDataReceived += Process_OutputDataReceived; @@ -80,13 +78,25 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}."); }); - return Task.WhenAny(completionSource.Task, timeoutTask).Unwrap(); - - void Process_Exited(object sender, EventArgs e) + var waitTask = Task.Run(() => { + // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously + // this code used Process.Exited, which could result in us missing some output due to the ordering of + // events. + // + // See the remarks here: https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx + if (!process.WaitForExit(Int32.MaxValue)) + { + // unreachable - the timeoutTask will kill the process before this happens. + throw new TimeoutException(); + } + + process.WaitForExit(); var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString()); - completionSource.SetResult(result); - } + return result; + }); + + return Task.WhenAny(waitTask, timeoutTask).Unwrap(); void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e) {