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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
da4ceac7d5
commit
837a634a22
@@ -4,7 +4,7 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests für die interne Agenten-Kommunikation A2A (#208).
|
||||
/// Tests for the internal agent communication A2A (#208).
|
||||
/// </summary>
|
||||
public sealed class AgentCommunicationTests
|
||||
{
|
||||
|
||||
@@ -3,17 +3,17 @@ using ClawdDotNet.Core.Instances;
|
||||
namespace ClawdDotNet.Web.Tests.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Ein Test, der nur dort etwas aussagt, wo der Instanz-Socket eine Datei ist.
|
||||
/// A test that only says something where the instance socket is a file.
|
||||
///
|
||||
/// <para>Unter Linux ist er ein Unix-Domain-Socket im Instanzverzeichnis und damit ein
|
||||
/// Eintrag im Dateisystem — er überlebt den Prozess, er hat Rechte, er kann liegen
|
||||
/// bleiben. Unter Windows ist er eine Named Pipe: kein Eintrag, keine Leiche, nichts
|
||||
/// aufzuräumen.</para>
|
||||
/// <para>Under Linux it is a Unix domain socket in the instance directory and thus an
|
||||
/// entry in the file system — it survives the process, it has rights, it can be left
|
||||
/// behind. Under Windows it is a named pipe: no entry, no corpse, nothing
|
||||
/// to clean up.</para>
|
||||
///
|
||||
/// <para>Solche Tests unter Windows mitlaufen zu lassen hieße, sie grün zu sehen, ohne
|
||||
/// dass irgendetwas geprüft wurde. Deshalb ein Übersprung mit Begründung statt eines
|
||||
/// stillen <c>return</c>: Im Bericht ist dann sichtbar, dass hier etwas <em>nicht</em>
|
||||
/// geprüft wurde. Dasselbe Muster wie <c>LinuxFactAttribute</c> in den Kern-Tests.</para>
|
||||
/// <para>Letting such tests run along under Windows would mean seeing them green without
|
||||
/// anything having been checked. Hence a skip with a reason instead of a
|
||||
/// silent <c>return</c>: in the report it is then visible that something was <em>not</em>
|
||||
/// checked here. The same pattern as <c>LinuxFactAttribute</c> in the core tests.</para>
|
||||
/// </summary>
|
||||
public sealed class SocketFileFactAttribute : FactAttribute
|
||||
{
|
||||
|
||||
@@ -12,17 +12,17 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Der Socket im Instanzverzeichnis (#528, Stufe 2 / E-M1).
|
||||
/// The socket in the instance directory (#528, stage 2 / E-M1).
|
||||
///
|
||||
/// <para>Über ihn wird der Instanzmanager die Instanz erreichen. Drei Zusagen hält
|
||||
/// dieser Test fest: Er ist <b>immer</b> da, auch ohne Weboberfläche. Er braucht
|
||||
/// <b>kein Token</b> — seine Grenze steht am Dateisystem. Und der TCP-Port braucht
|
||||
/// weiterhin eins, denn dort steht keine.</para>
|
||||
/// <para>The instance manager will reach the instance through it. This test records three
|
||||
/// promises: it is <b>always</b> there, even without a web UI. It needs
|
||||
/// <b>no token</b> — its boundary is the file system. And the TCP port still
|
||||
/// needs one, because there is none there.</para>
|
||||
///
|
||||
/// <para>Der letzte Punkt ist der, an dem eine Verwechslung teuer wäre: Wer die
|
||||
/// Unterscheidung aus fehlenden IP-Adressen erraten wollte, ließe im Zweifel eine
|
||||
/// TCP-Anfrage ohne Token durch. Sie kommt deshalb aus einer Marke, die der
|
||||
/// Socket-Zuhörer selbst setzt.</para>
|
||||
/// <para>The last point is the one where a mix-up would be expensive: whoever wanted to
|
||||
/// guess the distinction from missing IP addresses would, in case of doubt, let a
|
||||
/// TCP request through without a token. It therefore comes from a marker that the
|
||||
/// socket listener sets itself.</para>
|
||||
/// </summary>
|
||||
public sealed class InstanceSocketTests : IDisposable
|
||||
{
|
||||
@@ -34,7 +34,7 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
try { Directory.Delete(_root, recursive: true); }
|
||||
catch { /* Ein liegengebliebener Testordner faerbt keinen Lauf rot. */ }
|
||||
catch { /* A leftover test folder does not turn a run red. */ }
|
||||
}
|
||||
|
||||
private AppHost NeuerHost(bool mitWeboberflaeche, int port = 0)
|
||||
@@ -72,13 +72,13 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
return port;
|
||||
}
|
||||
|
||||
// ─── Der Socket trägt ───
|
||||
// ─── The socket holds ───
|
||||
|
||||
[Fact]
|
||||
public async Task Der_Socket_antwortet_auch_ohne_Weboberflaeche()
|
||||
{
|
||||
// Die Vorbelegung: webUiEnabled ist aus. Frueher lief dann gar nichts, und die
|
||||
// Instanz war von aussen nicht ansprechbar.
|
||||
// The default: webUiEnabled is off. Formerly nothing ran at all then, and the
|
||||
// instance was not addressable from outside.
|
||||
await using var host = NeuerHost(mitWeboberflaeche: false);
|
||||
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
|
||||
|
||||
@@ -100,12 +100,12 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
|
||||
web.ShouldNotBeNull();
|
||||
|
||||
// Kein Authorization-Kopf, mit Absicht.
|
||||
// No Authorization header, on purpose.
|
||||
using var client = InstanceEndpoint.CreateClient(host.InstancePath);
|
||||
(await client.GetAsync("/api/info")).EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
// ─── Der Port bleibt bewacht ───
|
||||
// ─── The port stays guarded ───
|
||||
|
||||
[Fact]
|
||||
public async Task Ueber_TCP_gilt_die_Token_Pflicht_weiter()
|
||||
@@ -127,7 +127,7 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
(await client.GetAsync("/api/info")).EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
// ─── Adressen ───
|
||||
// ─── Addresses ───
|
||||
|
||||
[Fact]
|
||||
public void Zwei_Instanzen_bekommen_zwei_Adressen()
|
||||
@@ -142,8 +142,8 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
[Fact]
|
||||
public void Dieselbe_Instanz_bekommt_dieselbe_Adresse()
|
||||
{
|
||||
// Der Manager rechnet die Adresse aus dem Pfad aus, den er selbst kennt — sie
|
||||
// muss also aus jeder Schreibweise desselben Verzeichnisses gleich herauskommen.
|
||||
// The manager computes the address from the path it knows itself — so it
|
||||
// must come out the same from every spelling of the same directory.
|
||||
var a = Path.Combine(_root, "Instances", "Test");
|
||||
var b = Path.Combine(_root, "Instances", "Unterwegs", "..", "Test");
|
||||
|
||||
@@ -151,14 +151,14 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
InstanceEndpoint.SocketPath(a).ShouldBe(InstanceEndpoint.SocketPath(b));
|
||||
}
|
||||
|
||||
// ─── Aufräumen ───
|
||||
// ─── Cleaning up ───
|
||||
|
||||
/// <summary>
|
||||
/// Eine liegengebliebene Socketdatei darf den nächsten Start nicht verhindern.
|
||||
/// A leftover socket file must not prevent the next start.
|
||||
///
|
||||
/// <para>Ein Unix-Domain-Socket überlebt den Prozess, der ihn angelegt hat. Nach
|
||||
/// einem harten Ende — genau dem Fall aus #529 — bekäme der nächste Start
|
||||
/// <c>EADDRINUSE</c> von einem Prozess, den es nicht mehr gibt.</para>
|
||||
/// <para>A Unix domain socket survives the process that created it. After
|
||||
/// a hard end — exactly the case from #529 — the next start would get
|
||||
/// <c>EADDRINUSE</c> from a process that no longer exists.</para>
|
||||
/// </summary>
|
||||
[SocketFileFact]
|
||||
public async Task Eine_liegengebliebene_Socketdatei_haelt_den_Start_nicht_auf()
|
||||
@@ -190,14 +190,14 @@ public sealed class InstanceSocketTests : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Die Steuerung des Instanzprozesses: beenden und Fenster nach vorn holen
|
||||
/// (#528, Stufen 3 und 5).
|
||||
/// Control of the instance process: end it and bring its window to the front
|
||||
/// (#528, stages 3 and 5).
|
||||
///
|
||||
/// <para><b>Beides gibt es ausschließlich über den Socket.</b> Über TCP existieren die
|
||||
/// Endpunkte nicht — auch mit gültigem Token nicht, und sie antworten dort mit 404 statt
|
||||
/// mit 403: Was es nicht gibt, muss man auch nicht erklären. Die Lebensdauer einer Instanz
|
||||
/// gehört dem Instanzmanager; eine Browsersitzung soll den Prozess, der sie bedient, weder
|
||||
/// beenden noch sein Fenster aufreißen können.</para>
|
||||
/// <para><b>Both exist exclusively via the socket.</b> Over TCP the
|
||||
/// endpoints do not exist — not even with a valid token, and there they answer with 404 instead of
|
||||
/// 403: what does not exist need not be explained. The lifetime of an instance
|
||||
/// belongs to the instance manager; a browser session should be able neither to end the process
|
||||
/// serving it nor to tear open its window.</para>
|
||||
/// </summary>
|
||||
public sealed class InstanceControlTests : IDisposable
|
||||
{
|
||||
@@ -209,7 +209,7 @@ public sealed class InstanceControlTests : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
try { Directory.Delete(_root, recursive: true); }
|
||||
catch { /* Ein liegengebliebener Testordner faerbt keinen Lauf rot. */ }
|
||||
catch { /* A leftover test folder does not turn a run red. */ }
|
||||
}
|
||||
|
||||
private AppHost NeuerHost(int port)
|
||||
@@ -264,7 +264,7 @@ public sealed class InstanceControlTests : IDisposable
|
||||
using var client = new HttpClient { BaseAddress = new Uri($"http://127.0.0.1:{port}") };
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {Token}");
|
||||
|
||||
// Mit gueltigem Token - und trotzdem nicht vorhanden.
|
||||
// With a valid token - and still not present.
|
||||
(await client.PostAsync("/api/instanz/beenden", content: null)).StatusCode
|
||||
.ShouldBe(System.Net.HttpStatusCode.NotFound);
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Kein Zugangsdatum verlässt die API.
|
||||
/// No credential leaves the API.
|
||||
///
|
||||
/// <para>Das ist die Prüfung, die man nicht von Hand machen will: Werkzeug-Einstellungen
|
||||
/// sind ein freies Wörterbuch, und ob darin ein Passwort steckt, entscheidet der Name des
|
||||
/// Schlüssels. Ein <c>return agent.Tools;</c> hätte den ganzen Baum samt Passwörtern ins
|
||||
/// Netz geschickt — die Sorte Fehler, die niemandem auffällt, weil alles funktioniert.</para>
|
||||
/// <para>This is the check nobody wants to do by hand: tool settings
|
||||
/// are a free dictionary, and whether there is a password in it is decided by the name of the
|
||||
/// key. A <c>return agent.Tools;</c> would have sent the whole tree including passwords onto the
|
||||
/// network — the kind of error nobody notices, because everything works.</para>
|
||||
/// </summary>
|
||||
public sealed class SecretMaskingTests
|
||||
{
|
||||
@@ -26,15 +26,15 @@ public sealed class SecretMaskingTests
|
||||
|
||||
var dto = Mapping.ToDto("Mail", einstellungen);
|
||||
|
||||
// Keys.ShouldContain statt ShouldContainKey: Die DTOs geben
|
||||
// IReadOnlyDictionary heraus, und Shouldlys Woerterbuch-Erweiterungen sitzen
|
||||
// auf IDictionary.
|
||||
// Keys.ShouldContain instead of ShouldContainKey: the DTOs hand out
|
||||
// IReadOnlyDictionary, and Shouldly's dictionary extensions sit
|
||||
// on IDictionary.
|
||||
dto.Values.Keys.ShouldContain("host");
|
||||
dto.Values.Keys.ShouldContain("port");
|
||||
dto.Values.Keys.ShouldNotContain("password");
|
||||
|
||||
// Was herauskommt, ist die Auskunft „da steht etwas" — mehr braucht eine
|
||||
// Anzeige nicht, und mehr darf sie nicht wissen.
|
||||
// What comes out is the information "something is there" — a display
|
||||
// needs no more, and may know no more.
|
||||
dto.Secrets["password"].ShouldBeTrue();
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ public sealed class SecretMaskingTests
|
||||
[InlineData("webUiToken")]
|
||||
public void Jeder_bekannte_Geheimnisname_wird_maskiert(string schluessel)
|
||||
{
|
||||
// Die Liste kommt aus ConfigSecrets und nicht aus einer zweiten hier: Eine
|
||||
// zweite waere die, die beim naechsten neuen Werkzeug vergessen wird.
|
||||
// The list comes from ConfigSecrets and not from a second one here: a
|
||||
// second would be the one forgotten with the next new tool.
|
||||
ConfigSecrets.IsSecretKey(schluessel).ShouldBeTrue();
|
||||
|
||||
Mapping.ToDto("X", new Dictionary<string, object?> { [schluessel] = "geheim" })
|
||||
@@ -83,8 +83,8 @@ public sealed class SecretMaskingTests
|
||||
[Fact]
|
||||
public void Ein_serialisiertes_DTO_enthaelt_das_Geheimnis_nicht()
|
||||
{
|
||||
// Der Test, der wirklich zaehlt: nicht die Struktur, sondern das, was ueber die
|
||||
// Leitung geht.
|
||||
// The test that really counts: not the structure, but what goes over the
|
||||
// line.
|
||||
var dto = Mapping.ToDto("Mail", new Dictionary<string, object?>
|
||||
{
|
||||
["host"] = "mail.example",
|
||||
|
||||
@@ -11,17 +11,17 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Die Weboberfläche muss sich zügig beenden lassen — auch mit offenen Ereignisströmen.
|
||||
/// The web UI must be able to shut down quickly — even with open event streams.
|
||||
///
|
||||
/// <para><b>Der Anlass.</b> Ein Ereignisstrom endet nie von selbst. Beim geordneten
|
||||
/// Herunterfahren legt der Browser nicht auf, also feuert <c>RequestAborted</c> nicht,
|
||||
/// und Kestrel wartet geduldig darauf, dass die Anfrage fertig wird. Erst nach der Frist
|
||||
/// von <c>StopAsync</c> wurde abgeschnitten: fünf Sekunden, in denen die Anwendung stand.
|
||||
/// Sichtbar wurde es beim Instanzwechsel — zwischen „Wechseln" und dem Neustart lag jedes
|
||||
/// Mal diese Pause, sobald irgendwo ein Browserfenster offen war.</para>
|
||||
/// <para><b>The occasion.</b> An event stream never ends by itself. During an orderly
|
||||
/// shutdown the browser does not hang up, so <c>RequestAborted</c> does not fire,
|
||||
/// and Kestrel waits patiently for the request to finish. Only after the deadline
|
||||
/// of <c>StopAsync</c> was it cut off: five seconds in which the application stood still.
|
||||
/// It became visible when switching instances — between "switch" and the restart there was this
|
||||
/// pause every time, as soon as a browser window was open anywhere.</para>
|
||||
///
|
||||
/// <para>Die Ströme hängen jetzt zusätzlich an <c>ApplicationStopping</c>. Dieser Test
|
||||
/// hält die Zusage fest, damit sie nicht beim nächsten Umbau still verlorengeht.</para>
|
||||
/// <para>The streams now additionally hang on <c>ApplicationStopping</c>. This test
|
||||
/// records the promise so it does not get silently lost in the next rework.</para>
|
||||
/// </summary>
|
||||
public sealed class ShutdownTests : IDisposable
|
||||
{
|
||||
@@ -31,9 +31,9 @@ public sealed class ShutdownTests : IDisposable
|
||||
private const string Token = "ein-hinreichend-langes-testtoken";
|
||||
|
||||
/// <summary>
|
||||
/// Grosszuegig bemessen: Gemessen wird gegen die Frist von StopAsync (fuenf
|
||||
/// Sekunden). Bleibt der Test unter zwei, ist die Zusage eingehalten, ohne dass ein
|
||||
/// langsamer Bauserver ihn rot faerbt.
|
||||
/// Generously sized: measured against the deadline of StopAsync (five
|
||||
/// seconds). If the test stays below two, the promise is kept without a
|
||||
/// slow build server turning it red.
|
||||
/// </summary>
|
||||
private static readonly TimeSpan Grenze = TimeSpan.FromSeconds(2);
|
||||
|
||||
@@ -63,8 +63,8 @@ public sealed class ShutdownTests : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ein freier Port vom Betriebssystem. Eine feste Zahl liesse zwei Testlaeufe
|
||||
/// nebeneinander scheitern — und genau solche Fehler sucht man am laengsten.
|
||||
/// A free port from the operating system. A fixed number would let two test runs
|
||||
/// fail side by side — and those are exactly the errors you search for the longest.
|
||||
/// </summary>
|
||||
private static int FreierPort()
|
||||
{
|
||||
@@ -87,8 +87,8 @@ public sealed class ShutdownTests : IDisposable
|
||||
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {Token}");
|
||||
|
||||
// Den Strom wirklich oeffnen und die erste Zeile abwarten: Erst dann haelt
|
||||
// Kestrel die Anfrage, und erst dann prueft der Test das, was er pruefen will.
|
||||
// Really open the stream and wait for the first line: only then does
|
||||
// Kestrel hold the request, and only then does the test check what it wants to check.
|
||||
using var antwort = await client.GetAsync(
|
||||
$"http://127.0.0.1:{port}/events?token={Token}",
|
||||
HttpCompletionOption.ResponseHeadersRead);
|
||||
@@ -125,14 +125,14 @@ public sealed class ShutdownTests : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ein belegter Port kostet die Weboberfläche, nicht die Instanz.
|
||||
/// A taken port costs the web UI, not the instance.
|
||||
///
|
||||
/// <para>Vorher gab <c>TryStart</c> hier <c>null</c> zurück, und damit war die
|
||||
/// gesamte HTTP-Fläche weg. Seit der Socket dazugehört, ist das die falsche
|
||||
/// Rangfolge: Über ihn wird der Instanzmanager die Instanz erreichen, und ihn wegen
|
||||
/// eines belegten Ports zu verlieren hieße, die Instanz unerreichbar zu machen, weil
|
||||
/// eine zweite schon läuft — also genau in dem Fall, für den es den Manager
|
||||
/// gibt.</para>
|
||||
/// <para>Previously <c>TryStart</c> returned <c>null</c> here, and with that the
|
||||
/// entire HTTP surface was gone. Since the socket belongs to it, that is the wrong
|
||||
/// order of priority: the instance manager will reach the instance through it, and losing it because
|
||||
/// of a taken port would mean making the instance unreachable because
|
||||
/// a second one is already running — i.e. exactly in the case the manager
|
||||
/// exists for.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Ein_belegter_Port_kostet_nur_die_Weboberflaeche()
|
||||
@@ -149,7 +149,7 @@ public sealed class ShutdownTests : IDisposable
|
||||
web.ShouldNotBeNull();
|
||||
web!.Url.ShouldBeNull("Die Weboberfläche konnte nicht binden — das gehört gesagt.");
|
||||
|
||||
// Der Socket traegt trotzdem.
|
||||
// The socket holds anyway.
|
||||
using var client = InstanceEndpoint.CreateClient(host.InstancePath);
|
||||
(await client.GetAsync("/api/info")).EnsureSuccessStatusCode();
|
||||
}
|
||||
@@ -157,6 +157,6 @@ public sealed class ShutdownTests : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
try { Directory.Delete(_root, recursive: true); }
|
||||
catch { /* Ein liegengebliebener Testordner faerbt keinen Lauf rot. */ }
|
||||
catch { /* A leftover test folder does not turn a run red. */ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Befunde aus der Sichtung der Weboberflaeche im Testbetrieb (#572): #591 (Feldnamen) und
|
||||
/// #536 (Richtung der A2A-Antworten).
|
||||
/// Findings from reviewing the web UI in test operation (#572): #591 (field names) and
|
||||
/// #536 (direction of the A2A answers).
|
||||
/// </summary>
|
||||
public sealed class TestbetriebWebTests
|
||||
{
|
||||
// ─── #591 Ereignisstrom und Uebertragungstypen ───
|
||||
// ─── #591 event stream and transfer types ───
|
||||
|
||||
[Fact]
|
||||
public void Protokollzeilen_im_Ereignisstrom_kommen_in_camelCase()
|
||||
@@ -63,7 +63,7 @@ public sealed class TestbetriebWebTests
|
||||
public void Einmalige_Aufgabe_hat_keinen_Termin()
|
||||
=> new TaskItem { Id = "t-1", Title = "Einrichtung" }.ToDto().When.ShouldBeNull();
|
||||
|
||||
// ─── #536 Absender und Empfaenger ───
|
||||
// ─── #536 sender and recipient ───
|
||||
|
||||
private static ChatEntry Anfrage(string vonName, string vonId, string text, int minute)
|
||||
=> new("user", $"[Nachricht von Agent \"{vonName}\" ({vonId})]\n\n{text}",
|
||||
|
||||
@@ -4,10 +4,10 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Web.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Die Weboberfläche macht aus einer lokalen Anwendung einen Netzwerkdienst, der Agenten
|
||||
/// mit Datei-, Mail-, FTP- und Datenbankzugriff steuert. Was hier geprüft wird, sind
|
||||
/// keine Feinheiten der Konfiguration, sondern die Bedingungen, unter denen sie
|
||||
/// überhaupt hochkommen darf.
|
||||
/// The web UI turns a local application into a network service that controls agents
|
||||
/// with file, mail, FTP and database access. What is checked here are
|
||||
/// not subtleties of configuration, but the conditions under which it
|
||||
/// may come up at all.
|
||||
/// </summary>
|
||||
public sealed class WebUiOptionsTests
|
||||
{
|
||||
@@ -27,7 +27,7 @@ public sealed class WebUiOptionsTests
|
||||
[Fact]
|
||||
public void Sie_ist_in_der_Vorbelegung_aus()
|
||||
{
|
||||
// Wer einen Netzwerkdienst will, schaltet ihn ein. Nicht andersherum.
|
||||
// Whoever wants a network service switches it on. Not the other way round.
|
||||
new InstanceConfig().WebUiEnabled.ShouldBeFalse();
|
||||
new InstanceConfig().WebUiBinding.ShouldBe("loopback");
|
||||
new InstanceConfig().WebServerPort.ShouldBe(7001);
|
||||
@@ -43,8 +43,8 @@ public sealed class WebUiOptionsTests
|
||||
[Fact]
|
||||
public void Ohne_Token_startet_sie_nicht_einmal_auf_Loopback()
|
||||
{
|
||||
// Auf einer Maschine, auf der Agenten Browser-Werkzeuge bedienen, ist
|
||||
// „localhost" keine Vertrauensgrenze.
|
||||
// On a machine on which agents operate browser tools,
|
||||
// "localhost" is no trust boundary.
|
||||
WebUiOptions.TryCreate(Instanz(token: ""), out var problem).ShouldBeNull();
|
||||
problem.ShouldNotBeNull();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public sealed class WebUiOptionsTests
|
||||
[Fact]
|
||||
public void Alles_ausser_any_bleibt_Loopback()
|
||||
{
|
||||
// Ein Tippfehler in der Instanzdatei darf die Oberflaeche nicht ins Netz stellen.
|
||||
// A typo in the instance file must not put the user interface onto the network.
|
||||
WebUiOptions.TryCreate(Instanz(binding: "alle"), out _)!.LoopbackOnly.ShouldBeTrue();
|
||||
WebUiOptions.TryCreate(Instanz(binding: ""), out _)!.LoopbackOnly.ShouldBeTrue();
|
||||
}
|
||||
@@ -107,8 +107,8 @@ public sealed class WebUiOptionsTests
|
||||
[Fact]
|
||||
public void Das_Token_steht_geschuetzt_in_der_Instanzdatei()
|
||||
{
|
||||
// Ohne den Eintrag in ConfigSecrets staende es im Klartext neben dem
|
||||
// geschuetzten OpenRouter-Schluessel.
|
||||
// Without the entry in ConfigSecrets it would be in plain text next to the
|
||||
// protected OpenRouter key.
|
||||
Core.Security.ConfigSecrets.IsSecretKey("webUiToken").ShouldBeTrue();
|
||||
|
||||
var config = Instanz(token: "ein-hinreichend-langes-token");
|
||||
|
||||
Reference in New Issue
Block a user