feat(worker): add external MCP reset-failed-task tool
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
90
tests/ClaudeDo.Worker.Tests/External/LifecycleMcpToolsTests.cs
vendored
Normal file
90
tests/ClaudeDo.Worker.Tests/External/LifecycleMcpToolsTests.cs
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Data.Repositories;
|
||||
using ClaudeDo.Worker.External;
|
||||
using ClaudeDo.Worker.Hub;
|
||||
using ClaudeDo.Worker.Lifecycle;
|
||||
using ClaudeDo.Worker.Runner;
|
||||
using ClaudeDo.Worker.State;
|
||||
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||
using ClaudeDo.Data.Git;
|
||||
using ClaudeDo.Worker.Config;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
namespace ClaudeDo.Worker.Tests.External;
|
||||
|
||||
public sealed class LifecycleMcpToolsTests : IDisposable
|
||||
{
|
||||
private readonly DbFixture _db = new();
|
||||
private readonly ClaudeDoDbContext _ctx;
|
||||
private readonly TaskRepository _tasks;
|
||||
private readonly ListRepository _lists;
|
||||
|
||||
public LifecycleMcpToolsTests()
|
||||
{
|
||||
_ctx = _db.CreateContext();
|
||||
_tasks = new TaskRepository(_ctx);
|
||||
_lists = new ListRepository(_ctx);
|
||||
}
|
||||
|
||||
public void Dispose() { _ctx.Dispose(); _db.Dispose(); }
|
||||
|
||||
private LifecycleMcpTools BuildSut()
|
||||
{
|
||||
var cfg = new WorkerConfig
|
||||
{
|
||||
SandboxRoot = Path.Combine(Path.GetTempPath(), $"cd_{Guid.NewGuid():N}"),
|
||||
LogRoot = Path.Combine(Path.GetTempPath(), $"cdl_{Guid.NewGuid():N}"),
|
||||
};
|
||||
var dbFactory = _db.CreateFactory();
|
||||
var broadcaster = new HubBroadcaster(new CapturingHubContext());
|
||||
var wtManager = new WorktreeManager(new GitService(), dbFactory, cfg, NullLogger<WorktreeManager>.Instance);
|
||||
var state = TaskStateServiceBuilder.Build(dbFactory).State;
|
||||
var reset = new TaskResetService(dbFactory, wtManager, broadcaster, state, NullLogger<TaskResetService>.Instance);
|
||||
return new LifecycleMcpTools(_tasks, reset);
|
||||
}
|
||||
|
||||
private async Task<TaskEntity> SeedTaskAsync(TaskStatus status)
|
||||
{
|
||||
var listId = Guid.NewGuid().ToString();
|
||||
await _lists.AddAsync(new ListEntity { Id = listId, Name = "L", CreatedAt = DateTime.UtcNow });
|
||||
var task = new TaskEntity
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(), ListId = listId, Title = "t",
|
||||
Status = status, CreatedAt = DateTime.UtcNow, CommitType = "chore",
|
||||
};
|
||||
await _tasks.AddAsync(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ResetFailedTask_OnFailed_ResetsToIdle()
|
||||
{
|
||||
var task = await SeedTaskAsync(TaskStatus.Failed);
|
||||
var sut = BuildSut();
|
||||
|
||||
await sut.ResetFailedTask(task.Id, CancellationToken.None);
|
||||
|
||||
var loaded = await _tasks.GetByIdAsync(task.Id);
|
||||
Assert.Equal(TaskStatus.Idle, loaded!.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ResetFailedTask_OnNonFailed_Throws()
|
||||
{
|
||||
var task = await SeedTaskAsync(TaskStatus.Done);
|
||||
var sut = BuildSut();
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.ResetFailedTask(task.Id, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ResetFailedTask_NotFound_Throws()
|
||||
{
|
||||
var sut = BuildSut();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.ResetFailedTask("missing", CancellationToken.None));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user