Fix flaky process output reading for dotnet-watch tests (#7173)
This commit is contained in:
parent
9c41d5b48f
commit
2365dced43
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue