Testanleitung: eigenes X-Display je Projekt fuer Parallelbetrieb
Damit mehrere Agenten gleichzeitig Oberflaechen testen koennen, bekommt jedes Projekt eine feste Displaynummer (Vorgabe Richard): :99 PolyTrader, :98 Predictalytics, :97 ClawdDotNet, :96 IBKRTrader, :95 und absteigend fuer kuenftige Projekte. Zwei Prozesse auf demselben Display sehen die Fenster des jeweils anderen - Klicks landen im falschen Programm, Aufnahmen zeigen fremde Anwendungen. Beim Durcharbeiten fielen zwei weitere Kollisionspunkte auf, die zum Parallelbetrieb dazugehoeren und mit aufgenommen wurden: - Screenshot- und Logdateien in /tmp brauchen ein Projektpraefix. /tmp/v_1.png ueberschreiben sich parallel laufende Projekte gegenseitig. - "xvfb-run -a" darf NICHT mehr verwendet werden: Das -a sucht sich selbst ein freies Display und beginnt dabei bei :99 - ausgerechnet PolyTraders Nummer. Stattdessen "xvfb-run -n <nummer>". Die Warnung ist nicht theoretisch: Auf der VM lag ein verwaister X98-Socket, entstanden durch genau so einen "xvfb-run -a"-Aufruf beim smoke-ui-Test, als :99 belegt war. Er blockierte Predictalytics' reservierte Nummer, ohne dass ein Prozess lief. Entfernt, und die Anleitung erklaert jetzt, wie man verwaiste Sockets erkennt (ls /tmp/.X11-unix/ gegen pgrep -a Xvfb lesen) und aufraeumt. Weiter ergaenzt: - pkill nie ohne Displaynummer - "pkill Xvfb" erschlaegt die Sitzungen aller anderen Projekte. - DISPLAY in jedem Skript setzen, sonst landet man auf :0, dem echten Desktop. - Die Skriptvorlage hat jetzt einen Kopf mit PROJEKT/DISP/FENSTER; das ist alles, was sich je Projekt unterscheidet. Praktisch gegengetestet. - Aufraeumabschnitt und Belegungsliste um Displays und Verzeichnisse erweitert. Nebenbei aufgefallen: Das PolyTrader-Publish lag unter ~/pt-test statt ~/polytrader-test und verletzte damit die eigene Verzeichniskonvention. Umbenannt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence.Ef;
|
||||
using PolyTraderSharp.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace PolyTrader.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Sichert die Befunde des Linux-Sichttests vom 26.08.2026 ab
|
||||
/// (docs/pruefplaene/BEFUND-Linux-Betrieb-2026-08-26.md), damit sie nicht zurückkehren.
|
||||
/// </summary>
|
||||
public class LinuxFindingsTests
|
||||
{
|
||||
// ── B-5: Windows-Pfad als Standardwert unter Linux ──────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void Mullvad_default_path_matches_the_platform()
|
||||
{
|
||||
string expected = System.OperatingSystem.IsWindows()
|
||||
? @"C:\Program Files\Mullvad VPN\resources\mullvad.exe"
|
||||
: "/usr/bin/mullvad";
|
||||
|
||||
Assert.Equal(expected, ServerSettings.DefaultMullvadCliPath);
|
||||
Assert.Equal(expected, new ServerSettings().MullvadCliPath);
|
||||
}
|
||||
|
||||
// ── B-14: mehrzeilige Texte in einzeiligen Feldern ──────────────────────────────
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(TrackedTrader.Description))]
|
||||
[InlineData(nameof(TrackedTrader.Reasoning))]
|
||||
public void Long_free_text_properties_are_marked_multiline(string propertyName)
|
||||
{
|
||||
var p = typeof(TrackedTrader).GetProperty(propertyName)!;
|
||||
var attr = p.GetCustomAttribute<DataTypeAttribute>();
|
||||
|
||||
Assert.NotNull(attr);
|
||||
Assert.Equal(DataType.MultilineText, attr!.DataType);
|
||||
}
|
||||
|
||||
// ── B-15: ein fehlerhafter Datensatz legt die Modul-Hydration lahm ──────────────
|
||||
|
||||
[Fact]
|
||||
public void Assigned_accounts_round_trip_through_json()
|
||||
{
|
||||
var set = new System.Collections.Generic.HashSet<int> { 1, 2 };
|
||||
Assert.Equal(set, AccountIdSetJson.Deserialize(AccountIdSetJson.Serialize(set)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Empty_column_becomes_an_empty_assignment()
|
||||
{
|
||||
Assert.Empty(AccountIdSetJson.Deserialize(null));
|
||||
Assert.Empty(AccountIdSetJson.Deserialize(""));
|
||||
Assert.Empty(AccountIdSetJson.Deserialize("[]"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Plain_number_list_is_still_understood()
|
||||
{
|
||||
AccountIdSetJson.ResetDiagnostics();
|
||||
|
||||
Assert.Equal(new System.Collections.Generic.HashSet<int> { 1, 2 },
|
||||
AccountIdSetJson.Deserialize("1,2"));
|
||||
Assert.Equal(0, AccountIdSetJson.MalformedCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unreadable_value_yields_an_empty_set_and_is_counted()
|
||||
{
|
||||
AccountIdSetJson.ResetDiagnostics();
|
||||
|
||||
// Der Fall aus dem Test: kaputter Wert statt JSON-Array. Frueher warf die
|
||||
// EF-Wertkonvertierung hier und es wurde KEIN einziger Trader geladen.
|
||||
Assert.Empty(AccountIdSetJson.Deserialize("{kaputt"));
|
||||
|
||||
Assert.Equal(1, AccountIdSetJson.MalformedCount);
|
||||
Assert.Equal("{kaputt", AccountIdSetJson.LastMalformedValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_that_is_not_a_number_list_is_not_silently_accepted()
|
||||
{
|
||||
AccountIdSetJson.ResetDiagnostics();
|
||||
|
||||
Assert.Empty(AccountIdSetJson.Deserialize("1,zwei"));
|
||||
Assert.Equal(1, AccountIdSetJson.MalformedCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user