LocalData/Tests/LocalDataTests/MigrationTests.swift
Matt Bruce 0afaf34c78 Tests AnyStorageKeyTests.swift, AuditTests.swift, LocalDataTests.swift (+13 more)
Summary:
- Tests: AnyStorageKeyTests.swift, AuditTests.swift, LocalDataTests.swift, MigrationAdditionalTests.swift, MigrationIntegrationTests.swift (+11 more)
- Added symbols: func makeStringKey, func makeUserDefaultsKey, func makeFileKey, func makeLegacyStringKey, func makeModernStringKey, func makePhoneOnlyKey (+14 more)
- Removed symbols: struct StringKey, typealias Value, struct TestKey, struct TestUserDefaultsKey, struct TestFileKey, struct LegacyStringKey (+19 more)

Stats:
- 16 files changed, 329 insertions(+), 386 deletions(-)
2026-01-18 14:53:30 -06:00

120 lines
4.0 KiB
Swift

import Foundation
import Testing
@testable import LocalData
private func makeLegacyKey(name: String, domain: StorageDomain) -> StorageKey<String> {
StorageKey(
name: name,
domain: domain,
security: .none,
owner: "Legacy",
description: "Legacy key"
)
}
private func makeModernKey(
name: String,
domain: StorageDomain,
legacyKey: AnyStorageKey?
) -> StorageKey<String> {
StorageKey(
name: name,
domain: domain,
security: .keychain(accessibility: .afterFirstUnlock, accessControl: .none),
owner: "Modern",
description: "Modern key",
migration: { destinationKey in
guard let legacyKey else { return nil }
return AnyStorageMigration(
SimpleLegacyMigration(destinationKey: destinationKey, sourceKey: legacyKey)
)
}
)
}
@Suite(.serialized)
struct MigrationTests {
private let router: StorageRouter
init() {
let testBaseURL = FileManager.default.temporaryDirectory.appending(path: "MigrationTests-\(UUID().uuidString)")
router = StorageRouter(
keychain: MockKeychainHelper(),
encryption: EncryptionHelper(keychain: MockKeychainHelper()),
file: FileStorageHelper(configuration: FileStorageConfiguration(baseURL: testBaseURL)),
defaults: UserDefaultsHelper(defaults: UserDefaults(suiteName: "MigrationTests-\(UUID().uuidString)")!)
)
}
@Test func automaticMigrationFromUserDefaultsToKeychain() async throws {
let legacyName = "legacy.user.name"
let modernName = "user.name"
let suiteName = "MigrationTests.\(UUID().uuidString)"
let secretValue = "Matt Bruce"
defer {
UserDefaults().removePersistentDomain(forName: suiteName)
}
// 1. Setup legacy data manually in UserDefaults
let legacyKey = makeLegacyKey(name: legacyName, domain: .userDefaults(suite: suiteName))
try await router.set(secretValue, for: legacyKey)
// Verify it exists in legacy location
let existsInLegacy = try await router.exists(legacyKey)
#expect(existsInLegacy == true)
// 2. Setup modern key with legacy source
let modernKey = makeModernKey(
name: modernName,
domain: .keychain(service: "test.migration"),
legacyKey: .key(legacyKey)
)
// 3. Trigger automatic migration via GET
let migratedValue = try await router.get(modernKey)
#expect(migratedValue == secretValue)
// 4. Verify data moved
// Modern should now exist
let existsInModern = try await router.exists(modernKey)
#expect(existsInModern == true)
// Legacy should be gone
let existsInLegacyAfter = try await router.exists(legacyKey)
#expect(existsInLegacyAfter == false)
}
@Test func manualMigrationSweep() async throws {
let legacyName = "legacy.manual.key"
let modernName = "modern.manual.key"
let suiteName = "MigrationTests.Manual.\(UUID().uuidString)"
let value = "Manual Data"
defer {
UserDefaults().removePersistentDomain(forName: suiteName)
}
// 1. Setup legacy data
let legacyKey = makeLegacyKey(name: legacyName, domain: .userDefaults(suite: suiteName))
try await router.set(value, for: legacyKey)
// 2. Setup modern key
let modernKey = makeModernKey(
name: modernName,
domain: .userDefaults(suite: suiteName),
legacyKey: .key(legacyKey)
)
// 3. Trigger manual migration
_ = try await router.forceMigration(for: modernKey)
// 4. Verify
let hasModern = try await router.exists(modernKey)
#expect(hasModern == true)
let hasLegacy = try await router.exists(legacyKey)
#expect(hasLegacy == false)
}
}