Files
wristivo/Adapters/WatchBridge/Tests/Watch/WatchRelayBridgeTests.swift
T

94 lines
3.4 KiB
Swift

import Foundation
import Testing
import RemoteCore
import WatchBridgeCommon
import WatchBridgeWatch
@MainActor
private final class FakeWatchSession: RelaySessionSending {
var activationState: RelayActivationState = .notActivated
var isReachable = true
var sent: [[String: Any]] = []
var reply: (([String: Any]) -> Void)?
var error: ((Error) -> Void)?
var replyTwice = false
func activate() { activationState = .activated }
func sendMessage(_ message: [String: Any],
replyHandler: @escaping ([String: Any]) -> Void,
errorHandler: @escaping (Error) -> Void) {
sent.append(message)
reply = replyHandler
error = errorHandler
}
func updateApplicationContext(_ context: [String: Any]) throws {}
func answer(_ value: [String: Any]) {
reply?(value)
if replyTwice { reply?(value); error?(RelayTestError.failed) }
}
}
private enum RelayTestError: Error { case failed }
@MainActor
@Test func watchNegotiatesBeforeSendingCommandAndUsesMilliseconds() async throws {
let fake = FakeWatchSession()
let bridge = WatchRelayBridge(session: fake)
bridge.activate()
bridge.activationDidComplete(error: nil)
bridge.beginSession()
#expect(fake.sent.count == 1)
let request = try RelayContainer(dictionary: fake.sent[0])
#expect(request.kind == .beginSession)
let sessionID = UUID(), tvID = UUID()
let grant = RemoteSessionGrant(sessionID: sessionID, televisionID: tvID,
issuedAt: Date(timeIntervalSince1970: 1_700_000_000),
maximumCommandLifetimeMilliseconds: 500)
fake.answer(try RelayContainer(kind: .session, value: grant).dictionary())
await Task.yield()
bridge.sendCommand(.right, now: Date(timeIntervalSince1970: 1_700_000_000))
#expect(fake.sent.count == 2)
let command = try RelayContainer(dictionary: fake.sent[1])
let envelope = try command.decode(CommandEnvelope.self, expectedKind: .command)
#expect(envelope.sessionID == sessionID)
#expect(envelope.televisionID == tvID)
#expect(envelope.sequence == 0)
#expect(envelope.expiresAt.timeIntervalSince1970 == 1_700_000_000.5)
}
@MainActor
@Test func watchDropsCommandsWhenUnreachableAndDuplicateRepliesCompleteOnce() async throws {
let fake = FakeWatchSession()
let bridge = WatchRelayBridge(session: fake)
bridge.activate()
bridge.activationDidComplete(error: nil)
fake.isReachable = false
bridge.beginSession()
#expect(fake.sent.isEmpty)
fake.isReachable = true
bridge.beginSession()
fake.replyTwice = true
let grant = RemoteSessionGrant(sessionID: UUID(), televisionID: UUID(), issuedAt: Date())
fake.answer(try RelayContainer(kind: .session, value: grant).dictionary())
await Task.yield()
#expect(bridge.state == .armed(sessionID: grant.sessionID, televisionID: grant.televisionID))
}
@MainActor
@Test func watchDeactivationDisarmsAndClearsGrant() async throws {
let fake = FakeWatchSession()
let bridge = WatchRelayBridge(session: fake)
bridge.activate()
bridge.activationDidComplete(error: nil)
bridge.beginSession()
let grant = RemoteSessionGrant(sessionID: UUID(), televisionID: UUID(), issuedAt: Date())
fake.answer(try RelayContainer(kind: .session, value: grant).dictionary())
await Task.yield()
bridge.didDeactivate()
#expect(bridge.state == .inactive)
#expect(fake.sent.count == 1)
}