1561 lines
75 KiB
Swift
1561 lines
75 KiB
Swift
import CodexBarCore
|
|
import Foundation
|
|
import Testing
|
|
@testable import CodexBar
|
|
|
|
@MainActor
|
|
extension CodexAccountScopedRefreshTests {
|
|
@Test
|
|
func `provider only history never backfills account quota publication`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-222222222222"))
|
|
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-333333333333"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-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: "target@example.com",
|
|
providerAccountID: "acct-target",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-target",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "sibling@example.com",
|
|
providerAccountID: "acct-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-sibling",
|
|
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 now = Date()
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
let isTarget = context.env["CODEX_HOME"] == targetHome.path
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: isTarget ? 1 : 22,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
let targetHistoryKey = try #require(CodexHistoryOwnership.canonicalKey(for: .providerAccount(
|
|
id: "acct-target")))
|
|
let sessionReset = now.addingTimeInterval(4 * 60 * 60)
|
|
let weeklyReset = now.addingTimeInterval(4 * 24 * 60 * 60)
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
targetHistoryKey: [
|
|
planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: now.addingTimeInterval(-60), usedPercent: 1, resetsAt: sessionReset),
|
|
]),
|
|
planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(at: now.addingTimeInterval(-60), usedPercent: 13, resetsAt: weeklyReset),
|
|
]),
|
|
],
|
|
])
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-target"
|
|
}?.snapshot)
|
|
#expect(targetSnapshot.primary?.usedPercent == 1)
|
|
#expect(targetSnapshot.primary?.windowMinutes == 0)
|
|
#expect(targetSnapshot.primary?.resetsAt == nil)
|
|
#expect(targetSnapshot.secondary == nil)
|
|
|
|
let siblingSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-sibling"
|
|
}?.snapshot)
|
|
#expect(siblingSnapshot.primary?.windowMinutes == 0)
|
|
#expect(siblingSnapshot.primary?.resetsAt == nil)
|
|
#expect(siblingSnapshot.secondary == nil)
|
|
|
|
let persistedTarget = try #require(snapshotStore.storedSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-target"
|
|
}?.snapshot)
|
|
#expect(persistedTarget.primary?.resetsAt == nil)
|
|
#expect(persistedTarget.secondary == nil)
|
|
#expect(store.snapshots[.codex]?.primary?.resetsAt == nil)
|
|
#expect(store.snapshots[.codex]?.secondary == nil)
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[targetHistoryKey]?.count == 2)
|
|
}
|
|
|
|
@Test
|
|
func `materializes single visible codex account email history into provider account history`() throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-single-account-materialize")
|
|
let store = self.makeUsageStore(settings: settings)
|
|
let visibleAccount = CodexVisibleAccount(
|
|
id: "materialize@example.com",
|
|
email: "materialize@example.com",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-materialize",
|
|
storedAccountID: nil,
|
|
selectionSource: .managedAccount(id: UUID()),
|
|
isActive: true,
|
|
isLive: false,
|
|
canReauthenticate: true,
|
|
canRemove: true)
|
|
let providerHistoryKey = try #require(CodexHistoryOwnership.canonicalKey(for: .providerAccount(
|
|
id: "acct-materialize")))
|
|
let emailHistoryKey = CodexHistoryOwnership.canonicalEmailHashKey(for: "materialize@example.com")
|
|
let legacyEmailHistoryKey = UsageStore._codexLegacyPlanUtilizationEmailHashKeyForTesting(
|
|
normalizedEmail: "materialize@example.com")
|
|
let session = planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: Date(timeIntervalSince1970: 1_800_000_000), usedPercent: 1),
|
|
])
|
|
let weekly = planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(at: Date(timeIntervalSince1970: 1_800_086_400), usedPercent: 13),
|
|
])
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
emailHistoryKey: [session],
|
|
legacyEmailHistoryKey: [weekly],
|
|
])
|
|
|
|
let histories = store.codexPlanUtilizationHistories(forVisibleAccount: visibleAccount)
|
|
|
|
#expect(histories == [session, weekly])
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[providerHistoryKey] == [session, weekly])
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[emailHistoryKey] == nil)
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[legacyEmailHistoryKey] == nil)
|
|
}
|
|
|
|
@Test
|
|
func `materializes provider account email history when sibling visible account uses another email`() throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-different-email-materialize")
|
|
settings.multiAccountMenuLayout = .stacked
|
|
let targetID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-121212121212"))
|
|
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-343434343434"))
|
|
let targetAccount = ManagedCodexAccount(
|
|
id: targetID,
|
|
email: "materialize-stack@example.com",
|
|
providerAccountID: "acct-materialize-stack",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-materialize-stack",
|
|
managedHomePath: "/tmp/materialize-stack-target",
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "other-stack@example.com",
|
|
providerAccountID: "acct-materialize-other",
|
|
workspaceLabel: "Other Team",
|
|
workspaceAccountID: "acct-materialize-other",
|
|
managedHomePath: "/tmp/materialize-stack-other",
|
|
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)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .managedAccount(id: targetID)
|
|
let store = self.makeUsageStore(settings: settings)
|
|
let visibleAccount = try #require(settings.codexVisibleAccountProjection.visibleAccounts.first {
|
|
$0.workspaceAccountID == "acct-materialize-stack"
|
|
})
|
|
let providerHistoryKey = try #require(CodexHistoryOwnership.canonicalKey(for: .providerAccount(
|
|
id: "acct-materialize-stack")))
|
|
let emailHistoryKey = CodexHistoryOwnership.canonicalEmailHashKey(for: "materialize-stack@example.com")
|
|
let legacyEmailHistoryKey = UsageStore._codexLegacyPlanUtilizationEmailHashKeyForTesting(
|
|
normalizedEmail: "materialize-stack@example.com")
|
|
let session = planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: Date(timeIntervalSince1970: 1_800_000_000), usedPercent: 1),
|
|
])
|
|
let weekly = planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(at: Date(timeIntervalSince1970: 1_800_086_400), usedPercent: 13),
|
|
])
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
emailHistoryKey: [session],
|
|
legacyEmailHistoryKey: [weekly],
|
|
])
|
|
|
|
let histories = store.codexPlanUtilizationHistories(forVisibleAccount: visibleAccount)
|
|
|
|
#expect(histories == [session, weekly])
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[providerHistoryKey] == [session, weekly])
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[emailHistoryKey] == nil)
|
|
#expect(store.planUtilizationHistory[.codex]?.accounts[legacyEmailHistoryKey] == nil)
|
|
}
|
|
|
|
@Test
|
|
func `selected codex refresh keeps ambiguous same email history out of provider account`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-selected-ambiguous-history")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "CCCCCCCC-DDDD-EEEE-FFFF-111111111111"))
|
|
let siblingID = try #require(UUID(uuidString: "CCCCCCCC-DDDD-EEEE-FFFF-222222222222"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-selected-history-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-selected-history-sibling-\(UUID().uuidString)", isDirectory: true)
|
|
try Self.writeCodexAuthFile(
|
|
homeURL: targetHome,
|
|
email: "selected-shared@example.com",
|
|
plan: "pro",
|
|
accountId: "acct-selected-target")
|
|
try Self.writeCodexAuthFile(
|
|
homeURL: siblingHome,
|
|
email: "selected-shared@example.com",
|
|
plan: "pro",
|
|
accountId: "acct-selected-sibling")
|
|
let targetAccount = ManagedCodexAccount(
|
|
id: targetID,
|
|
email: "selected-shared@example.com",
|
|
providerAccountID: "acct-selected-target",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-selected-target",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "selected-shared@example.com",
|
|
providerAccountID: "acct-selected-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-selected-sibling",
|
|
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 store = self.makeUsageStore(settings: settings)
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let providerHistoryKey = try #require(CodexHistoryOwnership.canonicalKey(for: .providerAccount(
|
|
id: "acct-selected-target")))
|
|
let emailHistoryKey = CodexHistoryOwnership.canonicalEmailHashKey(for: "selected-shared@example.com")
|
|
let legacyEmailHistoryKey = UsageStore._codexLegacyPlanUtilizationEmailHashKeyForTesting(
|
|
normalizedEmail: "selected-shared@example.com")
|
|
let staleSession = planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: now.addingTimeInterval(-2 * 60 * 60), usedPercent: 12),
|
|
])
|
|
let staleWeekly = planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(at: now.addingTimeInterval(-2 * 60 * 60), usedPercent: 24),
|
|
])
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
emailHistoryKey: [staleSession],
|
|
legacyEmailHistoryKey: [staleWeekly],
|
|
])
|
|
let currentSnapshot = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 4,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(3 * 60 * 60),
|
|
resetDescription: nil),
|
|
secondary: RateWindow(
|
|
usedPercent: 6,
|
|
windowMinutes: 10080,
|
|
resetsAt: now.addingTimeInterval(3 * 24 * 60 * 60),
|
|
resetDescription: nil),
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "selected-shared@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Target Team"))
|
|
|
|
await store.recordPlanUtilizationHistorySample(
|
|
provider: .codex,
|
|
snapshot: currentSnapshot,
|
|
now: now)
|
|
|
|
let buckets = try #require(store.planUtilizationHistory[.codex])
|
|
let providerHistory = try #require(buckets.accounts[providerHistoryKey])
|
|
#expect(providerHistory.flatMap(\.entries).allSatisfy { $0.capturedAt == now })
|
|
#expect(buckets.accounts[emailHistoryKey] == [staleSession])
|
|
#expect(buckets.accounts[legacyEmailHistoryKey] == [staleWeekly])
|
|
}
|
|
|
|
@Test
|
|
func `ignores active reset cache from another visible codex workspace`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-stale-active-cache")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-444444444444"))
|
|
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-555555555555"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-cache-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-cache-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: "shared@example.com",
|
|
providerAccountID: "acct-cache-target",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-cache-target",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "shared@example.com",
|
|
providerAccountID: "acct-cache-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-cache-sibling",
|
|
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 now = Date()
|
|
let staleReset = now.addingTimeInterval(2 * 60 * 60)
|
|
store.lastCodexAccountScopedRefreshGuard = CodexAccountScopedRefreshGuard(
|
|
source: .managedAccount(id: siblingID),
|
|
identity: .providerAccount(id: "acct-cache-sibling"),
|
|
accountKey: "shared@example.com")
|
|
store.lastKnownResetSnapshots[.codex] = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 44,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: RateWindow(
|
|
usedPercent: 55,
|
|
windowMinutes: 10080,
|
|
resetsAt: now.addingTimeInterval(2 * 24 * 60 * 60),
|
|
resetDescription: nil),
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "shared@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Sibling Team"))
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
let isTarget = context.env["CODEX_HOME"] == targetHome.path
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: isTarget ? 4 : 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now.addingTimeInterval(1))
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-cache-target"
|
|
}?.snapshot)
|
|
#expect(targetSnapshot.primary?.usedPercent == 4)
|
|
#expect(targetSnapshot.primary?.windowMinutes == 0)
|
|
#expect(targetSnapshot.primary?.resetsAt == nil)
|
|
#expect(targetSnapshot.secondary == nil)
|
|
#expect(store.snapshots[.codex]?.primary?.resetsAt == nil)
|
|
#expect(store.snapshots[.codex]?.secondary == nil)
|
|
#expect(store.lastKnownResetSnapshots[.codex]?.primary?.resetsAt == nil)
|
|
#expect(snapshotStore.storedSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-cache-target"
|
|
}?.snapshot?.primary?.resetsAt == nil)
|
|
}
|
|
|
|
@Test
|
|
func `uses active reset cache when scoped guard matches codex workspace with plan label`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-current-active-cache")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-666666666666"))
|
|
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-777777777777"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-current-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-current-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: "current@example.com",
|
|
providerAccountID: "acct-current-target",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-current-target",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "current@example.com",
|
|
providerAccountID: "acct-current-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-current-sibling",
|
|
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 now = Date()
|
|
let staleSessionReset = now.addingTimeInterval(3 * 60 * 60)
|
|
let staleWeeklyReset = now.addingTimeInterval(3 * 24 * 60 * 60)
|
|
let priorSnapshots = settings.codexVisibleAccountProjection.visibleAccounts.map { account in
|
|
CodexAccountUsageSnapshot(
|
|
account: account,
|
|
snapshot: account.workspaceAccountID == "acct-current-target"
|
|
? UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 2,
|
|
windowMinutes: 300,
|
|
resetsAt: staleSessionReset,
|
|
resetDescription: nil),
|
|
secondary: RateWindow(
|
|
usedPercent: 3,
|
|
windowMinutes: 10080,
|
|
resetsAt: staleWeeklyReset,
|
|
resetDescription: nil),
|
|
updatedAt: now.addingTimeInterval(-60))
|
|
: nil,
|
|
error: nil,
|
|
sourceLabel: "cached")
|
|
}
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: priorSnapshots)
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
let sessionReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let weeklyReset = now.addingTimeInterval(2 * 24 * 60 * 60)
|
|
let publicationGuard = CodexAccountScopedRefreshGuard(
|
|
source: .managedAccount(id: targetID),
|
|
identity: .providerAccount(id: "acct-current-target"),
|
|
accountKey: "current@example.com")
|
|
store.lastCodexUsagePublicationGuard = publicationGuard
|
|
store.lastCodexAccountScopedRefreshGuard = publicationGuard
|
|
store.lastKnownResetSnapshots[.codex] = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 44,
|
|
windowMinutes: 300,
|
|
resetsAt: sessionReset,
|
|
resetDescription: nil),
|
|
secondary: RateWindow(
|
|
usedPercent: 55,
|
|
windowMinutes: 10080,
|
|
resetsAt: weeklyReset,
|
|
resetDescription: nil),
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "current@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Pro"))
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
let isTarget = context.env["CODEX_HOME"] == targetHome.path
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: isTarget ? 4 : 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-current-target"
|
|
}?.snapshot)
|
|
#expect(targetSnapshot.primary?.usedPercent == 4)
|
|
#expect(targetSnapshot.primary?.windowMinutes == 300)
|
|
#expect(targetSnapshot.primary?.resetsAt == sessionReset)
|
|
#expect(targetSnapshot.secondary?.usedPercent == 55)
|
|
#expect(targetSnapshot.secondary?.windowMinutes == 10080)
|
|
#expect(targetSnapshot.secondary?.resetsAt == weeklyReset)
|
|
#expect(store.snapshots[.codex]?.primary?.resetsAt == sessionReset)
|
|
#expect(store.snapshots[.codex]?.secondary?.resetsAt == weeklyReset)
|
|
#expect(snapshotStore.storedSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-current-target"
|
|
}?.snapshot?.secondary?.resetsAt == weeklyReset)
|
|
}
|
|
|
|
@Test
|
|
func `ignores prior snapshot from same email different codex workspace`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-prior-workspace")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-888888888888"))
|
|
let oldID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-999999999999"))
|
|
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-AAAAAAAAAAAA"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-prior-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-prior-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: "prior@example.com",
|
|
providerAccountID: "acct-prior-new",
|
|
workspaceLabel: "New Team",
|
|
workspaceAccountID: "acct-prior-new",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "other-prior@example.com",
|
|
providerAccountID: "acct-prior-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-prior-sibling",
|
|
managedHomePath: siblingHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let oldVisibleAccount = CodexVisibleAccount(
|
|
id: "prior@example.com",
|
|
email: "prior@example.com",
|
|
workspaceLabel: "Old Team",
|
|
workspaceAccountID: "acct-prior-old",
|
|
storedAccountID: oldID,
|
|
selectionSource: .managedAccount(id: oldID),
|
|
isActive: false,
|
|
isLive: false,
|
|
canReauthenticate: false,
|
|
canRemove: false)
|
|
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 now = Date()
|
|
let staleReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [
|
|
CodexAccountUsageSnapshot(
|
|
account: oldVisibleAccount,
|
|
snapshot: UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 72,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "prior@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Old Team")),
|
|
error: nil,
|
|
sourceLabel: "cached"),
|
|
])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
let isTarget = context.env["CODEX_HOME"] == targetHome.path
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: isTarget ? 4 : 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-prior-new"
|
|
}?.snapshot)
|
|
#expect(targetSnapshot.primary?.usedPercent == 4)
|
|
#expect(targetSnapshot.primary?.windowMinutes == 0)
|
|
#expect(targetSnapshot.primary?.resetsAt == nil)
|
|
#expect(targetSnapshot.secondary == nil)
|
|
}
|
|
|
|
@Test
|
|
func `ignores ambiguous email history for same email codex workspaces`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-ambiguous-email-history")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "BBBBBBBB-CCCC-DDDD-EEEE-111111111111"))
|
|
let siblingID = try #require(UUID(uuidString: "BBBBBBBB-CCCC-DDDD-EEEE-222222222222"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-history-target-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-history-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: "history-shared@example.com",
|
|
providerAccountID: "acct-history-target",
|
|
workspaceLabel: "Target Team",
|
|
workspaceAccountID: "acct-history-target",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "history-shared@example.com",
|
|
providerAccountID: "acct-history-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-history-sibling",
|
|
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 now = Date()
|
|
let normalizedEmail = try #require(CodexIdentityResolver.normalizeEmail("history-shared@example.com"))
|
|
let emailHistoryKey = CodexHistoryOwnership.canonicalEmailHashKey(for: normalizedEmail)
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
emailHistoryKey: [
|
|
planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: now.addingTimeInterval(-60), usedPercent: 2, resetsAt: now.addingTimeInterval(3600)),
|
|
]),
|
|
planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(
|
|
at: now.addingTimeInterval(-60),
|
|
usedPercent: 33,
|
|
resetsAt: now.addingTimeInterval(4 * 24 * 60 * 60)),
|
|
]),
|
|
],
|
|
])
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
let isTarget = context.env["CODEX_HOME"] == targetHome.path
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: isTarget ? 4 : 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let targetSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.workspaceAccountID == "acct-history-target"
|
|
}?.snapshot)
|
|
#expect(targetSnapshot.primary?.usedPercent == 4)
|
|
#expect(targetSnapshot.primary?.windowMinutes == 0)
|
|
#expect(targetSnapshot.primary?.resetsAt == nil)
|
|
#expect(targetSnapshot.secondary == nil)
|
|
#expect(store.planUtilizationHistory[.codex]?.histories(for: emailHistoryKey).isEmpty == false)
|
|
}
|
|
|
|
@Test
|
|
func `email only live codex row does not inherit prior quota windows`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-live-prior")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-111111111111"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-prior-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-prior-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "live-prior@example.com",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .emailOnly(normalizedEmail: "live-prior@example.com"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-prior@example.com",
|
|
providerAccountID: "acct-managed-prior",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-prior",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .managedAccount(id: managedID)
|
|
|
|
let now = Date()
|
|
let priorReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let priorSnapshots = settings.codexVisibleAccountProjection.visibleAccounts.map { account in
|
|
CodexAccountUsageSnapshot(
|
|
account: account,
|
|
snapshot: account.selectionSource == .liveSystem
|
|
? UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 18,
|
|
windowMinutes: 300,
|
|
resetsAt: priorReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now.addingTimeInterval(-60))
|
|
: nil,
|
|
error: nil,
|
|
sourceLabel: "cached")
|
|
}
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: priorSnapshots)
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
self.installContextualCodexProvider(on: store) { _ in
|
|
UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let liveSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.selectionSource == .liveSystem
|
|
}?.snapshot)
|
|
#expect(liveSnapshot.primary?.usedPercent == 9)
|
|
#expect(liveSnapshot.primary?.windowMinutes == 0)
|
|
#expect(liveSnapshot.primary?.resetsAt == nil)
|
|
}
|
|
|
|
@Test
|
|
func `ignores live codex prior snapshot after auth fingerprint changes`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-live-prior-auth-change")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-222222222222"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-prior-auth-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-prior-auth-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "live-prior-auth@example.com",
|
|
authFingerprint: "current-live-auth-fingerprint",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .emailOnly(normalizedEmail: "live-prior-auth@example.com"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-prior-auth@example.com",
|
|
providerAccountID: "acct-managed-prior-auth",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-prior-auth",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .managedAccount(id: managedID)
|
|
|
|
let now = Date()
|
|
let priorReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let liveAccount = try #require(settings.codexVisibleAccountProjection.visibleAccounts.first {
|
|
$0.selectionSource == .liveSystem
|
|
})
|
|
let priorLiveAccount = CodexVisibleAccount(
|
|
id: liveAccount.id,
|
|
email: liveAccount.email,
|
|
workspaceLabel: liveAccount.workspaceLabel,
|
|
workspaceAccountID: liveAccount.workspaceAccountID,
|
|
authFingerprint: "stale-live-auth-fingerprint",
|
|
storedAccountID: liveAccount.storedAccountID,
|
|
selectionSource: liveAccount.selectionSource,
|
|
isActive: liveAccount.isActive,
|
|
isLive: liveAccount.isLive,
|
|
canReauthenticate: liveAccount.canReauthenticate,
|
|
canRemove: liveAccount.canRemove)
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [
|
|
CodexAccountUsageSnapshot(
|
|
account: priorLiveAccount,
|
|
snapshot: UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 18,
|
|
windowMinutes: 300,
|
|
resetsAt: priorReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now.addingTimeInterval(-60)),
|
|
error: nil,
|
|
sourceLabel: "cached"),
|
|
])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
self.installContextualCodexProvider(on: store) { _ in
|
|
UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let liveSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.selectionSource == .liveSystem
|
|
}?.snapshot)
|
|
#expect(liveSnapshot.primary?.usedPercent == 9)
|
|
#expect(liveSnapshot.primary?.windowMinutes == 0)
|
|
#expect(liveSnapshot.primary?.resetsAt == nil)
|
|
}
|
|
|
|
@Test
|
|
func `ignores active reset cache and email history after live auth fingerprint changes`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-live-active-auth-change")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-333333333333"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-active-auth-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-live-active-auth-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "live-active-auth@example.com",
|
|
authFingerprint: "current-live-active-auth",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .emailOnly(normalizedEmail: "live-active-auth@example.com"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-active-auth@example.com",
|
|
providerAccountID: "acct-managed-active-auth",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-active-auth",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .liveSystem
|
|
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
let now = Date()
|
|
let staleSessionReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let staleWeeklyReset = now.addingTimeInterval(2 * 24 * 60 * 60)
|
|
store.lastCodexAccountScopedRefreshGuard = CodexAccountScopedRefreshGuard(
|
|
source: .liveSystem,
|
|
identity: .emailOnly(normalizedEmail: "live-active-auth@example.com"),
|
|
accountKey: "live-active-auth@example.com",
|
|
authFingerprint: "stale-live-active-auth")
|
|
store.lastKnownResetSnapshots[.codex] = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 44,
|
|
windowMinutes: 300,
|
|
resetsAt: staleSessionReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now.addingTimeInterval(-60),
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "live-active-auth@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))
|
|
let emailHistoryKey = CodexHistoryOwnership.canonicalEmailHashKey(for: "live-active-auth@example.com")
|
|
store.planUtilizationHistory[.codex] = PlanUtilizationHistoryBuckets(accounts: [
|
|
emailHistoryKey: [
|
|
planSeries(name: .session, windowMinutes: 300, entries: [
|
|
planEntry(at: now.addingTimeInterval(-60), usedPercent: 44, resetsAt: staleSessionReset),
|
|
]),
|
|
planSeries(name: .weekly, windowMinutes: 10080, entries: [
|
|
planEntry(at: now.addingTimeInterval(-60), usedPercent: 55, resetsAt: staleWeeklyReset),
|
|
]),
|
|
],
|
|
])
|
|
self.installContextualCodexProvider(on: store) { _ in
|
|
UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 9,
|
|
windowMinutes: 0,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now)
|
|
}
|
|
|
|
await store.refreshCodexVisibleAccountsForMenu()
|
|
|
|
let liveSnapshot = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.selectionSource == .liveSystem
|
|
}?.snapshot)
|
|
#expect(liveSnapshot.primary?.usedPercent == 9)
|
|
#expect(liveSnapshot.primary?.windowMinutes == 0)
|
|
#expect(liveSnapshot.primary?.resetsAt == nil)
|
|
#expect(liveSnapshot.secondary == nil)
|
|
}
|
|
|
|
@Test
|
|
func `stacked visible refresh skips selected apply after live auth fingerprint changes`() async throws {
|
|
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-selected-auth-change")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-444444444444"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-auth-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-auth-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "selected-auth@example.com",
|
|
authFingerprint: "old-live-selected-auth",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .emailOnly(normalizedEmail: "selected-auth@example.com"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-selected-auth@example.com",
|
|
providerAccountID: "acct-managed-selected-auth",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-selected-auth",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .liveSystem
|
|
let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot
|
|
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
let now = Date()
|
|
let staleReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let priorDisplayedSnapshot = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 11,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "selected-auth@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))
|
|
store._setSnapshotForTesting(priorDisplayedSnapshot, provider: .codex)
|
|
store.lastKnownResetSnapshots[.codex] = priorDisplayedSnapshot
|
|
let priorGuard = store.currentCodexAccountScopedRefreshGuard(
|
|
preferCurrentSnapshot: false)
|
|
store.lastCodexUsagePublicationGuard = priorGuard
|
|
store.lastCodexAccountScopedRefreshGuard = priorGuard
|
|
let blocker = BlockingCodexFetchStrategy()
|
|
let liveHomePath = liveHome.path
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
if context.env["CODEX_HOME"] == liveHomePath {
|
|
return try await blocker.awaitResult()
|
|
}
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 7,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "managed-selected-auth@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Managed Team"))
|
|
}
|
|
|
|
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
|
|
await blocker.waitUntilStarted()
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "selected-auth@example.com",
|
|
authFingerprint: "new-live-selected-auth",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .emailOnly(normalizedEmail: "selected-auth@example.com"))
|
|
settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot(
|
|
activeSource: .liveSystem,
|
|
loadedAt: Date(),
|
|
snapshot: staleReconciliationSnapshot)
|
|
await blocker.resume(with: .success(UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 77,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "selected-auth@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))))
|
|
await refreshTask.value
|
|
|
|
#expect(store.snapshots[.codex] == nil)
|
|
#expect(store.lastKnownResetSnapshots[.codex] == nil)
|
|
#expect(!store.codexAccountSnapshots.contains {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
#expect(!snapshotStore.storedSnapshots.contains {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
}
|
|
|
|
@Test
|
|
func `stacked visible refresh keeps selected apply after live token fingerprint rotates`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-selected-token-rotation")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-888888888888"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-token-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-token-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "selected-token@example.com",
|
|
workspaceLabel: "Live Team",
|
|
workspaceAccountID: "acct-selected-token",
|
|
authFingerprint: "old-live-selected-token",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .providerAccount(id: "acct-selected-token"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-selected-token@example.com",
|
|
providerAccountID: "acct-managed-selected-token",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-selected-token",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .liveSystem
|
|
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
let blocker = BlockingCodexFetchStrategy()
|
|
let liveHomePath = liveHome.path
|
|
let now = Date()
|
|
let reset = now.addingTimeInterval(2 * 60 * 60)
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
if context.env["CODEX_HOME"] == liveHomePath {
|
|
return try await blocker.awaitResult()
|
|
}
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 7,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "managed-selected-token@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Managed Team"))
|
|
}
|
|
|
|
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
|
|
await blocker.waitUntilStarted()
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "selected-token@example.com",
|
|
workspaceLabel: "Live Team",
|
|
workspaceAccountID: "acct-selected-token",
|
|
authFingerprint: "new-live-selected-token",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .providerAccount(id: "acct-selected-token"))
|
|
await blocker.resume(with: .success(UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 77,
|
|
windowMinutes: 300,
|
|
resetsAt: reset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "selected-token@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Pro"))))
|
|
await refreshTask.value
|
|
|
|
let selectedSnapshot = try #require(store.snapshots[.codex])
|
|
#expect(selectedSnapshot.primary?.usedPercent == 77)
|
|
#expect(selectedSnapshot.accountEmail(for: .codex) == "selected-token@example.com")
|
|
#expect(selectedSnapshot.loginMethod(for: .codex) == "Pro")
|
|
#expect(store.lastCodexAccountScopedRefreshGuard?.authFingerprint == "new-live-selected-token")
|
|
|
|
let liveRow = try #require(store.codexAccountSnapshots.first {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
#expect(liveRow.account.authFingerprint == "new-live-selected-token")
|
|
#expect(liveRow.snapshot?.primary?.usedPercent == 77)
|
|
|
|
let persistedLive = try #require(snapshotStore.storedSnapshots.first {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
#expect(persistedLive.account.authFingerprint == "new-live-selected-token")
|
|
#expect(persistedLive.snapshot?.primary?.usedPercent == 77)
|
|
}
|
|
|
|
@Test
|
|
func `stacked visible refresh clears selected state after live account email changes`() async throws {
|
|
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = 60
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-selected-email-change")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let managedID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-777777777777"))
|
|
let liveHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-email-\(UUID().uuidString)", isDirectory: true)
|
|
let managedHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-selected-email-managed-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: liveHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: managedHome, withIntermediateDirectories: true)
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "old-selected@example.com",
|
|
workspaceLabel: "Live Team",
|
|
workspaceAccountID: "acct-selected-email",
|
|
authFingerprint: "old-live-selected-email",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .providerAccount(id: "acct-selected-email"))
|
|
let managedAccount = ManagedCodexAccount(
|
|
id: managedID,
|
|
email: "managed-selected-email@example.com",
|
|
providerAccountID: "acct-managed-selected-email",
|
|
workspaceLabel: "Managed Team",
|
|
workspaceAccountID: "acct-managed-selected-email",
|
|
managedHomePath: managedHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [managedAccount])
|
|
defer {
|
|
SettingsStore.codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting = nil
|
|
settings._test_managedCodexAccountStoreURL = nil
|
|
settings._test_liveSystemCodexAccount = nil
|
|
try? FileManager.default.removeItem(at: storeURL)
|
|
try? FileManager.default.removeItem(at: liveHome)
|
|
try? FileManager.default.removeItem(at: managedHome)
|
|
}
|
|
settings._test_managedCodexAccountStoreURL = storeURL
|
|
settings.codexActiveSource = .liveSystem
|
|
let staleReconciliationSnapshot = settings.codexAccountReconciliationSnapshot
|
|
|
|
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
|
|
let store = UsageStore(
|
|
fetcher: UsageFetcher(environment: [:]),
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
settings: settings,
|
|
codexAccountUsageSnapshotStore: snapshotStore,
|
|
startupBehavior: .testing)
|
|
let now = Date()
|
|
let staleReset = now.addingTimeInterval(2 * 60 * 60)
|
|
let priorDisplayedSnapshot = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 11,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "old-selected@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))
|
|
store._setSnapshotForTesting(priorDisplayedSnapshot, provider: .codex)
|
|
store.lastKnownResetSnapshots[.codex] = priorDisplayedSnapshot
|
|
store.lastCodexAccountScopedRefreshGuard = store.currentCodexAccountScopedRefreshGuard(
|
|
preferCurrentSnapshot: false)
|
|
let blocker = BlockingCodexFetchStrategy()
|
|
let liveHomePath = liveHome.path
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
if context.env["CODEX_HOME"] == liveHomePath {
|
|
return try await blocker.awaitResult()
|
|
}
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 7,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "managed-selected-email@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Managed Team"))
|
|
}
|
|
|
|
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
|
|
await blocker.waitUntilStarted()
|
|
settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
|
|
email: "new-selected@example.com",
|
|
workspaceLabel: "Live Team",
|
|
workspaceAccountID: "acct-selected-email",
|
|
authFingerprint: "new-live-selected-email",
|
|
codexHomePath: liveHome.path,
|
|
observedAt: Date(),
|
|
identity: .providerAccount(id: "acct-selected-email"))
|
|
settings.cachedCodexAccountReconciliationSnapshot = CachedCodexAccountReconciliationSnapshot(
|
|
activeSource: .liveSystem,
|
|
loadedAt: Date(),
|
|
snapshot: staleReconciliationSnapshot)
|
|
await blocker.resume(with: .success(UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 77,
|
|
windowMinutes: 300,
|
|
resetsAt: staleReset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "old-selected@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))))
|
|
await refreshTask.value
|
|
|
|
#expect(store.snapshots[.codex] == nil)
|
|
#expect(store.lastKnownResetSnapshots[.codex] == nil)
|
|
#expect(!store.codexAccountSnapshots.contains {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
#expect(store.codexAccountSnapshots.contains {
|
|
$0.account.workspaceAccountID == "acct-managed-selected-email"
|
|
})
|
|
#expect(!snapshotStore.storedSnapshots.contains {
|
|
$0.account.selectionSource == .liveSystem
|
|
})
|
|
#expect(snapshotStore.storedSnapshots.contains {
|
|
$0.account.workspaceAccountID == "acct-managed-selected-email"
|
|
})
|
|
}
|
|
|
|
@Test
|
|
func `stacked visible refresh discards selected apply after provider account email changes`() async throws {
|
|
let settings = self.makeSettingsStore(
|
|
suite: "CodexAccountVisibleHistoryBackfillTests-selected-provider-email-change")
|
|
settings.refreshFrequency = .manual
|
|
settings.multiAccountMenuLayout = .stacked
|
|
|
|
let targetID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-555555555555"))
|
|
let siblingID = try #require(UUID(uuidString: "DDDDDDDD-EEEE-FFFF-AAAA-666666666666"))
|
|
let targetHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-provider-email-\(UUID().uuidString)", isDirectory: true)
|
|
let siblingHome = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codex-visible-provider-email-sibling-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: targetHome, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: siblingHome, withIntermediateDirectories: true)
|
|
let originalTarget = ManagedCodexAccount(
|
|
id: targetID,
|
|
email: "old-provider@example.com",
|
|
providerAccountID: "acct-provider-email",
|
|
workspaceLabel: "Provider Team",
|
|
workspaceAccountID: "acct-provider-email",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let updatedTarget = ManagedCodexAccount(
|
|
id: targetID,
|
|
email: "new-provider@example.com",
|
|
providerAccountID: "acct-provider-email",
|
|
workspaceLabel: "Provider Team",
|
|
workspaceAccountID: "acct-provider-email",
|
|
managedHomePath: targetHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 3,
|
|
lastAuthenticatedAt: 3)
|
|
let siblingAccount = ManagedCodexAccount(
|
|
id: siblingID,
|
|
email: "sibling-provider@example.com",
|
|
providerAccountID: "acct-provider-sibling",
|
|
workspaceLabel: "Sibling Team",
|
|
workspaceAccountID: "acct-provider-sibling",
|
|
managedHomePath: siblingHome.path,
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
lastAuthenticatedAt: 2)
|
|
let storeURL = try self.makeManagedAccountStoreURL(accounts: [originalTarget, 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()
|
|
let reset = now.addingTimeInterval(90 * 60)
|
|
let prior = UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 63,
|
|
windowMinutes: 300,
|
|
resetsAt: reset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now.addingTimeInterval(-60),
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "old-provider@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Provider Team"))
|
|
let priorGuard = CodexAccountScopedRefreshGuard(
|
|
source: .managedAccount(id: targetID),
|
|
identity: .providerAccount(id: "acct-provider-email"),
|
|
accountKey: "old-provider@example.com")
|
|
store.snapshots[.codex] = prior
|
|
store.lastKnownResetSnapshots[.codex] = prior
|
|
store.lastCodexUsagePublicationGuard = priorGuard
|
|
store.lastCodexAccountScopedRefreshGuard = priorGuard
|
|
self.installContextualCodexProvider(on: store) { context in
|
|
if context.env["CODEX_HOME"] == targetHomePath {
|
|
return try await blocker.awaitResult()
|
|
}
|
|
return UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 11,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "sibling-provider@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: .success(UsageSnapshot(
|
|
primary: RateWindow(
|
|
usedPercent: 64,
|
|
windowMinutes: 300,
|
|
resetsAt: reset,
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: now,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "old-provider@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "Pro"))))
|
|
await refreshTask.value
|
|
|
|
#expect(store.snapshots[.codex] == nil)
|
|
#expect(store.lastKnownResetSnapshots[.codex] == nil)
|
|
#expect(!store.codexAccountSnapshots.contains {
|
|
$0.account.workspaceAccountID == "acct-provider-email"
|
|
})
|
|
#expect(store.codexAccountSnapshots.contains {
|
|
$0.account.workspaceAccountID == "acct-provider-sibling"
|
|
})
|
|
#expect(!snapshotStore.storedSnapshots.contains {
|
|
$0.account.workspaceAccountID == "acct-provider-email"
|
|
})
|
|
}
|
|
}
|