using ClaudeDo.Worker.Queue; using Microsoft.Extensions.Logging.Abstractions; namespace ClaudeDo.Worker.Tests.Queue; public sealed class RunCancellationRegistryTests { [Fact] public void TryCancel_RegisteredTask_CancelsAndReturnsTrue() { var sut = new RunCancellationRegistry(NullLogger.Instance); using var cts = new CancellationTokenSource(); Assert.True(sut.Register("t1", cts)); Assert.True(sut.TryCancel("t1")); Assert.True(cts.IsCancellationRequested); } [Fact] public void TryCancel_UnknownTask_ReturnsFalse() { var sut = new RunCancellationRegistry(NullLogger.Instance); Assert.False(sut.TryCancel("nope")); } [Fact] public void Register_SecondCallForSameTask_RefusesAndKeepsFirstRegistration() { // A double-dispatch (e.g. RunNow racing the queue picker for the same task) must not // let the second registration silently clobber the first — that would leave CancelAsync // pointing at the wrong (or already-finished) CTS. var sut = new RunCancellationRegistry(NullLogger.Instance); using var first = new CancellationTokenSource(); using var second = new CancellationTokenSource(); Assert.True(sut.Register("t1", first)); Assert.False(sut.Register("t1", second)); Assert.True(sut.TryCancel("t1")); Assert.True(first.IsCancellationRequested); Assert.False(second.IsCancellationRequested); } [Fact] public void Unregister_RemovesOnlyTheGivenRegistration() { var sut = new RunCancellationRegistry(NullLogger.Instance); using var first = new CancellationTokenSource(); sut.Register("t1", first); sut.Unregister("t1", first); // Slot is free again once the run that held it cleans up properly, so a genuine // sequential re-run can register a fresh CTS under the same task id. using var second = new CancellationTokenSource(); Assert.True(sut.Register("t1", second)); Assert.True(sut.TryCancel("t1")); Assert.True(second.IsCancellationRequested); } [Fact] public void TryCancel_DisposedCts_ReturnsFalse() { var sut = new RunCancellationRegistry(NullLogger.Instance); var cts = new CancellationTokenSource(); sut.Register("t1", cts); cts.Dispose(); Assert.False(sut.TryCancel("t1")); } }