|
| 1 | +"""Fault-injection check for the production settings-screen migration commit.""" |
| 2 | +import pathlib |
| 3 | +import subprocess |
| 4 | +import tempfile |
| 5 | + |
| 6 | +root = pathlib.Path(__file__).resolve().parents[2] |
| 7 | +source = (root / 'submodules/SettingsUI/Sources/ArchiveSettingsController.swift').read_text(encoding='utf-8') |
| 8 | +start = source.index(' if archiveSettings.legacyLockPasswordHash != nil') |
| 9 | +end = source.index('\n\n let controllerState', start) |
| 10 | +fixtures = ''' |
| 11 | +import Foundation |
| 12 | +struct Settings { |
| 13 | + var legacyLockPasswordHash: String? |
| 14 | + var isPasswordConfigured: Bool |
| 15 | + func clearingLegacyPasswordHash() -> Settings { |
| 16 | + var value = self; value.legacyLockPasswordHash = nil; return value |
| 17 | + } |
| 18 | + func withUpdatedIsPasswordConfigured(_ configured: Bool) -> Settings { |
| 19 | + var value = self; value.isPasswordConfigured = configured; return value |
| 20 | + } |
| 21 | +} |
| 22 | +final class Engine { |
| 23 | + var settings: Settings |
| 24 | + init(_ settings: Settings) { self.settings = settings } |
| 25 | +} |
| 26 | +struct Account { let peerId = 1 } |
| 27 | +struct Context { let account = Account(); let engine: Engine } |
| 28 | +struct ResultSignal { func startStandalone() -> Int { 0 } } |
| 29 | +func updateChatArchiveSettings(engine: Engine, _ f: (Settings) -> Settings) -> ResultSignal { |
| 30 | + engine.settings = f(engine.settings); return ResultSignal() |
| 31 | +} |
| 32 | +enum ArchivePasswordKeychain { |
| 33 | + static var stored = false |
| 34 | + static func hasPassword(peerId: Int) -> Bool { stored } |
| 35 | +} |
| 36 | +func applySettingsMigration(context: Context) { |
| 37 | + let archiveSettings = context.engine.settings |
| 38 | +''' |
| 39 | +tests = ''' |
| 40 | +} |
| 41 | +for alreadyConfigured in [false, true] { |
| 42 | + let engine = Engine(Settings(legacyLockPasswordHash: "legacy", isPasswordConfigured: alreadyConfigured)) |
| 43 | + ArchivePasswordKeychain.stored = false |
| 44 | + applySettingsMigration(context: Context(engine: engine)) |
| 45 | + precondition(engine.settings.legacyLockPasswordHash == "legacy", "Lost only credential after failed migration") |
| 46 | + precondition(engine.settings.isPasswordConfigured == alreadyConfigured) |
| 47 | + ArchivePasswordKeychain.stored = true |
| 48 | + applySettingsMigration(context: Context(engine: engine)) |
| 49 | + precondition(engine.settings.legacyLockPasswordHash == nil) |
| 50 | + precondition(engine.settings.isPasswordConfigured, "Notification protection was not mirrored") |
| 51 | +} |
| 52 | +print("Archive migration preserves credentials on failure and mirrors protection on success: passed") |
| 53 | +''' |
| 54 | +with tempfile.TemporaryDirectory(prefix='archive-migration-') as tmp: |
| 55 | + path = pathlib.Path(tmp) / 'main.swift' |
| 56 | + path.write_text(fixtures + source[start:end] + tests, encoding='utf-8') |
| 57 | + subprocess.run(['swift', str(path)], check=True) |
0 commit comments