Files
mobile-ios/RosettaTests/CallRoutingTests.swift

229 lines
7.3 KiB
Swift

import CryptoKit
import XCTest
@testable import Rosetta
@MainActor
final class CallRoutingTests: XCTestCase {
private let ownKey = "02-own"
private let peerA = "02-peer-a"
private let peerB = "02-peer-b"
override func setUp() {
super.setUp()
CallManager.shared.resetForSessionEnd()
CallManager.shared.bindAccount(publicKey: ownKey)
}
override func tearDown() {
CallManager.shared.resetForSessionEnd()
super.tearDown()
}
func testIncomingCallMovesToIncomingPhase() {
let packet = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertEqual(CallManager.shared.uiState.phase, .incoming)
XCTAssertEqual(CallManager.shared.uiState.peerPublicKey, peerA)
}
func testBusySignalEndsCurrentCallStateWithoutCrosstalk() {
CallManager.shared.testSetUiState(
CallUiState(
phase: .outgoing,
peerPublicKey: peerA,
statusText: "Calling..."
)
)
let packet = PacketSignalPeer(
src: "",
dst: "",
sharedPublic: "",
signalType: .endCallBecauseBusy,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
XCTAssertEqual(CallManager.shared.uiState.statusText, "User is busy")
XCTAssertEqual(CallManager.shared.uiState.peerPublicKey, "")
}
func testPeerDisconnectedSignalEndsCurrentCallState() {
CallManager.shared.testSetUiState(
CallUiState(
phase: .active,
peerPublicKey: peerA,
statusText: "Call active"
)
)
let packet = PacketSignalPeer(
src: "",
dst: "",
sharedPublic: "",
signalType: .endCallBecausePeerDisconnected,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
XCTAssertEqual(CallManager.shared.uiState.statusText, "Peer disconnected")
XCTAssertEqual(CallManager.shared.uiState.peerPublicKey, "")
}
func testInterleavingForeignSignalDoesNotOverrideActivePeer() {
CallManager.shared.testSetUiState(
CallUiState(
phase: .outgoing,
peerPublicKey: peerA,
statusText: "Calling..."
)
)
let foreignPacket = PacketSignalPeer(
src: peerB,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(foreignPacket)
XCTAssertEqual(CallManager.shared.uiState.phase, .outgoing)
XCTAssertEqual(CallManager.shared.uiState.peerPublicKey, peerA)
XCTAssertEqual(CallManager.shared.uiState.statusText, "Calling...")
}
func testLegacyOutgoingFlowCallAcceptKeyExchangeActive() {
let start = CallManager.shared.startOutgoingCall(
toPublicKey: peerA,
title: "Peer A",
username: "peer_a"
)
XCTAssertEqual(start, .started)
let accept = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: "",
signalType: .accept,
callId: "call-legacy-1",
joinToken: "join-legacy-1",
roomId: ""
)
CallManager.shared.testHandleSignalPacket(accept)
XCTAssertEqual(CallManager.shared.signalingMode, .legacy)
XCTAssertEqual(CallManager.shared.callId, "call-legacy-1")
XCTAssertEqual(CallManager.shared.joinToken, "join-legacy-1")
XCTAssertEqual(CallManager.shared.uiState.phase, .keyExchange)
let keyExchange = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: makePeerPublicHex(),
signalType: .keyExchange,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(keyExchange)
XCTAssertEqual(CallManager.shared.uiState.phase, .keyExchange)
// Legacy ACTIVE arrives as signal code 4 with empty roomId.
let active = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: "",
signalType: .createRoom,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(active)
XCTAssertEqual(CallManager.shared.uiState.phase, .webRtcExchange)
}
func testCreateRoomFallbackOutgoingFlowKeyExchangeBeforeAccept() {
let start = CallManager.shared.startOutgoingCall(
toPublicKey: peerA,
title: "Peer A",
username: "peer_a"
)
XCTAssertEqual(start, .started)
let keyExchange = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: makePeerPublicHex(),
signalType: .keyExchange,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(keyExchange)
XCTAssertEqual(CallManager.shared.signalingMode, .createRoom)
XCTAssertEqual(CallManager.shared.uiState.phase, .webRtcExchange)
}
func testDeferredAcceptCompletesWhenMetadataArrivesLater() {
CallManager.shared.setupIncomingCallFromPush(
callerKey: peerA,
callerName: "Peer A"
)
XCTAssertEqual(CallManager.shared.uiState.phase, .incoming)
let acceptResult = CallManager.shared.acceptIncomingCall()
XCTAssertEqual(acceptResult, .started)
XCTAssertTrue(CallManager.shared.pendingIncomingAccept)
XCTAssertEqual(CallManager.shared.uiState.phase, .keyExchange)
XCTAssertEqual(CallManager.shared.signalingMode, .undecided)
let delayedCall = PacketSignalPeer(
src: peerA,
dst: ownKey,
sharedPublic: "",
signalType: .call,
callId: "call-delayed-1",
joinToken: "join-delayed-1",
roomId: ""
)
CallManager.shared.testHandleSignalPacket(delayedCall)
XCTAssertEqual(CallManager.shared.signalingMode, .legacy)
XCTAssertFalse(CallManager.shared.pendingIncomingAccept)
XCTAssertEqual(CallManager.shared.callId, "call-delayed-1")
XCTAssertEqual(CallManager.shared.joinToken, "join-delayed-1")
XCTAssertEqual(CallManager.shared.uiState.phase, .keyExchange)
}
func testRingingTimeoutSignalTearsDownCall() {
let start = CallManager.shared.startOutgoingCall(
toPublicKey: peerA,
title: "Peer A",
username: "peer_a"
)
XCTAssertEqual(start, .started)
let timeoutPacket = PacketSignalPeer(
src: "",
dst: "",
sharedPublic: "",
signalType: .ringingTimeout,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(timeoutPacket)
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
XCTAssertEqual(CallManager.shared.uiState.statusText, "No answer")
}
private func makePeerPublicHex() -> String {
Curve25519.KeyAgreement.PrivateKey().publicKey.rawRepresentation.hexString
}
}