using ClaudeDo.Data; using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; using ClaudeDo.Worker.External; using ClaudeDo.Worker.Hub; using ClaudeDo.Worker.Tests.Infrastructure; namespace ClaudeDo.Worker.Tests.External; public sealed class ConfigMcpToolsTests : IDisposable { private readonly DbFixture _db = new(); private readonly ClaudeDoDbContext _ctx; private readonly ListRepository _lists; private readonly TaskRepository _tasks; private readonly ConfigMcpTools _sut; public ConfigMcpToolsTests() { _ctx = _db.CreateContext(); _lists = new ListRepository(_ctx); _tasks = new TaskRepository(_ctx); _sut = new ConfigMcpTools(_lists, _tasks, new HubBroadcaster(new CapturingHubContext()), _db.CreateFactory()); } public void Dispose() { _ctx.Dispose(); _db.Dispose(); } private async Task SeedListAsync() { var id = Guid.NewGuid().ToString(); await _lists.AddAsync(new ListEntity { Id = id, Name = "L", CreatedAt = DateTime.UtcNow }); return id; } [Fact] public async Task SetAndGetListConfig_RoundTrips() { var listId = await SeedListAsync(); var setResult = await _sut.SetListConfig(listId, "sonnet", "be terse", null, 42, CancellationToken.None); Assert.True(setResult.Ok); Assert.Equal(listId, setResult.ListId); Assert.NotNull(setResult.Config); Assert.Equal("sonnet", setResult.Config!.Model); var cfg = await _sut.GetListConfig(listId, CancellationToken.None); Assert.True(cfg.Found); Assert.NotNull(cfg.Config); Assert.Equal("sonnet", cfg.Config!.Model); Assert.Equal("be terse", cfg.Config.SystemPrompt); Assert.Null(cfg.Config.AgentPath); Assert.Equal(42, cfg.Config.MaxTurns); } [Fact] public async Task GetListConfig_NoConfigSet_ReturnsNotFound() { var listId = await SeedListAsync(); var cfg = await _sut.GetListConfig(listId, CancellationToken.None); Assert.False(cfg.Found); Assert.Null(cfg.Config); } [Fact] public async Task SetListConfig_AllNull_ClearsConfig() { var listId = await SeedListAsync(); await _sut.SetListConfig(listId, "sonnet", null, null, null, CancellationToken.None); var clearResult = await _sut.SetListConfig(listId, null, null, null, null, CancellationToken.None); Assert.True(clearResult.Ok); Assert.Null(clearResult.Config); var cfg = await _sut.GetListConfig(listId, CancellationToken.None); Assert.False(cfg.Found); } [Fact] public async Task SetTaskConfig_PersistsOverrides() { 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); var result = await _sut.SetTaskConfig(task.Id, "opus", null, null, 15, CancellationToken.None); Assert.True(result.Ok); Assert.Equal(task.Id, result.TaskId); Assert.Equal("opus", result.Config!.Model); Assert.Equal(15, result.Config.MaxTurns); var loaded = await _tasks.GetByIdAsync(task.Id); Assert.Equal("opus", loaded!.Model); Assert.Equal(15, loaded.MaxTurns); } [Fact] public async Task SetTaskConfig_NullField_ClearsThatOverride() { 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.None); var result = await _sut.SetTaskConfig(task.Id, "opus", null, "agent.md", null, 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); var loaded = await _tasks.GetByIdAsync(task.Id); Assert.Null(loaded!.SystemPrompt); Assert.Null(loaded.MaxTurns); } [Fact] public async Task GetTaskConfig_NoOverrideSet_ReturnsNotFound() { 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); var cfg = await _sut.GetTaskConfig(task.Id, CancellationToken.None); Assert.False(cfg.Found); Assert.Null(cfg.Config); } }