test(worker): consolidate fakes into Infrastructure/, drop tag-era names
- Extract FakeClaudeProcess to Infrastructure/FakeClaudeProcess.cs (was defined inline in QueueServiceTests #region); all consumers updated - Replace duplicate FakeHubContext/FakeHubClients/FakeClientProxy (QueueServiceTests) with existing CapturingHubContext from Infrastructure across all 7 affected files; Planning's file-local FakeHubContext kept - Rename SeedListWithAgentTag → SeedListAsync (return Task<string>, drop unused agentTagId tuple element) and SeedListWithAgentTagAsync → SeedListAsync - PrimeRunnerTests keeps its private nested FakeClaudeProcess: constructor API (delay/exitCode/lines/result params) differs from the shared one and replacement would require rewriting every test in that file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,6 @@ using ClaudeDo.Worker.Hub;
|
||||
using ClaudeDo.Worker.Queue;
|
||||
using ClaudeDo.Worker.Runner;
|
||||
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
@@ -49,7 +48,7 @@ public sealed class QueueServiceSlotGuardTests : IDisposable
|
||||
Func<string, string, IReadOnlyList<string>, Func<string, Task>, CancellationToken, Task<RunResult>>? handler = null)
|
||||
{
|
||||
var fake = new FakeClaudeProcess(handler);
|
||||
var broadcaster = new HubBroadcaster(new FakeHubContext());
|
||||
var broadcaster = new HubBroadcaster(new CapturingHubContext());
|
||||
var dbFactory = _db.CreateFactory();
|
||||
var wtManager = new WorktreeManager(new ClaudeDo.Data.Git.GitService(), dbFactory, _cfg, NullLogger<WorktreeManager>.Instance);
|
||||
var argsBuilder = new ClaudeArgsBuilder();
|
||||
@@ -63,7 +62,7 @@ public sealed class QueueServiceSlotGuardTests : IDisposable
|
||||
return (service, fake);
|
||||
}
|
||||
|
||||
private async Task<string> SeedListWithAgentTagAsync()
|
||||
private async Task<string> SeedListAsync()
|
||||
{
|
||||
var listId = Guid.NewGuid().ToString();
|
||||
await _listRepo.AddAsync(new ListEntity { Id = listId, Name = "Test", CreatedAt = DateTime.UtcNow });
|
||||
@@ -88,7 +87,7 @@ public sealed class QueueServiceSlotGuardTests : IDisposable
|
||||
[Fact]
|
||||
public async Task RunNow_Throws_When_Task_Already_Running_In_Queue_Slot()
|
||||
{
|
||||
var listId = await SeedListWithAgentTagAsync();
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedQueuedTaskAsync(listId);
|
||||
|
||||
// Gate keeps the queue slot occupied indefinitely.
|
||||
@@ -119,7 +118,7 @@ public sealed class QueueServiceSlotGuardTests : IDisposable
|
||||
[Fact]
|
||||
public async Task ContinueTask_Throws_When_Task_Already_Running_In_Queue_Slot()
|
||||
{
|
||||
var listId = await SeedListWithAgentTagAsync();
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedQueuedTaskAsync(listId);
|
||||
|
||||
var tcs = new TaskCompletionSource<RunResult>();
|
||||
|
||||
@@ -7,7 +7,6 @@ using ClaudeDo.Worker.Hub;
|
||||
using ClaudeDo.Worker.Queue;
|
||||
using ClaudeDo.Worker.Runner;
|
||||
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
@@ -50,7 +49,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
Func<string, string, IReadOnlyList<string>, Func<string, Task>, CancellationToken, Task<RunResult>>? handler = null)
|
||||
{
|
||||
var fake = new FakeClaudeProcess(handler);
|
||||
var broadcaster = new HubBroadcaster(new FakeHubContext());
|
||||
var broadcaster = new HubBroadcaster(new CapturingHubContext());
|
||||
var dbFactory = _db.CreateFactory();
|
||||
var wtManager = new WorktreeManager(new GitService(), dbFactory, _cfg, NullLogger<WorktreeManager>.Instance);
|
||||
var argsBuilder = new ClaudeArgsBuilder();
|
||||
@@ -64,11 +63,11 @@ public sealed class QueueServiceTests : IDisposable
|
||||
return (service, fake);
|
||||
}
|
||||
|
||||
private async Task<(string listId, long agentTagId)> SeedListWithAgentTag()
|
||||
private async Task<string> SeedListAsync()
|
||||
{
|
||||
var listId = Guid.NewGuid().ToString();
|
||||
await _listRepo.AddAsync(new ListEntity { Id = listId, Name = "Test", CreatedAt = DateTime.UtcNow });
|
||||
return (listId, 0L);
|
||||
return listId;
|
||||
}
|
||||
|
||||
private async Task<TaskEntity> SeedQueuedTask(string listId, DateTime? scheduledFor = null, DateTime? createdAt = null)
|
||||
@@ -90,7 +89,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task RunNow_Throws_When_Override_Slot_Busy()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
var tcs = new TaskCompletionSource<RunResult>();
|
||||
|
||||
var (service, _) = CreateService((_, _, _, _, ct) => tcs.Task);
|
||||
@@ -116,7 +115,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task ReQueuedReviewTask_ResumesSession_WithFeedbackPrompt_AndClearsFeedback()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
|
||||
IReadOnlyList<string>? capturedArgs = null;
|
||||
string? capturedPrompt = null;
|
||||
@@ -181,7 +180,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task Schedule_Filter_Skips_Future_Tasks()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
await SeedQueuedTask(listId, scheduledFor: DateTime.UtcNow.AddHours(1));
|
||||
|
||||
var (service, fake) = CreateService((_, _, _, _, _) =>
|
||||
@@ -202,7 +201,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task Queue_FIFO_Sequentiality()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
|
||||
var order = new List<string>();
|
||||
var gate1 = new TaskCompletionSource();
|
||||
@@ -249,7 +248,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task CancelTask_Triggers_Cancellation()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
|
||||
var running = new TaskCompletionSource();
|
||||
var cancelled = false;
|
||||
@@ -284,7 +283,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task RunNow_AutoRetries_On_Failure_With_SessionId()
|
||||
{
|
||||
var (listId, agentTagId) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedQueuedTask(listId);
|
||||
|
||||
var callCount = 0;
|
||||
@@ -327,7 +326,7 @@ public sealed class QueueServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task GetActive_Returns_Running_Slots()
|
||||
{
|
||||
var (listId, _) = await SeedListWithAgentTag();
|
||||
var listId = await SeedListAsync();
|
||||
var tcs = new TaskCompletionSource<RunResult>();
|
||||
|
||||
var (service, _) = CreateService((_, _, _, _, _) => tcs.Task);
|
||||
@@ -343,55 +342,3 @@ public sealed class QueueServiceTests : IDisposable
|
||||
tcs.SetResult(new RunResult { ExitCode = 0, ResultMarkdown = "ok" });
|
||||
}
|
||||
}
|
||||
|
||||
#region Test doubles
|
||||
|
||||
internal sealed class FakeClaudeProcess : IClaudeProcess
|
||||
{
|
||||
private readonly Func<string, string, IReadOnlyList<string>, Func<string, Task>, CancellationToken, Task<RunResult>> _handler;
|
||||
private int _callCount;
|
||||
|
||||
public int CallCount => _callCount;
|
||||
|
||||
public FakeClaudeProcess(
|
||||
Func<string, string, IReadOnlyList<string>, Func<string, Task>, CancellationToken, Task<RunResult>>? handler = null)
|
||||
{
|
||||
_handler = handler ?? ((_, _, _, _, _) =>
|
||||
Task.FromResult(new RunResult { ExitCode = 0, ResultMarkdown = "ok" }));
|
||||
}
|
||||
|
||||
public async Task<RunResult> RunAsync(IReadOnlyList<string> arguments, string prompt, string workingDirectory,
|
||||
Func<string, Task> onStdoutLine, CancellationToken ct)
|
||||
{
|
||||
Interlocked.Increment(ref _callCount);
|
||||
return await _handler(prompt, workingDirectory, arguments, onStdoutLine, ct);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FakeHubContext : IHubContext<WorkerHub>
|
||||
{
|
||||
public IHubClients Clients { get; } = new FakeHubClients();
|
||||
public IGroupManager Groups => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal sealed class FakeHubClients : IHubClients
|
||||
{
|
||||
private readonly FakeClientProxy _proxy = new();
|
||||
public IClientProxy All => _proxy;
|
||||
public IClientProxy AllExcept(IReadOnlyList<string> excludedConnectionIds) => _proxy;
|
||||
public IClientProxy Client(string connectionId) => _proxy;
|
||||
public IClientProxy Clients(IReadOnlyList<string> connectionIds) => _proxy;
|
||||
public IClientProxy Group(string groupName) => _proxy;
|
||||
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds) => _proxy;
|
||||
public IClientProxy Groups(IReadOnlyList<string> groupNames) => _proxy;
|
||||
public IClientProxy User(string userId) => _proxy;
|
||||
public IClientProxy Users(IReadOnlyList<string> userIds) => _proxy;
|
||||
}
|
||||
|
||||
internal sealed class FakeClientProxy : IClientProxy
|
||||
{
|
||||
public Task SendCoreAsync(string method, object?[] args, CancellationToken cancellationToken = default) =>
|
||||
Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user