498f407585
Introduce optional Apple account-backed credits with scoped gateway access while preserving local and BYOK paths. Refresh assistant behavior, tests, privacy disclosures, docs, and the website for the 2.0 experience.
55 lines
2.0 KiB
Swift
55 lines
2.0 KiB
Swift
// FlowPhysicalAudioStressTests.swift
|
|
// OSGKeyboardTests
|
|
//
|
|
// Physical-device release gate for the PiP playback ↔ capture transition.
|
|
// Excluded from PR presets because Simulator cannot model Bluetooth HFP.
|
|
|
|
import AVFoundation
|
|
@testable import OSGKeyboardHostSupport
|
|
@testable import OSGKeyboardShared
|
|
import XCTest
|
|
|
|
final class FlowPhysicalAudioStressTests: XCTestCase {
|
|
@MainActor
|
|
func testFiftyCapturePlaybackCyclesRemainStable() async throws {
|
|
#if targetEnvironment(simulator)
|
|
throw XCTSkip("Bluetooth HFP stress requires a physical iPhone")
|
|
#else
|
|
guard AVAudioApplication.shared.recordPermission == .granted else {
|
|
throw XCTSkip("Grant microphone permission to OSGKeyboard first")
|
|
}
|
|
|
|
let capture = FlowContinuousCapture()
|
|
let initialRSS = OSGDiag.memoryMB()
|
|
|
|
for iteration in 1...50 {
|
|
try await capture.start()
|
|
let receivedFrame = await capture.awaitAudioFlowing(timeout: 2)
|
|
XCTAssertTrue(receivedFrame, "No microphone frame in iteration \(iteration)")
|
|
XCTAssertTrue(capture.engineIsLive, "Engine not live in iteration \(iteration)")
|
|
|
|
capture.stop(releaseSession: false)
|
|
let playbackReady = await FlowAudioSessionCoordinator.shared.activatePlayback()
|
|
XCTAssertTrue(playbackReady, "PiP playback restore failed in iteration \(iteration)")
|
|
try? await Task.sleep(nanoseconds: 50_000_000)
|
|
}
|
|
|
|
try? await Task.sleep(nanoseconds: 500_000_000)
|
|
XCTAssertEqual(capture.engineActivationCount, 50)
|
|
XCTAssertEqual(
|
|
capture.routeRecoveryCount,
|
|
0,
|
|
"Stable routeConfigurationChange notifications must not rebuild the engine"
|
|
)
|
|
|
|
let growth = OSGDiag.memoryMB() - initialRSS
|
|
XCTAssertLessThan(
|
|
growth,
|
|
80,
|
|
"Fifty audio cycles retained \(String(format: "%.1f", growth)) MB"
|
|
)
|
|
FlowAudioSessionCoordinator.shared.deactivate()
|
|
#endif
|
|
}
|
|
}
|