Converge implementations of AwaitableProcess and ProcessEx (#26069)

* Converge implementations of AwaitableProcess and ProcessEx

* dotnet-watch tests are running in to the same issue as GRPC tests (https://github.com/dotnet/aspnetcore/pull/20341/files).
This change carries over some of the patterns from the other type to remedy this issue.

* Revive dotnet-watch tests on OSX

* Remove build artifacts that were accidentally commited to source.
This commit is contained in:
Pranav K 2020-09-18 16:32:06 -07:00 committed by GitHub
parent 7afaf45b54
commit 140f177d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 45 deletions

View File

@ -15,6 +15,8 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
public class AwaitableProcess : IDisposable public class AwaitableProcess : IDisposable
{ {
private readonly object _testOutputLock = new object();
private Process _process; private Process _process;
private readonly ProcessSpec _spec; private readonly ProcessSpec _spec;
private readonly List<string> _lines; private readonly List<string> _lines;
@ -22,6 +24,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
private ITestOutputHelper _logger; private ITestOutputHelper _logger;
private TaskCompletionSource<int> _exited; private TaskCompletionSource<int> _exited;
private bool _started; private bool _started;
private bool _disposed;
public AwaitableProcess(ProcessSpec spec, ITestOutputHelper logger) public AwaitableProcess(ProcessSpec spec, ITestOutputHelper logger)
{ {
@ -29,7 +32,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
_logger = logger; _logger = logger;
_source = new BufferBlock<string>(); _source = new BufferBlock<string>();
_lines = new List<string>(); _lines = new List<string>();
_exited = new TaskCompletionSource<int>(); _exited = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
} }
public IEnumerable<string> Output => _lines; public IEnumerable<string> Output => _lines;
@ -72,17 +75,17 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
_process.ErrorDataReceived += OnData; _process.ErrorDataReceived += OnData;
_process.Exited += OnExit; _process.Exited += OnExit;
_logger.WriteLine($"{DateTime.Now}: starting process: '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'"); WriteTestOutput($"{DateTime.Now}: starting process: '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'");
_process.Start(); _process.Start();
_started = true; _started = true;
_process.BeginErrorReadLine(); _process.BeginErrorReadLine();
_process.BeginOutputReadLine(); _process.BeginOutputReadLine();
_logger.WriteLine($"{DateTime.Now}: process started: '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'"); WriteTestOutput($"{DateTime.Now}: process started: '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'");
} }
public async Task<string> GetOutputLineAsync(string message, TimeSpan timeout) public async Task<string> GetOutputLineAsync(string message, TimeSpan timeout)
{ {
_logger.WriteLine($"Waiting for output line [msg == '{message}']. Will wait for {timeout.TotalSeconds} sec."); WriteTestOutput($"Waiting for output line [msg == '{message}']. Will wait for {timeout.TotalSeconds} sec.");
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cts.CancelAfter(timeout); cts.CancelAfter(timeout);
return await GetOutputLineAsync($"[msg == '{message}']", m => string.Equals(m, message, StringComparison.Ordinal), cts.Token); return await GetOutputLineAsync($"[msg == '{message}']", m => string.Equals(m, message, StringComparison.Ordinal), cts.Token);
@ -90,7 +93,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
public async Task<string> GetOutputLineStartsWithAsync(string message, TimeSpan timeout) public async Task<string> GetOutputLineStartsWithAsync(string message, TimeSpan timeout)
{ {
_logger.WriteLine($"Waiting for output line [msg.StartsWith('{message}')]. Will wait for {timeout.TotalSeconds} sec."); WriteTestOutput($"Waiting for output line [msg.StartsWith('{message}')]. Will wait for {timeout.TotalSeconds} sec.");
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cts.CancelAfter(timeout); cts.CancelAfter(timeout);
return await GetOutputLineAsync($"[msg.StartsWith('{message}')]", m => m != null && m.StartsWith(message, StringComparison.Ordinal), cts.Token); return await GetOutputLineAsync($"[msg.StartsWith('{message}')]", m => m != null && m.StartsWith(message, StringComparison.Ordinal), cts.Token);
@ -105,7 +108,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
var next = await _source.ReceiveAsync(cancellationToken); var next = await _source.ReceiveAsync(cancellationToken);
_lines.Add(next); _lines.Add(next);
var match = predicate(next); var match = predicate(next);
_logger.WriteLine($"{DateTime.Now}: recv: '{next}'. {(match ? "Matches" : "Does not match")} condition '{predicateName}'."); WriteTestOutput($"{DateTime.Now}: recv: '{next}'. {(match ? "Matches" : "Does not match")} condition '{predicateName}'.");
if (match) if (match)
{ {
return next; return next;
@ -124,7 +127,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
while (await _source.OutputAvailableAsync(cancellationToken)) while (await _source.OutputAvailableAsync(cancellationToken))
{ {
var next = await _source.ReceiveAsync(cancellationToken); var next = await _source.ReceiveAsync(cancellationToken);
_logger.WriteLine($"{DateTime.Now}: recv: '{next}'"); WriteTestOutput($"{DateTime.Now}: recv: '{next}'");
lines.Add(next); lines.Add(next);
} }
} }
@ -134,23 +137,40 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
private void OnData(object sender, DataReceivedEventArgs args) private void OnData(object sender, DataReceivedEventArgs args)
{ {
var line = args.Data ?? string.Empty; var line = args.Data ?? string.Empty;
_logger.WriteLine($"{DateTime.Now}: post: '{line}'");
WriteTestOutput($"{DateTime.Now}: post: '{line}'");
_source.Post(line); _source.Post(line);
} }
private void WriteTestOutput(string text)
{
lock (_testOutputLock)
{
if (!_disposed)
{
_logger.WriteLine(text);
}
}
}
private void OnExit(object sender, EventArgs args) private void OnExit(object sender, EventArgs args)
{ {
// Wait to ensure the process has exited and all output consumed // Wait to ensure the process has exited and all output consumed
_process.WaitForExit(); _process.WaitForExit();
_source.Complete(); _source.Complete();
_exited.TrySetResult(_process.ExitCode); _exited.TrySetResult(_process.ExitCode);
_logger.WriteLine($"Process {_process.Id} has exited"); WriteTestOutput($"Process {_process.Id} has exited");
} }
public void Dispose() public void Dispose()
{ {
_source.Complete(); _source.Complete();
lock (_testOutputLock)
{
_disposed = true;
}
if (_process != null) if (_process != null)
{ {
if (_started && !_process.HasExited) if (_started && !_process.HasExited)
@ -158,6 +178,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
_process.KillTree(); _process.KillTree();
} }
_process.CancelErrorRead();
_process.CancelOutputRead();
_process.ErrorDataReceived -= OnData; _process.ErrorDataReceived -= OnData;
_process.OutputDataReceived -= OnData; _process.OutputDataReceived -= OnData;
_process.Exited -= OnExit; _process.Exited -= OnExit;

View File

@ -1,4 +0,0 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")]

View File

@ -1,28 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyMetadataAttribute("SourceCommitUrl", "https://github.com/dotnet/aspnetcore/tree/")]
[assembly: System.Reflection.AssemblyMetadataAttribute("Serviceable", "True")]
[assembly: System.Reflection.AssemblyCompanyAttribute("Microsoft Corporation")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyCopyrightAttribute("© Microsoft Corporation. All rights reserved.")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("42.42.42.42424")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("5.0.0-dev")]
[assembly: System.Reflection.AssemblyProductAttribute("Microsoft ASP.NET Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("KitchenSink")]
[assembly: System.Reflection.AssemblyVersionAttribute("5.0.0.0")]
[assembly: System.Reflection.AssemblyMetadataAttribute("RepositoryUrl", "https://github.com/dotnet/aspnetcore")]
[assembly: System.Resources.NeutralResourcesLanguageAttribute("en-US")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -12,9 +12,6 @@
--> -->
<UseAspNetCoreSharedRuntime>true</UseAspNetCoreSharedRuntime> <UseAspNetCoreSharedRuntime>true</UseAspNetCoreSharedRuntime>
<DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp>true</DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp> <DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp>true</DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp>
<!-- Skipped due to https://github.com/dotnet/aspnetcore/issues/26061 -->
<SkipTests Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</SkipTests>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>