From dba67c1466b79855cb513ed68b07ae91c72ccfe2 Mon Sep 17 00:00:00 2001 From: jack <212554440+jackjackbits@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:12:50 +0200 Subject: [PATCH] Deflake AppArchitectureTests: raise the local waitUntil to settleTimeout (#1653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Deflake AppArchitectureTests: raise the local waitUntil to settleTimeout The file-local waitUntil defaulted to 3s — below the documented minimumSettleTimeout floor — and the recent-chats geo-dedup wait missed it on a loaded runner right after merge (the Combine hop through receive(on: .main) was starved). Every caller waits for a condition to become true, so green runs return immediately and never pay the 30s deadline. Co-Authored-By: Claude Fable 5 * Fix the real geo-dedup race: re-assert tracker state on each poll The 30s deadline didn't help — the recent-chats geo-dedup wait wasn't slow, it was permanently broken under parallel swift-test load: the view model's own channel binding delivers its initial .mesh selection asynchronously and resets the active participant geohash when it lands (GeohashSubscriptionManager → setActiveParticipantGeohash(nil)), wiping the test's setup so the dedup could never happen. Reproduced locally with `swift test --parallel`; standalone runs never hit it. The wait now re-asserts setActiveGeohash + recordParticipant on every poll (both idempotent) — the same self-healing pattern the geohash timeline test already uses for singleton interference. Interference heals on the next poll; a genuine dedup failure still times out. 6× full parallel runs green. Co-Authored-By: Claude Fable 5 --------- Co-authored-by: jack Co-authored-by: Claude Fable 5 --- bitchatTests/AppArchitectureTests.swift | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bitchatTests/AppArchitectureTests.swift b/bitchatTests/AppArchitectureTests.swift index 1ec52532..747e737b 100644 --- a/bitchatTests/AppArchitectureTests.swift +++ b/bitchatTests/AppArchitectureTests.swift @@ -69,7 +69,11 @@ private func makeArchitectureMessage( @MainActor private func waitUntil( - timeoutNanoseconds: UInt64 = 3_000_000_000, + // Settle deadline, not a latency budget (see TestConstants.settleTimeout): + // the old 3s default flaked on CI the moment a Combine hop through + // receive(on: .main) was starved. Every caller waits for a condition to + // become true, so passing runs return immediately. + timeoutNanoseconds: UInt64 = UInt64(TestConstants.settleTimeout * 1_000_000_000), pollNanoseconds: UInt64 = 20_000_000, _ condition: @escaping @MainActor () -> Bool ) async { @@ -580,11 +584,19 @@ struct AppArchitectureTests { // While that person is visible in the geohash roster, the chat row // collapses — same absent-from-rosters contract as mesh. - viewModel.participantTracker.setActiveGeohash("u4pruy") - viewModel.participantTracker.recordParticipant(pubkeyHex: pubkeyHex, geohash: "u4pruy") - + // + // Re-assert the tracker state on every poll: the view model's own + // channel binding delivers its initial .mesh selection asynchronously + // and resets the active participant geohash when it lands + // (GeohashSubscriptionManager.setActiveParticipantGeohash(nil)) — on + // a loaded parallel runner that reset arrives AFTER this setup and + // the dedup can never happen. Both calls are idempotent, so the + // interference heals on the next poll while a genuine dedup failure + // still times out. await waitUntil { - !peerListModel.recentChatRows.contains { $0.peerID == geoDMPeer } + viewModel.participantTracker.setActiveGeohash("u4pruy") + viewModel.participantTracker.recordParticipant(pubkeyHex: pubkeyHex, geohash: "u4pruy") + return !peerListModel.recentChatRows.contains { $0.peerID == geoDMPeer } } #expect(!peerListModel.recentChatRows.contains { $0.peerID == geoDMPeer }) #expect(peerListModel.recentChatRows.map(\.peerID) == [offlinePeerID])