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>
14 KiB
Linux-Testumgebung (gemeinsam genutzte VM)
Stand: 26.08.2026 · Eingerichtet beim ersten Linux-Lauf von PolyTrader (Roadmap A4a).
Diese Anleitung gilt projektübergreifend. Sie richtet sich an alle Agenten und Entwickler, die auf der VM testen — nicht nur an PolyTrader. Die maßgebliche Fassung liegt auf der Maschine selbst unter
~/TESTUMGEBUNG.md; dieses Dokument im PolyTrader-Repo ist die versionierte Kopie. Wer etwas an der Umgebung ändert, zieht beide nach.
1. Was diese Maschine ist
Eine Ubuntu-Desktop-VM zum Testen — nicht für Produktivbetrieb, nicht für echte Zugangsdaten, nicht für Geld bewegende Läufe.
| System | Ubuntu 26.04 LTS, Kernel 7.0, x86_64 |
| Ausstattung | 31 GB RAM, 5 CPUs, ~33 GB freier Plattenplatz |
| Erreichbar | 192.168.40.48 über einen WireGuard-Tunnel |
| Benutzer | richard |
| Besonderheit | Desktop-Umgebung vorhanden — grafische Anwendungen sind testbar, nicht nur Dienste |
Warum eine Desktop-VM? Weil sich damit beides prüfen lässt: der kopflose Serverbetrieb (systemd) und die grafische Oberfläche auf der Zielplattform.
2. Zugang einrichten
Der Zugang läuft über SSH-Schlüssel. Passwort-Anmeldung wird nicht verwendet — Agenten geben grundsätzlich keine Passwörter ein.
2.1 Schlüssel erzeugen (auf dem eigenen Rechner)
ssh-keygen -t ed25519 -f ~/.ssh/testvm_<projekt> -N "" -C "<projekt>@testvm"
Ein eigener Schlüssel je Projekt — dann lässt sich einzelnen Projekten der Zugang entziehen, ohne alle anderen auszusperren.
2.2 Öffentlichen Schlüssel hinterlegen
Der Inhalt von ~/.ssh/testvm_<projekt>.pub wird auf der VM in ~/.ssh/authorized_keys
eingetragen. Das muss ein Mensch tun (einmalig, mit Passwort). Direkt auf der VM:
mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '<INHALT DER .pub-DATEI>' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
2.3 SSH-Konfiguration (auf dem eigenen Rechner)
Host testvm
HostName 192.168.40.48
User richard
IdentityFile ~/.ssh/testvm_<projekt>
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 4
⚠️ Kein ControlMaster/ControlPath eintragen, wenn der Client unter Windows läuft —
Windows-OpenSSH unterstützt Verbindungs-Multiplexing nicht und scheitert mit
„Failed to connect to new control master". Stattdessen mehrere Prüfschritte pro Aufruf bündeln.
Test: ssh testvm "hostname"
3. Was installiert ist
| Werkzeug | Version | Anmerkung |
|---|---|---|
| .NET SDK | 10.0.111 (Runtime 10.0.11) | SDK, nicht nur Runtime — auf der VM kann gebaut werden |
| MariaDB | 11.8.6 | Dienst mariadb, lauscht auf localhost:3306 |
| Git | 2.53.0 | |
| Xvfb | vorhanden | Virtueller Framebuffer für GUI-Tests ohne Bildschirm (siehe 4.7) |
| xdotool | vorhanden | Klicks und Tastatureingaben skripten |
| ImageMagick | vorhanden | import für Bildschirmaufnahmen, convert zum Zuschneiden |
| JetBrains Rider | vorhanden | |
| Docker | nicht installiert | |
| Node.js | nicht installiert |
Nicht vorhandene Werkzeuge dürfen installiert werden — aber bitte in der Belegungsliste (Abschnitt 6) vermerken, damit andere wissen, was sich geändert hat.
4. Konventionen für mehrere Projekte
Die Maschine wird von mehreren Projekten geteilt. Diese Regeln verhindern, dass sich Tests gegenseitig zerstören:
4.1 Datenbanken — je Projekt eine eigene
Niemals eine fremde Datenbank mitbenutzen und niemals eine Produktivdatenbank verbinden.
# Passwort erzeugen und ablegen (nur für den Besitzer lesbar)
PW=$(openssl rand -base64 18 | tr -d "/+=" | head -c 20)
echo "$PW" > ~/.<projekt>_test_dbpw && chmod 600 ~/.<projekt>_test_dbpw
sudo mariadb -e "CREATE DATABASE IF NOT EXISTS <projekt>_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '<projekt>_test'@'localhost' IDENTIFIED BY '$PW';
GRANT ALL PRIVILEGES ON <projekt>_test.* TO '<projekt>_test'@'localhost';
FLUSH PRIVILEGES;"
| Was | Schema | Beispiel |
|---|---|---|
| Datenbank | <projekt>_test |
polytrader_test |
| Benutzer | <projekt>_test@localhost |
polytrader_test |
| Passwortdatei | ~/.<projekt>_test_dbpw (Rechte 600) |
Die Rechte enden an der eigenen Datenbank — GRANT ALL ON <projekt>_test.*, nie global.
4.2 Verzeichnisse
| Zweck | Ort |
|---|---|
| Quellcode | ~/RiderProjects/<projekt> |
| Publish/Testlauf im Benutzerkontext | ~/<projekt>-test (voller Projektname, keine Kürzel) |
| Installation als Dienst | /opt/<projekt> |
4.3 systemd-Dienste
Unit-Name = Projektname: <projekt>.service. Eigenes Dienstkonto je Projekt:
sudo useradd --system --home-dir /opt/<projekt> --shell /usr/sbin/nologin <projekt>
Nach dem Test abschalten (Abschnitt 7) — sonst laufen irgendwann fünf Dienste, die niemand mehr zuordnen kann, und der nächste Test misst gegen fremde Last.
4.4 Ports
Vor dem Belegen prüfen: ss -tlnp. Belegte Ports stehen in Abschnitt 6. Wer einen Port dauerhaft
belegt, trägt ihn dort ein.
4.5 X-Displays — feste Nummer je Projekt
Damit mehrere Agenten gleichzeitig Oberflächen testen können, bekommt jedes Projekt ein eigenes virtuelles Display. Zwei Prozesse auf demselben Display sehen die Fenster des jeweils anderen — Klicks landen im falschen Programm, Aufnahmen zeigen fremde Anwendungen.
| Display | Projekt |
|---|---|
:99 |
PolyTrader |
:98 |
Predictalytics |
:97 |
ClawdDotNet |
:96 |
IBKRTrader |
:95 und absteigend |
künftige Projekte (nächstes freies von oben nach unten) |
Wer ein neues Projekt aufnimmt, trägt seine Nummer in die Belegungsliste (Abschnitt 6) ein.
Belegte Displays prüfen:
ls /tmp/.X11-unix/ # X0 = der echte Desktop, X99 = PolyTrader usw.
pgrep -a Xvfb # zeigt, welcher Xvfb auf welchem Display läuft
Verwaiste Sockets — beide Befehle gemeinsam lesen: Steht in /tmp/.X11-unix/ ein X98, zu
dem pgrep keinen Prozess zeigt, ist das ein Überbleibsel eines abgestürzten oder hart beendeten
Xvfb. Die Nummer wirkt dann belegt, obwohl sie frei ist. Aufräumen:
sudo rm -f /tmp/.X11-unix/X98
(Genau so entstanden: ein xvfb-run -a, das sich :98 nahm, weil :99 gerade lief — siehe die
Warnung in 4.7.)
⚠️ Drei Regeln, damit der Parallelbetrieb wirklich trägt:
DISPLAYin jedem Skript setzen (export DISPLAY=:98). Fehlt die Variable, landet man auf:0— dem echten Desktop — und stört den Menschen, der dort gerade arbeitet.- Nie
pkill Xvfbohne Displaynummer. Das erschlägt die Sitzungen aller anderen Projekte. Immerpkill -f "Xvfb :98". Dasselbe gilt für die eigene Anwendung:pkill -fmit einem zu allgemeinen Muster trifft fremde Prozesse — besser die gemerkte PID beenden. - Dateien in
/tmpmit Projektpräfix./tmp/v_1.pngüberschreibt sich gegenseitig; nimm/tmp/<projekt>_v_1.png. Gleiches gilt für Logdateien und Skripte.
4.6 Erhöhte Rechte
sudo verlangt normalerweise ein Passwort. Für Testläufe kann es befristet freigeschaltet werden
(ein Mensch, einmalig):
echo "richard ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/99-testing && sudo chmod 440 /etc/sudoers.d/99-testing
Nach Abschluss wieder entfernen:
sudo rm /etc/sudoers.d/99-testing
Das hebt den Schutz für das Konto vollständig auf — vertretbar auf einer Test-VM hinter VPN, aber nicht dauerhaft und niemals auf einer Produktivmaschine.
4.7 GUI-Anwendungen ohne Bildschirm testen
Braucht eine Anwendung X11, scheitert sie über SSH mit XOpenDisplay failed. Für einen einzelnen
Durchlauf genügt:
xvfb-run -n <deine-nummer> ./MeineAnwendung --irgendein-schalter
⚠️ Nicht xvfb-run -a verwenden. Das -a sucht sich selbst ein freies Display und beginnt
dabei bei :99 — also ausgerechnet auf PolyTraders Nummer. Läuft dort gerade nichts, belegt es
diese Nummer; startet PolyTrader kurz darauf, kollidieren beide. Mit -n 98 (bzw. der eigenen
Nummer aus 4.5) bleibt die Zuordnung eindeutig.
4.8 Oberflächen selbst begutachten — ohne Bildschirm, ohne fremde Hilfe
Ein Agent kann die Oberfläche eigenständig prüfen. Kein Mensch muss am Bildschirm sitzen und Bildschirmfotos schicken. Das Verfahren hat sich am 26.08.2026 bewährt und sieben Befunde zutage gefördert, darunter einen, der sämtliche Tabellen der Anwendung unsichtbar machte.
Drei Werkzeuge, alle installiert: Xvfb (virtuelles Display), xdotool (Klicken und Tippen),
ImageMagick (import für Aufnahmen, convert zum Zuschneiden).
Anders als xvfb-run wird das Display hier dauerhaft gestartet, damit sich zwischen den
Aufnahmen navigieren lässt:
#!/bin/bash
# Kopf anpassen - das ist alles, was sich je Projekt unterscheidet:
PROJEKT="polytrader"
DISP=":99" # eigene Nummer aus Abschnitt 4.5!
FENSTER="^PolyTrader$"
cd ~/$PROJEKT-test
export DISPLAY=$DISP
pkill -f "Xvfb $DISP" 2>/dev/null; sleep 1
Xvfb $DISP -screen 0 1600x1000x24 >/dev/null 2>&1 &
sleep 3
nohup ./MeineAnwendung > /tmp/${PROJEKT}_gui.log 2>&1 &
APP=$!
sleep 25 # Startzeit großzügig bemessen
# Fenster-ID ermitteln (bestaetigt, dass die Oberflaeche ueberhaupt erscheint)
xdotool search --name "$FENSTER" | head -1
# navigieren und aufnehmen - Dateinamen mit Projektpraefix, sonst
# ueberschreiben sich parallel laufende Projekte gegenseitig
shoot() { sleep 5; import -window root /tmp/${PROJEKT}_$1.png; echo " $1"; }
shoot 1_start
xdotool mousemove 127 205 click 1; shoot 2_zweite_ansicht
xdotool mousemove 127 237 click 1; shoot 3_dritte_ansicht
kill $APP 2>/dev/null; sleep 2; pkill -f "Xvfb $DISP" 2>/dev/null
Danach die Bilder abholen und ansehen:
scp testvm:'/tmp/polytrader_*.png' .
Was sich dabei bewährt hat:
- Großzügige Wartezeiten. 25 Sekunden nach dem Start, 5 Sekunden nach jedem Klick. Wird zu früh aufgenommen, entsteht ein halb gezeichnetes Fenster, und man sucht Fehler, die keine sind.
- Klickpunkte aus dem ersten Bild ablesen. Erst eine Aufnahme machen, dort die Koordinaten der Menüpunkte bestimmen, dann das Skript damit bestücken.
- Details vergrößern statt raten. Bei einem Verdacht den Ausschnitt herausschneiden:
convert v_1_start.png -crop 560x130+265+540 +repage -resize 200% /tmp/detail.png - Kontraste nachmessen statt schätzen. Ob Text lesbar ist, lässt sich ausrechnen — Pixelfarben auslesen und das WCAG-Verhältnis bestimmen (4,5:1 für normalen Text). So wird aus „wirkt blass" ein belegter Befund.
- Nur eine Instanz des eigenen Projekts gleichzeitig. Läuft der systemd-Dienst noch, schreiben
zwei Prozesse in dieselbe Datenbank und es entstehen Fehler, die nichts mit der Oberfläche zu tun
haben. Vorher
sudo systemctl stop <projekt>. (Ein anderes Projekt auf seinem eigenen Display stört dagegen nicht — dafür ist die Trennung aus 4.5 da.) - Auf Zeichen achten, die falsch aussehen. Fehlt eine Icon-Schriftart, ersetzt Fontconfig sie stillschweigend durch etwas anderes — ein Kalendersymbol wird dann zu einer sinnlosen Zahl. Das fällt nur im Bild auf, nie im Log.
Für einen Test mit echtem Bildschirm kann trotzdem jemand am Desktop der VM sitzen (oder RDP nutzen, Port 3389 ist offen) — nötig ist es für die Sichtprüfung nicht.
5. Was hier nicht passieren darf
- Keine Produktivdatenbank verbinden. Hintergrunddienste schreiben oft ungefragt — bei
PolyTrader etwa synchronisiert der
MarketSyncServiceselbständig Marktdaten. - Keine echten Handels-/Zugangsdaten hinterlegen. Keine privaten Schlüssel, keine Live-API-Zugänge, keine Lizenzschlüssel für Produktivsysteme.
- Keine fremden Projektverzeichnisse oder Datenbanken anfassen.
- Nichts Dauerhaftes hinterlassen, was nicht in Abschnitt 6 steht.
6. Belegung (bei Änderungen fortschreiben)
Datenbanken
| Datenbank | Benutzer | Projekt | seit |
|---|---|---|---|
polytrader_test |
polytrader_test@localhost |
PolyTrader | 26.08.2026 |
Dienste
| Unit | Konto | Verzeichnis | Projekt | seit |
|---|---|---|---|---|
polytrader.service |
polytrader |
/opt/polytrader |
PolyTrader | 26.08.2026 |
Verzeichnisse
| Projekt | Publish-Verzeichnis | Dienst |
|---|---|---|
| PolyTrader | ~/polytrader-test |
/opt/polytrader |
X-Displays (Vergabe siehe 4.5)
| Display | Projekt | Stand |
|---|---|---|
:0 |
echter Desktop — nie belegen | |
:99 |
PolyTrader | 26.08.2026 |
:98 |
Predictalytics | reserviert |
:97 |
ClawdDotNet | reserviert |
:96 |
IBKRTrader | reserviert |
:95 abwärts |
frei für künftige Projekte |
Ports (Stand 26.08.2026)
| Port | Belegt durch |
|---|---|
| 22 | SSH |
| 3306 | MariaDB (nur localhost) |
| 3389 | RDP |
| 5000 | vorhandener Dienst (nur IPv6-localhost) |
| 631 | CUPS |
Nachträglich installiert: MariaDB 11.8.6, Xvfb, xdotool, ImageMagick, x11-utils (alle am 26.08.2026 für PolyTrader).
7. Aufräumen nach dem Test
# Virtuelles Display beenden (falls noch offen) - NUR das eigene!
pkill -f "Xvfb :<deine-nummer>"
rm -f /tmp/<projekt>_*.png /tmp/<projekt>_gui.log
# Dienst abschalten und entfernen
sudo systemctl disable --now <projekt>
sudo rm -f /etc/systemd/system/<projekt>.service /etc/logrotate.d/<projekt>
sudo systemctl daemon-reload
# Dateien
sudo rm -rf /opt/<projekt> ~/<projekt>-test
sudo userdel <projekt>
# Datenbank (nur wenn nicht mehr gebraucht)
sudo mariadb -e "DROP DATABASE <projekt>_test; DROP USER '<projekt>_test'@'localhost';"
rm -f ~/.<projekt>_test_dbpw
# sudo-Freigabe zurücknehmen
sudo rm -f /etc/sudoers.d/99-testing
Danach Abschnitt 6 nachziehen.
8. Bekannte Einschränkungen
- Claude Code lässt sich auf dieser VM nicht betreiben. Es blockiert die Maschine bis zum Neustart; mehrere Reparaturversuche waren erfolglos, es wird auf ein Update gewartet. Agenten arbeiten deshalb über SSH von außen. (Speichermangel ist nicht die Ursache — die Maschine hat 31 GB, davon 25 GB frei.)
- Verbindungs-Multiplexing funktioniert nicht mit Windows-OpenSSH (siehe 2.3).
- Die Systemzeitzone ist Testgegenstand. Für realistische Servertests wird sie zeitweise auf
UTC gestellt (
sudo timedatectl set-timezone UTC). Wer sie ändert, stellt sie danach zurück — Standard hier istEurope/Berlin.