Files
Kordant/iOS/KordantTests/LaunchTimeTests.swift
Michael Freno e33ddf3002 feat: complete Tasks 21-28 — backend integration, security hardening, UI tests & CI
- Add Apple Sign-In backend (JWKS verification, account linking, session management)
- Implement push notification deep linking with NotificationDeepLinkRouter
- Add jailbreak detection, runtime integrity monitoring, secure enclave service
- Implement OAuth social login, token refresh, and secure logout flows
- Add image caching (memory/disk), optimizer, upload queue, async semaphore
- Implement notification analytics, type preferences, and category setup
- Expand UI test suite with UITestBase, accessibility, auth flow, performance tests
- Add CI pipeline for iOS UI tests (3 device sizes) and performance benchmarks
- Restructure Xcode project to manual groups with KordantWidgets target
- Add SwiftLint, Swift Collections/Algorithms/GoogleSignIn dependencies
- Update project.yml for XcodeGen with new targets and configurations
2026-06-02 15:01:38 -04:00

174 lines
5.7 KiB
Swift

import Testing
@testable import Kordant
import SwiftUI
import OSLog
// MARK: - LaunchTimer Tests
struct LaunchTimerTests {
@Test("LaunchTimer tracks elapsed time since process start")
func elapsedSinceProcessStart() {
let timer = LaunchTimer.shared
let elapsed = timer.elapsedSinceProcessStart
#expect(elapsed >= 0)
}
@Test("LaunchTimer measures phase start and end")
func measurePhase() {
let timer = LaunchTimer.shared
let id = timer.startPhase("TestPhase")
#expect(id >= 0)
// Simulate some work
try? Task.checkCancellation()
timer.endPhase("TestPhase", signpostID: id)
let report = timer.report()
#expect(report["TestPhase_start"] != nil)
#expect(report["TestPhase_end"] != nil)
#expect(report["TestPhase_duration"] != nil)
#expect(report["total"] != nil)
}
@Test("LaunchTimer logs events")
func logEvent() {
let timer = LaunchTimer.shared
timer.logEvent("TestEvent", "test message")
let report = timer.report()
#expect(report["TestEvent"] != nil)
}
@Test("LaunchTimer report includes total time")
func reportContainsTotal() {
let timer = LaunchTimer.shared
let report = timer.report()
#expect(report["total"] != nil)
#expect(report["total"]! >= 0)
}
}
// MARK: - Launch Performance Tests
struct LaunchPerformanceTests {
/// Measures AuthService initialization time (should be fast, < 10ms)
@Test("AuthService init is fast (no blocking work)")
@MainActor
func authServiceInitTime() {
let keychain = MockKeychainService()
let apiClient = MockAuthAPIClient()
let start = Date()
let service = AuthService(keychain: keychain, apiClient: apiClient)
let elapsed = -start.timeIntervalSinceNow
// AuthService init should be nearly instantaneous since restoreSession is deferred
#expect(elapsed < 0.01, "AuthService init took \(elapsed)s (expected < 10ms)")
}
/// Measures session restoration time
@Test("AuthService restoreSession completes quickly")
@MainActor
func sessionRestoreTime() async {
let keychain = MockKeychainService()
let apiClient = MockAuthAPIClient()
let service = AuthService(keychain: keychain, apiClient: apiClient)
let start = Date()
service.restoreSession()
let elapsed = -start.timeIntervalSinceNow
// Session restore involves keychain lookups, should be fast
#expect(elapsed < 0.05, "Session restore took \(elapsed)s (expected < 50ms)")
}
/// Measures SecurityManager initialization (should be lightweight)
@Test("SecurityManager init is fast")
@MainActor
func securityManagerInitTime() {
let start = Date()
_ = SecurityManager.shared
let elapsed = -start.timeIntervalSinceNow
// SecurityManager should be lazy, init should be instant
#expect(elapsed < 0.01, "SecurityManager init took \(elapsed)s (expected < 10ms)")
}
/// Measures NetworkMonitor initialization (should be lazy)
@Test("NetworkMonitor init is fast")
func networkMonitorInitTime() {
let start = Date()
let monitor = NetworkMonitor()
let elapsed = -start.timeIntervalSinceNow
// NetworkMonitor should not start monitoring on init
#expect(elapsed < 0.01, "NetworkMonitor init took \(elapsed)s (expected < 10ms)")
monitor.stopMonitoring()
}
/// Measures ImageCacheService initialization (should be lazy)
@Test("ImageCacheService shared init is fast")
@MainActor
func imageCacheServiceInitTime() {
let start = Date()
_ = ImageCacheService.shared
let elapsed = -start.timeIntervalSinceNow
// ImageCacheService should not load metadata on init
#expect(elapsed < 0.05, "ImageCacheService init took \(elapsed)s (expected < 50ms)")
}
}
// MARK: - Lazy Loading Verification Tests
struct LazyLoadingTests {
@Test("AuthService does not restore session in init")
@MainActor
func authServiceNoRestoreOnInit() {
let keychain = MockKeychainService()
let apiClient = MockAuthAPIClient()
// Store a token in keychain
try? keychain.store(key: "jwt", value: Data("test-token".utf8))
try? keychain.store(key: "currentUser", value: try! JSONEncoder().encode(
User(id: "1", name: "Test", email: "test@test.com")
))
let service = AuthService(keychain: keychain, apiClient: apiClient)
// Session should NOT be restored in init
#expect(service.state == .unauthenticated)
#expect(service.currentUser == nil)
// After explicit restore, state should update
service.restoreSession()
#expect(service.state == .authenticated)
}
@Test("NetworkMonitor does not start monitoring on init")
func networkMonitorLazyStart() {
let monitor = NetworkMonitor()
// The monitor property should exist but monitoring should not have started
// We can't directly check the private flag, but we verify the behavior
// by checking that the default isConnected value hasn't changed
#expect(monitor.isConnected == true) // Default value, not from actual monitoring
monitor.stopMonitoring()
}
}
// MARK: - Build Configuration Tests
struct BuildConfigTests {
@Test("LaunchTimer is available in all configurations")
func launchTimerAvailable() {
let timer = LaunchTimer.shared
#expect(timer != nil)
}
@Test("Build configuration is accessible")
func buildConfig() {
#expect(ProcessInfo.processInfo.operatingSystemVersionString.count > 0)
}
}