import CodexBarCoreimport Foundationimport Testing@testable import CodexBar @MainActorextension CodexAccountScopedRefreshTests { @Test func `same account token refresh fingerprint change keeps codex usage success`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-fingerprint-change") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot let store = self.makeUsageStore(settings: settings) let blocker = BlockingCodexFetchStrategy() self.installBlockingCodexProvider(on: store, blocker: blocker) let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) } await blocker.waitUntilStarted() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot( activeSource: .liveSystem, loadedAt: Date(), snapshot: staleReconciliationSnapshot) await blocker.resume(with: .success(self.codexSnapshot(email: "alpha@example.com", usedPercent: 25))) await refreshTask.value #expect(store.snapshots[.codex]?.primary?.usedPercent == 25) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") #expect(store.errors[.codex] == nil) } @Test func `same account token refresh fingerprint change keeps reset backfill`() async { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-reset-backfill") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) let resetsAt = Date().addingTimeInterval(45 * 60) store.lastCodexAccountScopedRefreshGuard = store.freshCodexAccountScopedRefreshGuard() store.lastKnownResetSnapshots[.codex] = UsageSnapshot( primary: RateWindow( usedPercent: 10, windowMinutes: 300, resetsAt: resetsAt, resetDescription: "resets soon"), secondary: nil, updatedAt: Date(), identity: ProviderIdentitySnapshot( providerID: .codex, accountEmail: "alpha@example.com", accountOrganization: nil, loginMethod: "Pro")) settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) self.installImmediateCodexProvider( on: store, snapshot: self.codexSnapshot(email: "alpha@example.com", usedPercent: 25)) await store.refreshProvider(.codex, allowDisabled: true) #expect(store.snapshots[.codex]?.primary?.usedPercent == 25) #expect(store.snapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastKnownResetSnapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") } @Test func `same account token refresh fingerprint change keeps scoped state during prepare`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-prepare") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) let resetsAt = Date().addingTimeInterval(45 * 60) let cached = UsageSnapshot( primary: RateWindow( usedPercent: 10, windowMinutes: 300, resetsAt: resetsAt, resetDescription: "resets soon"), secondary: nil, updatedAt: Date(), identity: ProviderIdentitySnapshot( providerID: .codex, accountEmail: "alpha@example.com", accountOrganization: nil, loginMethod: "Pro")) store.snapshots[.codex] = cached store.lastKnownResetSnapshots[.codex] = cached store.credits = self.credits(remaining: 42) store.lastCodexAccountScopedRefreshGuard = store.freshCodexAccountScopedRefreshGuard() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let invalidated = store.prepareCodexAccountScopedRefreshIfNeeded() #expect(!invalidated) #expect(store.snapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastKnownResetSnapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.credits?.remaining == 42) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") } @Test func `usage success applies when auth fingerprint appears after refresh starts`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-auth-fingerprint-appears") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: nil, codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .emailOnly(normalizedEmail: "alpha@example.com")) let store = self.makeUsageStore(settings: settings) let expectedGuard = store.freshCodexAccountScopedRefreshGuard() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .emailOnly(normalizedEmail: "alpha@example.com")) #expect(store.shouldApplyCodexUsageResult( expectedGuard: expectedGuard, usage: self.codexSnapshot(email: "alpha@example.com", usedPercent: 25))) } @Test func `same account token refresh fingerprint change discards codex usage failure`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-fingerprint-failure") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot let store = self.makeUsageStore(settings: settings) let blocker = BlockingCodexFetchStrategy() self.installBlockingCodexProvider(on: store, blocker: blocker) let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) } await blocker.waitUntilStarted() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot( activeSource: .liveSystem, loadedAt: Date(), snapshot: staleReconciliationSnapshot) await blocker.resume(with: .failure(TestRefreshError(message: "old token failure"))) await refreshTask.value #expect(store.snapshots[.codex] == nil) #expect(store.errors[.codex] == nil) } @Test func `same account token refresh fingerprint change keeps codex credits success`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-credits-success") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) store._test_codexCreditsLoaderOverride = { settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) return CreditsSnapshot(remaining: 42, events: [], updatedAt: Date()) } defer { store._test_codexCreditsLoaderOverride = nil } await store.refreshCreditsIfNeeded() #expect(store.credits?.remaining == 42) #expect(store.lastCreditsSnapshotAccountKey == "alpha@example.com") #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") #expect(store.lastCreditsError == nil) } @Test func `credits refresh key separates same account auth fingerprints`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-credits-key-auth-fingerprint") let store = self.makeUsageStore(settings: settings) let oldGuard = CodexAccountScopedRefreshGuard( source: .liveSystem, identity: .providerAccount(id: "acct-alpha"), accountKey: "alpha@example.com", authFingerprint: "old-token-material") let newGuard = CodexAccountScopedRefreshGuard( source: .liveSystem, identity: .providerAccount(id: "acct-alpha"), accountKey: "alpha@example.com", authFingerprint: "new-token-material") #expect(store.codexCreditsRefreshKey(expectedGuard: oldGuard) != store.codexCreditsRefreshKey(expectedGuard: newGuard)) } @Test func `same account token refresh fingerprint change keeps dashboard success`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-success") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) return self.dashboard(email: "alpha@example.com", creditsRemaining: 64, usedPercent: 27) } defer { store._test_openAIDashboardLoaderOverride = nil } await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: expectedGuard) #expect(store.openAIDashboard?.creditsRemaining == 64) #expect(store.openAIDashboard?.signedInEmail == "alpha@example.com") #expect(store.lastOpenAIDashboardError == nil) #expect(store.openAIDashboardRequiresLogin == false) } @Test func `dashboard refresh key separates same account auth fingerprints`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-dashboard-key-auth-fingerprint") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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 blocker = BlockingManagedOpenAIDashboardLoader() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in try await blocker.awaitResult() } defer { store._test_openAIDashboardLoaderOverride = nil } let oldGuard = store.freshCodexOpenAIWebRefreshGuard() let oldRefreshTask = Task { await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: oldGuard) } await blocker.waitUntilStarted(count: 1) settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let newGuard = store.freshCodexOpenAIWebRefreshGuard() let newRefreshTask = Task { await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: newGuard) } let didStartFreshRefresh = await blocker.waitUntilStartedWithin(count: 2) #expect(didStartFreshRefresh) guard didStartFreshRefresh else { await blocker.resumeNext(with: .failure(TestRefreshError(message: "stale dashboard failure"))) await oldRefreshTask.value await newRefreshTask.value return } await blocker.resumeNext(with: .failure(TestRefreshError(message: "old dashboard failure"))) await blocker.resumeNext(with: .success(self.dashboard( email: "alpha@example.com", creditsRemaining: 64, usedPercent: 27))) await oldRefreshTask.value await newRefreshTask.value #expect(store.openAIDashboard?.creditsRemaining == 64) #expect(store.lastOpenAIDashboardError == nil) } @Test func `same account token refresh fingerprint change discards dashboard failure`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-failure") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) throw TestRefreshError(message: "old dashboard failure") } defer { store._test_openAIDashboardLoaderOverride = nil } await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardError == nil) #expect(store.openAIDashboardRequiresLogin == false) } @Test func `same account token refresh fingerprint change applies dashboard policy failure`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-policy-failure") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) await store.applyOpenAIDashboard( self.dashboard(email: "other@example.com", creditsRemaining: 64, usedPercent: 27), targetEmail: "alpha@example.com", expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardError?.contains("OpenAI dashboard signed in as other@example.com") == true) #expect(store.openAIDashboardRequiresLogin == true) } @Test func `stacked visible refresh discards selected failure after managed token fingerprint rotates`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-selected-managed-token-failure") settings.refreshFrequency = .manual settings.multiAccountMenuLayout = .stacked let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-444444444444")) let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-333333333333")) let targetHome = FileManager.default.temporaryDirectory .appendingPathComponent("codex-visible-managed-token-\(UUID().uuidString)", isDirectory: true) let siblingHome = FileManager.default.temporaryDirectory .appendingPathComponent("codex-visible-managed-token-sibling-\(UUID().uuidString)", isDirectory: true) try FileManager.default.createDirectory(at: targetHome, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: siblingHome, withIntermediateDirectories: true) let targetAccount = ManagedCodexAccount( id: targetID, email: "managed-token@example.com", providerAccountID: "acct-managed-token", workspaceLabel: "Managed Team", workspaceAccountID: "acct-managed-token", authFingerprint: "old-managed-token", managedHomePath: targetHome.path, createdAt: 1, updatedAt: 2, lastAuthenticatedAt: 2) let updatedTarget = ManagedCodexAccount( id: targetID, email: "managed-token@example.com", providerAccountID: "acct-managed-token", workspaceLabel: "Managed Team", workspaceAccountID: "acct-managed-token", authFingerprint: "new-managed-token", managedHomePath: targetHome.path, createdAt: 1, updatedAt: 3, lastAuthenticatedAt: 3) let siblingAccount = ManagedCodexAccount( id: siblingID, email: "managed-token-sibling@example.com", providerAccountID: "acct-managed-token-sibling", workspaceLabel: "Sibling Team", workspaceAccountID: "acct-managed-token-sibling", authFingerprint: "sibling-managed-token", managedHomePath: siblingHome.path, createdAt: 1, updatedAt: 2,Lines 1–500 of 1492. Load more
import CodexBarCore import Foundation import Testing @testable import CodexBar @MainActor extension CodexAccountScopedRefreshTests { @Test func `same account token refresh fingerprint change keeps codex usage success`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-fingerprint-change") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot let store = self.makeUsageStore(settings: settings) let blocker = BlockingCodexFetchStrategy() self.installBlockingCodexProvider(on: store, blocker: blocker) let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) } await blocker.waitUntilStarted() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot( activeSource: .liveSystem, loadedAt: Date(), snapshot: staleReconciliationSnapshot) await blocker.resume(with: .success(self.codexSnapshot(email: "alpha@example.com", usedPercent: 25))) await refreshTask.value #expect(store.snapshots[.codex]?.primary?.usedPercent == 25) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") #expect(store.errors[.codex] == nil) } @Test func `same account token refresh fingerprint change keeps reset backfill`() async { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-reset-backfill") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) let resetsAt = Date().addingTimeInterval(45 * 60) store.lastCodexAccountScopedRefreshGuard = store.freshCodexAccountScopedRefreshGuard() store.lastKnownResetSnapshots[.codex] = UsageSnapshot( primary: RateWindow( usedPercent: 10, windowMinutes: 300, resetsAt: resetsAt, resetDescription: "resets soon"), secondary: nil, updatedAt: Date(), identity: ProviderIdentitySnapshot( providerID: .codex, accountEmail: "alpha@example.com", accountOrganization: nil, loginMethod: "Pro")) settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) self.installImmediateCodexProvider( on: store, snapshot: self.codexSnapshot(email: "alpha@example.com", usedPercent: 25)) await store.refreshProvider(.codex, allowDisabled: true) #expect(store.snapshots[.codex]?.primary?.usedPercent == 25) #expect(store.snapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastKnownResetSnapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") } @Test func `same account token refresh fingerprint change keeps scoped state during prepare`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-prepare") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) let resetsAt = Date().addingTimeInterval(45 * 60) let cached = UsageSnapshot( primary: RateWindow( usedPercent: 10, windowMinutes: 300, resetsAt: resetsAt, resetDescription: "resets soon"), secondary: nil, updatedAt: Date(), identity: ProviderIdentitySnapshot( providerID: .codex, accountEmail: "alpha@example.com", accountOrganization: nil, loginMethod: "Pro")) store.snapshots[.codex] = cached store.lastKnownResetSnapshots[.codex] = cached store.credits = self.credits(remaining: 42) store.lastCodexAccountScopedRefreshGuard = store.freshCodexAccountScopedRefreshGuard() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let invalidated = store.prepareCodexAccountScopedRefreshIfNeeded() #expect(!invalidated) #expect(store.snapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.lastKnownResetSnapshots[.codex]?.primary?.resetsAt == resetsAt) #expect(store.credits?.remaining == 42) #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") } @Test func `usage success applies when auth fingerprint appears after refresh starts`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-auth-fingerprint-appears") defer { settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: nil, codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .emailOnly(normalizedEmail: "alpha@example.com")) let store = self.makeUsageStore(settings: settings) let expectedGuard = store.freshCodexAccountScopedRefreshGuard() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .emailOnly(normalizedEmail: "alpha@example.com")) #expect(store.shouldApplyCodexUsageResult( expectedGuard: expectedGuard, usage: self.codexSnapshot(email: "alpha@example.com", usedPercent: 25))) } @Test func `same account token refresh fingerprint change discards codex usage failure`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-fingerprint-failure") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot let store = self.makeUsageStore(settings: settings) let blocker = BlockingCodexFetchStrategy() self.installBlockingCodexProvider(on: store, blocker: blocker) let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) } await blocker.waitUntilStarted() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot( activeSource: .liveSystem, loadedAt: Date(), snapshot: staleReconciliationSnapshot) await blocker.resume(with: .failure(TestRefreshError(message: "old token failure"))) await refreshTask.value #expect(store.snapshots[.codex] == nil) #expect(store.errors[.codex] == nil) } @Test func `same account token refresh fingerprint change keeps codex credits success`() async { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60 let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-credits-success") defer { SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil settings._test_liveSystemCodexAccount = nil } settings.refreshFrequency = .manual settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "old-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let store = self.makeUsageStore(settings: settings) store._test_codexCreditsLoaderOverride = { settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) return CreditsSnapshot(remaining: 42, events: [], updatedAt: Date()) } defer { store._test_codexCreditsLoaderOverride = nil } await store.refreshCreditsIfNeeded() #expect(store.credits?.remaining == 42) #expect(store.lastCreditsSnapshotAccountKey == "alpha@example.com") #expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-token-material") #expect(store.lastCreditsError == nil) } @Test func `credits refresh key separates same account auth fingerprints`() { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-credits-key-auth-fingerprint") let store = self.makeUsageStore(settings: settings) let oldGuard = CodexAccountScopedRefreshGuard( source: .liveSystem, identity: .providerAccount(id: "acct-alpha"), accountKey: "alpha@example.com", authFingerprint: "old-token-material") let newGuard = CodexAccountScopedRefreshGuard( source: .liveSystem, identity: .providerAccount(id: "acct-alpha"), accountKey: "alpha@example.com", authFingerprint: "new-token-material") #expect(store.codexCreditsRefreshKey(expectedGuard: oldGuard) != store.codexCreditsRefreshKey(expectedGuard: newGuard)) } @Test func `same account token refresh fingerprint change keeps dashboard success`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-success") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) return self.dashboard(email: "alpha@example.com", creditsRemaining: 64, usedPercent: 27) } defer { store._test_openAIDashboardLoaderOverride = nil } await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: expectedGuard) #expect(store.openAIDashboard?.creditsRemaining == 64) #expect(store.openAIDashboard?.signedInEmail == "alpha@example.com") #expect(store.lastOpenAIDashboardError == nil) #expect(store.openAIDashboardRequiresLogin == false) } @Test func `dashboard refresh key separates same account auth fingerprints`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-dashboard-key-auth-fingerprint") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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 blocker = BlockingManagedOpenAIDashboardLoader() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in try await blocker.awaitResult() } defer { store._test_openAIDashboardLoaderOverride = nil } let oldGuard = store.freshCodexOpenAIWebRefreshGuard() let oldRefreshTask = Task { await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: oldGuard) } await blocker.waitUntilStarted(count: 1) settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) let newGuard = store.freshCodexOpenAIWebRefreshGuard() let newRefreshTask = Task { await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: newGuard) } let didStartFreshRefresh = await blocker.waitUntilStartedWithin(count: 2) #expect(didStartFreshRefresh) guard didStartFreshRefresh else { await blocker.resumeNext(with: .failure(TestRefreshError(message: "stale dashboard failure"))) await oldRefreshTask.value await newRefreshTask.value return } await blocker.resumeNext(with: .failure(TestRefreshError(message: "old dashboard failure"))) await blocker.resumeNext(with: .success(self.dashboard( email: "alpha@example.com", creditsRemaining: 64, usedPercent: 27))) await oldRefreshTask.value await newRefreshTask.value #expect(store.openAIDashboard?.creditsRemaining == 64) #expect(store.lastOpenAIDashboardError == nil) } @Test func `same account token refresh fingerprint change discards dashboard failure`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-failure") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() store._test_openAIDashboardLoaderOverride = { _, _, _, _ in settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) throw TestRefreshError(message: "old dashboard failure") } defer { store._test_openAIDashboardLoaderOverride = nil } await store.refreshOpenAIDashboardIfNeeded(force: true, expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardError == nil) #expect(store.openAIDashboardRequiresLogin == false) } @Test func `same account token refresh fingerprint change applies dashboard policy failure`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-token-refresh-dashboard-policy-failure") let codexMetadata = try #require(ProviderDescriptorRegistry.metadata[.codex]) settings.setProviderEnabled(provider: .codex, metadata: codexMetadata, enabled: true) settings.refreshFrequency = .manual settings.openAIWebAccessEnabled = true settings.codexCookieSource = .auto 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() settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount( email: "alpha@example.com", authFingerprint: "new-token-material", codexHomePath: "/Users/test/.codex", observedAt: Date(), identity: .providerAccount(id: "acct-alpha")) await store.applyOpenAIDashboard( self.dashboard(email: "other@example.com", creditsRemaining: 64, usedPercent: 27), targetEmail: "alpha@example.com", expectedGuard: expectedGuard) #expect(store.openAIDashboard == nil) #expect(store.lastOpenAIDashboardError?.contains("OpenAI dashboard signed in as other@example.com") == true) #expect(store.openAIDashboardRequiresLogin == true) } @Test func `stacked visible refresh discards selected failure after managed token fingerprint rotates`() async throws { let settings = self.makeSettingsStore( suite: "CodexAccountScopedRefreshTests-selected-managed-token-failure") settings.refreshFrequency = .manual settings.multiAccountMenuLayout = .stacked let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-444444444444")) let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-333333333333")) let targetHome = FileManager.default.temporaryDirectory .appendingPathComponent("codex-visible-managed-token-\(UUID().uuidString)", isDirectory: true) let siblingHome = FileManager.default.temporaryDirectory .appendingPathComponent("codex-visible-managed-token-sibling-\(UUID().uuidString)", isDirectory: true) try FileManager.default.createDirectory(at: targetHome, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: siblingHome, withIntermediateDirectories: true) let targetAccount = ManagedCodexAccount( id: targetID, email: "managed-token@example.com", providerAccountID: "acct-managed-token", workspaceLabel: "Managed Team", workspaceAccountID: "acct-managed-token", authFingerprint: "old-managed-token", managedHomePath: targetHome.path, createdAt: 1, updatedAt: 2, lastAuthenticatedAt: 2) let updatedTarget = ManagedCodexAccount( id: targetID, email: "managed-token@example.com", providerAccountID: "acct-managed-token", workspaceLabel: "Managed Team", workspaceAccountID: "acct-managed-token", authFingerprint: "new-managed-token", managedHomePath: targetHome.path, createdAt: 1, updatedAt: 3, lastAuthenticatedAt: 3) let siblingAccount = ManagedCodexAccount( id: siblingID, email: "managed-token-sibling@example.com", providerAccountID: "acct-managed-token-sibling", workspaceLabel: "Sibling Team", workspaceAccountID: "acct-managed-token-sibling", authFingerprint: "sibling-managed-token", managedHomePath: siblingHome.path, createdAt: 1, updatedAt: 2,