feat(app): add resilient Flow recovery and privacy-safe analytics
Unify PiP recovery across startup and foreground transitions, surface actionable status, and add privacy-safe analytics plus the refreshed onboarding and account experience. Update documentation assets and advance the release build to 84.
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
// FlowPiPRecoveryPolicyTests.swift
|
||||
// OSGKeyboardTests
|
||||
|
||||
@testable import OSGKeyboard
|
||||
import XCTest
|
||||
|
||||
final class FlowPiPRecoveryPolicyTests: XCTestCase {
|
||||
|
||||
// MARK: - Reconciliation
|
||||
|
||||
func testNoSessionIntentNeverStartsRecovery() {
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.reconciliationDecision(
|
||||
wantsActiveSession: false,
|
||||
isAppForeground: true,
|
||||
isPictureInPictureActive: false
|
||||
),
|
||||
.noSessionIntent
|
||||
)
|
||||
}
|
||||
|
||||
func testActivePiPIsIdempotent() {
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.reconciliationDecision(
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: true,
|
||||
isPictureInPictureActive: true
|
||||
),
|
||||
.alreadyActive
|
||||
)
|
||||
}
|
||||
|
||||
func testTakeoverWaitsWhileAppIsInBackground() {
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.reconciliationDecision(
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: false,
|
||||
isPictureInPictureActive: false
|
||||
),
|
||||
.waitForForeground
|
||||
)
|
||||
}
|
||||
|
||||
func testReturningToForegroundStartsRecovery() {
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.reconciliationDecision(
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: true,
|
||||
isPictureInPictureActive: false
|
||||
),
|
||||
.startRecovery
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Bounded retry
|
||||
|
||||
func testRetryPolicyUsesThreeIncreasingBoundedAttempts() {
|
||||
XCTAssertEqual(FlowPiPRecoveryPolicy.maxAttempts, 3)
|
||||
XCTAssertEqual(
|
||||
(1...FlowPiPRecoveryPolicy.maxAttempts).map {
|
||||
FlowPiPRecoveryPolicy.retryDelay(beforeAttempt: $0)
|
||||
},
|
||||
[0, 0.25, 0.6]
|
||||
)
|
||||
XCTAssertEqual(FlowPiPRecoveryPolicy.totalBudget, 5)
|
||||
}
|
||||
|
||||
func testRetryTimeoutsNeverExceedRemainingBudget() {
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.hostTimeout(attempt: 1, remainingBudget: 0.4),
|
||||
0.4
|
||||
)
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.hostTimeout(attempt: 2, remainingBudget: 4),
|
||||
0.25
|
||||
)
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 0.3),
|
||||
0.3
|
||||
)
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 4),
|
||||
1.4
|
||||
)
|
||||
XCTAssertEqual(
|
||||
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 0.01),
|
||||
0.01
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Late completion safety
|
||||
|
||||
func testCurrentForegroundOperationCanContinue() {
|
||||
XCTAssertTrue(
|
||||
FlowPiPRecoveryPolicy.canContinue(
|
||||
operation: 7,
|
||||
currentOperation: 7,
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: true,
|
||||
taskIsCancelled: false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testOldGenerationCannotOverwriteNewRecovery() {
|
||||
XCTAssertFalse(
|
||||
FlowPiPRecoveryPolicy.canContinue(
|
||||
operation: 6,
|
||||
currentOperation: 7,
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: true,
|
||||
taskIsCancelled: false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testExplicitEndPreventsLateRecovery() {
|
||||
XCTAssertFalse(
|
||||
FlowPiPRecoveryPolicy.canContinue(
|
||||
operation: 7,
|
||||
currentOperation: 8,
|
||||
wantsActiveSession: false,
|
||||
isAppForeground: true,
|
||||
taskIsCancelled: true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testBackgroundAndCancellationBothStopRecovery() {
|
||||
XCTAssertFalse(
|
||||
FlowPiPRecoveryPolicy.canContinue(
|
||||
operation: 7,
|
||||
currentOperation: 7,
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: false,
|
||||
taskIsCancelled: false
|
||||
)
|
||||
)
|
||||
XCTAssertFalse(
|
||||
FlowPiPRecoveryPolicy.canContinue(
|
||||
operation: 7,
|
||||
currentOperation: 7,
|
||||
wantsActiveSession: true,
|
||||
isAppForeground: true,
|
||||
taskIsCancelled: true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user