Files
steipete--codexbar/Tests/CodexBarTests/CodexAccountAuthFingerprintApplyTests.swift
2026-07-13 12:22:33 +08:00

1500 lines
70 KiB
Swift

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)
let publicationGuard = store.freshCodexAccountScopedRefreshGuard()
store.lastCodexUsagePublicationGuard = publicationGuard
store.lastCodexAccountScopedRefreshGuard = publicationGuard
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,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let blocker = BlockingCodexFetchStrategy()
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
return try await blocker.awaitResult()
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-token-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
await blocker.waitUntilStarted()
try FileManagedCodexAccountStore(fileURL: storeURL).storeAccounts(ManagedCodexAccountSet(
version: FileManagedCodexAccountStore.currentVersion,
accounts: [updatedTarget, siblingAccount]))
await blocker.resume(with: .failure(TestRefreshError(message: "old managed token failure")))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
#expect(!store.codexAccountSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-token"
})
#expect(!snapshotStore.storedSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-token"
})
}
@Test
func `stacked visible refresh discards selected failure after managed auth file rotates`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-selected-managed-auth-file-failure")
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-121212121212"))
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-131313131313"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-auth-file-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-auth-file-sibling-\(UUID().uuidString)", isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-file-token@example.com",
plan: "Pro",
accountId: "acct-managed-file-token")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
let targetAccount = ManagedCodexAccount(
id: targetID,
email: "managed-file-token@example.com",
providerAccountID: "acct-managed-file-token",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-file-token",
authFingerprint: oldFingerprint,
managedHomePath: targetHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let siblingAccount = ManagedCodexAccount(
id: siblingID,
email: "managed-file-token-sibling@example.com",
providerAccountID: "acct-managed-file-token-sibling",
workspaceLabel: "Sibling Team",
workspaceAccountID: "acct-managed-file-token-sibling",
authFingerprint: "sibling-managed-file-token",
managedHomePath: siblingHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let blocker = BlockingCodexFetchStrategy()
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
return try await blocker.awaitResult()
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-file-token-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
await blocker.waitUntilStarted()
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-file-token@example.com",
plan: "Team",
accountId: "acct-managed-file-token")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .failure(TestRefreshError(message: "old managed auth file failure")))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
#expect(!store.codexAccountSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-file-token"
})
#expect(!snapshotStore.storedSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-file-token"
})
}
@Test
func `stacked visible refresh keeps selected failure when managed auth file rotated before start`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-selected-managed-auth-file-current-failure")
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-161616161616"))
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-171717171717"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-current-failure-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-current-sibling-\(UUID().uuidString)", isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-current-failure@example.com",
plan: "Pro",
accountId: "acct-managed-current-failure")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
let targetAccount = ManagedCodexAccount(
id: targetID,
email: "managed-current-failure@example.com",
providerAccountID: "acct-managed-current-failure",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-current-failure",
authFingerprint: oldFingerprint,
managedHomePath: targetHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let siblingAccount = ManagedCodexAccount(
id: siblingID,
email: "managed-current-sibling@example.com",
providerAccountID: "acct-managed-current-sibling",
workspaceLabel: "Sibling Team",
workspaceAccountID: "acct-managed-current-sibling",
authFingerprint: "sibling-managed-current",
managedHomePath: siblingHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-current-failure@example.com",
plan: "Team",
accountId: "acct-managed-current-failure")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
#expect(newFingerprint != oldFingerprint)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
throw TestRefreshError(message: "current managed auth file failure")
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-current-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
await store.refreshCodexVisibleAccountsForMenu()
#expect(store.errors[.codex] == "current managed auth file failure")
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
$0.account.workspaceAccountID == "acct-managed-current-failure"
})
#expect(targetSnapshot.error == "current managed auth file failure")
#expect(targetSnapshot.account.authFingerprint == newFingerprint)
let persistedTargetSnapshot = try #require(snapshotStore.storedSnapshots.first {
$0.account.workspaceAccountID == "acct-managed-current-failure"
})
#expect(persistedTargetSnapshot.error == "current managed auth file failure")
#expect(persistedTargetSnapshot.account.authFingerprint == newFingerprint)
}
@Test
func `stacked visible refresh discards selected success after managed auth file switches accounts`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-selected-managed-auth-file-success")
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-141414141414"))
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-151515151515"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-auth-success-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent(
"codex-visible-managed-auth-success-sibling-\(UUID().uuidString)",
isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-old-success@example.com",
plan: "Pro",
accountId: "acct-managed-old-success")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
let targetAccount = ManagedCodexAccount(
id: targetID,
email: "managed-old-success@example.com",
providerAccountID: "acct-managed-old-success",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-old-success",
authFingerprint: oldFingerprint,
managedHomePath: targetHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let siblingAccount = ManagedCodexAccount(
id: siblingID,
email: "managed-success-sibling@example.com",
providerAccountID: "acct-managed-success-sibling",
workspaceLabel: "Sibling Team",
workspaceAccountID: "acct-managed-success-sibling",
authFingerprint: "sibling-managed-success",
managedHomePath: siblingHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let blocker = BlockingCodexFetchStrategy()
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
return try await blocker.awaitResult()
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-success-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
await blocker.waitUntilStarted()
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-new-success@example.com",
plan: "Pro",
accountId: "acct-managed-new-success")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .success(UsageSnapshot(
primary: RateWindow(
usedPercent: 64,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-old-success@example.com",
accountOrganization: nil,
loginMethod: "Managed Team"))))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
#expect(!store.codexAccountSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-old-success"
})
#expect(!snapshotStore.storedSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-old-success"
})
}
@Test
func `stacked visible refresh keeps migrated managed account after token rotation`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-migrated-managed-token-rotation")
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-171717171717"))
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-181818181818"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-migrated-managed-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent(
"codex-visible-migrated-managed-sibling-\(UUID().uuidString)",
isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "migrated-managed@example.com",
plan: "Pro",
accountId: "acct-migrated-managed")
try Self.writeCodexAuthFile(
homeURL: siblingHome,
email: "migrated-sibling@example.com",
plan: "Pro",
accountId: "acct-migrated-sibling")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
let siblingFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: siblingHome.path))
let targetAccount = ManagedCodexAccount(
id: targetID,
email: "migrated-managed@example.com",
providerAccountID: "acct-migrated-managed",
workspaceLabel: "Managed Team",
authFingerprint: oldFingerprint,
managedHomePath: targetHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let siblingAccount = ManagedCodexAccount(
id: siblingID,
email: "migrated-sibling@example.com",
providerAccountID: "acct-migrated-sibling",
workspaceLabel: "Sibling Team",
authFingerprint: siblingFingerprint,
managedHomePath: siblingHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let blocker = BlockingCodexFetchStrategy()
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
return try await blocker.awaitResult()
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "migrated-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
await blocker.waitUntilStarted()
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "migrated-managed@example.com",
plan: "Team",
accountId: "acct-migrated-managed")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .success(UsageSnapshot(
primary: RateWindow(
usedPercent: 64,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "migrated-managed@example.com",
accountOrganization: nil,
loginMethod: "Managed Team"))))
await refreshTask.value
let selectedSnapshot = try #require(store.snapshots[.codex])
#expect(selectedSnapshot.primary?.usedPercent == 64)
let targetRow = try #require(store.codexAccountSnapshots.first {
$0.account.workspaceAccountID == "acct-migrated-managed"
})
#expect(targetRow.account.authFingerprint == newFingerprint)
#expect(targetRow.snapshot?.primary?.usedPercent == 64)
let persistedTarget = try #require(snapshotStore.storedSnapshots.first {
$0.account.workspaceAccountID == "acct-migrated-managed"
})
#expect(persistedTarget.account.authFingerprint == newFingerprint)
#expect(persistedTarget.snapshot?.primary?.usedPercent == 64)
}
@Test
func `stacked visible refresh discards selected success after managed auth file email changes`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-selected-managed-auth-email-success")
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-191919191919"))
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-202020202020"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-visible-managed-auth-email-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent(
"codex-visible-managed-auth-email-sibling-\(UUID().uuidString)",
isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-old-email@example.com",
plan: "Pro",
accountId: "acct-managed-email-same")
try Self.writeCodexAuthFile(
homeURL: siblingHome,
email: "managed-email-sibling@example.com",
plan: "Pro",
accountId: "acct-managed-email-sibling")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
let siblingFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: siblingHome.path))
let targetAccount = ManagedCodexAccount(
id: targetID,
email: "managed-old-email@example.com",
providerAccountID: "acct-managed-email-same",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-email-same",
authFingerprint: oldFingerprint,
managedHomePath: targetHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let siblingAccount = ManagedCodexAccount(
id: siblingID,
email: "managed-email-sibling@example.com",
providerAccountID: "acct-managed-email-sibling",
workspaceLabel: "Sibling Team",
workspaceAccountID: "acct-managed-email-sibling",
authFingerprint: siblingFingerprint,
managedHomePath: siblingHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [targetAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
codexAccountUsageSnapshotStore: snapshotStore,
startupBehavior: .testing)
let blocker = BlockingCodexFetchStrategy()
let targetHomePath = targetHome.path
let now = Date()
self.installContextualCodexProvider(on: store) { context in
if context.env["CODEX_HOME"] == targetHomePath {
return try await blocker.awaitResult()
}
return UsageSnapshot(
primary: RateWindow(
usedPercent: 9,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-email-sibling@example.com",
accountOrganization: nil,
loginMethod: "Sibling Team"))
}
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
await blocker.waitUntilStarted()
try Self.writeCodexAuthFile(
homeURL: targetHome,
email: "managed-new-email@example.com",
plan: "Pro",
accountId: "acct-managed-email-same")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: targetHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .success(UsageSnapshot(
primary: RateWindow(
usedPercent: 64,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-old-email@example.com",
accountOrganization: nil,
loginMethod: "Managed Team"))))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
#expect(!store.codexAccountSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-email-same"
})
#expect(!snapshotStore.storedSnapshots.contains {
$0.account.workspaceAccountID == "acct-managed-email-same"
})
}
@Test
func `managed failure guard reads current auth file fingerprint`() throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-managed-auth-file-fingerprint")
settings.refreshFrequency = .manual
let accountID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-555555555555"))
let managedHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-managed-auth-file-\(UUID().uuidString)", isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "managed-auth@example.com",
plan: "Pro",
accountId: "acct-managed-auth")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
let managedAccount = ManagedCodexAccount(
id: accountID,
email: "managed-auth@example.com",
providerAccountID: "acct-managed-auth",
workspaceLabel: "Managed Auth",
workspaceAccountID: "acct-managed-auth",
authFingerprint: oldFingerprint,
managedHomePath: managedHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: managedHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: accountID)
let store = self.makeUsageStore(settings: settings)
let expectedGuard = store.freshCodexAccountScopedRefreshGuard()
#expect(expectedGuard.authFingerprint == oldFingerprint)
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "managed-auth@example.com",
plan: "Team",
accountId: "acct-managed-auth")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
#expect(newFingerprint != oldFingerprint)
#expect(store.freshCodexAccountScopedRefreshGuard().authFingerprint == newFingerprint)
#expect(!store.shouldApplyCodexScopedFailure(expectedGuard: expectedGuard))
#expect(!store.shouldApplyCodexScopedNonUsageFailure(expectedGuard: expectedGuard))
try FileManager.default.removeItem(at: managedHome)
#expect(store.freshCodexAccountScopedRefreshGuard().authFingerprint == nil)
let staleUsage = UsageSnapshot(
primary: RateWindow(
usedPercent: 41,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: Date(),
identity: ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "managed-auth@example.com",
accountOrganization: nil,
loginMethod: "Managed Auth"))
#expect(!store.shouldApplyCodexUsageResult(expectedGuard: expectedGuard, usage: staleUsage))
#expect(!store.shouldApplyCodexScopedFailure(expectedGuard: expectedGuard))
#expect(!store.shouldApplyCodexScopedNonUsageFailure(expectedGuard: expectedGuard))
}
@Test
func `stale auth fingerprint cache at refresh start keeps current codex usage success`() async {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-stale-start-cache-current-auth")
defer {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil
settings._test_liveSystemCodexAccount = nil
}
settings.refreshFrequency = .manual
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
email: "alpha@example.com",
authFingerprint: "old-email-only-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .emailOnly(normalizedEmail: "alpha@example.com"))
let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
email: "alpha@example.com",
authFingerprint: "new-email-only-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .emailOnly(normalizedEmail: "alpha@example.com"))
settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot(
activeSource: .liveSystem,
loadedAt: Date(),
snapshot: staleReconciliationSnapshot)
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()
await blocker.resume(with: .success(self.codexSnapshot(email: "alpha@example.com", usedPercent: 33)))
await refreshTask.value
#expect(store.snapshots[.codex]?.primary?.usedPercent == 33)
#expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-email-only-auth")
#expect(store.errors[.codex] == nil)
}
@Test
func `same provider account live email change discards stale codex usage success`() async {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-provider-email-change")
defer {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil
settings._test_liveSystemCodexAccount = nil
}
settings.refreshFrequency = .manual
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
email: "old@example.com",
authFingerprint: "old-provider-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .providerAccount(id: "acct-shared"))
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: "new@example.com",
authFingerprint: "new-provider-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .providerAccount(id: "acct-shared"))
settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot(
activeSource: .liveSystem,
loadedAt: Date(),
snapshot: staleReconciliationSnapshot)
await blocker.resume(with: .success(self.codexSnapshot(email: "old@example.com", usedPercent: 25)))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
}
@Test
func `same provider account managed email change discards stale codex usage success`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-managed-provider-email-change")
settings.refreshFrequency = .manual
let accountID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-161616161616"))
let managedHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-managed-provider-email-\(UUID().uuidString)", isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "old-managed@example.com",
plan: "Pro",
accountId: "acct-managed-shared")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
let managedAccount = ManagedCodexAccount(
id: accountID,
email: "old-managed@example.com",
providerAccountID: "acct-managed-shared",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-shared",
authFingerprint: oldFingerprint,
managedHomePath: managedHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: managedHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: accountID)
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()
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "new-managed@example.com",
plan: "Pro",
accountId: "acct-managed-shared")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .success(self.codexSnapshot(email: "old-managed@example.com", usedPercent: 25)))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
}
@Test
func `managed codex usage success without email applies when auth guard matches`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-managed-usage-without-email")
settings.refreshFrequency = .manual
let accountID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-171717171717"))
let managedHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-managed-usage-without-email-\(UUID().uuidString)", isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "email-less-managed@example.com",
plan: "Pro",
accountId: "acct-managed-email-less")
let authFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
let managedAccount = ManagedCodexAccount(
id: accountID,
email: "email-less-managed@example.com",
providerAccountID: "acct-managed-email-less",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-email-less",
authFingerprint: authFingerprint,
managedHomePath: managedHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: managedHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: accountID)
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()
await blocker.resume(with: .success(UsageSnapshot(
primary: RateWindow(
usedPercent: 25,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: Date())))
await refreshTask.value
#expect(store.snapshots[.codex]?.primary?.usedPercent == 25)
#expect(store.snapshots[.codex]?.accountEmail(for: .codex) == "email-less-managed@example.com")
#expect(store.errors[.codex] == nil)
#expect(store.lastCodexAccountScopedRefreshGuard?.accountKey == "email-less-managed@example.com")
#expect(store.codexAccountSnapshots.first?.account.email == "email-less-managed@example.com")
#expect(store.codexAccountSnapshots.first?.snapshot?.accountEmail(for: .codex) ==
"email-less-managed@example.com")
}
@Test
func `same provider account managed email change discards stale codex usage success without email`() async throws {
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-managed-provider-email-change-without-email")
settings.refreshFrequency = .manual
let accountID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-181818181818"))
let managedHome = FileManager.default.temporaryDirectory
.appendingPathComponent(
"codex-managed-provider-email-without-email-\(UUID().uuidString)",
isDirectory: true)
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "old-managed-empty@example.com",
plan: "Pro",
accountId: "acct-managed-shared-empty")
let oldFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
let managedAccount = ManagedCodexAccount(
id: accountID,
email: "old-managed-empty@example.com",
providerAccountID: "acct-managed-shared-empty",
workspaceLabel: "Managed Team",
workspaceAccountID: "acct-managed-shared-empty",
authFingerprint: oldFingerprint,
managedHomePath: managedHome.path,
createdAt: 1,
updatedAt: 2,
lastAuthenticatedAt: 2)
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: managedHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: accountID)
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()
try Self.writeCodexAuthFile(
homeURL: managedHome,
email: "new-managed-empty@example.com",
plan: "Pro",
accountId: "acct-managed-shared-empty")
let newFingerprint = try #require(CodexAuthFingerprint.fingerprint(homePath: managedHome.path))
#expect(newFingerprint != oldFingerprint)
await blocker.resume(with: .success(UsageSnapshot(
primary: RateWindow(
usedPercent: 25,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: Date())))
await refreshTask.value
#expect(store.snapshots[.codex] == nil)
#expect(store.errors[.codex] == nil)
}
@Test
func `same email email-only auth fingerprint switch discards stale codex usage success`() async {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60
let settings = self.makeSettingsStore(
suite: "CodexAccountScopedRefreshTests-email-only-fingerprint-switch")
defer {
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil
settings._test_liveSystemCodexAccount = nil
}
settings.refreshFrequency = .manual
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
email: "alpha@example.com",
authFingerprint: "old-email-only-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .emailOnly(normalizedEmail: "alpha@example.com"))
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-email-only-auth",
codexHomePath: "/Users/test/.codex",
observedAt: Date(),
identity: .emailOnly(normalizedEmail: "alpha@example.com"))
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] == nil)
#expect(store.errors[.codex] == nil)
}
}