Files
ClawdDotNet/tests/ClawdDotNet.App.Tests/Services/TestHost.cs
T
Richard 1e9cb789c8 Weboberflaeche hinzugefuegt und Fachlogik nach App herausgeloest (#493, #494)
- ClawdDotNet.Web: Kestrel im Prozess der Anwendung, Token-Absicherung (TokenGate mit FixedTimeEquals), Endpunkte unter /api, Ereignisstrom unter /events (Server-Sent Events) und fortlaufendes Log-Streaming.

- Weboberflaeche (wwwroot/): Vollstaendiges Single-Page-Frontend mit nativem HTML5, CSS3 und ES-Modulen ohne Buildschritt (strikt textContent, #-Routing, sofortiger Login-Sprung bei fehlendem Token, Light/Dark-Theme, lokale Barlow-Schriften).

- ClawdDotNet.App: Fachlogik aus den Avalonia-ViewModels in Dienste herausgeloest (AgentAdministration, JobAdministration, ServiceAdministration, RunCoordinator) und ueber InstanceChange synchronisiert.

- Tests: ClawdDotNet.Web.Tests und ClawdDotNet.App.Tests hinzugefuegt, alle 684 Tests erfolgreich.
2026-09-07 21:56:02 +02:00

68 lines
2.3 KiB
C#

using ClawdDotNet.App.Services;
using ClawdDotNet.App.Settings;
using ClawdDotNet.Core.Config;
using ClawdDotNet.Core.Tools;
using Microsoft.Extensions.Logging.Abstractions;
namespace ClawdDotNet.App.Tests.Services;
/// <summary>
/// Ein <see cref="AppHost"/> ohne Engine, Scanner und Netz — genug für die
/// Verwaltungsdienste.
///
/// <para>Möglich ist das, weil <c>AppHost.StartAsync</c> nur <em>ein</em> Weg ist, einen
/// aufzubauen: Die Eigenschaften sind <c>required init</c>, mehr braucht es nicht. Was
/// hier fehlt — <c>Engine</c>, <c>Scanner</c>, <c>Staging</c> — ist auch im Betrieb
/// regelmäßig null, und genau dieses Verhalten soll geprüft werden.</para>
/// </summary>
internal sealed class TestHost : IDisposable
{
private readonly string _root;
public AppHost Host { get; }
/// <summary>Jede Änderung, die über <c>SaveInstance</c> gelaufen ist.</summary>
public List<InstanceChange> 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"
};
}