using ClawdDotNet.App.Services; using ClawdDotNet.App.Settings; using ClawdDotNet.Core.Config; using ClawdDotNet.Core.Tools; using Microsoft.Extensions.Logging.Abstractions; using ClawdDotNet.Core.Instances; namespace ClawdDotNet.App.Tests.Services; /// /// Ein ohne Engine, Scanner und Netz — genug für die /// Verwaltungsdienste. /// /// Möglich ist das, weil AppHost.StartAsync nur ein Weg ist, einen /// aufzubauen: Die Eigenschaften sind required init, mehr braucht es nicht. Was /// hier fehlt — Engine, Scanner, Staging — ist auch im Betrieb /// regelmäßig null, und genau dieses Verhalten soll geprüft werden. /// internal sealed class TestHost : IDisposable { private readonly string _root; public AppHost Host { get; } /// Jede Änderung, die über SaveInstance gelaufen ist. public List Changes { get; } = []; public TestHost(params AgentConfig[] agents) { _root = Path.Combine( Path.GetTempPath(), "clawd-tests", "host-" + Guid.NewGuid().ToString("N")[..8]); var instancesDir = Path.Combine(_root, "Instances"); var instancePath = Path.Combine(instancesDir, "Test"); Directory.CreateDirectory(instancePath); var instance = new InstanceConfig { InstanceName = "Test" }; instance.Agents.AddRange(agents); Host = new AppHost { Settings = new SettingsManager(_root), Directories = new InstanceDirectoryManager(instancesDir), Instance = instance, InstancePath = instancePath, LogDirectory = Path.Combine(_root, "Logs"), LoggerFactory = NullLoggerFactory.Instance, Tools = new ToolRegistry() }; Host.InstanceChanged += Changes.Add; } public void Dispose() { try { Directory.Delete(_root, recursive: true); } catch { /* Ein liegengebliebener Testordner ist kein Grund, einen Lauf rot zu färben. */ } } public static AgentConfig Agent(string agentId, string displayName = "") => new() { AgentId = agentId, DisplayName = displayName.Length == 0 ? agentId : displayName, Model = "anthropic/claude-sonnet-4-5" }; }