process/src/process.tests/CancellationTests.cs
Louis Seubert 1e4687aff6
Some checks failed
default / dotnet-default-workflow (push) Failing after 54s
build: initial project release
2026-01-20 22:58:15 +01:00

181 lines
No EOL
4.5 KiB
C#

// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
using System.Text;
using Geekeey.Process.Buffered;
namespace Geekeey.Process.Tests;
internal sealed class CancellationTests
{
private static Action<string> NotifyOnStart(out TaskCompletionSource tcs)
{
// run the continuation async on the thread pool to allow the io reader to complete
var source = tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
return line =>
{
if (line.Contains("Sleeping for", StringComparison.OrdinalIgnoreCase))
{
source.TrySetResult();
}
};
}
[Test]
public async Task I_can_execute_a_command_and_cancel_it_immediately()
{
// Arrange
using var cts = new CancellationTokenSource();
var stdout = new StringBuilder();
var target = PipeTarget.Merge(
PipeTarget.ToDelegate(NotifyOnStart(out var tcs)),
PipeTarget.ToStringBuilder(stdout)
);
var cmd = new Command(Testing.Fixture.Program.FilePath)
.WithArguments(["sleep", "00:00:30"]) |
target;
// Act
var task = cmd.ExecuteAsync(cts.Token);
await tcs.Task;
await cts.CancelAsync();
// Assert
await Assert.That(async () => await task).Throws<OperationCanceledException>();
using (Assert.Multiple())
{
await Assert.That(ProcessTree.HasExited(task.ProcessId)).IsTrue();
await Assert.That(stdout.ToString()).Contains("Sleeping for");
await Assert.That(stdout.ToString()).DoesNotContain("Done.");
}
}
[Test]
public async Task I_can_execute_a_command_and_kill_it_immediately()
{
// Arrange
var stdout = new StringBuilder();
var target = PipeTarget.Merge(
PipeTarget.ToDelegate(NotifyOnStart(out var tcs)),
PipeTarget.ToStringBuilder(stdout)
);
var cmd = new Command(Testing.Fixture.Program.FilePath)
.WithArguments(["sleep", "00:00:30"]) |
target;
// Act
var task = cmd.ExecuteAsync();
await tcs.Task;
task.Kill();
// Assert
await Assert.That(async () => await task).Throws<CommandExecutionException>();
using (Assert.Multiple())
{
await Assert.That(ProcessTree.HasExited(task.ProcessId)).IsTrue();
await Assert.That(stdout.ToString()).Contains("Sleeping for");
await Assert.That(stdout.ToString()).DoesNotContain("Done.");
}
}
[Test]
public async Task I_can_execute_a_command_with_buffering_and_kill_it_immediately()
{
// Arrange
var stdout = new StringBuilder();
var target = PipeTarget.Merge(
PipeTarget.ToDelegate(NotifyOnStart(out var tcs)),
PipeTarget.ToStringBuilder(stdout)
);
var cmd = new Command(Testing.Fixture.Program.FilePath)
.WithArguments(["sleep", "00:00:30"]) |
target;
// Act
var task = cmd.ExecuteBufferedAsync();
await tcs.Task;
task.Kill();
// Assert
await Assert.That(async () => await task).Throws<CommandExecutionException>();
using (Assert.Multiple())
{
await Assert.That(ProcessTree.HasExited(task.ProcessId)).IsTrue();
await Assert.That(stdout.ToString()).Contains("Sleeping for");
await Assert.That(stdout.ToString()).DoesNotContain("Done.");
}
}
[Test]
public async Task I_can_execute_a_command_and_interrupt_it_immediately()
{
// Arrange
var stdout = new StringBuilder();
var target = PipeTarget.Merge(
PipeTarget.ToDelegate(NotifyOnStart(out var tcs)),
PipeTarget.ToStringBuilder(stdout)
);
var cmd = new Command(Testing.Fixture.Program.FilePath)
.WithArguments(["sleep", "00:00:30"]) |
target;
// Act
var task = cmd.ExecuteAsync();
await tcs.Task;
task.Interrupt();
// Assert
await Assert.That(async () => await task).ThrowsNothing();
using (Assert.Multiple())
{
await Assert.That(ProcessTree.HasExited(task.ProcessId)).IsTrue();
await Assert.That(stdout.ToString()).Contains("Sleeping for");
await Assert.That(stdout.ToString()).Contains("Done.");
}
}
[Test]
public async Task I_can_execute_a_command_with_buffering_and_interrupt_it_immediately()
{
// Arrange
var stdout = new StringBuilder();
var target = PipeTarget.Merge(
PipeTarget.ToDelegate(NotifyOnStart(out var tcs)),
PipeTarget.ToStringBuilder(stdout)
);
var cmd = new Command(Testing.Fixture.Program.FilePath)
.WithArguments(["sleep", "00:00:30"]) |
target;
// Act
var task = cmd.ExecuteBufferedAsync();
await tcs.Task;
task.Interrupt();
// Assert
await Assert.That(async () => await task).ThrowsNothing();
using (Assert.Multiple())
{
await Assert.That(ProcessTree.HasExited(task.ProcessId)).IsTrue();
await Assert.That(stdout.ToString()).Contains("Sleeping for");
await Assert.That(stdout.ToString()).Contains("Done.");
}
}
}