Fix flaky process output reading for dotnet-watch tests (#7173)

This commit is contained in:
BrennanConroy 2019-02-08 14:37:53 -08:00 committed by GitHub
parent 9c41d5b48f
commit 2365dced43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 34 deletions

View File

@ -19,7 +19,8 @@
<Repository>%(RepositoryBuildOrder.Identity)</Repository> <Repository>%(RepositoryBuildOrder.Identity)</Repository>
<AdditionalProperties> <AdditionalProperties>
RepositoryToBuild=%(RepositoryBuildOrder.Identity); RepositoryToBuild=%(RepositoryBuildOrder.Identity);
BuildRepositoryRoot=$([MSBuild]::NormalizeDirectory(%(RepositoryBuildOrder.RootPath))) BuildRepositoryRoot=$([MSBuild]::NormalizeDirectory(%(RepositoryBuildOrder.RootPath)));
SkipTests=%(RepositoryBuildOrder.SkipTests)
</AdditionalProperties> </AdditionalProperties>
</BatchedRepository> </BatchedRepository>
</ItemGroup> </ItemGroup>
@ -171,7 +172,7 @@
<Message Text="============ Testing $(RepositoryToBuild) ============" Importance="High" /> <Message Text="============ Testing $(RepositoryToBuild) ============" Importance="High" />
<Exec Condition="'$(SkipTestsDueToMissingSharedFx)' != 'true' " <Exec Condition="'$(SkipTestsDueToMissingSharedFx)' != 'true' AND '$(SkipTests)' != 'true'"
Command="./$(_BuildScriptToExecute) -Path $(BuildRepositoryRoot) $(BuildArguments)" Command="./$(_BuildScriptToExecute) -Path $(BuildRepositoryRoot) $(BuildArguments)"
IgnoreStandardErrorWarningFormat="true" IgnoreStandardErrorWarningFormat="true"
WorkingDirectory="$(RepositoryRoot)" WorkingDirectory="$(RepositoryRoot)"
@ -182,7 +183,7 @@
<CallTarget Targets="_RestoreOriginalRepoLockFile" /> <CallTarget Targets="_RestoreOriginalRepoLockFile" />
<ItemGroup> <ItemGroup>
<RepositoryTestResult Update="$(RepositoryToBuild)" Success="true" Condition="'$(TestExitCode)' == '0' OR '$(SkipTestsDueToMissingSharedFx)' == 'true' " /> <RepositoryTestResult Update="$(RepositoryToBuild)" Success="true" Condition="'$(TestExitCode)' == '0' OR '$(SkipTestsDueToMissingSharedFx)' == 'true' OR '$(SkipTests)' == 'true' " />
</ItemGroup> </ItemGroup>
<Message Text="============ Done testing $(RepositoryToBuild) ============" Importance="High" /> <Message Text="============ Done testing $(RepositoryToBuild) ============" Importance="High" />

View File

@ -7,7 +7,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<RepositoryBuildOrder Include="EntityFrameworkCore" Order="8" /> <RepositoryBuildOrder Include="EntityFrameworkCore" Order="8" SkipTests="true" />
<RepositoryBuildOrder Include="Templating" Order="17" RootPath="$(RepositoryRoot)src\Templating\" /> <RepositoryBuildOrder Include="Templating" Order="17" RootPath="$(RepositoryRoot)src\Templating\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -37,17 +37,31 @@ namespace Microsoft.DotNet.Watcher.Internal
{ {
cancellationToken.Register(() => processState.TryKill()); cancellationToken.Register(() => processState.TryKill());
process.OutputDataReceived += (_, a) =>
{
if (!string.IsNullOrEmpty(a.Data))
{
processSpec.OutputCapture.AddLine(a.Data);
}
};
process.ErrorDataReceived += (_, a) =>
{
if (!string.IsNullOrEmpty(a.Data))
{
processSpec.OutputCapture.AddLine(a.Data);
}
};
stopwatch.Start(); stopwatch.Start();
process.Start(); process.Start();
_reporter.Verbose($"Started '{processSpec.Executable}' with process id {process.Id}"); _reporter.Verbose($"Started '{processSpec.Executable}' with process id {process.Id}");
if (processSpec.IsOutputCaptured) if (processSpec.IsOutputCaptured)
{ {
await Task.WhenAll( process.BeginErrorReadLine();
processState.Task, process.BeginOutputReadLine();
ConsumeStreamAsync(process.StandardOutput, processSpec.OutputCapture.AddLine), await processState.Task;
ConsumeStreamAsync(process.StandardError, processSpec.OutputCapture.AddLine)
);
} }
else else
{ {
@ -86,15 +100,6 @@ namespace Microsoft.DotNet.Watcher.Internal
return process; return process;
} }
private static async Task ConsumeStreamAsync(StreamReader reader, Action<string> consume)
{
string line;
while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null)
{
consume?.Invoke(line);
}
}
private class ProcessState : IDisposable private class ProcessState : IDisposable
{ {
private readonly IReporter _reporter; private readonly IReporter _reporter;

View File

@ -49,19 +49,8 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
await _app.IsWaitingForFileChange(); await _app.IsWaitingForFileChange();
try File.SetLastWriteTime(source, DateTime.Now);
{ await _app.HasRestarted(TimeSpan.FromMinutes(1));
File.SetLastWriteTime(source, DateTime.Now);
await _app.HasRestarted();
}
catch (Exception ex)
{
_logger.WriteLine("Retrying. First attempt to restart app failed: " + ex.Message);
// retry
File.SetLastWriteTime(source, DateTime.Now);
await _app.HasRestarted();
}
} }
} }

View File

@ -0,0 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]

View File

@ -42,7 +42,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
public string SourceDirectory { get; } public string SourceDirectory { get; }
public Task HasRestarted() public Task HasRestarted()
=> Process.GetOutputLineAsync(StartedMessage, DefaultMessageTimeOut); => HasRestarted(DefaultMessageTimeOut);
public Task HasRestarted(TimeSpan timeout)
=> Process.GetOutputLineAsync(StartedMessage, timeout);
public async Task HasExited() public async Task HasExited()
{ {
@ -50,9 +53,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
await Process.GetOutputLineStartsWithAsync(WatchExitedMessage, DefaultMessageTimeOut); await Process.GetOutputLineStartsWithAsync(WatchExitedMessage, DefaultMessageTimeOut);
} }
public async Task IsWaitingForFileChange() public Task IsWaitingForFileChange()
{ {
await Process.GetOutputLineStartsWithAsync(WaitingForFileChangeMessage, DefaultMessageTimeOut); return Process.GetOutputLineStartsWithAsync(WaitingForFileChangeMessage, DefaultMessageTimeOut);
} }
public bool UsePollingWatcher { get; set; } public bool UsePollingWatcher { get; set; }