Merge branch 'release/2.2'

This commit is contained in:
Nate McMaster 2018-10-02 09:23:42 -07:00
commit 1e41958884
No known key found for this signature in database
GPG Key ID: A778D9601BD78810
5 changed files with 58 additions and 26 deletions

View File

@ -10,6 +10,8 @@ namespace Microsoft.DotNet.Watcher.Internal
{ {
internal class DotnetFileWatcher : IFileSystemWatcher internal class DotnetFileWatcher : IFileSystemWatcher
{ {
private volatile bool _disposed;
private readonly Func<string, FileSystemWatcher> _watcherFactory; private readonly Func<string, FileSystemWatcher> _watcherFactory;
private FileSystemWatcher _fileSystemWatcher; private FileSystemWatcher _fileSystemWatcher;
@ -46,6 +48,11 @@ namespace Microsoft.DotNet.Watcher.Internal
private void WatcherErrorHandler(object sender, ErrorEventArgs e) private void WatcherErrorHandler(object sender, ErrorEventArgs e)
{ {
if (_disposed)
{
return;
}
var exception = e.GetException(); var exception = e.GetException();
// Win32Exception may be triggered when setting EnableRaisingEvents on a file system type // Win32Exception may be triggered when setting EnableRaisingEvents on a file system type
@ -62,6 +69,11 @@ namespace Microsoft.DotNet.Watcher.Internal
private void WatcherRenameHandler(object sender, RenamedEventArgs e) private void WatcherRenameHandler(object sender, RenamedEventArgs e)
{ {
if (_disposed)
{
return;
}
NotifyChange(e.OldFullPath); NotifyChange(e.OldFullPath);
NotifyChange(e.FullPath); NotifyChange(e.FullPath);
@ -79,6 +91,11 @@ namespace Microsoft.DotNet.Watcher.Internal
private void WatcherChangeHandler(object sender, FileSystemEventArgs e) private void WatcherChangeHandler(object sender, FileSystemEventArgs e)
{ {
if (_disposed)
{
return;
}
NotifyChange(e.FullPath); NotifyChange(e.FullPath);
} }
@ -98,15 +115,7 @@ namespace Microsoft.DotNet.Watcher.Internal
{ {
enableEvents = _fileSystemWatcher.EnableRaisingEvents; enableEvents = _fileSystemWatcher.EnableRaisingEvents;
_fileSystemWatcher.EnableRaisingEvents = false; DisposeInnerWatcher();
_fileSystemWatcher.Created -= WatcherChangeHandler;
_fileSystemWatcher.Deleted -= WatcherChangeHandler;
_fileSystemWatcher.Changed -= WatcherChangeHandler;
_fileSystemWatcher.Renamed -= WatcherRenameHandler;
_fileSystemWatcher.Error -= WatcherErrorHandler;
_fileSystemWatcher.Dispose();
} }
_fileSystemWatcher = _watcherFactory(BasePath); _fileSystemWatcher = _watcherFactory(BasePath);
@ -122,6 +131,19 @@ namespace Microsoft.DotNet.Watcher.Internal
} }
} }
private void DisposeInnerWatcher()
{
_fileSystemWatcher.EnableRaisingEvents = false;
_fileSystemWatcher.Created -= WatcherChangeHandler;
_fileSystemWatcher.Deleted -= WatcherChangeHandler;
_fileSystemWatcher.Changed -= WatcherChangeHandler;
_fileSystemWatcher.Renamed -= WatcherRenameHandler;
_fileSystemWatcher.Error -= WatcherErrorHandler;
_fileSystemWatcher.Dispose();
}
public bool EnableRaisingEvents public bool EnableRaisingEvents
{ {
get => _fileSystemWatcher.EnableRaisingEvents; get => _fileSystemWatcher.EnableRaisingEvents;
@ -130,7 +152,8 @@ namespace Microsoft.DotNet.Watcher.Internal
public void Dispose() public void Dispose()
{ {
_fileSystemWatcher.Dispose(); _disposed = true;
DisposeInnerWatcher();
} }
} }
} }

View File

@ -4,9 +4,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Microsoft.Extensions.CommandLineUtils; using Microsoft.Extensions.CommandLineUtils;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -80,25 +80,30 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
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."); _logger.WriteLine($"Waiting for output line [msg == '{message}']. Will wait for {timeout.TotalSeconds} sec.");
return await GetOutputLineAsync(m => string.Equals(m, message, StringComparison.Ordinal)).TimeoutAfter(timeout); var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);
return await GetOutputLineAsync($"[msg == '{message}']", m => string.Equals(m, message, StringComparison.Ordinal), cts.Token);
} }
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."); _logger.WriteLine($"Waiting for output line [msg.StartsWith('{message}')]. Will wait for {timeout.TotalSeconds} sec.");
return await GetOutputLineAsync(m => m != null && m.StartsWith(message, StringComparison.Ordinal)).TimeoutAfter(timeout); var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);
return await GetOutputLineAsync($"[msg.StartsWith('{message}')]", m => m != null && m.StartsWith(message, StringComparison.Ordinal), cts.Token);
} }
private async Task<string> GetOutputLineAsync(Predicate<string> predicate) private async Task<string> GetOutputLineAsync(string predicateName, Predicate<string> predicate, CancellationToken cancellationToken)
{ {
while (!_source.Completion.IsCompleted) while (!_source.Completion.IsCompleted)
{ {
while (await _source.OutputAvailableAsync()) while (await _source.OutputAvailableAsync(cancellationToken))
{ {
var next = await _source.ReceiveAsync(); var next = await _source.ReceiveAsync(cancellationToken);
_lines.Add(next); _lines.Add(next);
_logger.WriteLine($"{DateTime.Now}: recv: '{next}'"); var match = predicate(next);
if (predicate(next)) _logger.WriteLine($"{DateTime.Now}: recv: '{next}'. {(match ? "Matches" : "Does not match")} condition '{predicateName}'.");
if (match)
{ {
return next; return next;
} }
@ -108,14 +113,14 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
return null; return null;
} }
public async Task<IList<string>> GetAllOutputLines() public async Task<IList<string>> GetAllOutputLinesAsync(CancellationToken cancellationToken)
{ {
var lines = new List<string>(); var lines = new List<string>();
while (!_source.Completion.IsCompleted) while (!_source.Completion.IsCompleted)
{ {
while (await _source.OutputAvailableAsync()) while (await _source.OutputAvailableAsync(cancellationToken))
{ {
var next = await _source.ReceiveAsync(); var next = await _source.ReceiveAsync(cancellationToken);
_logger.WriteLine($"{DateTime.Now}: recv: '{next}'"); _logger.WriteLine($"{DateTime.Now}: recv: '{next}'");
lines.Add(next); lines.Add(next);
} }

View File

@ -13,10 +13,12 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
public class DotNetWatcherTests : IDisposable public class DotNetWatcherTests : IDisposable
{ {
private readonly ITestOutputHelper _logger;
private readonly KitchenSinkApp _app; private readonly KitchenSinkApp _app;
public DotNetWatcherTests(ITestOutputHelper logger) public DotNetWatcherTests(ITestOutputHelper logger)
{ {
_logger = logger;
_app = new KitchenSinkApp(logger); _app = new KitchenSinkApp(logger);
} }
@ -52,8 +54,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
File.SetLastWriteTime(source, DateTime.Now); File.SetLastWriteTime(source, DateTime.Now);
await _app.HasRestarted(); await _app.HasRestarted();
} }
catch catch (Exception ex)
{ {
_logger.WriteLine("Retrying. First attempt to restart app failed: " + ex.Message);
// retry // retry
File.SetLastWriteTime(source, DateTime.Now); File.SetLastWriteTime(source, DateTime.Now);
await _app.HasRestarted(); await _app.HasRestarted();

View File

@ -4,6 +4,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.DotNet.Watcher.Tools.Tests; using Microsoft.DotNet.Watcher.Tools.Tests;
using Xunit; using Xunit;
@ -101,7 +102,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
await _app.PrepareAsync(); await _app.PrepareAsync();
_app.Start(new [] { "--list" }); _app.Start(new [] { "--list" });
var lines = await _app.Process.GetAllOutputLines(); var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
var lines = await _app.Process.GetAllOutputLinesAsync(cts.Token);
var files = lines.Where(l => !l.StartsWith("watch :")); var files = lines.Where(l => !l.StartsWith("watch :"));
AssertEx.EqualFileList( AssertEx.EqualFileList(

View File

@ -39,9 +39,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
var pid2 = await _app.GetProcessId(); var pid2 = await _app.GetProcessId();
Assert.NotEqual(pid, pid2); Assert.NotEqual(pid, pid2);
// first app should have shut down
Assert.Throws<ArgumentException>(() => Process.GetProcessById(pid));
} }
[Fact] [Fact]