refactor(worker): extract ProgressReporter from TaskMergeService
Pulls the MCP idle-timeout progress loop out of TaskMergeService into a standalone ProgressReporter (Lifecycle namespace) shared by the verify gate and preview-verify call sites, and adds a per-item i/n overload (ReportItem) for upcoming batch progress in D2/D3.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
using ClaudeDo.Worker.Lifecycle;
|
||||
using ModelContextProtocol;
|
||||
using Xunit;
|
||||
|
||||
namespace ClaudeDo.Worker.Tests.Lifecycle;
|
||||
|
||||
// A synchronously-collecting IProgress<T>: Progress<T> marshals through the SynchronizationContext
|
||||
// captured at construction, which is unreliable to assert on immediately in a test.
|
||||
file sealed class SyncProgress<T> : IProgress<T>
|
||||
{
|
||||
public readonly List<T> Reports = new();
|
||||
public void Report(T value) => Reports.Add(value);
|
||||
}
|
||||
|
||||
public sealed class ProgressReporterTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task RunAsync_NoProgressOrOnTick_ReturnsWorkResultWithoutTicking()
|
||||
{
|
||||
var result = await ProgressReporter.RunAsync(Task.FromResult(42), TimeSpan.FromMilliseconds(10), null, "message");
|
||||
|
||||
Assert.Equal(42, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsync_SlowWork_ReportsProgressOnEachTick()
|
||||
{
|
||||
var progress = new SyncProgress<ProgressNotificationValue>();
|
||||
var work = Task.Delay(250).ContinueWith(_ => "done");
|
||||
|
||||
var result = await ProgressReporter.RunAsync(work, TimeSpan.FromMilliseconds(50), progress, "waiting");
|
||||
|
||||
Assert.Equal("done", result);
|
||||
Assert.NotEmpty(progress.Reports);
|
||||
Assert.All(progress.Reports, r => Assert.Contains("waiting", r.Message));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReportItem_ReportsMessageAndProgressTotalForEachItem()
|
||||
{
|
||||
var progress = new SyncProgress<ProgressNotificationValue>();
|
||||
|
||||
for (var i = 1; i <= 3; i++)
|
||||
ProgressReporter.ReportItem(progress, "cleaning worktrees", i, 3);
|
||||
|
||||
Assert.Equal(3, progress.Reports.Count);
|
||||
Assert.Equal("cleaning worktrees (1/3)", progress.Reports[0].Message);
|
||||
Assert.Equal("cleaning worktrees (2/3)", progress.Reports[1].Message);
|
||||
Assert.Equal("cleaning worktrees (3/3)", progress.Reports[2].Message);
|
||||
Assert.Equal(3, progress.Reports[2].Total);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReportItem_NoProgress_DoesNotThrow()
|
||||
{
|
||||
ProgressReporter.ReportItem(null, "cleaning worktrees", 1, 3);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user