enhancement
major
minor
major
minor
major
#30026
Instabiler Test: TestQueueReporter#testGetReport schlägt fehl, wenn zwei Builds auf demselben Knoten gleichzeitig laufen oder der Rechner ausgelastet ist
Problem
test.com.top_logic.reporting.remote.client.TestQueueReporter.testGetReport (Modul com.top_logic.reporting) schlägt sporadisch mit einem AssertionFailedError ohne Meldung fehl. Im erneuten Lauf ist er grün.
Beobachtet in tl-ci-pr #296/#298, #356/#358, #382/#383 und #665/#666. Jeweils liefen zwei Builds gleichzeitig. #665 und #666 starteten in derselben Sekunde (29.10.2026 06:19:15), in den Workspaces tl-ci-pr und tl-ci-pr@2, und beide schlugen in diesem Test fehl:
junit.framework.AssertionFailedError at test.com.top_logic.reporting.remote.client.TestQueueReporter.testGetReport(TestQueueReporter.java:78)
Im Log von #665:
ERROR [ReportCreator]: com.top_logic.base.office.ppt.POIPowerpoint - Error setting values. java.io.FileNotFoundException: /tmp/report/done/1f4f619d1a1862a67fe-7fff_SET_.ppt (No such file or directory) at com.top_logic.reporting.queue.ReportCreator.doCreateReport(ReportCreator.java:162)
Ursache
1. Gemeinsames Queue-Verzeichnis. Der QueueReporter legt seine Warteschlange im Verzeichnis report unter java.io.tmpdir an, solange path nicht konfiguriert ist (ReportQueueConstants.java:19-22). Weder die Anwendungs- noch die Testkonfiguration setzt path. Damit benutzen alle Builds (und alle Anwendungen) auf einem Knoten dasselbe /tmp/report/{open,work,done,error,temp}.
AbstractReporterTest löscht diese Verzeichnisse vor und nach jedem Test vollständig (setUp() Z. 57, tearDown() Z. 68, cleanUpDirectories() Z. 175). Der zweite Build löscht damit Aufträge und Ergebnisse des ersten, während dessen CreatorRunner daran arbeitet. Das Ergebnis kann nicht nach done geschrieben werden (FileNotFoundException). Auch das Verschieben nach error misslingt (ReportCreator.createReport() Z. 98-101). Der Auftrag liegt dann in keinem Verzeichnis mehr, getStatus() liefert die Dauer -1, also isError(), und Z. 78 assertFalse(status.isError()) schlägt fehl.
Der Runner des anderen Builds kann außerdem fremde Aufträge aus open übernehmen.
2. Feste Wartezeit. Der Test wartet fest 3 s (TestQueueReporter.java:74) und erwartet danach einen fertigen PPT-Report (Z. 79 assertTrue(status.isDone())). Unter Last dauert die POI-Erzeugung länger. Dann schlägt Z. 79 fehl, ebenfalls ohne Meldung.
3. Runner wird nicht gestoppt. QueueReporter.shutDown() (Z. 361-364) setzt nur das nicht-volatile Flag CreatorRunner.stopped (Z. 23, 76-78) und wartet nicht auf das Ende des Threads. tearDown() räumt die Verzeichnisse auf, während der Runner des vorherigen Tests (z.B. testCreateReport) noch einen Report schreibt. Diese Konstellation ist auch innerhalb eines Builds möglich.
Lösung
- Queue-Verzeichnis im Speicherbereich der Anwendung: reportingConf.xml setzt path der Sektion ReportQueueConstants auf %TMP_PATH% (%STORAGE_PATH%/var/tmp). Die Warteschlange liegt damit unter %TMP_PATH%/report statt unter java.io.tmpdir/report. Mehrere Anwendungen auf einem Rechner teilen sich keine Warteschlange mehr. In Tests folgt %STORAGE_PATH% dem Scratch-Verzeichnis, jeder Build-Workspace hat damit sein eigenes Queue-Verzeichnis.
- QueueReporter.initDirectories() legt das Queue-Verzeichnis samt fehlender Elternverzeichnisse an (mkdirs()), statt ein bereits existierendes Basisverzeichnis vorauszusetzen. %TMP_PATH% existiert in einer frischen Anwendung noch nicht.
- Thread.sleep(3000) durch Polling ersetzt: getStatus(id) wird abgefragt, bis isDone() oder isError() gilt, mit Timeout 60 s. Die Assertions haben Meldungen (Status, erwartete Dauer, Exception).
- CreatorRunner.stopped ist volatile, stopRunner() unterbricht den Thread. QueueReporter.shutDown() wartet mit join() (höchstens 30 s) auf sein Ende, bevor tearDown() die Verzeichnisse löscht.
Hinweis für Anwendungen: Aufträge, die beim Update noch in java.io.tmpdir/report liegen, werden nicht übernommen. Wer das bisherige Verzeichnis behalten will, setzt path in der Sektion ReportQueueConstants der eigenen Konfiguration.
Test
- TestQueueReporter in zwei gleichzeitig laufenden Builds auf demselben Knoten.