using ClawdDotNet.Core.Config;
using Shouldly;
namespace ClawdDotNet.App.Tests;
///
/// Wohin eine Instanz protokolliert und sichert — und dass zwei Instanzen dabei nicht
/// im selben Ordner landen (#528, Stufe 1).
///
/// Der Anlass. Beide Vorgaben waren anwendungsweit. In Startup.log
/// standen deshalb abwechselnd Zeilen zweier Instanzen, ohne Kennzeichnung, welche
/// gerade spricht; und weil die Aufbewahrung nach Präfix in genau einem Ordner
/// aufräumt, warf die laufende Instanz die Archive der anderen mit weg. Solange das so
/// ist, ist jede Fehlersuche im Mehrinstanzbetrieb Ratearbeit.
///
/// Was aus #375 bleibt. Ein relativer Wert zählt gegen das
/// Instanzverzeichnis, nicht gegen das Arbeitsverzeichnis des Prozesses. Ein
/// systemd-Dienst ohne WorkingDirectory= startet in /, und "./Logs"
/// zeigte dann auf /Logs — für ein Dienstkonto nicht anlegbar.
///
public sealed class LogDirectoryResolutionTests
{
private static readonly string InstancePath =
Path.GetFullPath(Path.Combine(Path.GetTempPath(), "clawd-tests", "Instance-Test"));
private static InstanceConfig Instance(
string logDirectory = "", string backupDirectory = "", string? workingDirectory = null)
=> new()
{
LogDirectory = logDirectory,
BackupDirectory = backupDirectory,
WorkingDirectory = workingDirectory ?? InstancePath
};
// ─── Vorgaben ───
[Fact]
public void Die_Vorbelegungen_sind_leer()
{
// Der Kern: Leer heisst „nimm den Ordner dieser Instanz". Steht hier ein Wert,
// traegt ihn jede neue Instanz mit sich herum.
new InstanceConfig().LogDirectory.ShouldBe("");
new InstanceConfig().BackupDirectory.ShouldBe("");
}
[Fact]
public void Ohne_Angabe_protokolliert_die_Instanz_in_ihr_eigenes_Verzeichnis()
{
AppHost.ResolveLogDirectory(Instance(), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Logs"));
}
[Fact]
public void Ohne_Angabe_sichert_die_Instanz_in_ihr_eigenes_Verzeichnis()
{
AppHost.ResolveBackupDirectory(Instance(), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Backups"));
}
///
/// Das eigentliche Versprechen von Stufe 1. Alles andere in dieser Datei prüft die
/// Mechanik; dieser Test prüft die Zusage.
///
[Fact]
public void Zwei_Instanzen_ohne_Angabe_teilen_sich_nichts()
{
var a = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "clawd-tests", "Instance-A"));
var b = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "clawd-tests", "Instance-B"));
var logA = AppHost.ResolveLogDirectory(Instance(workingDirectory: a), a);
var logB = AppHost.ResolveLogDirectory(Instance(workingDirectory: b), b);
var backupA = AppHost.ResolveBackupDirectory(Instance(workingDirectory: a), a);
var backupB = AppHost.ResolveBackupDirectory(Instance(workingDirectory: b), b);
logA.ShouldNotBe(logB);
backupA.ShouldNotBe(backupB);
}
// ─── Eingetragene Werte ───
[Fact]
public void Ein_absoluter_Wert_geht_vor()
{
var eigenesLog = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "clawd-eigene-logs"));
var eigenesBackup = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "clawd-eigene-sicherungen"));
AppHost.ResolveLogDirectory(Instance(logDirectory: eigenesLog), InstancePath)
.ShouldBe(eigenesLog);
AppHost.ResolveBackupDirectory(Instance(backupDirectory: eigenesBackup), InstancePath)
.ShouldBe(eigenesBackup);
}
[Fact]
public void Ein_relativer_Wert_zaehlt_gegen_das_Instanzverzeichnis()
{
// Nicht gegen das Arbeitsverzeichnis des Prozesses — das war der Fehler aus #375.
AppHost.ResolveLogDirectory(Instance(logDirectory: "./Protokolle"), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Protokolle"));
}
[Fact]
public void Ein_relativer_Wert_haengt_nicht_am_Arbeitsverzeichnis_des_Prozesses()
{
AppHost.ResolveLogDirectory(Instance(logDirectory: "./Protokolle"), InstancePath)
.ShouldNotBe(Path.GetFullPath("./Protokolle"));
}
[Theory]
[InlineData("./Logs")]
[InlineData("Logs")]
public void Die_alte_Vorbelegung_zeigt_auf_dieselbe_Stelle_wie_keine_Angabe(string alt)
{
// Deshalb darf LoadInstanceConfig sie zu „leer" machen, ohne dass sich etwas
// verschiebt.
AppHost.ResolveLogDirectory(Instance(logDirectory: alt), InstancePath)
.ShouldBe(AppHost.ResolveLogDirectory(Instance(), InstancePath));
}
[Fact]
public void Nur_Leerzeichen_gelten_als_keine_Angabe()
{
AppHost.ResolveLogDirectory(Instance(logDirectory: " "), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Logs"));
}
// ─── Bezugspunkt ───
[Fact]
public void Ein_leeres_WorkingDirectory_faellt_auf_den_Instanzpfad_zurueck()
{
// Das Feld steht seit CreateInstance absolut in der Datei, kann aber von Hand
// geleert worden sein. Dann trägt der Ort, aus dem geladen wurde.
AppHost.ResolveLogDirectory(
Instance(logDirectory: "Logs", workingDirectory: ""), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Logs"));
}
[Fact]
public void Ein_relatives_WorkingDirectory_faellt_ebenfalls_auf_den_Instanzpfad_zurueck()
{
// "./data/" ist die alte Vorbelegung des Feldes und wäre wieder gegen das
// Arbeitsverzeichnis des Prozesses aufgelöst worden.
AppHost.ResolveLogDirectory(
Instance(logDirectory: "Logs", workingDirectory: "./data/"), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Logs"));
}
}