Files
mobile-ios/RosettaTests/CallPushIntegrationTests.swift

276 lines
11 KiB
Swift

import Testing
@testable import Rosetta
// MARK: - Push Notification Extended Tests
struct PushNotificationExtendedTests {
@Test("Realistic FCM token round-trip")
func fcmTokenRoundTrip() throws {
// Real FCM tokens are ~163 chars
let fcmToken = "dQw4w9WgXcQ:APA91bHnzPc5Y0z4R8kP3mN6vX2tL7wJ1qA5sD8fG0hK3lZ9xC2vB4nM7oP1iU8yT6rE5wQ3jF4kL2mN0bV7cX9sD1aF3gH5jK7lP9oI2uY4tR6eW8qZ0xC"
var packet = PacketPushNotification()
packet.notificationsToken = fcmToken
packet.action = .subscribe
packet.tokenType = .fcm
packet.deviceId = "ios-fcm-device"
let decoded = try decode(packet)
#expect(decoded.notificationsToken == fcmToken)
#expect(decoded.action == .subscribe)
#expect(decoded.tokenType == .fcm)
#expect(decoded.deviceId == "ios-fcm-device")
}
@Test("Realistic APNs hex token round-trip")
func apnsTokenRoundTrip() throws {
let apnsToken = "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
var packet = PacketPushNotification()
packet.notificationsToken = apnsToken
packet.action = .subscribe
packet.tokenType = .voipApns
packet.deviceId = "ios-voip-device"
let decoded = try decode(packet)
#expect(decoded.notificationsToken == apnsToken)
#expect(decoded.action == .subscribe)
#expect(decoded.tokenType == .voipApns)
#expect(decoded.deviceId == "ios-voip-device")
}
@Test("Long token (256 chars) round-trip — stress test UInt32 string length")
func longTokenRoundTrip() throws {
let longToken = String(repeating: "x", count: 256)
var packet = PacketPushNotification()
packet.notificationsToken = longToken
packet.action = .subscribe
packet.tokenType = .fcm
packet.deviceId = "ios-long-device"
let decoded = try decode(packet)
#expect(decoded.notificationsToken == longToken)
#expect(decoded.notificationsToken.count == 256)
#expect(decoded.tokenType == .fcm)
#expect(decoded.deviceId == "ios-long-device")
}
@Test("Unicode token round-trip")
func unicodeTokenRoundTrip() throws {
let unicodeToken = "Токен-Гайдара-📱"
var packet = PacketPushNotification()
packet.notificationsToken = unicodeToken
packet.action = .subscribe
packet.tokenType = .fcm
packet.deviceId = "ios-unicode-device"
let decoded = try decode(packet)
#expect(decoded.notificationsToken == unicodeToken)
#expect(decoded.tokenType == .fcm)
#expect(decoded.deviceId == "ios-unicode-device")
}
@Test("Unsubscribe action round-trip")
func unsubscribeRoundTrip() throws {
var packet = PacketPushNotification()
packet.notificationsToken = "test-token"
packet.action = .unsubscribe
packet.tokenType = .voipApns
packet.deviceId = "ios-unsub-device"
let decoded = try decode(packet)
#expect(decoded.action == .unsubscribe)
#expect(decoded.notificationsToken == "test-token")
#expect(decoded.tokenType == .voipApns)
#expect(decoded.deviceId == "ios-unsub-device")
}
private func decode(_ packet: PacketPushNotification) throws -> PacketPushNotification {
let data = PacketRegistry.encode(packet)
guard let result = PacketRegistry.decode(from: data),
let decoded = result.packet as? PacketPushNotification
else { throw TestError("Failed to decode PacketPushNotification") }
#expect(result.packetId == 0x10)
return decoded
}
}
// MARK: - Signal Peer Call Flow Tests
struct SignalPeerCallFlowTests {
@Test("Incoming call signal with realistic secp256k1 keys")
func incomingCallSignalRoundTrip() throws {
let caller = "02a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
let callee = "03f0e1d2c3b4a5968778695a4b3c2d1e0f9e8d7c6b5a49382716051a2b3c4d5e6f"
let packet = PacketSignalPeer(src: caller, dst: callee, sharedPublic: "",
signalType: .call, callId: "call-1", joinToken: "join-1", roomId: "")
let decoded = try decode(packet)
#expect(decoded.signalType == .call)
#expect(decoded.src == caller)
#expect(decoded.dst == callee)
#expect(decoded.sharedPublic == "")
#expect(decoded.callId == "call-1")
#expect(decoded.joinToken == "join-1")
#expect(decoded.roomId == "")
}
@Test("Key exchange with X25519 public key")
func keyExchangeRoundTrip() throws {
let x25519Key = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
let packet = PacketSignalPeer(src: "02src", dst: "02dst", sharedPublic: x25519Key,
signalType: .keyExchange, roomId: "")
let decoded = try decode(packet)
#expect(decoded.signalType == .keyExchange)
#expect(decoded.sharedPublic == x25519Key)
#expect(decoded.roomId == "")
}
@Test("Create room with UUID room ID")
func createRoomRoundTrip() throws {
let roomId = "550e8400-e29b-41d4-a716-446655440000"
let packet = PacketSignalPeer(src: "02src", dst: "02dst", sharedPublic: "",
signalType: .createRoom, roomId: roomId)
let decoded = try decode(packet)
#expect(decoded.signalType == .createRoom)
#expect(decoded.roomId == roomId)
#expect(decoded.sharedPublic == "")
}
@Test("endCallBecauseBusy short format — 3 bytes wire size, no src/dst")
func endCallBusyShortFormat() throws {
let packet = PacketSignalPeer(src: "ignored", dst: "ignored", sharedPublic: "ignored",
signalType: .endCallBecauseBusy, roomId: "ignored")
let data = PacketRegistry.encode(packet)
// Short form: 2 bytes packetId + 1 byte signalType = 3 bytes
#expect(data.count == 3)
let decoded = try decode(packet)
#expect(decoded.signalType == .endCallBecauseBusy)
#expect(decoded.src == "")
#expect(decoded.dst == "")
}
@Test("endCallBecausePeerDisconnected short format — 3 bytes wire size")
func endCallDisconnectedShortFormat() throws {
let packet = PacketSignalPeer(src: "ignored", dst: "ignored", sharedPublic: "ignored",
signalType: .endCallBecausePeerDisconnected, roomId: "ignored")
let data = PacketRegistry.encode(packet)
#expect(data.count == 3)
let decoded = try decode(packet)
#expect(decoded.signalType == .endCallBecausePeerDisconnected)
}
@Test("RINGING_TIMEOUT short format — 3 bytes wire size")
func ringingTimeoutShortFormat() throws {
let packet = PacketSignalPeer(src: "ignored", dst: "ignored", sharedPublic: "ignored",
signalType: .ringingTimeout, roomId: "ignored")
let data = PacketRegistry.encode(packet)
#expect(data.count == 3)
let decoded = try decode(packet)
#expect(decoded.signalType == .ringingTimeout)
#expect(decoded.src == "")
#expect(decoded.dst == "")
}
private func decode(_ packet: PacketSignalPeer) throws -> PacketSignalPeer {
let data = PacketRegistry.encode(packet)
guard let result = PacketRegistry.decode(from: data),
let decoded = result.packet as? PacketSignalPeer
else { throw TestError("Failed to decode PacketSignalPeer") }
#expect(result.packetId == 0x1A)
return decoded
}
}
// MARK: - Enum Parity Tests
struct CallPushEnumParityTests {
@Test("SignalType enum values match server",
arguments: [
(SignalType.call, 0), (SignalType.keyExchange, 1), (SignalType.activeCall, 2),
(SignalType.endCall, 3), (SignalType.createRoom, 4),
(SignalType.endCallBecausePeerDisconnected, 5), (SignalType.endCallBecauseBusy, 6),
(SignalType.accept, 7), (SignalType.ringingTimeout, 8)
])
func signalTypeEnumValues(pair: (SignalType, Int)) {
#expect(pair.0.rawValue == pair.1)
}
@Test("WebRTCSignalType enum values match server",
arguments: [(WebRTCSignalType.offer, 0), (WebRTCSignalType.answer, 1),
(WebRTCSignalType.iceCandidate, 2)])
func webRTCSignalTypeValues(pair: (WebRTCSignalType, Int)) {
#expect(pair.0.rawValue == pair.1)
}
}
// MARK: - Wire Format Byte-Level Tests
struct CallPushWireFormatTests {
@Test("PushNotification byte layout: token→action→tokenType→deviceId")
func pushNotificationByteLayout() {
var packet = PacketPushNotification()
packet.notificationsToken = "A"
packet.action = .unsubscribe
packet.tokenType = .voipApns
packet.deviceId = "D"
let data = PacketRegistry.encode(packet)
#expect(data.count == 16)
// packetId = 0x0010
#expect(data[0] == 0x00); #expect(data[1] == 0x10)
// token "A": length=1, 'A'=0x0041
#expect(data[2] == 0x00); #expect(data[3] == 0x00)
#expect(data[4] == 0x00); #expect(data[5] == 0x01)
#expect(data[6] == 0x00); #expect(data[7] == 0x41)
// action = 1 (unsubscribe)
#expect(data[8] == 0x01)
// tokenType = 1 (voipApns)
#expect(data[9] == 0x01)
// deviceId "D": length=1, 'D'=0x0044
#expect(data[10] == 0x00); #expect(data[11] == 0x00)
#expect(data[12] == 0x00); #expect(data[13] == 0x01)
#expect(data[14] == 0x00); #expect(data[15] == 0x44)
}
@Test("SignalPeer call byte layout: signalType→src→dst→callId→joinToken")
func signalPeerCallByteLayout() {
let packet = PacketSignalPeer(src: "S", dst: "D", sharedPublic: "",
signalType: .call, roomId: "")
let data = PacketRegistry.encode(packet)
#expect(data.count == 23)
// packetId = 0x001A
#expect(data[0] == 0x00); #expect(data[1] == 0x1A)
// signalType = 0 (call)
#expect(data[2] == 0x00)
// src "S": length=1, 'S'=0x0053
#expect(data[3] == 0x00); #expect(data[4] == 0x00)
#expect(data[5] == 0x00); #expect(data[6] == 0x01)
#expect(data[7] == 0x00); #expect(data[8] == 0x53)
// dst "D": length=1, 'D'=0x0044
#expect(data[9] == 0x00); #expect(data[10] == 0x00)
#expect(data[11] == 0x00); #expect(data[12] == 0x01)
#expect(data[13] == 0x00); #expect(data[14] == 0x44)
// callId "": length=0
#expect(data[15] == 0x00); #expect(data[16] == 0x00)
#expect(data[17] == 0x00); #expect(data[18] == 0x00)
// joinToken "": length=0
#expect(data[19] == 0x00); #expect(data[20] == 0x00)
#expect(data[21] == 0x00); #expect(data[22] == 0x00)
}
}
// MARK: - Helpers
private struct TestError: Error, CustomStringConvertible {
let description: String
init(_ message: String) { self.description = message }
}