test: Live-E2E-Test gegen SDK-Sync-Wettlauf abgesichert (sporadisch rot)

matrix 6.2 wirft den Fehler einer veralteten Sync-Antwort, bevor es die
Request-ID prueft: die 401 eines alten Long-Polls nach dem Logout loeste ein
zweites clear() aus (nach dispose -> "databaseFactory not initialized").
_logoutWithoutStraySync haelt die Sync-Schleife an und laesst den Long-Poll
auslaufen. Danach 3/3 Laeufe gruen, 0 verspaetete Logout-Meldungen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Bernd Steckmeister
2026-10-07 11:55:29 +02:00
co-authored by Claude Opus 5.5
parent d5ff7982a0
commit f4d334a60b
+20 -3
View File
@@ -207,6 +207,23 @@ Future<void> _login(Client client, _TestAccounts acc,
); );
} }
/// Logout ohne Nachzügler. matrix 6.2 prüft bei einer FEHLER-Antwort des
/// Sync-Long-Polls nicht, ob die Anfrage noch aktuell ist: Läuft beim Logout
/// noch ein Long-Poll mit dem alten Token, kommt dessen 401 (M_UNKNOWN_TOKEN)
/// später zurück und das SDK ruft erneut `clear()`. Direkt nach einem
/// Re-Login würde das die NEUE Session löschen, nach `dispose()` wirft es
/// (DB geschlossen → Fallback auf die globale sqflite-Factory) – genau das
/// machte diesen Test sporadisch rot (2026-10-07). Deshalb erst die
/// Sync-Schleife anhalten, den laufenden Long-Poll regulär auslaufen lassen
/// (≤ 30 s), dann abmelden. `clear()` schaltet backgroundSync wieder ein.
Future<void> _logoutWithoutStraySync(Client client) async {
client.backgroundSync = false;
await client
.oneShotSync(timeout: Duration.zero)
.timeout(const Duration(seconds: 60));
await client.logout();
}
/// Holt (oder erzeugt) den unverschlüsselten Autopilot-Testraum. /// Holt (oder erzeugt) den unverschlüsselten Autopilot-Testraum.
Future<Room> _ensureTestRoom(Client client) async { Future<Room> _ensureTestRoom(Client client) async {
const roomName = 'Pyramid Autopilot Testraum'; const roomName = 'Pyramid Autopilot Testraum';
@@ -340,7 +357,7 @@ void main() {
expect(client.userID?.toLowerCase(), acc.user1.toLowerCase()); expect(client.userID?.toLowerCase(), acc.user1.toLowerCase());
// ── Phase 4: Logout → Re-Login → alte Nachricht wieder lesbar ── // ── Phase 4: Logout → Re-Login → alte Nachricht wieder lesbar ──
await client.logout(); await _logoutWithoutStraySync(client);
expect(client.isLogged(), isFalse); expect(client.isLogged(), isFalse);
await _login(client, acc, await _login(client, acc,
user: acc.user1, pass: acc.pass1, device: 'Autopilot Enc-Test 2'); user: acc.user1, pass: acc.pass1, device: 'Autopilot Enc-Test 2');
@@ -348,7 +365,7 @@ void main() {
expect(await _timelineContains(roomAfter, marker), isTrue, expect(await _timelineContains(roomAfter, marker), isTrue,
reason: 'Alte Nachricht nach Logout+Re-Login nicht mehr lesbar'); reason: 'Alte Nachricht nach Logout+Re-Login nicht mehr lesbar');
// Aufräumen: Session serverseitig beenden, DB wird dabei geleert. // Aufräumen: Session serverseitig beenden, DB wird dabei geleert.
await client.logout(); await _logoutWithoutStraySync(client);
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);
}, },
skip: skip, skip: skip,
@@ -414,7 +431,7 @@ void main() {
expect(roomAfter, isNotNull, expect(roomAfter, isNotNull,
reason: 'Testraum nach Migration nicht mehr in der DB'); reason: 'Testraum nach Migration nicht mehr in der DB');
// Aufräumen (Session serverseitig beenden). // Aufräumen (Session serverseitig beenden).
await client.logout(); await _logoutWithoutStraySync(client);
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);
}, },
skip: skip, skip: skip,