Merge claudedo/02f6746fd67b4217a581f2f911f6ff0d

This commit is contained in:
mika kuns
2026-08-10 14:56:10 +02:00
3 changed files with 157 additions and 29 deletions
+100 -11
View File
@@ -37,7 +37,7 @@ public sealed class ConfigMcpToolsTests : IDisposable
{
var listId = await SeedListAsync();
var setResult = await _sut.SetListConfig(listId, "sonnet", "be terse", null, 42, CancellationToken.None);
var setResult = await _sut.SetListConfig(listId, "sonnet", "be terse", null, 42, cancellationToken: CancellationToken.None);
Assert.True(setResult.Ok);
Assert.Equal(listId, setResult.ListId);
Assert.NotNull(setResult.Config);
@@ -65,12 +65,41 @@ public sealed class ConfigMcpToolsTests : IDisposable
}
[Fact]
public async Task SetListConfig_AllNull_ClearsConfig()
public async Task SetListConfig_PartialUpdate_LeavesOtherFieldsUntouched()
{
var listId = await SeedListAsync();
await _sut.SetListConfig(listId, "sonnet", null, null, null, CancellationToken.None);
await _sut.SetListConfig(listId, "opus", "be terse", "agent.md", 30, cancellationToken: CancellationToken.None);
var clearResult = await _sut.SetListConfig(listId, null, null, null, null, CancellationToken.None);
var result = await _sut.SetListConfig(listId, maxTurns: 40, cancellationToken: CancellationToken.None);
Assert.Equal("opus", result.Config!.Model);
Assert.Equal("be terse", result.Config.SystemPrompt);
Assert.Equal("agent.md", result.Config.AgentPath);
Assert.Equal(40, result.Config.MaxTurns);
}
[Fact]
public async Task SetListConfig_ClearFields_ClearsOnlyNamedField()
{
var listId = await SeedListAsync();
await _sut.SetListConfig(listId, "opus", "be terse", "agent.md", 30, cancellationToken: CancellationToken.None);
var result = await _sut.SetListConfig(listId, clearFields: new[] { "model" }, cancellationToken: CancellationToken.None);
Assert.Null(result.Config!.Model);
Assert.Equal("be terse", result.Config.SystemPrompt);
Assert.Equal("agent.md", result.Config.AgentPath);
Assert.Equal(30, result.Config.MaxTurns);
}
[Fact]
public async Task SetListConfig_AllFieldsCleared_DeletesConfig()
{
var listId = await SeedListAsync();
await _sut.SetListConfig(listId, "sonnet", null, null, null, cancellationToken: CancellationToken.None);
var clearResult = await _sut.SetListConfig(
listId, clearFields: new[] { "model", "systemPrompt", "agentPath", "maxTurns" }, cancellationToken: CancellationToken.None);
Assert.True(clearResult.Ok);
Assert.Null(clearResult.Config);
@@ -78,6 +107,15 @@ public sealed class ConfigMcpToolsTests : IDisposable
Assert.False(cfg.Found);
}
[Fact]
public async Task SetListConfig_UnknownClearField_Throws()
{
var listId = await SeedListAsync();
await Assert.ThrowsAsync<InvalidOperationException>(() =>
_sut.SetListConfig(listId, clearFields: new[] { "bogus" }, cancellationToken: CancellationToken.None));
}
[Fact]
public async Task SetTaskConfig_PersistsOverrides()
{
@@ -93,7 +131,7 @@ public sealed class ConfigMcpToolsTests : IDisposable
};
await _tasks.AddAsync(task);
var result = await _sut.SetTaskConfig(task.Id, "opus", null, null, 15, CancellationToken.None);
var result = await _sut.SetTaskConfig(task.Id, "opus", null, null, 15, cancellationToken: CancellationToken.None);
Assert.True(result.Ok);
Assert.Equal(task.Id, result.TaskId);
@@ -106,7 +144,7 @@ public sealed class ConfigMcpToolsTests : IDisposable
}
[Fact]
public async Task SetTaskConfig_NullField_ClearsThatOverride()
public async Task SetTaskConfig_PartialUpdate_LeavesOtherOverridesUntouched()
{
var listId = await SeedListAsync();
var task = new TaskEntity
@@ -119,19 +157,70 @@ public sealed class ConfigMcpToolsTests : IDisposable
CommitType = "chore",
};
await _tasks.AddAsync(task);
await _sut.SetTaskConfig(task.Id, "opus", "be terse", "agent.md", 15, CancellationToken.None);
await _sut.SetTaskConfig(task.Id, "opus", "be terse", "agent.md", 15, cancellationToken: CancellationToken.None);
var result = await _sut.SetTaskConfig(task.Id, "opus", null, "agent.md", null, CancellationToken.None);
var result = await _sut.SetTaskConfig(task.Id, maxTurns: 40, cancellationToken: CancellationToken.None);
Assert.True(result.Ok);
Assert.Equal("opus", result.Config!.Model);
Assert.Equal("be terse", result.Config.SystemPrompt);
Assert.Equal("agent.md", result.Config.AgentPath);
Assert.Equal(40, result.Config.MaxTurns);
var loaded = await _tasks.GetByIdAsync(task.Id);
Assert.Equal("opus", loaded!.Model);
Assert.Equal("be terse", loaded.SystemPrompt);
Assert.Equal(40, loaded.MaxTurns);
}
[Fact]
public async Task SetTaskConfig_ClearFields_ClearsOnlyNamedOverride()
{
var listId = await SeedListAsync();
var task = new TaskEntity
{
Id = Guid.NewGuid().ToString(),
ListId = listId,
Title = "t",
Status = ClaudeDo.Data.Models.TaskStatus.Idle,
CreatedAt = DateTime.UtcNow,
CommitType = "chore",
};
await _tasks.AddAsync(task);
await _sut.SetTaskConfig(task.Id, "opus", "be terse", "agent.md", 15, cancellationToken: CancellationToken.None);
var result = await _sut.SetTaskConfig(task.Id, clearFields: new[] { "systemPrompt" }, cancellationToken: CancellationToken.None);
Assert.True(result.Ok);
Assert.Equal("opus", result.Config!.Model);
Assert.Null(result.Config.SystemPrompt);
Assert.Equal("agent.md", result.Config.AgentPath);
Assert.Null(result.Config.MaxTurns);
Assert.Equal(15, result.Config.MaxTurns);
var loaded = await _tasks.GetByIdAsync(task.Id);
Assert.Null(loaded!.SystemPrompt);
Assert.Null(loaded.MaxTurns);
Assert.Equal("opus", loaded!.Model);
Assert.Null(loaded.SystemPrompt);
Assert.Equal("agent.md", loaded.AgentPath);
Assert.Equal(15, loaded.MaxTurns);
}
[Fact]
public async Task SetTaskConfig_UnknownClearField_Throws()
{
var listId = await SeedListAsync();
var task = new TaskEntity
{
Id = Guid.NewGuid().ToString(),
ListId = listId,
Title = "t",
Status = ClaudeDo.Data.Models.TaskStatus.Idle,
CreatedAt = DateTime.UtcNow,
CommitType = "chore",
};
await _tasks.AddAsync(task);
await Assert.ThrowsAsync<InvalidOperationException>(() =>
_sut.SetTaskConfig(task.Id, clearFields: new[] { "bogus" }, cancellationToken: CancellationToken.None));
}
[Fact]
@@ -81,7 +81,7 @@ public sealed class EffectiveRunConfigTests : IDisposable
public async Task Task_override_beats_list_override_beats_preset()
{
var listId = await SeedListAsync();
await _sut.SetListConfig(listId, "opus", null, "list-agent.md", 50, CancellationToken.None);
await _sut.SetListConfig(listId, "opus", null, "list-agent.md", 50, cancellationToken: CancellationToken.None);
var task = await SeedTaskAsync(listId, t => { t.Model = "haiku"; t.MaxTurns = 12; });
var result = await _sut.GetEffectiveRunConfig(task.Id, CancellationToken.None);
@@ -98,7 +98,7 @@ public sealed class EffectiveRunConfigTests : IDisposable
public async Task List_override_wins_when_no_task_override()
{
var listId = await SeedListAsync();
await _sut.SetListConfig(listId, "opus", null, null, 50, CancellationToken.None);
await _sut.SetListConfig(listId, "opus", null, null, 50, cancellationToken: CancellationToken.None);
var task = await SeedTaskAsync(listId);
var result = await _sut.GetEffectiveRunConfig(task.Id, CancellationToken.None);