* [automation/dotnet] Start implementing structured event log support * Add Events and their models * Introduce new IStringToEnumConverter This is intended to be used for converting a non-standard enum names into corresponding enum values. The converter is utilized via StringToEnumJsonConverter with OperationType and DiffKind. * Add event-log support to up, refresh, destroy * Update event-log tests * Use lock instead of semaphore in EventLogWatcher * Add ChangeSummary to PreviewResult * Minor update * Add doc comments to Events * Use PropertyDiffModel in StepEventMetadataModel * Set Events to public * Set properties to public * Fix PreludeEvent.Config doc comment * Remove TODOs * Update Pulumi.Automation.xml * Set PULUMI_DEBUG_COMMANDs in Workspace. * Split Events and their models to separate files * Rename abbreviated Events * Remove CancelEventModel * Rename HandlesEvents test project and stack * Update CHANGELOG_PENDING.md * Rename abbreviated EngineEvent properties * Implement custom exceptions * Move event-log setup to LocalPulumiCmd * Update comments * Implement polling EventLogWatcher This replaces the previous watcher which utilized FileSystemWatcher. * Guard against onEvent throwing * Dispose CancellationTokenSource * WIP: try more direct error handling in EventLogWatcher * A bit more tests * Reformat * Update sdk/dotnet/Pulumi.Automation.Tests/EventLogWatcherTests.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Update sdk/dotnet/Pulumi.Automation/Events/EventLogWatcher.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Update sdk/dotnet/Pulumi.Automation/Events/EventLogWatcher.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Update sdk/dotnet/Pulumi.Automation.Tests/EventLogWatcherTests.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Update sdk/dotnet/Pulumi.Automation/Events/EventLogWatcher.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Update sdk/dotnet/Pulumi.Automation/Events/EventLogWatcher.cs Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com> * Make race condition workaround more explicit * Untabify * Remove unnecessary using and change String to string * Update doc comments on Events Co-authored-by: Anton Tayanovskyy <anton@pulumi.com> Co-authored-by: Anton Tayanovskyy <anton.tayanovskyy@gmail.com>
102 lines
2.8 KiB
C#
102 lines
2.8 KiB
C#
// Copyright 2016-2021, Pulumi Corporation
|
|
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.IO;
|
|
using System;
|
|
using Pulumi.Automation.Events;
|
|
using Xunit;
|
|
|
|
namespace Pulumi.Automation.Tests
|
|
{
|
|
|
|
public class EventLogWatcherTests
|
|
{
|
|
|
|
[Fact]
|
|
public async Task ReceivesBasicEvent()
|
|
{
|
|
using var fx = new Fixture();
|
|
await fx.Write("{}");
|
|
await fx.Watcher.Stop();
|
|
Assert.Equal(1, fx.EventCounter);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReceivesManyBasicEvents()
|
|
{
|
|
using var fx = new Fixture();
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
await fx.Write("{}");
|
|
}
|
|
await fx.Watcher.Stop();
|
|
Assert.Equal(10, fx.EventCounter);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PropagatesUserExceptionsToCaller()
|
|
{
|
|
using var fx = new Fixture();
|
|
|
|
fx.Action = ev =>
|
|
{
|
|
throw new MyException();
|
|
};
|
|
|
|
await fx.Write("{}");
|
|
|
|
await Assert.ThrowsAsync<MyException>(async () =>
|
|
{
|
|
await fx.Watcher.Stop();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PermitsUserInitiatedCancellation()
|
|
{
|
|
using var fx = new Fixture();
|
|
fx.CancellationTokenSource.Cancel();
|
|
await fx.Watcher.AwaitPollingTask();
|
|
}
|
|
|
|
private class MyException : Exception { }
|
|
|
|
private class Fixture : IDisposable
|
|
{
|
|
public int EventCounter;
|
|
public string LogFileName { get; }
|
|
public StreamWriter Writer { get; }
|
|
public EventLogWatcher Watcher { get; }
|
|
public CancellationTokenSource CancellationTokenSource { get; }
|
|
|
|
public Action<EngineEvent>? Action { get; set; }
|
|
public Fixture()
|
|
{
|
|
this.CancellationTokenSource = new CancellationTokenSource();
|
|
this.LogFileName = Path.GetTempFileName();
|
|
this.Writer = new StreamWriter(this.LogFileName);
|
|
this.Watcher = new EventLogWatcher(this.LogFileName, onEvent: ev =>
|
|
{
|
|
Interlocked.Increment(ref this.EventCounter);
|
|
this.Action?.Invoke(ev);
|
|
}, this.CancellationTokenSource.Token);
|
|
}
|
|
|
|
public async Task Write(string text)
|
|
{
|
|
await this.Writer.WriteLineAsync(text);
|
|
await this.Writer.FlushAsync();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Watcher.Dispose();
|
|
this.CancellationTokenSource.Dispose();
|
|
this.Writer.Dispose();
|
|
File.Delete(this.LogFileName);
|
|
}
|
|
}
|
|
}
|
|
}
|