import CodexBarCore import Foundation import Testing @testable import CodexBar extension CodexAccountScopedRefreshTests { @Test func `dashboard refresh accepted via unresolved routing fallback during account scoped refresh`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-dashboard-unresolved-routing-fallback") let isolatedHome = FileManager.default.temporaryDirectory .appendingPathComponent("codex-dashboard-unresolved-routing-\(UUID().uuidString)", isDirectory: true) try? FileManager.default.createDirectory(at: isolatedHome, withIntermediateDirectories: true) let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.refreshFrequency = .manual settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto settings.codexActiveSource = .liveSystem settings._test_liveSystemCodexAccount = nil settings._test_codexReconciliationEnvironment = ["CODEX_HOME": isolatedHome.path] defer { settings._test_codexReconciliationEnvironment = nil try? FileManager.default.removeItem(at: isolatedHome) } let store = self.makeUsageStore(settings: settings) store.lastKnownLiveSystemCodexEmail = nil self.installImmediateCodexProvider( on: store, snapshot: self.codexSnapshot(email: "work@company.com", usedPercent: 12)) store._test_codexCreditsLoaderOverride = { self.credits(remaining: 55) } defer { store._test_codexCreditsLoaderOverride = nil } var observedTargetEmail: String? store._test_openAIDashboardLoaderOverride = { accountEmail, _, _, _ in observedTargetEmail = accountEmail #expect(store.currentCodexOpenAIWebRefreshGuard().source == .liveSystem) #expect(store.currentCodexOpenAIWebRefreshGuard().identity == .unresolved) return self.dashboard(email: "work@company.com", creditsRemaining: 33, usedPercent: 12) } defer { store._test_openAIDashboardLoaderOverride = nil } await store.refreshCodexAccountScopedState(allowDisabled: true) #expect(observedTargetEmail == "work@company.com") #expect(store.currentCodexOpenAIWebRefreshGuard().identity == .unresolved) #expect(store.openAIDashboard?.signedInEmail == "work@company.com") #expect(store.lastOpenAIDashboardSnapshot?.signedInEmail == "work@company.com") #expect(store.openAIDashboardRequiresLogin == false) #expect(store.lastOpenAIDashboardError == nil) #expect(store.snapshots[.codex]?.accountEmail(for: .codex) == "work@company.com") #expect(store.lastSourceLabels[.codex] == "test-codex") #expect(store.credits?.remaining == 55) #expect(store.lastCreditsSource == .api) } @Test func `dashboard fail closed clears dashboard derived usage credits cache and visible dashboard`() async throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let settings = self.makeSettingsStore(suite: "CodexAccountScopedRefreshTests-dashboard-fail-closed-cleanup") let managedHome = FileManager.default.temporaryDirectory .appendingPathComponent(UUID().uuidString, isDirectory: true) defer { try? FileManager.default.removeItem(at: managedHome) } try Self.writeCodexAuthFile( homeURL: managedHome, email: "managed@example.com", plan: "pro", accountId: "acct-managed") let managedAccount = ManagedCodexAccount( id: UUID(), email: "managed@example.com", managedHomePath: managedHome.path, createdAt: 1, updatedAt: 1, lastAuthenticatedAt: 1) let managedStoreURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount]) defer { settings._test_managedCodexAccountStoreURL = nil settings._test_activeManagedCodexAccount = nil try? FileManager.default.removeItem(at: managedStoreURL) } settings.refreshFrequency = .manual settings.codexCookieSource = .auto settings._test_managedCodexAccountStoreURL = managedStoreURL settings._test_activeManagedCodexAccount = managedAccount settings.codexActiveSource = .managedAccount(id: managedAccount.id) let store = self.makeUsageStore(settings: settings) store._setSnapshotForTesting( self.codexSnapshot(email: "managed@example.com", usedPercent: 20), provider: .codex) store.lastSourceLabels[.codex] = "openai-web" let staleCredits = self.credits(remaining: 20) store.credits = staleCredits store.lastCreditsSnapshot = staleCredits store.lastCreditsSnapshotAccountKey = "managed@example.com" store.lastCreditsSource = .dashboardWeb store.openAIDashboard = self.dashboard(email: "managed@example.com", creditsRemaining: 20, usedPercent: 20) store.lastOpenAIDashboardSnapshot = store.openAIDashboard OpenAIDashboardCacheStore.save(OpenAIDashboardCache( accountEmail: "managed@example.com", snapshot: self.dashboard(email: "managed@example.com", creditsRemaining: 20, usedPercent: 20))) await store.applyOpenAIDashboard( self.dashboard(email: "other@example.com", creditsRemaining: 9, usedPercent: 35), targetEmail: "managed@example.com") #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardSnapshot == nil) #expect(store.snapshots[.codex] == nil) #expect(store.credits == nil) #expect(store.lastCreditsSource == .none) #expect(OpenAIDashboardCacheStore.load() == nil) #expect(store.openAIDashboardRequiresLogin == true) #expect(store.lastOpenAIDashboardError?.contains("OpenAI dashboard signed in as other@example.com") == true) } @Test func `dashboard fail closed cleanup applies after same account managed token rotation`() async throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-dashboard-fail-closed-token-rotation-cleanup") let managedHome = FileManager.default.temporaryDirectory .appendingPathComponent(UUID().uuidString, isDirectory: true) defer { try? FileManager.default.removeItem(at: managedHome) } try Self.writeCodexAuthFile( homeURL: managedHome, email: "managed@example.com", plan: "pro", accountId: "acct-managed") let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path)) let managedAccount = ManagedCodexAccount( id: UUID(), email: "managed@example.com", providerAccountID: "acct-managed", workspaceLabel: "Managed", workspaceAccountID: "acct-managed", authFingerprint: oldFingerprint, managedHomePath: managedHome.path, createdAt: 1, updatedAt: 1, lastAuthenticatedAt: 1) let managedStoreURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount]) defer { settings._test_managedCodexAccountStoreURL = nil settings._test_activeManagedCodexAccount = nil try? FileManager.default.removeItem(at: managedStoreURL) } settings.refreshFrequency = .manual settings.codexCookieSource = .auto settings._test_managedCodexAccountStoreURL = managedStoreURL settings._test_activeManagedCodexAccount = managedAccount settings.codexActiveSource = .managedAccount(id: managedAccount.id) let store = self.makeUsageStore(settings: settings) let expectedGuard = store.freshCodexOpenAIWebRefreshGuard() #expect(expectedGuard.authFingerprint == oldFingerprint) store._setSnapshotForTesting( self.codexSnapshot(email: "managed@example.com", usedPercent: 20), provider: .codex) store.lastSourceLabels[.codex] = "openai-web" let staleCredits = self.credits(remaining: 20) store.credits = staleCredits store.lastCreditsSnapshot = staleCredits store.lastCreditsSnapshotAccountKey = "managed@example.com" store.lastCreditsSource = .dashboardWeb store.openAIDashboard = self.dashboard(email: "managed@example.com", creditsRemaining: 20, usedPercent: 20) store.lastOpenAIDashboardSnapshot = store.openAIDashboard OpenAIDashboardCacheStore.save(OpenAIDashboardCache( accountEmail: "managed@example.com", snapshot: self.dashboard(email: "managed@example.com", creditsRemaining: 20, usedPercent: 20))) try Self.writeCodexAuthFile( homeURL: managedHome, email: "managed@example.com", plan: "team", accountId: "acct-managed") let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path)) #expect(newFingerprint != oldFingerprint) let currentGuard = store.freshCodexOpenAIWebRefreshGuard() #expect(currentGuard.identity == expectedGuard.identity) #expect(currentGuard.accountKey == expectedGuard.accountKey) #expect(currentGuard.authFingerprint == newFingerprint) await store.applyOpenAIDashboard( self.dashboard(email: "other@example.com", creditsRemaining: 9, usedPercent: 35), targetEmail: "managed@example.com", expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardSnapshot == nil) #expect(store.snapshots[.codex] == nil) #expect(store.credits == nil) #expect(store.lastCreditsSource == .none) #expect(OpenAIDashboardCacheStore.load() == nil) #expect(store.openAIDashboardRequiresLogin == true) #expect(store.lastOpenAIDashboardError?.contains("OpenAI dashboard signed in as other@example.com") == true) } @Test func `dashboard fail closed cleanup applies after same live account email changes during token rotation`() async { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-dashboard-fail-closed-live-email-rotation-cleanup") settings.refreshFrequency = .manual settings.codexCookieSource = .auto settings.codexActiveSource = .liveSystem settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) defer { settings._test_liveSystemCodexAccount = nil } let store = self.makeUsageStore(settings: settings) let expectedGuard = store.freshCodexOpenAIWebRefreshGuard() #expect(expectedGuard.accountKey == "alpha@example.com") #expect(expectedGuard.authFingerprint == "old-token-material") store._setSnapshotForTesting( self.codexSnapshot(email: "alpha@example.com", usedPercent: 20), provider: .codex) store.lastSourceLabels[.codex] = "openai-web" let staleCredits = self.credits(remaining: 20) store.credits = staleCredits store.lastCreditsSnapshot = staleCredits store.lastCreditsSnapshotAccountKey = "alpha@example.com" store.lastCreditsSource = .dashboardWeb store.openAIDashboard = self.dashboard(email: "alpha@example.com", creditsRemaining: 20, usedPercent: 20) store.lastOpenAIDashboardSnapshot = store.openAIDashboard OpenAIDashboardCacheStore.save(OpenAIDashboardCache( accountEmail: "alpha@example.com", snapshot: self.dashboard(email: "alpha@example.com", creditsRemaining: 20, usedPercent: 20))) settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "beta@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let currentGuard = store.freshCodexOpenAIWebRefreshGuard() #expect(currentGuard.identity == expectedGuard.identity) #expect(currentGuard.accountKey == "beta@example.com") #expect(currentGuard.authFingerprint == "new-token-material") await store.applyOpenAIDashboard( self.dashboard(email: "alpha@example.com", creditsRemaining: 9, usedPercent: 35), targetEmail: "alpha@example.com", expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardSnapshot == nil) #expect(store.snapshots[.codex] == nil) #expect(store.credits == nil) #expect(store.lastCreditsSource == .none) #expect(OpenAIDashboardCacheStore.load() == nil) #expect(store.openAIDashboardRequiresLogin == true) #expect(store.lastOpenAIDashboardError?.contains("OpenAI dashboard signed in as alpha@example.com") == true) } }