using ClawdDotNet.Core.Storage;
using ClawdDotNet.Core.Tasks;
using ClawdDotNet.Core.Tests.Infrastructure;
using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
namespace ClawdDotNet.Core.Tests.Tasks;
///
/// #689/#715: A status the run set itself is the run's word. An agent that escalates, or sets
/// its task to blocked to report up, must not see it overwritten with "done" when the run ends.
///
public sealed class RunSetStatusTests : IDisposable
{
private readonly string _directory = Path.Combine(Path.GetTempPath(), "clawd-tests", Guid.NewGuid().ToString("N"));
private readonly SqliteTaskRepository _repo;
private readonly FakeTimeProvider _clock = new(new DateTimeOffset(2027, 3, 10, 12, 0, 0, TimeSpan.Zero));
public RunSetStatusTests()
{
_repo = new SqliteTaskRepository(new SqliteStorage(Path.Combine(_directory, "state.db")));
}
public void Dispose()
{
SqliteStorage.ReleasePooledConnections(_directory);
try { Directory.Delete(_directory, recursive: true); }
catch { /* cleanup is secondary */ }
}
/// A run that sets its own task to a status, as the taskboard tool would.
private sealed class SettingDispatcher(SqliteTaskRepository repo, TaskItemStatus? set) : ITaskDispatcher
{
public async Task DispatchAsync(TaskItem task, CancellationToken ct)
{
if (set is { } status)
await repo.SetStatusAsync(task.Id, status, DateTime.UtcNow, ct);
return TaskLauf.Erledigt;
}
}
private async Task RunWith(TaskItemStatus? set)
{
await _repo.UpsertAsync(new TaskItem { Id = "t-1", Title = "Work", Assignee = "@worker" }, default);
var scanner = new TaskScanner(_repo, new SettingDispatcher(_repo, set), NullLoggerFactory.Instance, clock: _clock);
await scanner.ScanOnceAsync(default);
return (await _repo.GetAsync("t-1", default))!.Status;
}
[Theory]
[InlineData(TaskItemStatus.Blocked)]
[InlineData(TaskItemStatus.Canceled)]
public async Task A_status_the_run_set_itself_is_kept(TaskItemStatus set)
=> (await RunWith(set)).ShouldBe(set);
[Fact]
public async Task A_run_that_sets_nothing_is_done()
=> (await RunWith(null)).ShouldBe(TaskItemStatus.Done);
}