using ClaudeDo.Data; using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; using ClaudeDo.Worker.External; using ClaudeDo.Worker.Hub; using ClaudeDo.Worker.Tests.Infrastructure; using Xunit; namespace ClaudeDo.Worker.Tests.Hub; /// BaseBranch und PowerUseAllowed sitzen in der SetConfigAsync-kopiert-verbatim-Falle: jeder Writer, /// der sie nicht durchreicht, setzt sie still zurück. public sealed class ListConfigBaseBranchTests : IDisposable { private readonly DbFixture _db = new(); public void Dispose() => _db.Dispose(); private WorkerHub CreateHub() { var factory = _db.CreateFactory(); var broadcaster = new HubBroadcaster(new CapturingHubContext()); var hub = new WorkerHub( null!, null!, null!, null!, broadcaster, factory, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, new ClaudeDo.Worker.Online.OnlineInboxConfig(), new ClaudeDo.Worker.OnlineRefreshTokenStore(new ClaudeDo.Worker.DpapiTokenStore("unused.token")), new ClaudeDo.Worker.Runner.PendingQuestionRegistry(), null!); hub.Clients = new FakeHubCallerClients(new RecordingClientProxy()); hub.Context = new FakeHubCallerContext(); return hub; } private async Task SeedListAsync(string? baseBranch, bool powerUse = false) { var listId = Guid.NewGuid().ToString(); await using var ctx = _db.CreateContext(); var repo = new ListRepository(ctx); await repo.AddAsync(new ListEntity { Id = listId, Name = "L", CreatedAt = DateTime.UtcNow }); await repo.SetConfigAsync(new ListConfigEntity { ListId = listId, BaseBranch = baseBranch, PowerUseAllowed = powerUse }); return listId; } private async Task ReadConfigAsync(string listId) { await using var ctx = _db.CreateContext(); return await new ListRepository(ctx).GetConfigAsync(listId); } private ConfigMcpTools CreateTool(ClaudeDoDbContext ctx) => new(new ListRepository(ctx), new TaskRepository(ctx), new HubBroadcaster(new CapturingHubContext()), _db.CreateFactory()); [Fact] public async Task set_list_config_preserves_BaseBranch_and_PowerUseAllowed() { var listId = await SeedListAsync("dev", powerUse: true); await using var ctx = _db.CreateContext(); await CreateTool(ctx).SetListConfig(listId, model: "opus", cancellationToken: CancellationToken.None); var cfg = await ReadConfigAsync(listId); Assert.Equal("dev", cfg!.BaseBranch); Assert.True(cfg.PowerUseAllowed); } [Fact] public async Task get_list_config_returns_BaseBranch() { var listId = await SeedListAsync("dev"); await using var ctx = _db.CreateContext(); var result = await CreateTool(ctx).GetListConfig(listId, CancellationToken.None); Assert.Equal("dev", result.Config!.BaseBranch); } [Fact] public async Task UpdateListConfig_null_keeps_BaseBranch() { var listId = await SeedListAsync("dev"); await CreateHub().UpdateListConfig(new UpdateListConfigDto(listId, "opus", null, null)); Assert.Equal("dev", (await ReadConfigAsync(listId))!.BaseBranch); } [Fact] public async Task UpdateListConfig_empty_clears_BaseBranch() { var listId = await SeedListAsync("dev"); await CreateHub().UpdateListConfig(new UpdateListConfigDto(listId, "opus", null, null, BaseBranch: "")); Assert.Null((await ReadConfigAsync(listId))!.BaseBranch); } [Fact] public async Task UpdateListConfig_sets_BaseBranch_and_GetListConfig_returns_it() { var listId = await SeedListAsync(null); var hub = CreateHub(); await hub.UpdateListConfig(new UpdateListConfigDto(listId, null, null, null, BaseBranch: "dev")); Assert.Equal("dev", (await hub.GetListConfig(listId))!.BaseBranch); } }