734 lines · 35.6 KB · Swift
RawDownload
import CodexBarCoreimport Foundationimport Testing@testable import CodexBar @Suite(.serialized)@MainActorstruct CodexAccountPromotionServiceTests {    @Test    func `happy path promotion swaps target auth into live home`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-happy-path")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        try container.persistAccounts([target])        container.settings.codexActiveSource = .managedAccount(id: target.id)        try container.removeLiveAuthFile()         let targetAuthData = try container.managedAuthData(for: target)        let result = try await container.makeService().promoteManagedAccount(id: target.id)        let accounts = try container.loadAccounts().accounts         #expect(result.targetManagedAccountID == target.id)        #expect(result.outcome == .promoted)        #expect(result.displacedLiveDisposition == .none)        #expect(result.didMutateLiveAuth)        #expect(result.resultingActiveSource == .liveSystem)        #expect(try container.liveAuthData() == targetAuthData)        #expect(accounts.count == 1)        #expect(accounts.first?.id == target.id)        #expect(container.settings.codexActiveSource == .liveSystem)        #expect(container.usageStore.snapshots[.codex]?.accountEmail(for: .codex) == "beta@example.com")    }     @Test    func `displaced live oauth is imported before target auth is promoted`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-displaced-import",            workspaceIdentities: [                "acct-alpha": CodexOpenAIWorkspaceIdentity(                    workspaceAccountID: "acct-alpha",                    workspaceLabel: "Personal"),            ])        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        try container.persistAccounts([target])        container.settings.codexActiveSource = .managedAccount(id: target.id)        let displacedLiveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha")         let result = try await container.makeService().promoteManagedAccount(id: target.id)        let accounts = try container.loadAccounts().accounts        let importedID: UUID        switch result.displacedLiveDisposition {        case let .imported(managedAccountID):            importedID = managedAccountID        case .none, .alreadyManaged:            Issue.record("Expected displaced live account import")            throw PromotionTestError.unexpectedDisposition        }        let imported = try #require(accounts.first(where: { $0.id == importedID }))         #expect(accounts.count == 2)        #expect(imported.email == "alpha@example.com")        #expect(imported.providerAccountID == "acct-alpha")        #expect(imported.workspaceLabel == "Personal")        #expect(imported.workspaceAccountID == "acct-alpha")        #expect(imported.authFingerprint == CodexAuthFingerprint.fingerprint(data: displacedLiveAuthData))        #expect(try container.managedAuthData(for: imported) == displacedLiveAuthData)        #expect(try container.liveAuthData() == container.managedAuthData(for: target))    }     @Test    func `displaced live already managed uses reconciliation identity dedupe`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-already-managed")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        let existingManagedLive = try container.createManagedAccount(            persistedEmail: "legacy@example.com",            authEmail: "alpha@example.com",            authAccountID: "acct-alpha",            persistedProviderAccountID: nil)        try container.persistAccounts([target, existingManagedLive])        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha",            apiKey: "sk-fresh-live")         let result = try await container.makeService().promoteManagedAccount(id: target.id)        let accounts = try container.loadAccounts().accounts        let refreshedManagedLive = try #require(accounts.first(where: { $0.id == existingManagedLive.id }))         #expect(result.displacedLiveDisposition == .alreadyManaged(managedAccountID: existingManagedLive.id))        #expect(accounts.count == 2)        #expect(accounts.contains(where: { $0.id == existingManagedLive.id }))        #expect(refreshedManagedLive.authFingerprint == CodexAuthFingerprint.fingerprint(data: liveAuthData))        #expect(try container.managedAuthData(for: refreshedManagedLive) == liveAuthData)        #expect(try container.liveAuthData() == container.managedAuthData(for: target))    }     @Test    func `provider only live auth refreshes existing managed account using persisted email`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-already-managed-no-email")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        let existingManagedLive = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target, existingManagedLive])        let liveAuthData = try container.writeLiveOAuthAuthFileWithoutEmail(accountID: "acct-alpha")         let result = try await container.makeService().promoteManagedAccount(id: target.id)        let accounts = try container.loadAccounts().accounts        let refreshedManagedLive = try #require(accounts.first(where: { $0.id == existingManagedLive.id }))         #expect(result.displacedLiveDisposition == .alreadyManaged(managedAccountID: existingManagedLive.id))        #expect(refreshedManagedLive.email == "alpha@example.com")        #expect(refreshedManagedLive.providerAccountID == "acct-alpha")        #expect(refreshedManagedLive.authFingerprint == CodexAuthFingerprint.fingerprint(data: liveAuthData))        #expect(try container.managedAuthData(for: refreshedManagedLive) == liveAuthData)    }     @Test    func `provider only live auth matching target converges and keeps managed active source`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-provider-only-convergence")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target])        let liveAuthData = try container.writeLiveOAuthAuthFileWithoutEmail(accountID: "acct-alpha")        container.settings.codexActiveSource = .managedAccount(id: target.id)         let result = try await container.makeService().promoteManagedAccount(id: target.id)         #expect(result.outcome == .convergedNoOp)        #expect(result.displacedLiveDisposition == .none)        #expect(result.didMutateLiveAuth == false)        #expect(result.resultingActiveSource == .managedAccount(id: target.id))        #expect(try container.liveAuthData() == liveAuthData)        #expect(try container.loadAccounts().accounts.count == 1)        #expect(container.settings.codexActiveSource == .managedAccount(id: target.id))    }     @Test    func `provider only live auth matching target converges when target managed auth is missing`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-provider-only-convergence-missing-target-auth")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target])        container.settings.codexActiveSource = .managedAccount(id: target.id)        try FileManager.default.removeItem(            at: URL(fileURLWithPath: target.managedHomePath, isDirectory: true)                .appendingPathComponent("auth.json", isDirectory: false))        let liveAuthData = try container.writeLiveOAuthAuthFileWithoutEmail(accountID: "acct-alpha")         let result = try await container.makeService().promoteManagedAccount(id: target.id)         #expect(result.outcome == .convergedNoOp)        #expect(result.displacedLiveDisposition == .none)        #expect(result.didMutateLiveAuth == false)        #expect(result.resultingActiveSource == .managedAccount(id: target.id))        #expect(try container.liveAuthData() == liveAuthData)        #expect(container.settings.codexActiveSource == .managedAccount(id: target.id))    }     @Test    func `snapshot convergence no op does not require target managed auth file`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-snapshot-convergence-with-missing-target-auth")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target])        try FileManager.default.removeItem(            at: URL(fileURLWithPath: target.managedHomePath, isDirectory: true)                .appendingPathComponent("auth.json", isDirectory: false))        container.settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(            email: "alpha@example.com",            codexHomePath: container.liveHomeURL.path,            observedAt: Date(),            identity: .emailOnly(normalizedEmail: "alpha@example.com"))        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha")         let result = try await container.makeService().promoteManagedAccount(id: target.id)         #expect(result.outcome == .convergedNoOp)        #expect(result.displacedLiveDisposition == .none)        #expect(result.didMutateLiveAuth == false)        #expect(try container.liveAuthData() == liveAuthData)    }     @Test    func `convergence no-op does not rewrite live auth or import displaced live`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-convergence")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target])        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha")         let result = try await container.makeService().promoteManagedAccount(id: target.id)         #expect(result.outcome == .convergedNoOp)        #expect(result.displacedLiveDisposition == .none)        #expect(result.didMutateLiveAuth == false)        #expect(try container.liveAuthData() == liveAuthData)        #expect(try container.loadAccounts().accounts.count == 1)        #expect(container.settings.codexActiveSource == .liveSystem)    }     @Test    func `same email different workspace imports displaced live as a distinct managed account`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-same-email-different-workspace",            workspaceIdentities: [                "acct-personal": CodexOpenAIWorkspaceIdentity(                    workspaceAccountID: "acct-personal",                    workspaceLabel: "Personal"),            ])        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alice@example.com",            authAccountID: "acct-team",            workspaceLabel: "Team",            workspaceAccountID: "acct-team")        try container.persistAccounts([target])        _ = try container.writeLiveOAuthAuthFile(email: "alice@example.com", accountID: "acct-personal")         let result = try await container.makeService().promoteManagedAccount(id: target.id)        let importedID: UUID        switch result.displacedLiveDisposition {        case let .imported(managedAccountID):            importedID = managedAccountID        case .none, .alreadyManaged:            Issue.record("Expected same-email different-workspace import")            throw PromotionTestError.unexpectedDisposition        }        let accounts = try container.loadAccounts().accounts        let imported = try #require(accounts.first(where: { $0.id == importedID }))         #expect(accounts.count == 2)        #expect(imported.id != target.id)        #expect(imported.email == "alice@example.com")        #expect(imported.providerAccountID == "acct-personal")        #expect(imported.workspaceLabel == "Personal")        #expect(imported.workspaceAccountID == "acct-personal")    }     @Test    func `mixed api key and oauth live auth still preserves displaced live identity`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-mixed-auth-preservation",            workspaceIdentities: [                "acct-alpha": CodexOpenAIWorkspaceIdentity(                    workspaceAccountID: "acct-alpha",                    workspaceLabel: "Personal"),            ])        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        try container.persistAccounts([target])        _ = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha",            apiKey: "sk-mixed-live")         let result = try await container.makeService().promoteManagedAccount(id: target.id)        let importedID: UUID        switch result.displacedLiveDisposition {        case let .imported(managedAccountID):            importedID = managedAccountID        case .none, .alreadyManaged:            Issue.record("Expected displaced live import for mixed auth material")            throw PromotionTestError.unexpectedDisposition        }        let imported = try #require(try container.loadAccounts().accounts.first(where: { $0.id == importedID }))         #expect(imported.email == "alpha@example.com")        #expect(imported.providerAccountID == "acct-alpha")        #expect(imported.workspaceLabel == "Personal")    }     @Test    func `store commit failure leaves live auth untouched because promotion preserves before mutating`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-store-failure")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        try container.persistAccounts([target])        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha")        let swapper = RecordingCodexLiveAuthSwapper()        let store = RecordingManagedCodexAccountStore(base: container.fileStore) { _ in            throw PromotionTestError.storeWriteFailed        }         await #expect(throws: CodexAccountPromotionError.managedStoreCommitFailed) {            try await container.makeService(                store: store,                liveAuthSwapper: swapper).promoteManagedAccount(id: target.id)        }         #expect(swapper.swapCallCount == 0)        #expect(try container.liveAuthData() == liveAuthData)        #expect(try container.loadAccounts().accounts.count == 1)        #expect(try container.loadAccounts().accounts.first?.id == target.id)        #expect(try container.managedHomeURLs().count == 1)    }     @Test    func `refresh store failure leaves existing managed metadata stale after auth copy`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-refresh-store-failure")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        let existingManagedLive = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target, existingManagedLive])        let originalManagedAuthData = try container.managedAuthData(for: existingManagedLive)        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha",            apiKey: "sk-refreshed-live")        let swapper = RecordingCodexLiveAuthSwapper()        let store = RecordingManagedCodexAccountStore(base: container.fileStore) { accounts in            if accounts.account(id: existingManagedLive.id)?                .lastAuthenticatedAt != existingManagedLive.lastAuthenticatedAt            {                throw PromotionTestError.storeWriteFailed            }        }         await #expect(throws: CodexAccountPromotionError.managedStoreCommitFailed) {            try await container.makeService(                store: store,                liveAuthSwapper: swapper).promoteManagedAccount(id: target.id)        }         let accounts = try container.loadAccounts().accounts        let persistedManagedLive = try #require(accounts.first(where: { $0.id == existingManagedLive.id }))        #expect(swapper.swapCallCount == 0)        #expect(try container.managedAuthData(for: persistedManagedLive) != originalManagedAuthData)        #expect(try container.managedAuthData(for: persistedManagedLive) == liveAuthData)        #expect(persistedManagedLive.lastAuthenticatedAt == existingManagedLive.lastAuthenticatedAt)    }     @Test    func `already managed refresh resolves workspace metadata from live auth home`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-already-managed-workspace-refresh")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        let existingManagedLive = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha",            workspaceLabel: "Stale",            workspaceAccountID: "acct-alpha")        try container.persistAccounts([target, existingManagedLive])        _ = try container.writeLiveOAuthAuthFile(email: "alpha@example.com", accountID: "acct-alpha")         let service = CodexAccountPromotionService(            store: container.fileStore,            homeFactory: container.homeFactory,            identityReader: container.identityReader,            workspaceResolver: HomePathWorkspaceResolver(                byHomePath: [                    container.liveHomeURL.path: CodexOpenAIWorkspaceIdentity(                        workspaceAccountID: "acct-alpha",                        workspaceLabel: "Fresh"),                    existingManagedLive.managedHomePath: CodexOpenAIWorkspaceIdentity(                        workspaceAccountID: "acct-alpha",                        workspaceLabel: "Stale"),                ]),            snapshotLoader: SettingsStoreCodexAccountReconciliationSnapshotLoader(settingsStore: container.settings),            authMaterialReader: DefaultCodexAuthMaterialReader(),            liveAuthSwapper: DefaultCodexLiveAuthSwapper(),            activeSourceWriter: SettingsStoreCodexActiveSourceWriter(settingsStore: container.settings),            accountScopedRefresher: UsageStoreCodexAccountScopedRefresher(usageStore: container.usageStore),            baseEnvironment: container.baseEnvironment,            fileManager: .default)         let result = try await service.promoteManagedAccount(id: target.id)        let accounts = try container.loadAccounts().accounts        let refreshedManagedLive = try #require(accounts.first(where: { $0.id == existingManagedLive.id }))         #expect(result.displacedLiveDisposition == .alreadyManaged(managedAccountID: existingManagedLive.id))        #expect(refreshedManagedLive.workspaceLabel == "Fresh")        #expect(refreshedManagedLive.workspaceAccountID == "acct-alpha")    }     @Test    func `live swap failure keeps preserved displaced live import in the managed store`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-swap-failure")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",            authAccountID: "acct-beta")        try container.persistAccounts([target])        container.settings.codexActiveSource = .managedAccount(id: target.id)        let liveAuthData = try container.writeLiveOAuthAuthFile(            email: "alpha@example.com",            accountID: "acct-alpha")        let swapper = RecordingCodexLiveAuthSwapper { _, _ in            throw PromotionTestError.swapFailed        }         await #expect(throws: CodexAccountPromotionError.liveAuthSwapFailed) {            try await container.makeService(liveAuthSwapper: swapper).promoteManagedAccount(id: target.id)        }         let accounts = try container.loadAccounts().accounts        let imported = try #require(accounts.first(where: { $0.id != target.id }))        #expect(accounts.count == 2)        #expect(imported.authFingerprint == CodexAuthFingerprint.fingerprint(data: liveAuthData))        #expect(try container.managedAuthData(for: imported) == liveAuthData)        #expect(try container.liveAuthData() == liveAuthData)        #expect(container.settings.codexActiveSource == .managedAccount(id: target.id))    }     @Test    func `target managed auth without email is rejected before swap`() async throws {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-target-auth-missing-email")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "alpha@example.com",            authAccountID: "acct-alpha")        try container.persistAccounts([target])        container.settings.codexActiveSource = .managedAccount(id: target.id)        _ = try container.writeManagedOAuthAuthFileWithoutEmail(for: target, accountID: "acct-alpha")        let swapper = RecordingCodexLiveAuthSwapper()         await #expect(throws: CodexAccountPromotionError.targetManagedAccountAuthUnreadable) {            try await container.makeService(liveAuthSwapper: swapper).promoteManagedAccount(id: target.id)        }         #expect(swapper.swapCallCount == 0)        #expect(try container.liveAuthData() == nil)        #expect(try container.loadAccounts().accounts.count == 1)        #expect(container.settings.codexActiveSource == .managedAccount(id: target.id))    }     @Test    func `provider account collision after stale managed home repairs existing record to preserved auth`()        async throws    {        let container = try CodexAccountPromotionTestContainer(            suiteName: "CodexAccountPromotionServiceTests-stale-home-collision")        defer { container.tearDown() }         let target = try container.createManagedAccount(            persistedEmail: "beta@example.com",

Lines 1–500 of 734.