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

763 lines
32 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@MainActor
struct UsageStoreDisabledProviderCleanupTests {
@Test
func `disabled cleanup rejects stale provider publication after re-enable`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-provider-race")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.amp, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
let stale = Self.usageSnapshot(usedPercent: 71)
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: stale)
}
let staleTask = Task { await store.refreshProvider(.amp) }
await gate.waitUntilStarted()
try Self.setProvider(.amp, enabled: false, settings: settings)
store.clearDisabledProviderState(enabledProviders: [])
try Self.setProvider(.amp, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
#expect(store.snapshot(for: .amp) == nil)
let fresh = Self.usageSnapshot(usedPercent: 19)
store._test_providerFetchOutcomeOverride = { _ in Self.providerOutcome(snapshot: fresh) }
await store.refreshProvider(.amp)
#expect(store.snapshot(for: .amp)?.primary?.usedPercent == 19)
}
@Test
func `quick provider toggle rejects stale publication before cleanup runs`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-provider-config-race")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.amp, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: Self.usageSnapshot(usedPercent: 71))
}
let staleTask = Task { await store.refreshProvider(.amp) }
await gate.waitUntilStarted()
try Self.setProvider(.amp, enabled: false, settings: settings)
try Self.setProvider(.amp, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
#expect(store.snapshot(for: .amp) == nil)
}
@Test
func `provider order change preserves in-flight publication`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-provider-order")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.amp, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: Self.usageSnapshot(usedPercent: 43))
}
let refreshTask = Task { await store.refreshProvider(.amp) }
await gate.waitUntilStarted()
settings.setProviderOrder(Array(settings.orderedProviders().reversed()))
await gate.resume()
await refreshTask.value
#expect(store.snapshot(for: .amp)?.primary?.usedPercent == 43)
}
@Test
func `provider config round trip rejects stale publication before cleanup runs`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-provider-config")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.amp, enabled: true, settings: settings)
settings.updateProviderConfig(provider: .amp) { $0.source = .auto }
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: Self.usageSnapshot(usedPercent: 71))
}
let staleTask = Task { await store.refreshProvider(.amp) }
await gate.waitUntilStarted()
settings.updateProviderConfig(provider: .amp) { $0.source = .api }
settings.updateProviderConfig(provider: .amp) { $0.source = .auto }
await gate.resume()
await staleTask.value
#expect(store.snapshot(for: .amp) == nil)
}
@Test
func `base URL change rejects suspended token account result and cache`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-base-url")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.sub2api, enabled: true, settings: settings)
settings.updateProviderConfig(provider: .sub2api) { config in
config.enterpriseHost = "https://first.example.test"
}
settings.addTokenAccount(provider: .sub2api, label: "Primary", token: "k1")
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: Self.usageSnapshot(usedPercent: 71))
}
let staleTask = Task { await store.refreshProvider(.sub2api) }
await gate.waitUntilStarted()
settings.updateProviderConfig(provider: .sub2api) { config in
config.enterpriseHost = "https://second.example.test"
}
await gate.resume()
await staleTask.value
#expect(store.snapshot(for: .sub2api) == nil)
#expect(store.accountSnapshots[.sub2api] == nil)
}
@Test
func `disabled cleanup preserves explicit allow-disabled refresh`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-allow-disabled")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
try Self.setOnlyProvider(.amp, enabled: false, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerFetchOutcomeOverride = { _ in
await gate.suspend()
return Self.providerOutcome(snapshot: Self.usageSnapshot(usedPercent: 27))
}
let refreshTask = Task { await store.refreshProvider(.amp, allowDisabled: true) }
await gate.waitUntilStarted()
store.clearDisabledProviderState(enabledProviders: [])
await gate.resume()
await refreshTask.value
#expect(store.snapshot(for: .amp)?.primary?.usedPercent == 27)
store.clearDisabledProviderState(enabledProviders: [])
#expect(store.snapshot(for: .amp) == nil)
}
@Test
func `disabled cleanup rejects stale status success after re-enable`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-status-success")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerStatusFetchOverride = { _ in
await gate.suspend()
return ProviderStatus(indicator: .major, description: "stale", updatedAt: Date())
}
let staleTask = Task { await store.refreshProviderStatus(.codex) }
await gate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
try Self.setProvider(.codex, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
#expect(store.statuses[.codex] == nil)
store._test_providerStatusFetchOverride = { _ in
ProviderStatus(indicator: .none, description: "fresh", updatedAt: Date())
}
await store.refreshProviderStatus(.codex)
#expect(store.statuses[.codex]?.description == "fresh")
}
@Test
func `disabled cleanup rejects stale status failure after re-enable`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-status-failure")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_providerStatusFetchOverride = { _ in
await gate.suspend()
throw CleanupTestError.failed
}
let staleTask = Task { await store.refreshProviderStatus(.codex) }
await gate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
store.clearDisabledProviderState(enabledProviders: [])
try Self.setProvider(.codex, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
#expect(store.statuses[.codex] == nil)
}
@Test
func `disabled cleanup rejects stale token result after re-enable`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-race")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.costUsageEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
var loadCount = 0
store._test_tokenUsageSnapshotLoaderOverride = { _, _, _, _, historyDays in
loadCount += 1
if loadCount == 1 {
await gate.suspend()
return Self.tokenSnapshot(tokens: 710, historyDays: historyDays)
}
return Self.tokenSnapshot(tokens: 190, historyDays: historyDays)
}
let staleTask = Task { await store.refreshTokenUsage(.codex, force: true) }
await gate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
store.clearDisabledProviderState(enabledProviders: [])
try Self.setProvider(.codex, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
for _ in 0..<100 where store.tokenSnapshot(for: .codex) == nil {
try await Task.sleep(for: .milliseconds(10))
}
#expect(store.tokenSnapshot(for: .codex)?.sessionTokens == 190)
#expect(loadCount == 2)
}
@Test
func `disabled cleanup replaces stale token failure with fresh retry`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-failure")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.costUsageEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
var loadCount = 0
store._test_tokenUsageSnapshotLoaderOverride = { _, _, _, _, historyDays in
loadCount += 1
if loadCount == 1 {
await gate.suspend()
throw CleanupTestError.failed
}
return Self.tokenSnapshot(tokens: 190, historyDays: historyDays)
}
let staleTask = Task { await store.refreshTokenUsage(.codex, force: true) }
await gate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
store.clearDisabledProviderState(enabledProviders: [])
try Self.setProvider(.codex, enabled: true, settings: settings)
await gate.resume()
await staleTask.value
for _ in 0..<100 where store.tokenSnapshot(for: .codex) == nil {
try await Task.sleep(for: .milliseconds(10))
}
#expect(store.tokenSnapshot(for: .codex)?.sessionTokens == 190)
#expect(store.tokenError(for: .codex) == nil)
#expect(loadCount == 2)
}
@Test
func `disabled token completion preserves retry through active sequence`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-sequence")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.costUsageEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
try Self.setProvider(.claude, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let codexGate = CleanupAsyncGate()
let claudeGate = CleanupAsyncGate()
var codexLoads = 0
var claudeLoads = 0
store._test_tokenUsageSnapshotLoaderOverride = { provider, _, _, _, historyDays in
switch provider {
case .codex:
codexLoads += 1
if codexLoads == 1 {
await codexGate.suspend()
return Self.tokenSnapshot(tokens: 710, historyDays: historyDays)
}
return Self.tokenSnapshot(tokens: 190, historyDays: historyDays)
case .claude:
claudeLoads += 1
if claudeLoads == 1 {
await claudeGate.suspend()
}
return Self.tokenSnapshot(tokens: 50, historyDays: historyDays)
default:
return Self.tokenSnapshot(tokens: 1, historyDays: historyDays)
}
}
store.scheduleTokenRefreshForTesting()
await codexGate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
store.clearDisabledProviderState(enabledProviders: [.claude])
await codexGate.resume()
await claudeGate.waitUntilStarted()
try Self.setProvider(.codex, enabled: true, settings: settings)
store.scheduleTokenRefreshForTesting()
await claudeGate.resume()
for _ in 0..<200
where store.tokenSnapshot(for: .codex)?.sessionTokens != 190 || claudeLoads != 2
{
try await Task.sleep(for: .milliseconds(10))
}
#expect(store.tokenSnapshot(for: .codex)?.sessionTokens == 190)
#expect(codexLoads == 2)
#expect(claudeLoads == 1)
}
@Test
func `token configuration change rejects stale result`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-scope")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.costUsageEnabled = true
settings.costUsageHistoryDays = 30
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
var loadCount = 0
store._test_tokenUsageSnapshotLoaderOverride = { _, _, _, _, historyDays in
loadCount += 1
if loadCount == 1 {
await gate.suspend()
return Self.tokenSnapshot(tokens: 710, historyDays: historyDays)
}
return Self.tokenSnapshot(tokens: 190, historyDays: historyDays)
}
let staleTask = Task { await store.refreshTokenUsage(.codex, force: true) }
await gate.waitUntilStarted()
settings.costUsageHistoryDays = 7
await gate.resume()
await staleTask.value
for _ in 0..<100 where store.tokenSnapshot(for: .codex) == nil {
try await Task.sleep(for: .milliseconds(10))
}
#expect(store.tokenSnapshot(for: .codex)?.sessionTokens == 190)
#expect(loadCount == 2)
}
@Test
func `cached token hydration rejects disable re-enable completion`() async throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-token-cache")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.costUsageEnabled = true
try Self.setOnlyProvider(.codex, enabled: true, settings: settings)
let store = Self.makeUsageStore(settings: settings)
let gate = CleanupAsyncGate()
store._test_cachedCodexTokenSnapshotLoaderOverride = { now, _, historyDays in
await gate.suspend()
return (
snapshot: Self.tokenSnapshot(tokens: 710, historyDays: historyDays, updatedAt: now),
lastRefreshAt: now)
}
store.hydrateCachedTokenSnapshots()
await gate.waitUntilStarted()
try Self.setProvider(.codex, enabled: false, settings: settings)
try Self.setProvider(.codex, enabled: true, settings: settings)
await gate.resume()
for _ in 0..<10 {
await Task.yield()
}
#expect(store.tokenSnapshot(for: .codex) == nil)
#expect(store.tokenLastAttemptAt(for: .codex) == nil)
}
@Test
func `disabled provider cleanup clears derived reset scope and warning state`() throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-derived")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
let metadata = ProviderRegistry.shared.metadata
for provider in UsageProvider.allCases {
try settings.setProviderEnabled(
provider: provider,
metadata: #require(metadata[provider]),
enabled: false)
}
try settings.setProviderEnabled(provider: .codex, metadata: #require(metadata[.codex]), enabled: true)
let store = Self.makeUsageStore(settings: settings)
let staleSnapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 40, windowMinutes: 300, resetsAt: Date(), resetDescription: nil),
secondary: nil,
updatedAt: Date())
let retainedSnapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 12, windowMinutes: 300, resetsAt: Date(), resetDescription: nil),
secondary: nil,
updatedAt: Date())
store._setSnapshotForTesting(staleSnapshot, provider: .kilo)
store.lastKnownResetSnapshots[.kilo] = staleSnapshot
store.lastKnownResetSnapshots[.codex] = retainedSnapshot
store.kiloScopeSnapshots = [
KiloScopeSnapshot(
id: KiloUsageScope.personal.scopeIdentifier,
scope: .personal,
snapshot: staleSnapshot,
errorMessage: nil,
sourceLabel: "personal"),
KiloScopeSnapshot(
id: "org-stale",
scope: .organization(id: "org-stale", name: "Stale Org"),
snapshot: staleSnapshot,
errorMessage: nil,
sourceLabel: "org"),
]
store.providerStorageFootprints[.kilo] = ProviderStorageFootprint(
provider: .kilo,
totalBytes: 42,
paths: ["/tmp/kilo"],
missingPaths: [],
unreadablePaths: [],
components: [],
updatedAt: Date())
store.quotaWarningState[UsageStore.QuotaWarningStateKey(provider: .kilo, window: .session)] =
UsageStore.QuotaWarningState(lastRemaining: 20, firedThresholds: [50], source: .primary)
store.quotaWarningState[UsageStore.QuotaWarningStateKey(provider: .codex, window: .session)] =
UsageStore.QuotaWarningState(lastRemaining: 80, firedThresholds: [20], source: .primary)
store.predictivePaceWarningNotifiedKeys = [
PredictivePaceWarningStateKey(
provider: .kilo,
accountDiscriminator: "kilo",
window: .session,
resetWindow: PredictivePaceWarningResetWindow(windowMinutes: 300, resetsAt: Date())),
PredictivePaceWarningStateKey(
provider: .codex,
accountDiscriminator: "codex",
window: .session,
resetWindow: PredictivePaceWarningResetWindow(windowMinutes: 300, resetsAt: Date())),
]
store.lastTokenFetchAt[.kilo] = Date()
store.lastTokenFetchScope[.kilo] = "stale"
store.clearDisabledProviderState(enabledProviders: Set(store.enabledProvidersForDisplay()))
#expect(store.snapshot(for: .kilo) == nil)
#expect(store.lastKnownResetSnapshots[.kilo] == nil)
#expect(store.kiloScopeSnapshots.isEmpty)
#expect(store.providerStorageFootprints[.kilo] == nil)
#expect(store.quotaWarningState[UsageStore.QuotaWarningStateKey(provider: .kilo, window: .session)] == nil)
#expect(store.predictivePaceWarningNotifiedKeys.allSatisfy { $0.provider != .kilo })
#expect(store.lastTokenFetchAt[.kilo] == nil)
#expect(store.lastTokenFetchScope[.kilo] == nil)
#expect(store.lastKnownResetSnapshots[.codex]?.primary?.usedPercent == 12)
#expect(store.quotaWarningState[UsageStore.QuotaWarningStateKey(provider: .codex, window: .session)] != nil)
#expect(store.predictivePaceWarningNotifiedKeys.contains { $0.provider == .codex })
}
@Test
func `disabled Codex cleanup clears account snapshots and publication guard`() throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-codex")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
let metadata = ProviderRegistry.shared.metadata
for provider in UsageProvider.allCases {
try settings.setProviderEnabled(
provider: provider,
metadata: #require(metadata[provider]),
enabled: false)
}
try settings.setProviderEnabled(provider: .claude, metadata: #require(metadata[.claude]), enabled: true)
let store = Self.makeUsageStore(settings: settings)
let account = CodexVisibleAccount(
id: "stale@example.com",
email: "stale@example.com",
storedAccountID: nil,
selectionSource: .liveSystem,
isActive: true,
isLive: true,
canReauthenticate: true,
canRemove: true)
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 33, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
updatedAt: Date())
store._setSnapshotForTesting(snapshot, provider: .codex)
store.lastKnownResetSnapshots[.codex] = snapshot
store.codexAccountSnapshots = [
CodexAccountUsageSnapshot(account: account, snapshot: snapshot, error: nil, sourceLabel: "stale"),
]
store.lastCodexUsagePublicationGuard = CodexAccountScopedRefreshGuard(
source: .liveSystem,
identity: .emailOnly(normalizedEmail: "stale@example.com"),
accountKey: "stale@example.com",
authFingerprint: "stale-fingerprint")
store.lastCodexAccountScopedRefreshGuard = store.lastCodexUsagePublicationGuard
store.clearDisabledProviderState(enabledProviders: Set(store.enabledProvidersForDisplay()))
#expect(store.snapshot(for: .codex) == nil)
#expect(store.lastKnownResetSnapshots[.codex] == nil)
#expect(store.codexAccountSnapshots.isEmpty)
#expect(store.lastCodexUsagePublicationGuard == nil)
#expect(store.lastCodexAccountScopedRefreshGuard != nil)
}
@Test
func `disabled Claude cleanup clears swap runtime without touching settings`() throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-claude-swap")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.claudeSwapEnabled = true
settings.claudeSwapExecutablePath = "/tmp/cswap-fixture"
let metadata = ProviderRegistry.shared.metadata
for provider in UsageProvider.allCases {
try settings.setProviderEnabled(
provider: provider,
metadata: #require(metadata[provider]),
enabled: false)
}
try settings.setProviderEnabled(provider: .codex, metadata: #require(metadata[.codex]), enabled: true)
let store = Self.makeUsageStore(settings: settings)
store.claudeSwapAccountSnapshots = [
ProviderAccountUsageSnapshot(
id: ProviderAccountIdentity(source: ClaudeSwapAccountProjection.sourceName, opaqueID: "1"),
provider: .claude,
displayLabel: "account@example.com",
isActive: false,
snapshot: nil,
error: "Token expired",
sourceLabel: ClaudeSwapAccountProjection.sourceLabel),
]
store.claudeSwapLastRefreshAt = Date()
store.claudeSwapLastError = "stale"
store.clearDisabledProviderState(enabledProviders: Set(store.enabledProvidersForDisplay()))
#expect(store.claudeSwapAccountSnapshots.isEmpty)
#expect(store.claudeSwapLastRefreshAt == nil)
#expect(store.claudeSwapLastError == nil)
#expect(settings.claudeSwapEnabled)
#expect(settings.claudeSwapExecutablePath == "/tmp/cswap-fixture")
}
@Test
func `unavailable provider cleanup clears derived reset and scope state`() throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreDisabledProviderCleanupTests-unavailable")
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
let metadata = ProviderRegistry.shared.metadata
for provider in UsageProvider.allCases {
try settings.setProviderEnabled(
provider: provider,
metadata: #require(metadata[provider]),
enabled: false)
}
try settings.setProviderEnabled(provider: .kilo, metadata: #require(metadata[.kilo]), enabled: true)
let store = Self.makeUsageStore(settings: settings)
let staleSnapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 55, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
updatedAt: Date())
store._setSnapshotForTesting(staleSnapshot, provider: .kilo)
store.lastKnownResetSnapshots[.kilo] = staleSnapshot
store.kiloScopeSnapshots = [
KiloScopeSnapshot(
id: KiloUsageScope.personal.scopeIdentifier,
scope: .personal,
snapshot: staleSnapshot,
errorMessage: nil,
sourceLabel: "personal"),
KiloScopeSnapshot(
id: "org-stale",
scope: .organization(id: "org-stale", name: "Stale Org"),
snapshot: staleSnapshot,
errorMessage: nil,
sourceLabel: "org"),
]
store.clearUnavailableProviderState(
displayEnabledProviders: [.kilo],
availableProviders: [])
#expect(store.snapshot(for: .kilo) == nil)
#expect(store.lastKnownResetSnapshots[.kilo] == nil)
#expect(store.kiloScopeSnapshots.isEmpty)
}
private static func makeSettingsStore(suite: String) -> SettingsStore {
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let settings = SettingsStore(
userDefaults: defaults,
configStore: testConfigStore(suiteName: suite),
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore(),
codexCookieStore: InMemoryCookieHeaderStore(),
claudeCookieStore: InMemoryCookieHeaderStore(),
cursorCookieStore: InMemoryCookieHeaderStore(),
opencodeCookieStore: InMemoryCookieHeaderStore(),
factoryCookieStore: InMemoryCookieHeaderStore(),
minimaxCookieStore: InMemoryMiniMaxCookieStore(),
minimaxAPITokenStore: InMemoryMiniMaxAPITokenStore(),
kimiTokenStore: InMemoryKimiTokenStore(),
kimiK2TokenStore: InMemoryKimiK2TokenStore(),
augmentCookieStore: InMemoryCookieHeaderStore(),
ampCookieStore: InMemoryCookieHeaderStore(),
copilotTokenStore: InMemoryCopilotTokenStore(),
tokenAccountStore: InMemoryTokenAccountStore())
settings.providerDetectionCompleted = true
return settings
}
private static func makeUsageStore(settings: SettingsStore) -> UsageStore {
UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
environmentBase: [:])
}
private static func setOnlyProvider(
_ provider: UsageProvider,
enabled: Bool,
settings: SettingsStore) throws
{
let metadata = ProviderRegistry.shared.metadata
for candidate in UsageProvider.allCases {
try settings.setProviderEnabled(
provider: candidate,
metadata: #require(metadata[candidate]),
enabled: candidate == provider && enabled)
}
}
private static func setProvider(
_ provider: UsageProvider,
enabled: Bool,
settings: SettingsStore) throws
{
try settings.setProviderEnabled(
provider: provider,
metadata: #require(ProviderRegistry.shared.metadata[provider]),
enabled: enabled)
}
private static func usageSnapshot(usedPercent: Double) -> UsageSnapshot {
UsageSnapshot(
primary: RateWindow(
usedPercent: usedPercent,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil),
secondary: nil,
updatedAt: Date())
}
private static func providerOutcome(snapshot: UsageSnapshot) -> ProviderFetchOutcome {
ProviderFetchOutcome(
result: .success(ProviderFetchResult(
usage: snapshot,
credits: nil,
dashboard: nil,
sourceLabel: "fixture",
strategyID: "fixture",
strategyKind: .cli)),
attempts: [])
}
private static func tokenSnapshot(
tokens: Int,
historyDays: Int,
updatedAt: Date = Date()) -> CostUsageTokenSnapshot
{
CostUsageTokenSnapshot(
sessionTokens: tokens,
sessionCostUSD: 1,
last30DaysTokens: tokens,
last30DaysCostUSD: 1,
historyDays: historyDays,
daily: [
CostUsageDailyReport.Entry(
date: "2026-07-11",
inputTokens: tokens,
outputTokens: 0,
totalTokens: tokens,
costUSD: 1,
modelsUsed: [],
modelBreakdowns: nil),
],
updatedAt: updatedAt)
}
}
private enum CleanupTestError: LocalizedError {
case failed
var errorDescription: String? {
"fixture failure"
}
}
private actor CleanupAsyncGate {
private var started = false
private var startWaiters: [CheckedContinuation<Void, Never>] = []
private var releaseContinuation: CheckedContinuation<Void, Never>?
func suspend() async {
self.started = true
for waiter in self.startWaiters {
waiter.resume()
}
self.startWaiters.removeAll()
await withCheckedContinuation { continuation in
self.releaseContinuation = continuation
}
}
func waitUntilStarted() async {
guard !self.started else { return }
await withCheckedContinuation { continuation in
self.startWaiters.append(continuation)
}
}
func resume() {
self.releaseContinuation?.resume()
self.releaseContinuation = nil
}
}