diff --git a/bitchatTests/BLEServiceCoreTests.swift b/bitchatTests/BLEServiceCoreTests.swift index 5c48832a..3c856e19 100644 --- a/bitchatTests/BLEServiceCoreTests.swift +++ b/bitchatTests/BLEServiceCoreTests.swift @@ -39,7 +39,7 @@ struct BLEServiceCoreTests { ble._test_handlePacket(packet, fromPeerID: sender, signingPublicKey: signingKey) let receivedDuplicate = await TestHelpers.waitUntil( { delegate.publicMessagesSnapshot().count > 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!receivedDuplicate) @@ -117,7 +117,7 @@ struct BLEServiceCoreTests { let unsignedRelayed = await TestHelpers.waitUntil( { outbound.count(ofType: .leave) > 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!unsignedRelayed) #expect(ble.currentPeerSnapshots().contains { $0.peerID == alicePeerID }) @@ -133,7 +133,7 @@ struct BLEServiceCoreTests { let badSignatureRelayed = await TestHelpers.waitUntil( { outbound.count(ofType: .leave) > 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!badSignatureRelayed) #expect(ble.currentPeerSnapshots().contains { $0.peerID == alicePeerID }) @@ -1209,7 +1209,7 @@ struct BLEServiceCoreTests { let didObservePanicClosure = await withCheckedContinuation { continuation in DispatchQueue.global(qos: .userInitiated).async { let didObserveClosure = panicIngressObserver.waitUntilClosed( - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) gate.release() continuation.resume(returning: didObserveClosure) @@ -1340,7 +1340,7 @@ struct BLEServiceCoreTests { // rotated sender IDs never bought a sixth response. let exceededBudget = await TestHelpers.waitUntil( { outbound.count(ofType: .pong) > budget }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!exceededBudget) #expect(outbound.count(ofType: .pong) == budget) diff --git a/bitchatTests/ChatViewModelRefactoringTests.swift b/bitchatTests/ChatViewModelRefactoringTests.swift index d576106d..afc8e443 100644 --- a/bitchatTests/ChatViewModelRefactoringTests.swift +++ b/bitchatTests/ChatViewModelRefactoringTests.swift @@ -43,14 +43,14 @@ struct ChatViewModelRefactoringTests { transport.simulateConnect(peerID, nickname: "alice") let didResolve = await TestHelpers.waitUntil({ viewModel.getPeerIDForNickname("alice") != nil }, - timeout: TestConstants.shortTimeout) + timeout: TestConstants.settleTimeout) #expect(didResolve) // Action: User types /msg command viewModel.sendMessage("/msg @alice Hello Private World") let didSend = await TestHelpers.waitUntil({ transport.sentPrivateMessages.count == 1 }, - timeout: TestConstants.shortTimeout) + timeout: TestConstants.settleTimeout) #expect(didSend) // Assert: @@ -74,7 +74,7 @@ struct ChatViewModelRefactoringTests { transport.simulateConnect(peerID, nickname: "troll") let didResolve = await TestHelpers.waitUntil({ viewModel.getPeerIDForNickname("troll") != nil }, - timeout: TestConstants.shortTimeout) + timeout: TestConstants.settleTimeout) #expect(didResolve) // Action @@ -83,7 +83,7 @@ struct ChatViewModelRefactoringTests { // Assert // Verify identity manager was called to block "fingerprint_123" let didBlock = await TestHelpers.waitUntil({ identity.isBlocked(fingerprint: "fingerprint_123") }, - timeout: TestConstants.shortTimeout) + timeout: TestConstants.settleTimeout) #expect(didBlock) } @@ -114,7 +114,7 @@ struct ChatViewModelRefactoringTests { // Wait for async processing with proper timeout let found = await TestHelpers.waitUntil( { viewModel.privateChats[senderID]?.first?.content == "Secret" }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) // Assert @@ -140,7 +140,7 @@ struct ChatViewModelRefactoringTests { { viewModel.publicMessages(for: .mesh).contains(where: { $0.content == "Public Hi" }) }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) // Assert diff --git a/bitchatTests/ChatViewModelTests.swift b/bitchatTests/ChatViewModelTests.swift index 2093359d..7e4e46a1 100644 --- a/bitchatTests/ChatViewModelTests.swift +++ b/bitchatTests/ChatViewModelTests.swift @@ -321,7 +321,7 @@ struct ChatViewModelCommandTests { transport.simulateConnect(peerID, nickname: "Alice") let resolved = await TestHelpers.waitUntil({ viewModel.getPeerIDForNickname("Alice") == peerID - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.negativeWaitWindow) #expect(resolved) viewModel.handleCommand("/msg Alice") @@ -422,7 +422,7 @@ struct ChatViewModelServiceLifecycleTests { transport.sentReadReceipts.contains { $0.peerID == peerID && $0.receipt.originalMessageID == "read-1" } - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.negativeWaitWindow) #expect(sentReadReceipt) #expect(!viewModel.unreadPrivateMessages.contains(peerID)) @@ -506,7 +506,7 @@ struct ChatViewModelReceivingTests { let found = await TestHelpers.waitUntil({ viewModel.publicMessages(for: .mesh).contains { $0.content == "Public hello from Bob" } - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(found) } @@ -535,11 +535,11 @@ struct ChatViewModelNoisePayloadTests { let stored = await TestHelpers.waitUntil({ viewModel.privateChats[peerID]?.contains(where: { $0.id == "pm-noise-1" && $0.content == "Secret hello" }) == true - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) let acked = await TestHelpers.waitUntil({ transport.sentDeliveryAcks.contains { $0.messageID == "pm-noise-1" && $0.peerID == peerID } - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(stored) #expect(acked) @@ -579,7 +579,7 @@ struct ChatViewModelNoisePayloadTests { return name == "Bob" } return false - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(delivered) } @@ -617,7 +617,7 @@ struct ChatViewModelNoisePayloadTests { return true } return false - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) let conversationStoreUpdated = await TestHelpers.waitUntil({ let messages = viewModel.conversations.conversationsByID[.directPeer(peerID)]?.messages ?? [] @@ -626,7 +626,7 @@ struct ChatViewModelNoisePayloadTests { return true } return false - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(privateChatUpdated) #expect(conversationStoreUpdated) @@ -730,7 +730,7 @@ struct ChatViewModelVerificationTests { let bound = await TestHelpers.waitUntil({ viewModel.unifiedPeerService.peers.contains { $0.peerID == peerID } - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(bound) let qr = VerificationService.VerificationQR( @@ -982,7 +982,7 @@ struct ChatViewModelPeerTests { let cleaned = await TestHelpers.waitUntil({ !viewModel.unreadPrivateMessages.contains(stalePeer) - }, timeout: TestConstants.defaultTimeout) + }, timeout: TestConstants.settleTimeout) #expect(cleaned) } diff --git a/bitchatTests/EndToEnd/CourierEndToEndTests.swift b/bitchatTests/EndToEnd/CourierEndToEndTests.swift index ac68c145..53de683b 100644 --- a/bitchatTests/EndToEnd/CourierEndToEndTests.swift +++ b/bitchatTests/EndToEnd/CourierEndToEndTests.swift @@ -142,7 +142,7 @@ struct CourierEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -151,7 +151,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, signingPublicKey: alice.noiseSigningPublicKeyData()) let carried = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(carried) @@ -161,7 +161,7 @@ struct CourierEndToEndTests { bob.sendBroadcastAnnounce() let announced = await TestHelpers.waitUntil( { bobOut.first(ofType: .announce) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(announced) let announcePacket = try #require(bobOut.first(ofType: .announce)) @@ -169,7 +169,7 @@ struct CourierEndToEndTests { let handedOver = await TestHelpers.waitUntil( { carolOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(handedOver) // With CoreBluetooth disabled there is no physical link for the send @@ -183,7 +183,7 @@ struct CourierEndToEndTests { bob._test_handlePacket(handoverPacket, fromPeerID: carol.myPeerID) let received = await TestHelpers.waitUntil( { !bobDelegate.snapshot().isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(received) @@ -229,7 +229,7 @@ struct CourierEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -237,7 +237,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, signingPublicKey: alice.noiseSigningPublicKeyData()) let carried = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(carried) @@ -245,7 +245,7 @@ struct CourierEndToEndTests { bob.sendBroadcastAnnounce() let announced = await TestHelpers.waitUntil( { bobOut.first(ofType: .announce) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(announced) let announcePacket = try #require(bobOut.first(ofType: .announce)) @@ -253,7 +253,7 @@ struct CourierEndToEndTests { let handedOver = await TestHelpers.waitUntil( { carolOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(handedOver) let handoverPacket = try #require(carolOut.first(ofType: .courierEnvelope)) @@ -265,7 +265,7 @@ struct CourierEndToEndTests { bob._test_handlePacket(handoverPacket, fromPeerID: carol.myPeerID) let delivered = await TestHelpers.waitUntil( { !bobDelegate.snapshot().isEmpty }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!delivered) } @@ -293,7 +293,7 @@ struct CourierEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -301,7 +301,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, signingPublicKey: alice.noiseSigningPublicKeyData()) let carried = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(carried) @@ -310,7 +310,7 @@ struct CourierEndToEndTests { let leakedOnUnverifiedAnnounce = await TestHelpers.waitUntil( { carolOut.count(ofType: .courierEnvelope) > 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!leakedOnUnverifiedAnnounce) #expect(!carol.courierStore.isEmpty) @@ -318,7 +318,7 @@ struct CourierEndToEndTests { bob.sendBroadcastAnnounce() let announced = await TestHelpers.waitUntil( { bobOut.first(ofType: .announce) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(announced) let verifiedAnnounce = try #require(bobOut.first(ofType: .announce)) @@ -326,7 +326,7 @@ struct CourierEndToEndTests { let handedOver = await TestHelpers.waitUntil( { carolOut.count(ofType: .courierEnvelope) == 1 }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(handedOver) #expect(!carol.courierStore.isEmpty) @@ -355,7 +355,7 @@ struct CourierEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -363,14 +363,14 @@ struct CourierEndToEndTests { carol._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, signingPublicKey: alice.noiseSigningPublicKeyData()) let carried = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(carried) bob.sendBroadcastAnnounce() let announced = await TestHelpers.waitUntil( { bobOut.first(ofType: .announce) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(announced) let directAnnounce = try #require(bobOut.first(ofType: .announce)) @@ -385,7 +385,7 @@ struct CourierEndToEndTests { let remoteHandover = await TestHelpers.waitUntil( { carolOut.count(ofType: .courierEnvelope) == 1 }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(remoteHandover) #expect(!carol.courierStore.isEmpty) @@ -398,7 +398,7 @@ struct CourierEndToEndTests { bob.sendBroadcastAnnounce() let reannounced = await TestHelpers.waitUntil( { bobOut.all(ofType: .announce).contains { $0.timestamp != directAnnounce.timestamp } }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(reannounced) let freshAnnounce = try #require( @@ -410,7 +410,7 @@ struct CourierEndToEndTests { let refloodedInCooldown = await TestHelpers.waitUntil( { carolOut.count(ofType: .courierEnvelope) > 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!refloodedInCooldown) #expect(!carol.courierStore.isEmpty) @@ -424,7 +424,7 @@ struct CourierEndToEndTests { bob.sendBroadcastAnnounce() let announcedAgain = await TestHelpers.waitUntil( { bobOut.all(ofType: .announce).contains { $0.timestamp != directAnnounce.timestamp && $0.timestamp != freshAnnounce.timestamp } }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(announcedAgain) let directAgain = try #require( @@ -434,7 +434,7 @@ struct CourierEndToEndTests { let handedOverWithoutLinkProof = await TestHelpers.waitUntil( { carolOut.count(ofType: .courierEnvelope) > 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!handedOverWithoutLinkProof) #expect(!carol.courierStore.isEmpty) @@ -457,7 +457,7 @@ struct CourierEndToEndTests { let queuedPacket = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!queuedPacket) } @@ -494,7 +494,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(packet, fromPeerID: alicePeerID, signingPublicKey: alice.getSigningPublicKeyData()) let stored = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!stored) } @@ -532,7 +532,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(packet, fromPeerID: alicePeerID, signingPublicKey: alice.getSigningPublicKeyData()) let stored = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!stored) } @@ -575,7 +575,7 @@ struct CourierEndToEndTests { carol._test_handlePacket(packet, fromPeerID: mallory.myPeerID, preseedPeer: false) let stored = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!stored) } @@ -602,14 +602,14 @@ struct CourierEndToEndTests { let delivered = await TestHelpers.waitUntil( { !bobDelegate.snapshot().isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(delivered) // Give a duplicate delivery a chance to surface, then confirm the // second copy never reached the delegate. let duplicated = await TestHelpers.waitUntil( { bobDelegate.snapshot().count > 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!duplicated) #expect(bobDelegate.snapshot().count == 1) @@ -629,7 +629,7 @@ struct CourierEndToEndTests { let initiated = await TestHelpers.waitUntil( { outbound.count(ofType: .noiseHandshake) > 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!initiated) @@ -639,7 +639,7 @@ struct CourierEndToEndTests { ble.sendDeliveryAck(for: "msg-2", to: present) let initiatedForPresent = await TestHelpers.waitUntil( { outbound.count(ofType: .noiseHandshake) > 0 }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(initiatedForPresent) } diff --git a/bitchatTests/EndToEnd/PrekeyEndToEndTests.swift b/bitchatTests/EndToEnd/PrekeyEndToEndTests.swift index 79bd28b5..692c8f6d 100644 --- a/bitchatTests/EndToEnd/PrekeyEndToEndTests.swift +++ b/bitchatTests/EndToEnd/PrekeyEndToEndTests.swift @@ -87,7 +87,7 @@ struct PrekeyEndToEndTests { peer.sendBroadcastAnnounce() let published = await TestHelpers.waitUntil( { tap.first(ofType: .announce) != nil && tap.first(ofType: .prekeyBundle) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(published) return ( @@ -124,7 +124,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(cached) @@ -138,7 +138,7 @@ struct PrekeyEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -149,7 +149,7 @@ struct PrekeyEndToEndTests { carol._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, signingPublicKey: alice.noiseSigningPublicKeyData()) let carried = await TestHelpers.waitUntil( { !carol.courierStore.isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(carried) @@ -158,7 +158,7 @@ struct PrekeyEndToEndTests { bob.sendBroadcastAnnounce() let reannounced = await TestHelpers.waitUntil( { bobOut.first(ofType: .announce) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(reannounced) let handoverTrigger = try #require(bobOut.first(ofType: .announce)) @@ -166,7 +166,7 @@ struct PrekeyEndToEndTests { let handedOver = await TestHelpers.waitUntil( { carolOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(handedOver) let handoverPacket = try #require(carolOut.first(ofType: .courierEnvelope)) @@ -178,7 +178,7 @@ struct PrekeyEndToEndTests { bob._test_handlePacket(handoverPacket, fromPeerID: carol.myPeerID) let received = await TestHelpers.waitUntil( { !bobDelegate.snapshot().isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(received) @@ -207,7 +207,7 @@ struct PrekeyEndToEndTests { bob._test_handlePacket(redelivery, fromPeerID: carol.myPeerID) let redelivered = await TestHelpers.waitUntil( { bobDelegate.snapshot().count == 2 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!redelivered) #expect(bobDelegate.snapshot().count == 1) @@ -235,7 +235,7 @@ struct PrekeyEndToEndTests { )) let deposited = await TestHelpers.waitUntil( { aliceOut.first(ofType: .courierEnvelope) != nil }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(deposited) let depositPacket = try #require(aliceOut.first(ofType: .courierEnvelope)) @@ -248,7 +248,7 @@ struct PrekeyEndToEndTests { bob._test_handlePacket(depositPacket, fromPeerID: alice.myPeerID, preseedPeer: false) let received = await TestHelpers.waitUntil( { !bobDelegate.snapshot().isEmpty }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(received) let delivered = try #require(bobDelegate.snapshot().first) @@ -272,7 +272,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!cached) } @@ -310,7 +310,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!cached) } @@ -328,7 +328,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.defaultTimeout + timeout: TestConstants.settleTimeout ) #expect(cached) // The verified bundle now participates in Alice's sync rounds. @@ -364,7 +364,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!cached) #expect(!alice._test_hasGossipPrekeyBundle(for: bob.myPeerID)) @@ -396,7 +396,7 @@ struct PrekeyEndToEndTests { let cached = await TestHelpers.waitUntil( { alice.prekeyBundleStore.hasUsableBundle(for: bob.noiseStaticPublicKeyData()) }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!cached) #expect(!alice._test_hasGossipPrekeyBundle(for: bob.myPeerID)) diff --git a/bitchatTests/GossipSyncManagerTests.swift b/bitchatTests/GossipSyncManagerTests.swift index ff2c406d..e0f3580c 100644 --- a/bitchatTests/GossipSyncManagerTests.swift +++ b/bitchatTests/GossipSyncManagerTests.swift @@ -37,7 +37,7 @@ struct GossipSyncManagerTests { } manager.scheduleInitialSyncToPeer(PeerID(str: "FFFFFFFFFFFFFFFF"), delaySeconds: 0.0) - try await TestHelpers.waitFor({ delegate.lastPacket != nil }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.lastPacket != nil }, timeout: TestConstants.settleTimeout) } let lastPacket = try #require(delegate.lastPacket, "Expected sync packet to be sent") @@ -394,7 +394,7 @@ struct GossipSyncManagerTests { ) manager.handleRequestSync(from: peer, request: request) - try await TestHelpers.waitFor({ delegate.packets.count == 2 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 2 }, timeout: TestConstants.settleTimeout) // Barrier: flush the sync queue so a late third packet would be visible. manager._performMaintenanceSynchronously(now: Date()) let sentPackets = delegate.packets @@ -477,7 +477,7 @@ struct GossipSyncManagerTests { manager.handleRequestSync(from: peer, request: request) manager.handleRequestSync(from: peer, request: request) - try await TestHelpers.waitFor({ delegate.packets.count >= 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count >= 1 }, timeout: TestConstants.settleTimeout) // Barrier: both requests have been processed once this returns. manager._performMaintenanceSynchronously(now: Date()) #expect(delegate.packets.count == 1) @@ -498,7 +498,7 @@ struct GossipSyncManagerTests { manager.scheduleInitialSyncToPeer(PeerID(str: "FFFFFFFFFFFFFFFF"), delaySeconds: 0.0) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) let packet = try #require(delegate.packets.first) let request = try #require(RequestSyncPacket.decode(from: packet.payload)) let types = try #require(request.types) @@ -553,7 +553,7 @@ struct GossipSyncManagerTests { let request = RequestSyncPacket(p: 4, m: 1, data: Data(), types: .fragment) manager.handleRequestSync(from: peer, request: request) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) let sentPackets = delegate.packets #expect(sentPackets.count == 1) #expect(sentPackets[0].type == MessageType.fragment.rawValue) @@ -615,7 +615,7 @@ struct GossipSyncManagerTests { ) manager.handleRequestSync(from: PeerID(str: "FFFFFFFFFFFFFFFF"), request: request) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) // Barrier: flush the sync queue so a late second packet would be visible. manager._performMaintenanceSynchronously(now: Date()) let sentPackets = delegate.packets @@ -641,7 +641,7 @@ struct GossipSyncManagerTests { let stalledID = try #require(Data(hexString: "0102030405060708")) manager.requestMissingFragments(fragmentIDs: [stalledID]) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) let sent = try #require(delegate.packets.first) #expect(sent.type == MessageType.requestSync.rawValue) #expect(sent.ttl == 0) @@ -697,7 +697,7 @@ struct GossipSyncManagerTests { // And a .prekeyBundle sync request is answered with the stored packet. let request = RequestSyncPacket(p: 7, m: 1, data: Data(), types: .prekeyBundle) manager.handleRequestSync(from: PeerID(str: "FFFFFFFFFFFFFFFF"), request: request) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) let served = try #require(delegate.packets.first) #expect(served.type == MessageType.prekeyBundle.rawValue) #expect(served.isRSR) @@ -774,7 +774,7 @@ struct GossipSyncManagerTests { ) let restored = await TestHelpers.waitUntil( { second._messageCount(for: PeerID(hexData: senderID)) == 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.settleTimeout ) #expect(restored) } @@ -844,7 +844,7 @@ struct GossipSyncManagerTests { !FileManager.default.fileExists(atPath: fileURL.path) && manager._messageCount(for: PeerID(hexData: senderID)) == 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.settleTimeout ) #expect(erased) } diff --git a/bitchatTests/Services/NetworkActivationServiceTests.swift b/bitchatTests/Services/NetworkActivationServiceTests.swift index 29c5bfb1..7faa4681 100644 --- a/bitchatTests/Services/NetworkActivationServiceTests.swift +++ b/bitchatTests/Services/NetworkActivationServiceTests.swift @@ -63,7 +63,7 @@ final class NetworkActivationServiceTests: XCTestCase { context.service.start() context.service.setUserTorEnabled(false) - wait(for: [notified], timeout: TestConstants.settleTimeout) + wait(for: [notified], timeout: TestConstants.negativeWaitWindow) context.notificationCenter.removeObserver(token) XCTAssertFalse(context.service.userTorEnabled) diff --git a/bitchatTests/Services/NoiseEncryptionServiceTests.swift b/bitchatTests/Services/NoiseEncryptionServiceTests.swift index 819e8d89..a2031983 100644 --- a/bitchatTests/Services/NoiseEncryptionServiceTests.swift +++ b/bitchatTests/Services/NoiseEncryptionServiceTests.swift @@ -166,7 +166,7 @@ struct NoiseEncryptionServiceTests { #expect(!receiver.hasSession(with: claimedAlicePeerID)) let emittedAuthentication = await TestHelpers.waitUntil( { recorder.count > 0 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!emittedAuthentication) } @@ -216,7 +216,7 @@ struct NoiseEncryptionServiceTests { #expect(try receiver.decrypt(after, from: alicePeerID) == Data("after".utf8)) let emittedReplacementAuthentication = await TestHelpers.waitUntil( { recorder.count > 1 }, - timeout: TestConstants.shortTimeout + timeout: TestConstants.negativeWaitWindow ) #expect(!emittedReplacementAuthentication) } diff --git a/bitchatTests/Sync/GossipSyncBoardTests.swift b/bitchatTests/Sync/GossipSyncBoardTests.swift index 7fe8bdcf..6e5b5357 100644 --- a/bitchatTests/Sync/GossipSyncBoardTests.swift +++ b/bitchatTests/Sync/GossipSyncBoardTests.swift @@ -48,7 +48,7 @@ struct GossipSyncBoardTests { let request = RequestSyncPacket(p: 4, m: 1, data: Data(), types: .board) manager.handleRequestSync(from: PeerID(str: "FFFFFFFFFFFFFFFF"), request: request) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) let sent = try #require(delegate.packets.first) #expect(sent.type == MessageType.boardPost.rawValue) #expect(sent.isRSR) @@ -69,7 +69,7 @@ struct GossipSyncBoardTests { let boardRequest = RequestSyncPacket(p: 4, m: 1, data: Data(), types: .board) manager.handleRequestSync(from: PeerID(str: "FFFFFFFFFFFFFFFF"), request: boardRequest) - try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.shortTimeout) + try await TestHelpers.waitFor({ delegate.packets.count == 1 }, timeout: TestConstants.settleTimeout) #expect(delegate.packets.count == 1) #expect(delegate.packets.first?.type == MessageType.boardPost.rawValue) } diff --git a/bitchatTests/TestUtilities/TestConstants.swift b/bitchatTests/TestUtilities/TestConstants.swift index 37948f92..6cfe3d97 100644 --- a/bitchatTests/TestUtilities/TestConstants.swift +++ b/bitchatTests/TestUtilities/TestConstants.swift @@ -44,6 +44,21 @@ struct TestConstants { /// latency assumption in disguise. static let minimumSettleTimeout: TimeInterval = 10.0 + /// For waits whose **expected outcome is `false`** — "prove this does not + /// happen". + /// + /// The floor above is wrong for these, and inverted: a negative wait always + /// runs its deadline out, so `settleTimeout` would spend 30 s per case + /// proving nothing extra. Starvation cannot cause a false failure here + /// either — a starved runner only makes the thing *less* likely to happen, + /// so the assertion still holds. Short is correct, and naming it says the + /// polarity out loud instead of leaving a bare literal that reads like the + /// mistake this file exists to prevent. + /// + /// `TestTimingHygieneTests` accepts this by name. Using it for a wait you + /// expect to succeed reintroduces exactly the flake class it sits next to. + static let negativeWaitWindow: TimeInterval = 1.0 + static let testNickname1 = "Alice" static let testNickname2 = "Bob" diff --git a/bitchatTests/TestUtilities/TestTimingHygieneTests.swift b/bitchatTests/TestUtilities/TestTimingHygieneTests.swift index 94a90861..f5621e8e 100644 --- a/bitchatTests/TestUtilities/TestTimingHygieneTests.swift +++ b/bitchatTests/TestUtilities/TestTimingHygieneTests.swift @@ -93,15 +93,29 @@ struct TestTimingHygieneTests { ].map { try? NSRegularExpression(pattern: $0) }.compactMap { $0 } #expect(patterns.count == 2, "hygiene regexes failed to compile") + // Named constants hide the same mistake behind a symbol, and did: the + // fifth flake of the session was `timeout: TestConstants.shortTimeout` + // (1 s) on a positive wait, which a literals-only scan cannot see. + // `negativeWaitWindow` is deliberately absent — short is correct there. + let bannedConstants = ["shortTimeout", "defaultTimeout"] + var offenders: [String] = [] for line in lines where !Self.isWaived(line) { let range = NSRange(line.text.startIndex..., in: line.text) + var flagged = false for pattern in patterns { guard let match = pattern.firstMatch(in: line.text, range: range), let valueRange = Range(match.range(at: 1), in: line.text), let value = TimeInterval(line.text[valueRange]), value < TestConstants.minimumSettleTimeout else { continue } offenders.append("\(line.file):\(line.number) — \(value)s: \(line.text.trimmingCharacters(in: .whitespaces))") + flagged = true + break + } + guard !flagged else { continue } + for name in bannedConstants + where line.text.contains("timeout: TestConstants.\(name)") { + offenders.append("\(line.file):\(line.number) — TestConstants.\(name): \(line.text.trimmingCharacters(in: .whitespaces))") break } }