Files
ClaudeDo/tests/ClaudeDo.Worker.Tests/Infrastructure/TaskStateServiceBuilder.cs
T

58 lines
1.9 KiB
C#

using ClaudeDo.Data;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Planning;
using ClaudeDo.Worker.Queue;
using ClaudeDo.Worker.State;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
namespace ClaudeDo.Worker.Tests.Infrastructure;
/// Test-only helper that wires TaskStateService and PlanningChainCoordinator
/// against a shared DB factory, breaking the Func cycle between them.
public static class TaskStateServiceBuilder
{
public sealed record Built(
TaskStateService State,
PlanningChainCoordinator Chain,
CapturingHubContext Hub,
Func<int> WakeCount,
CountingQueueWaker Waker,
RunCancellationRegistry RunCancels);
public static Built Build(
IDbContextFactory<ClaudeDoDbContext> dbFactory, Func<IActiveMergeState>? mergeState = null)
{
var hub = new CapturingHubContext();
var broadcaster = new HubBroadcaster(hub);
var waker = new CountingQueueWaker();
var runCancels = new RunCancellationRegistry(NullLogger<RunCancellationRegistry>.Instance);
TaskStateService? state = null;
var chain = new PlanningChainCoordinator(dbFactory, () => state!);
state = new TaskStateService(
dbFactory,
broadcaster,
waker,
chain,
runCancels,
mergeState ?? (() => NoActiveMergeState.Instance),
NullLogger<TaskStateService>.Instance);
return new Built(state, chain, hub, () => waker.Count, waker, runCancels);
}
}
file sealed class NoActiveMergeState : IActiveMergeState
{
public static readonly NoActiveMergeState Instance = new();
public bool HasActiveMerge(string taskId) => false;
}
public sealed class CountingQueueWaker : IQueueWaker
{
private int _count;
public int Count => Volatile.Read(ref _count);
public void Wake() => Interlocked.Increment(ref _count);
}