Files
ClawdDotNet/tests/ClawdDotNet.App.Tests/LogDirectoryResolutionTests.cs
T
RichardandClaude Opus 5.5 837a634a22 Stufe 4c (#764): Kommentare in C#, WebUI-Skripten, CSS und HTML auf Englisch
Rund 2.600 Kommentarblöcke in 310 C#-Dateien übersetzt, Begründungen vollständig
erhalten: blockweise gleiche Anzahl wie vorher, kein Block unter 60 % seiner
Länge, der Code außerhalb der Kommentare per Tokenizer byte-identisch geprüft.
Zitate deutscher Oberflächentexte und Testdaten bleiben deutsch.

WebUI: Kommentare in JS/CSS/HTML übersetzt, JSDoc-@param an die in 4b
umbenannten Parameter angeglichen.

Dabei behoben:
- 4b hatte "tag" (HTML-Tag) als deutsches "Tag" gelesen und zu "dayValue"
  gemacht (makeElement, svg, Tagesübersicht) - zurück auf tag/day.
- Aufgaben "InProgress" bekamen die Plakettenart "laufend", für die es nie eine
  CSS-Klasse gab - jetzt "success" wie laufende Instanzen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 12:45:03 +02:00

150 lines
5.9 KiB
C#

using ClawdDotNet.Core.Config;
using Shouldly;
namespace ClawdDotNet.App.Tests;
/// <summary>
/// Where an instance logs to and backs up to — and that two instances do not end up
/// in the same folder (#528, stage 1).
///
/// <para><b>The occasion.</b> Both defaults were application-wide. <c>Startup.log</c>
/// therefore contained alternating lines of two instances, without marking which one
/// was speaking; and because retention cleans up by prefix in exactly one folder,
/// the running instance threw away the other's archives along with its own. As long as that is
/// the case, every troubleshooting session in multi-instance operation is guesswork.</para>
///
/// <para><b>What remains from #375.</b> A relative value is resolved against the
/// instance directory, not against the working directory of the process. A
/// systemd service without <c>WorkingDirectory=</c> starts in <c>/</c>, and <c>"./Logs"</c>
/// then pointed to <c>/Logs</c> — not creatable for a service account.</para>
/// </summary>
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
};
// ─── Defaults ───
[Fact]
public void Die_Vorbelegungen_sind_leer()
{
// The core: empty means "take the folder of this instance". If a value stands here,
// every new instance carries it around.
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"));
}
/// <summary>
/// The actual promise of stage 1. Everything else in this file checks the
/// mechanics; this test checks the promise.
/// </summary>
[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);
}
// ─── Entered values ───
[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()
{
// Not against the working directory of the process — that was the error from #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)
{
// That's why LoadInstanceConfig may turn them into "empty" without anything
// shifting.
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"));
}
// ─── Reference point ───
[Fact]
public void Ein_leeres_WorkingDirectory_faellt_auf_den_Instanzpfad_zurueck()
{
// Since CreateInstance the field is in the file as an absolute path, but may have been
// emptied by hand. Then the place it was loaded from carries the day.
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/" is the old default of the field and would again have been resolved against the
// working directory of the process.
AppHost.ResolveLogDirectory(
Instance(logDirectory: "Logs", workingDirectory: "./data/"), InstancePath)
.ShouldBe(Path.Combine(InstancePath, "Logs"));
}
}