mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 05:05:19 +00:00
Add comprehensive tests for Noise handshake stability improvements
- Add test for peer restart detection and session recovery - Add test for nonce desynchronization detection - Add test for concurrent encryption thread safety - Add test for session stale detection - Add test for handshake after decryption failure - Add integration test for peer presence tracking and reconnection - Add integration test for encrypted messages after peer restart These tests ensure: - Sessions properly recover when a peer restarts - Nonce desynchronization is detected correctly - Encryption operations are thread-safe under concurrent load - Identity announcements are sent on reconnection after silence - Encrypted messages work after session re-establishment
This commit is contained in:
@@ -270,6 +270,124 @@ final class IntegrationTests: XCTestCase {
|
||||
XCTAssertEqual(receivedMessages.count, totalMessages)
|
||||
}
|
||||
|
||||
func testPeerPresenceTrackingAndReconnection() {
|
||||
// Test peer presence tracking and identity announcement on reconnection
|
||||
connect("Alice", "Bob")
|
||||
|
||||
// Establish Noise sessions
|
||||
do {
|
||||
try establishNoiseSession("Alice", "Bob")
|
||||
} catch {
|
||||
XCTFail("Failed to establish Noise session: \(error)")
|
||||
}
|
||||
|
||||
let expectation = XCTestExpectation(description: "Peer reconnection handled")
|
||||
var bobReceivedIdentityAnnounce = false
|
||||
var aliceReceivedIdentityAnnounce = false
|
||||
|
||||
// Track identity announcements
|
||||
nodes["Bob"]!.packetDeliveryHandler = { packet in
|
||||
if packet.type == MessageType.noiseIdentityAnnounce.rawValue {
|
||||
bobReceivedIdentityAnnounce = true
|
||||
if aliceReceivedIdentityAnnounce {
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodes["Alice"]!.packetDeliveryHandler = { packet in
|
||||
if packet.type == MessageType.noiseIdentityAnnounce.rawValue {
|
||||
aliceReceivedIdentityAnnounce = true
|
||||
if bobReceivedIdentityAnnounce {
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate disconnect (out of range)
|
||||
disconnect("Alice", "Bob")
|
||||
|
||||
// Wait to simulate extended disconnect period
|
||||
Thread.sleep(forTimeInterval: 0.5)
|
||||
|
||||
// Reconnect
|
||||
connect("Alice", "Bob")
|
||||
|
||||
// Both should receive identity announcements after reconnection
|
||||
wait(for: [expectation], timeout: TestConstants.defaultTimeout)
|
||||
XCTAssertTrue(bobReceivedIdentityAnnounce)
|
||||
XCTAssertTrue(aliceReceivedIdentityAnnounce)
|
||||
}
|
||||
|
||||
func testEncryptedMessageAfterPeerRestart() {
|
||||
// Test that encrypted messages work after one peer restarts
|
||||
connect("Alice", "Bob")
|
||||
do {
|
||||
try establishNoiseSession("Alice", "Bob")
|
||||
} catch {
|
||||
XCTFail("Failed to establish Noise session: \(error)")
|
||||
}
|
||||
|
||||
// Exchange an encrypted message
|
||||
let firstExpectation = XCTestExpectation(description: "First message received")
|
||||
nodes["Bob"]!.messageDeliveryHandler = { message in
|
||||
if message.content == "Before restart" && message.isPrivate {
|
||||
firstExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
nodes["Alice"]!.sendPrivateMessage("Before restart", to: TestConstants.testPeerID2, recipientNickname: "Bob")
|
||||
wait(for: [firstExpectation], timeout: TestConstants.defaultTimeout)
|
||||
|
||||
// Simulate Bob restart by recreating his Noise manager
|
||||
let bobKey = Curve25519.KeyAgreement.PrivateKey()
|
||||
noiseManagers["Bob"] = NoiseSessionManager(localStaticKey: bobKey)
|
||||
|
||||
// Bob should initiate new handshake
|
||||
let handshakeExpectation = XCTestExpectation(description: "New handshake completed")
|
||||
|
||||
nodes["Bob"]!.packetDeliveryHandler = { packet in
|
||||
if packet.type == MessageType.noiseHandshakeInit.rawValue {
|
||||
// Bob initiates new handshake after restart
|
||||
do {
|
||||
let response = try self.noiseManagers["Alice"]!.handleIncomingHandshake(
|
||||
from: TestConstants.testPeerID2,
|
||||
message: packet.payload
|
||||
)
|
||||
if let resp = response {
|
||||
// Send response back to Bob
|
||||
let responsePacket = TestHelpers.createTestPacket(
|
||||
type: MessageType.noiseHandshakeResp.rawValue,
|
||||
payload: resp
|
||||
)
|
||||
self.nodes["Bob"]!.simulateIncomingPacket(responsePacket)
|
||||
}
|
||||
} catch {
|
||||
XCTFail("Handshake handling failed: \(error)")
|
||||
}
|
||||
} else if packet.type == MessageType.noiseHandshakeResp.rawValue && packet.senderID.hexEncodedString() == TestConstants.testPeerID1 {
|
||||
// Final handshake message (message 3 in XX pattern)
|
||||
handshakeExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger handshake by trying to send a message
|
||||
nodes["Bob"]!.sendPrivateMessage("After restart", to: TestConstants.testPeerID1, recipientNickname: "Alice")
|
||||
|
||||
wait(for: [handshakeExpectation], timeout: TestConstants.defaultTimeout)
|
||||
|
||||
// Now messages should work again
|
||||
let secondExpectation = XCTestExpectation(description: "Message after restart received")
|
||||
nodes["Alice"]!.messageDeliveryHandler = { message in
|
||||
if message.content == "After restart success" && message.isPrivate {
|
||||
secondExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
nodes["Bob"]!.sendPrivateMessage("After restart success", to: TestConstants.testPeerID1, recipientNickname: "Alice")
|
||||
wait(for: [secondExpectation], timeout: TestConstants.defaultTimeout)
|
||||
}
|
||||
|
||||
func testLargeScaleNetwork() {
|
||||
// Create larger network
|
||||
for i in 5...10 {
|
||||
|
||||
Reference in New Issue
Block a user