升级 AppStore 缓存 Key 并在覆盖安装时强制重新登录。
统一账号作用域 Key 对齐 Android,新增缓存 schema 迁移清理旧数据,并同步更新相关模块与单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
160
suixinkanTests/AppStoreCacheMigrationTests.swift
Normal file
160
suixinkanTests/AppStoreCacheMigrationTests.swift
Normal file
@ -0,0 +1,160 @@
|
||||
//
|
||||
// AppStoreCacheMigrationTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
/// 验证覆盖升级清理、强制退出以及缓存结构版本幂等性。
|
||||
final class AppStoreCacheMigrationTests: XCTestCase {
|
||||
|
||||
private var suiteName: String!
|
||||
private var defaults: UserDefaults!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
suiteName = "AppStoreCacheMigrationTests.\(UUID().uuidString)"
|
||||
defaults = UserDefaults(suiteName: suiteName)
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
defaults = nil
|
||||
suiteName = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testFirstInitializationClearsLegacyAndPreReleaseKeysAndForcesLogout() {
|
||||
let exactKeysToRemove = [
|
||||
"suixinkan.session.v1",
|
||||
"apns_device_token",
|
||||
"apns_uploaded_token",
|
||||
"home.common.menu.uris",
|
||||
"home.common.menu.android.baseline.v2",
|
||||
"home.routing.unknown.records",
|
||||
"payment.voice.broadcast.enabled",
|
||||
"key_in_token",
|
||||
"key_last_login_username",
|
||||
"key_privacy_agreement_accepted",
|
||||
"key_in_user_id",
|
||||
"key_in_user_name",
|
||||
"key_in_real_name",
|
||||
"key_in_avatar",
|
||||
"key_in_phone",
|
||||
"key_in_account_type",
|
||||
"key_in_account_display_name",
|
||||
"key_in_role_id",
|
||||
"key_in_role_code",
|
||||
"key_in_role_name",
|
||||
"key_in_current_scenic_id",
|
||||
"key_in_current_scenic_name",
|
||||
"key_in_current_store_id",
|
||||
"key_role_permission_list",
|
||||
"key_in_permission",
|
||||
"key_current_role_scenic_list",
|
||||
"key_online_status",
|
||||
"key_last_location_report_time",
|
||||
"key_location_reminder_minutes",
|
||||
"key_is_open_receive_voice",
|
||||
"scenic_queue_tts_enabled",
|
||||
"scenic_queue_background_poll_enabled",
|
||||
"scenic_queue_selected_spot_id",
|
||||
"scenic_queue_selected_spot_name",
|
||||
"scenic_queue_custom_tts_text",
|
||||
"scenic_queue_photo_estimate_seconds",
|
||||
"scenic_queue_broadcast_interval_seconds",
|
||||
"scenic_queue_countdown_threshold_seconds",
|
||||
"scenic_queue_show_start_shooting_button",
|
||||
"scenic_queue_auto_call_ahead_count",
|
||||
"scenic_queue_quick_call_button_enabled",
|
||||
"scenic_queue_prepare_call_button_enabled",
|
||||
"scenic_queue_config_logs",
|
||||
"scenic_queue_settings_snapshot",
|
||||
"scenic_queue_preset_voices",
|
||||
]
|
||||
let dynamicKeysToRemove = [
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_id",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_name",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_settings_snapshot_spot_33",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_preset_voices_spot_33",
|
||||
"scenic_22_spot_33_scenic_queue_settings_snapshot",
|
||||
"scenic_22_spot_33_scenic_queue_preset_voices",
|
||||
"scenic_22_scenic_queue_settings_snapshot",
|
||||
"1001_store_user_key_in_role_id",
|
||||
"1001_store_user_key_role_permission_list",
|
||||
"1001_store_user_key_in_permission",
|
||||
"1001_store_user_key_current_role_scenic_list",
|
||||
"1001_store_user_key_online_status",
|
||||
"1001_store_user_key_last_location_report_time",
|
||||
"1001_store_user_key_location_reminder_minutes",
|
||||
"1001_store_user_key_is_open_receive_voice",
|
||||
"1001_store_user_role__common_uris",
|
||||
"1001_store_user_role_photographer_common_uris",
|
||||
"1001_store_user__scenic_queue_punch_spot_id",
|
||||
"1001_store_user__scenic_queue_punch_spot_name",
|
||||
"1001_store_user__scenic_queue_punch_spot_remark",
|
||||
"1001_store_user__scenic_queue_remark",
|
||||
"1001_store_user__scenic_queue_settings_snapshot",
|
||||
"1001_store_user__scenic_queue_offline_tts_v1",
|
||||
"1001_store_user__scenic_queue_preset_voices_v1",
|
||||
]
|
||||
let keysToPreserve = [
|
||||
"third_party.sentinel",
|
||||
"home.common.menu.uris.extra",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_identifier",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33_backup",
|
||||
"scenic_22_spot_33_scenic_queue_settings_snapshot_backup",
|
||||
"unrelated_key_in_permission_extra",
|
||||
"scenic_user_1001_key_in_role_code",
|
||||
"scenic_user_1001_scenic_22_scenic_queue_punch_spot_id",
|
||||
"scenic_user_1001_scenic_22_spot_33_scenic_queue_settings_snapshot",
|
||||
]
|
||||
let keysToRemove = exactKeysToRemove + dynamicKeysToRemove
|
||||
keysToRemove.forEach { defaults.set("legacy", forKey: $0) }
|
||||
keysToPreserve.forEach { defaults.set("keep", forKey: $0) }
|
||||
defaults.set(true, forKey: "key_privacy_agreement_accepted")
|
||||
|
||||
let store = AppStore(defaults: defaults)
|
||||
|
||||
XCTAssertFalse(store.session.isLoggedIn)
|
||||
XCTAssertNil(store.session.lastLoginUsername)
|
||||
XCTAssertFalse(store.session.privacyAgreementAccepted)
|
||||
keysToRemove.forEach { XCTAssertNil(defaults.object(forKey: $0), "未清理 Key:\($0)") }
|
||||
keysToPreserve.forEach {
|
||||
XCTAssertEqual(defaults.string(forKey: $0), "keep", "误清理 Key:\($0)")
|
||||
}
|
||||
XCTAssertEqual(
|
||||
defaults.integer(forKey: AppStoreCacheMigrator.schemaVersionKey),
|
||||
AppStoreCacheMigrator.currentSchemaVersion
|
||||
)
|
||||
}
|
||||
|
||||
func testMigrationRunsOnlyOnceAndPreservesNewSession() {
|
||||
defaults.set("keep", forKey: "third_party.sentinel")
|
||||
var store = AppStore(defaults: defaults)
|
||||
store.session.token = "new-token"
|
||||
store.session.lastLoginUsername = "13800000000"
|
||||
store.session.privacyAgreementAccepted = true
|
||||
store.session.userId = "1001"
|
||||
store.session.accountType = .scenicUser
|
||||
store.session.roleCode = "photographer"
|
||||
store.session.currentScenicId = 22
|
||||
store.scenicQueue.punchSpotId = "33"
|
||||
store.scenicQueue.punchSpotName = "东门"
|
||||
|
||||
store = AppStore(defaults: defaults)
|
||||
|
||||
XCTAssertTrue(store.session.isLoggedIn)
|
||||
XCTAssertEqual(store.session.token, "new-token")
|
||||
XCTAssertEqual(store.session.lastLoginUsername, "13800000000")
|
||||
XCTAssertTrue(store.session.privacyAgreementAccepted)
|
||||
XCTAssertEqual(store.session.roleCode, "photographer")
|
||||
XCTAssertEqual(store.session.currentScenicId, 22)
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotId, "33")
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotName, "东门")
|
||||
XCTAssertEqual(defaults.string(forKey: "third_party.sentinel"), "keep")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user