946 lines · 41.6 KB · Swift
RawDownload
import CodexBarCoreimport Foundationimport Testing@testable import CodexBar @Suite(.serialized)struct CodexAccountReconciliationTests {    @MainActor    private static func makeSettings(suite: String) throws -> SettingsStore {        let defaults = try #require(UserDefaults(suiteName: suite))        defaults.removePersistentDomain(forName: suite)        defaults.set(true, forKey: "providerDetectionCompleted")        let settings = SettingsStore(            userDefaults: defaults,            configStore: testConfigStore(suiteName: suite),            zaiTokenStore: NoopZaiTokenStore(),            syntheticTokenStore: NoopSyntheticTokenStore())        settings.providerDetectionCompleted = true        return settings    }     @Test    @MainActor    func `settings store exposes codex reconciliation accessors using managed and live overrides`() throws {        let suite = "CodexAccountReconciliationTests-settings-store"        let settings = try Self.makeSettings(suite: suite)        let managed = ManagedCodexAccount(            id: UUID(),            email: "managed@example.com",            managedHomePath: "/tmp/managed-home",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let live = ObservedSystemCodexAccount(            email: "system@example.com",            codexHomePath: "/Users/test/.codex",            observedAt: Date())        settings._test_activeManagedCodexAccount = managed        settings._test_liveSystemCodexAccount = live        settings.codexActiveSource = .managedAccount(id: managed.id)        defer {            settings._test_activeManagedCodexAccount = nil            settings._test_liveSystemCodexAccount = nil        }         let snapshot = settings.codexAccountReconciliationSnapshot        let projection = settings.codexVisibleAccountProjection         #expect(settings.codexActiveSource == .managedAccount(id: managed.id))        #expect(snapshot.storedAccounts.map(\.id) == [managed.id])        #expect(snapshot.storedAccounts.map(\.email) == [managed.email])        #expect(snapshot.activeStoredAccount?.id == managed.id)        #expect(snapshot.activeStoredAccount?.email == managed.email)        #expect(snapshot.liveSystemAccount?.email == live.email)        #expect(snapshot.liveSystemAccount?.codexHomePath == live.codexHomePath)        #expect(snapshot.liveSystemAccount?.observedAt == live.observedAt)        #expect(snapshot.liveSystemAccount?.identity == .emailOnly(normalizedEmail: "system@example.com"))        #expect(snapshot.matchingStoredAccountForLiveSystemAccount == nil)        #expect(snapshot.activeSource == .managedAccount(id: managed.id))        #expect(snapshot.hasUnreadableAddedAccountStore == false)        #expect(Set(projection.visibleAccounts.map(\.email)) == ["managed@example.com", "system@example.com"])        #expect(settings.codexVisibleAccounts == projection.visibleAccounts)        #expect(projection.activeVisibleAccountID == "managed@example.com")        #expect(projection.liveVisibleAccountID == "system@example.com")    }     @Test    @MainActor    func `settings store managed override does not leak ambient live system account`() throws {        let suite = "CodexAccountReconciliationTests-managed-only"        let settings = try Self.makeSettings(suite: suite)        let managed = ManagedCodexAccount(            id: UUID(),            email: "managed@example.com",            managedHomePath: "/tmp/managed-home",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        settings._test_activeManagedCodexAccount = managed        settings.codexActiveSource = .managedAccount(id: managed.id)        defer {            settings._test_activeManagedCodexAccount = nil        }         let snapshot = settings.codexAccountReconciliationSnapshot        let projection = settings.codexVisibleAccountProjection         #expect(settings.codexActiveSource == .managedAccount(id: managed.id))        #expect(snapshot.liveSystemAccount == nil)        #expect(snapshot.matchingStoredAccountForLiveSystemAccount == nil)        #expect(snapshot.activeSource == .managedAccount(id: managed.id))        #expect(projection.visibleAccounts.map(\.email) == ["managed@example.com"])        #expect(projection.activeVisibleAccountID == "managed@example.com")        #expect(projection.liveVisibleAccountID == nil)    }     @Test    @MainActor    func `settings store reconciliation environment override drives live observation with synthetic store`() throws {        let suite = "CodexAccountReconciliationTests-environment-only"        let settings = try Self.makeSettings(suite: suite)        let ambientHome = FileManager.default.temporaryDirectory.appendingPathComponent(            UUID().uuidString,            isDirectory: true)        try Self.writeCodexAuthFile(homeURL: ambientHome, email: "ambient@example.com", plan: "pro")        settings._test_codexReconciliationEnvironment = ["CODEX_HOME": ambientHome.path]        defer {            settings._test_codexReconciliationEnvironment = nil            try? FileManager.default.removeItem(at: ambientHome)        }         let snapshot = settings.codexAccountReconciliationSnapshot        let projection = settings.codexVisibleAccountProjection         #expect(settings.codexActiveSource == .liveSystem)        #expect(snapshot.storedAccounts.isEmpty)        #expect(snapshot.activeStoredAccount == nil)        #expect(snapshot.liveSystemAccount?.email == "ambient@example.com")        #expect(snapshot.liveSystemAccount?.codexHomePath == ambientHome.path)        #expect(snapshot.matchingStoredAccountForLiveSystemAccount == nil)        #expect(snapshot.activeSource == .liveSystem)        #expect(projection.visibleAccounts.map(\.email) == ["ambient@example.com"])        #expect(projection.activeVisibleAccountID == "ambient@example.com")        #expect(projection.liveVisibleAccountID == "ambient@example.com")    }     @Test    @MainActor    func `settings store can reuse short lived codex reconciliation snapshot`() throws {        let suite = "CodexAccountReconciliationTests-short-lived-cache"        let settings = try Self.makeSettings(suite: suite)        let ambientHome = FileManager.default.temporaryDirectory.appendingPathComponent(            UUID().uuidString,            isDirectory: true)        try Self.writeCodexAuthFile(homeURL: ambientHome, email: "cached@example.com", plan: "pro")        settings._test_codexReconciliationEnvironment = ["CODEX_HOME": ambientHome.path]        SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60        defer {            SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil            settings._test_codexReconciliationEnvironment = nil            try? FileManager.default.removeItem(at: ambientHome)        }         let first = settings.codexAccountReconciliationSnapshot        try FileManager.default.removeItem(at: ambientHome)        let cached = settings.codexAccountReconciliationSnapshot        settings.invalidateCodexAccountReconciliationSnapshotCache()        let refreshed = settings.codexAccountReconciliationSnapshot         #expect(first.liveSystemAccount?.email == "cached@example.com")        #expect(cached.liveSystemAccount?.email == "cached@example.com")        #expect(refreshed.liveSystemAccount == nil)    }     @Test    @MainActor    func `codex active source write invalidates short lived reconciliation snapshot`() throws {        let suite = "CodexAccountReconciliationTests-active-source-cache-invalidation"        let settings = try Self.makeSettings(suite: suite)        let ambientHome = FileManager.default.temporaryDirectory.appendingPathComponent(            UUID().uuidString,            isDirectory: true)        try Self.writeCodexAuthFile(homeURL: ambientHome, email: "before@example.com", plan: "pro")        settings._test_codexReconciliationEnvironment = ["CODEX_HOME": ambientHome.path]        SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60        defer {            SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil            settings._test_codexReconciliationEnvironment = nil            try? FileManager.default.removeItem(at: ambientHome)        }         #expect(settings.codexAccountReconciliationSnapshot.liveSystemAccount?.email == "before@example.com")        try Self.writeCodexAuthFile(homeURL: ambientHome, email: "after@example.com", plan: "pro")        settings.codexActiveSource = .liveSystem         #expect(settings.codexAccountReconciliationSnapshot.liveSystemAccount?.email == "after@example.com")    }     @Test    @MainActor    func `managed account changes invalidate short lived reconciliation snapshot`() throws {        let suite = "CodexAccountReconciliationTests-managed-change-cache-invalidation"        let settings = try Self.makeSettings(suite: suite)        let storeURL = FileManager.default.temporaryDirectory            .appendingPathComponent("codex-managed-store-\(UUID().uuidString).json")        try Self.writeManagedCodexStore(            ManagedCodexAccountSet(version: FileManagedCodexAccountStore.currentVersion, accounts: []),            to: storeURL)        let stored = ManagedCodexAccount(            id: UUID(),            email: "stored@example.com",            managedHomePath: "/tmp/stored-managed-home",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        settings._test_managedCodexAccountStoreURL = storeURL        settings.codexActiveSource = .managedAccount(id: stored.id)        SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60        defer {            SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil            settings._test_managedCodexAccountStoreURL = nil            try? FileManager.default.removeItem(at: storeURL)        }         #expect(settings.codexAccountReconciliationSnapshot.storedAccounts.isEmpty)        try Self.writeManagedCodexStore(            ManagedCodexAccountSet(version: FileManagedCodexAccountStore.currentVersion, accounts: [stored]),            to: storeURL)        settings.refreshCodexAccountReconciliationAfterManagedAccountsDidChange()         #expect(settings.codexAccountReconciliationSnapshot.storedAccounts.map(\.id) == [stored.id])    }     @Test    @MainActor    func `settings store home path override also keeps reconciliation hermetic`() throws {        let suite = "CodexAccountReconciliationTests-home-path-only"        let settings = try Self.makeSettings(suite: suite)        settings._test_activeManagedCodexRemoteHomePath = "/tmp/managed-route-home"        settings._test_liveSystemCodexAccount = nil        settings._test_codexReconciliationEnvironment = nil        defer {            settings._test_activeManagedCodexRemoteHomePath = nil            settings._test_liveSystemCodexAccount = nil            settings._test_codexReconciliationEnvironment = nil        }         let snapshot = settings.codexAccountReconciliationSnapshot        let projection = settings.codexVisibleAccountProjection         #expect(snapshot.storedAccounts.isEmpty)        #expect(snapshot.activeStoredAccount == nil)        #expect(snapshot.liveSystemAccount == nil)        #expect(snapshot.matchingStoredAccountForLiveSystemAccount == nil)        #expect(projection.visibleAccounts.isEmpty)        #expect(projection.activeVisibleAccountID == nil)        #expect(projection.liveVisibleAccountID == nil)    }     @Test    @MainActor    func `settings store home path override keeps active source hermetic without persisted source`() throws {        let suite = "CodexAccountReconciliationTests-home-path-hermetic-source"        let settings = try Self.makeSettings(suite: suite)        let ambient = ManagedCodexAccount(            id: UUID(),            email: "ambient-managed@example.com",            managedHomePath: "/tmp/ambient-managed-home",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let accounts = ManagedCodexAccountSet(            version: FileManagedCodexAccountStore.currentVersion,            accounts: [ambient])        let storeURL = FileManager.default.temporaryDirectory            .appendingPathComponent("codex-managed-store-\(UUID().uuidString).json")        try Self.writeManagedCodexStore(accounts, to: storeURL)         settings._test_managedCodexAccountStoreURL = storeURL        settings._test_activeManagedCodexRemoteHomePath = "/tmp/managed-route-home"        defer {            settings._test_managedCodexAccountStoreURL = nil            settings._test_activeManagedCodexRemoteHomePath = nil            try? FileManager.default.removeItem(at: storeURL)        }         let snapshot = settings.codexAccountReconciliationSnapshot         #expect(settings.codexActiveSource == .liveSystem)        #expect(settings.providerConfig(for: .codex)?.codexActiveSource == nil)        #expect(snapshot.storedAccounts.map(\.id) == [ambient.id])        #expect(snapshot.storedAccounts.map(\.email) == [ambient.email])        #expect(snapshot.activeStoredAccount == nil)        #expect(snapshot.activeSource == .liveSystem)    }     @Test    @MainActor    func `settings store normal reconciliation path honors persisted active source`() throws {        let suite = "CodexAccountReconciliationTests-normal-path-active-source"        let settings = try Self.makeSettings(suite: suite)        let persistedSource = CodexActiveSource.managedAccount(id: UUID())        settings.codexActiveSource = persistedSource         let snapshot = settings.codexAccountReconciliationSnapshot         #expect(snapshot.activeSource == persistedSource)    }     @Test    @MainActor    func `settings store debug managed store U R L override loads on disk accounts`() throws {        let suite = "CodexAccountReconciliationTests-debug-store-url"        let settings = try Self.makeSettings(suite: suite)        let stored = ManagedCodexAccount(            id: UUID(),            email: "stored@example.com",            managedHomePath: "/tmp/stored-managed-home",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let accounts = ManagedCodexAccountSet(            version: FileManagedCodexAccountStore.currentVersion,            accounts: [stored])        let storeURL = FileManager.default.temporaryDirectory            .appendingPathComponent("codex-managed-store-\(UUID().uuidString).json")        try Self.writeManagedCodexStore(accounts, to: storeURL)         settings._test_managedCodexAccountStoreURL = storeURL        settings.codexActiveSource = .managedAccount(id: stored.id)        defer {            settings._test_managedCodexAccountStoreURL = nil            try? FileManager.default.removeItem(at: storeURL)        }         let snapshot = settings.codexAccountReconciliationSnapshot         #expect(snapshot.storedAccounts.map(\.id) == [stored.id])        #expect(snapshot.storedAccounts.map(\.email) == [stored.email])        #expect(snapshot.activeStoredAccount?.id == stored.id)        #expect(snapshot.activeStoredAccount?.email == stored.email)        #expect(snapshot.activeSource == .managedAccount(id: stored.id))    }     @Test    func `live only visible account is active when active source is live system`() {        let live = ObservedSystemCodexAccount(            email: "live@example.com",            codexHomePath: "/Users/test/.codex",            observedAt: Date())        let projection = CodexVisibleAccountProjection.make(from: CodexAccountReconciliationSnapshot(            storedAccounts: [],            activeStoredAccount: nil,            liveSystemAccount: live,            matchingStoredAccountForLiveSystemAccount: nil,            activeSource: .liveSystem,            hasUnreadableAddedAccountStore: false))         #expect(projection.visibleAccounts.map(\.email) == ["live@example.com"])        #expect(projection.activeVisibleAccountID == "live@example.com")        #expect(projection.liveVisibleAccountID == "live@example.com")    }     @Test    func `workspace hydration changes snapshot equality and visible display state`() {        let accountID = UUID()        let baseAccount = ManagedCodexAccount(            id: accountID,            email: "user@example.com",            providerAccountID: "account-live",            managedHomePath: "/tmp/managed-a",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let hydratedAccount = ManagedCodexAccount(            id: accountID,            email: "user@example.com",            providerAccountID: "account-live",            workspaceLabel: "Team Alpha",            workspaceAccountID: "account-live",            managedHomePath: "/tmp/managed-a",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let baseSnapshot = CodexAccountReconciliationSnapshot(            storedAccounts: [baseAccount],            activeStoredAccount: baseAccount,            liveSystemAccount: nil,            matchingStoredAccountForLiveSystemAccount: nil,            activeSource: .managedAccount(id: accountID),            hasUnreadableAddedAccountStore: false)        let hydratedSnapshot = CodexAccountReconciliationSnapshot(            storedAccounts: [hydratedAccount],            activeStoredAccount: hydratedAccount,            liveSystemAccount: nil,            matchingStoredAccountForLiveSystemAccount: nil,            activeSource: .managedAccount(id: accountID),            hasUnreadableAddedAccountStore: false)         let baseProjection = CodexVisibleAccountProjection.make(from: baseSnapshot)        let hydratedProjection = CodexVisibleAccountProjection.make(from: hydratedSnapshot)         #expect(baseSnapshot != hydratedSnapshot)        #expect(baseProjection.visibleAccounts.first?.displayName == "user@example.com")        #expect(hydratedProjection.visibleAccounts.first?.displayName == "user@example.com — Team Alpha")    }     @Test    func `matching live system account does not duplicate stored identity`() {        let stored = ManagedCodexAccount(            id: UUID(),            email: "user@example.com",            managedHomePath: "/tmp/managed-a",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let accounts = ManagedCodexAccountSet(version: 1, accounts: [stored])        let live = ObservedSystemCodexAccount(            email: "USER@example.com",            codexHomePath: "/Users/test/.codex",            observedAt: Date())        let reconciler = DefaultCodexAccountReconciler(            storeLoader: { accounts },            systemObserver: StubSystemObserver(account: live),            activeSource: .managedAccount(id: stored.id),            baseEnvironment: [:])         let projection = reconciler.loadVisibleAccounts()         #expect(projection.visibleAccounts.count == 1)        #expect(projection.activeVisibleAccountID == "user@example.com")        #expect(projection.liveVisibleAccountID == "user@example.com")    }     @Test    func `matching live system account prefers live workspace label and keeps stored fallback`() {        let stored = ManagedCodexAccount(            id: UUID(),            email: "user@example.com",            providerAccountID: "account-live",            workspaceLabel: "Saved Team",            workspaceAccountID: "account-live",            managedHomePath: "/tmp/managed-a",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let liveWithLabel = ObservedSystemCodexAccount(            email: "USER@example.com",            workspaceLabel: "Live Team",            workspaceAccountID: "account-live",            codexHomePath: "/Users/test/.codex",            observedAt: Date(),            identity: .providerAccount(id: "account-live"))        let labeledSnapshot = CodexAccountReconciliationSnapshot(            storedAccounts: [stored],            activeStoredAccount: stored,            liveSystemAccount: liveWithLabel,            matchingStoredAccountForLiveSystemAccount: stored,            activeSource: .managedAccount(id: stored.id),            hasUnreadableAddedAccountStore: false,            storedAccountRuntimeIdentities: [stored.id: .providerAccount(id: "account-live")],            storedAccountRuntimeEmails: [stored.id: "user@example.com"])        let liveWithoutLabel = ObservedSystemCodexAccount(            email: "USER@example.com",            workspaceLabel: nil,            workspaceAccountID: "account-live",            codexHomePath: "/Users/test/.codex",            observedAt: Date(),            identity: .providerAccount(id: "account-live"))        let fallbackSnapshot = CodexAccountReconciliationSnapshot(            storedAccounts: [stored],            activeStoredAccount: stored,            liveSystemAccount: liveWithoutLabel,            matchingStoredAccountForLiveSystemAccount: stored,            activeSource: .managedAccount(id: stored.id),            hasUnreadableAddedAccountStore: false,            storedAccountRuntimeIdentities: [stored.id: .providerAccount(id: "account-live")],            storedAccountRuntimeEmails: [stored.id: "user@example.com"])        let liveWithEmptyLabel = ObservedSystemCodexAccount(            email: "USER@example.com",            workspaceLabel: "   \n\t  ",            workspaceAccountID: "account-live",            codexHomePath: "/Users/test/.codex",            observedAt: Date(),            identity: .providerAccount(id: "account-live"))        let emptyLabelSnapshot = CodexAccountReconciliationSnapshot(            storedAccounts: [stored],            activeStoredAccount: stored,            liveSystemAccount: liveWithEmptyLabel,            matchingStoredAccountForLiveSystemAccount: stored,            activeSource: .managedAccount(id: stored.id),            hasUnreadableAddedAccountStore: false,            storedAccountRuntimeIdentities: [stored.id: .providerAccount(id: "account-live")],            storedAccountRuntimeEmails: [stored.id: "user@example.com"])         let labeledProjection = CodexVisibleAccountProjection.make(from: labeledSnapshot)        let fallbackProjection = CodexVisibleAccountProjection.make(from: fallbackSnapshot)        let emptyLabelProjection = CodexVisibleAccountProjection.make(from: emptyLabelSnapshot)         #expect(labeledProjection.visibleAccounts.count == 1)        #expect(labeledProjection.visibleAccounts.first?.workspaceLabel == "Live Team")        #expect(labeledProjection.visibleAccounts.first?.displayName == "user@example.com — Live Team")        #expect(fallbackProjection.visibleAccounts.count == 1)        #expect(fallbackProjection.visibleAccounts.first?.workspaceLabel == "Saved Team")        #expect(fallbackProjection.visibleAccounts.first?.displayName == "user@example.com — Saved Team")        #expect(emptyLabelProjection.visibleAccounts.count == 1)        #expect(emptyLabelProjection.visibleAccounts.first?.workspaceLabel == "Saved Team")        #expect(emptyLabelProjection.visibleAccounts.first?.displayName == "user@example.com — Saved Team")    }     @Test    func `matching live system account resolves merged row selection to live system`() {        let stored = ManagedCodexAccount(            id: UUID(),            email: "user@example.com",            managedHomePath: "/tmp/managed-a",            createdAt: 1,            updatedAt: 2,            lastAuthenticatedAt: 3)        let live = ObservedSystemCodexAccount(

Lines 1–500 of 946.