Merge claudedo/dc5d5776339b4da6a5fb628a5c2ed648
This commit is contained in:
@@ -131,6 +131,35 @@ public sealed class TaskNumberAllocatorTests : IDisposable
|
||||
Assert.All(numbers, n => Assert.True(n > 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddAsync_recreates_a_missing_app_settings_row_instead_of_crashing()
|
||||
{
|
||||
await SeedListAsync();
|
||||
await _ctx.Database.ExecuteSqlRawAsync("DELETE FROM app_settings");
|
||||
|
||||
var task = NewTask("l1");
|
||||
await new TaskRepository(_ctx).AddAsync(task);
|
||||
|
||||
Assert.True(task.Number > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddAsync_noncollision_DbUpdateException_surfaces_immediately_without_burning_numbers()
|
||||
{
|
||||
await SeedListAsync();
|
||||
var badTask = NewTask("no-such-list");
|
||||
|
||||
await Assert.ThrowsAsync<DbUpdateException>(() => new TaskRepository(_ctx).AddAsync(badTask));
|
||||
|
||||
// The failed attempt above should have burned exactly one number (attempt #1, no
|
||||
// collision-driven retries) -- confirm the next successful insert isn't several numbers
|
||||
// further along.
|
||||
var goodTask = NewTask("l1");
|
||||
await new TaskRepository(_ctx).AddAsync(goodTask);
|
||||
|
||||
Assert.Equal(2, goodTask.Number);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetByNumberAsync_finds_the_task_and_returns_null_for_unknown_numbers()
|
||||
{
|
||||
|
||||
@@ -253,6 +253,52 @@ public sealed class TaskWaitMcpToolsTests : IDisposable
|
||||
Assert.True(sw.Elapsed >= TimeSpan.FromMilliseconds(900), $"took {sw.Elapsed}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WaitForTaskChange_UnknownNumberHashForm_ReturnsImmediatelyAsNotFound()
|
||||
{
|
||||
var sut = BuildSut();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var result = await sut.WaitForTaskChange(["#999999"], timeoutSeconds: 30, cancellationToken: CancellationToken.None);
|
||||
|
||||
sw.Stop();
|
||||
Assert.False(result.TimedOut);
|
||||
Assert.Equal("NotFound", Assert.Single(result.Changed).Status);
|
||||
Assert.True(sw.Elapsed < TimeSpan.FromSeconds(2), $"took {sw.Elapsed}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WaitForTaskChange_UnknownBareNumber_ReturnsImmediatelyAsNotFound()
|
||||
{
|
||||
var sut = BuildSut();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var result = await sut.WaitForTaskChange(["999999"], timeoutSeconds: 30, cancellationToken: CancellationToken.None);
|
||||
|
||||
sw.Stop();
|
||||
Assert.False(result.TimedOut);
|
||||
Assert.Equal("NotFound", Assert.Single(result.Changed).Status);
|
||||
Assert.True(sw.Elapsed < TimeSpan.FromSeconds(2), $"took {sw.Elapsed}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WaitForTaskChange_MixOfValidAndUnknownNumber_ReportsBothCorrectly()
|
||||
{
|
||||
var task = await SeedTaskAsync(TaskStatus.WaitingForReview);
|
||||
var sut = BuildSut();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var result = await sut.WaitForTaskChange(
|
||||
[$"#{task.Number}", "#999999"], timeoutSeconds: 30, cancellationToken: CancellationToken.None);
|
||||
|
||||
sw.Stop();
|
||||
Assert.False(result.TimedOut);
|
||||
Assert.Equal(2, result.Changed.Count);
|
||||
Assert.Contains(result.Changed, c => c.TaskId == task.Id && c.Status == "WaitingForReview");
|
||||
Assert.Contains(result.Changed, c => c.TaskId == "#999999" && c.Status == "NotFound");
|
||||
Assert.True(sw.Elapsed < TimeSpan.FromSeconds(2), $"took {sw.Elapsed}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaxTimeoutSeconds_StaysComfortablyUnderMcpToolTimeout()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user