mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-07-27 09:55:13 +00:00
141 lines
5.1 KiB
Swift
141 lines
5.1 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodeBurnMenubar
|
|
|
|
private func menubarPayload(cost: Double) -> MenubarPayload {
|
|
MenubarPayload(
|
|
generated: "test",
|
|
current: CurrentBlock(
|
|
label: "Today",
|
|
cost: cost,
|
|
calls: 1,
|
|
sessions: 1,
|
|
oneShotRate: nil,
|
|
inputTokens: 1,
|
|
outputTokens: 1,
|
|
cacheHitPercent: 0,
|
|
topActivities: [],
|
|
topModels: [],
|
|
localModelSavings: LocalModelSavings(totalUSD: 0, calls: 0, byModel: [], byProvider: []),
|
|
providers: ["claude": cost],
|
|
topProjects: [],
|
|
modelEfficiency: [],
|
|
topSessions: [],
|
|
retryTax: RetryTax(totalUSD: 0, retries: 0, editTurns: 0, byModel: []),
|
|
routingWaste: RoutingWaste(totalSavingsUSD: 0, baselineModel: "", baselineCostPerEdit: 0, byModel: []),
|
|
tools: [],
|
|
skills: [],
|
|
subagents: [],
|
|
mcpServers: []
|
|
),
|
|
optimize: OptimizeBlock(findingCount: 0, savingsUSD: 0, topFindings: []),
|
|
history: HistoryBlock(daily: [])
|
|
)
|
|
}
|
|
|
|
@Suite("AppStore refresh recovery")
|
|
@MainActor
|
|
struct AppStoreRefreshRecoveryTests {
|
|
@Test("stale visible payload triggers hard recovery without clearing cache")
|
|
func stalePayloadTriggersHardRecoveryWithoutClearingCache() {
|
|
let store = AppStore()
|
|
store.setCachedPayloadForTesting(
|
|
menubarPayload(cost: 92.33),
|
|
period: .today,
|
|
provider: .all,
|
|
fetchedAt: Date().addingTimeInterval(-180)
|
|
)
|
|
|
|
#expect(store.todayPayload?.current.cost == 92.33)
|
|
#expect(store.needsInteractivePayloadRefresh)
|
|
#expect(store.needsStatusPayloadRefresh)
|
|
#expect(store.hasStaleInteractivePayload)
|
|
#expect(store.shouldResetInteractiveRefreshPipeline)
|
|
|
|
store.resetRefreshState(clearCache: false)
|
|
|
|
#expect(store.todayPayload?.current.cost == 92.33)
|
|
}
|
|
|
|
@Test("fresh visible payload does not trigger hard recovery")
|
|
func freshPayloadDoesNotTriggerHardRecovery() {
|
|
let store = AppStore()
|
|
store.setCachedPayloadForTesting(
|
|
menubarPayload(cost: 164.06),
|
|
period: .today,
|
|
provider: .all,
|
|
fetchedAt: Date()
|
|
)
|
|
|
|
#expect(!store.needsInteractivePayloadRefresh)
|
|
#expect(!store.needsStatusPayloadRefresh)
|
|
#expect(!store.hasStaleInteractivePayload)
|
|
#expect(!store.shouldResetInteractiveRefreshPipeline)
|
|
}
|
|
|
|
@Test("missing today status payload needs status refresh")
|
|
func missingTodayStatusPayloadNeedsStatusRefresh() {
|
|
let store = AppStore()
|
|
|
|
#expect(store.todayPayload == nil)
|
|
#expect(store.needsStatusPayloadRefresh)
|
|
}
|
|
|
|
@Test("missing unattempted payload triggers hard recovery")
|
|
func missingUnattemptedPayloadTriggersHardRecovery() {
|
|
let store = AppStore()
|
|
|
|
#expect(!store.hasCachedData)
|
|
#expect(!store.hasAttemptedCurrentKeyLoad)
|
|
#expect(store.needsInteractivePayloadRefresh)
|
|
#expect(store.hasMissingInteractivePayloadWithoutAttempt)
|
|
#expect(store.shouldResetInteractiveRefreshPipeline)
|
|
}
|
|
|
|
@Test("orphaned stale in-flight entry does not block stuck-loading recovery")
|
|
func staleInFlightDoesNotBlockRecovery() {
|
|
let store = AppStore()
|
|
// A quiet refresh torn down across sleep/wake can leave an in-flight
|
|
// entry behind for the current key with no cache and no active loading
|
|
// counter, far older than the watchdog window. Recovery must clear it
|
|
// and proceed instead of bailing on the in-flight guard forever.
|
|
store.seedInFlightForTesting(period: .today, provider: .all, insertedAt: Date().addingTimeInterval(-3600))
|
|
|
|
#expect(store.isInFlightForTesting(period: .today, provider: .all))
|
|
|
|
let canRecover = store.prepareStuckLoadingRecovery()
|
|
|
|
#expect(canRecover)
|
|
#expect(!store.isInFlightForTesting(period: .today, provider: .all))
|
|
}
|
|
|
|
@Test("healthy in-flight fetch is not killed by recovery")
|
|
func healthyInFlightFetchSurvivesRecovery() {
|
|
let store = AppStore()
|
|
store.seedInFlightForTesting(period: .today, provider: .all, insertedAt: Date())
|
|
|
|
let canRecover = store.prepareStuckLoadingRecovery()
|
|
|
|
#expect(!canRecover)
|
|
#expect(store.isInFlightForTesting(period: .today, provider: .all))
|
|
}
|
|
|
|
@Test("prepareStuckLoadingRecovery clears stale loading bookkeeping for the current key")
|
|
func popoverRecoveryClearsStuckLoading() {
|
|
let store = AppStore()
|
|
// Seed an orphaned in-flight entry older than the 60s watchdog so the
|
|
// stale-clear path runs, mimicking a fetch torn down across sleep/wake.
|
|
store.seedInFlightForTesting(
|
|
period: .today,
|
|
provider: .all,
|
|
insertedAt: Date().addingTimeInterval(-120)
|
|
)
|
|
#expect(store.isInFlightForTesting(period: .today, provider: .all))
|
|
|
|
let willFetch = store.prepareStuckLoadingRecovery()
|
|
|
|
#expect(willFetch)
|
|
#expect(!store.isInFlightForTesting(period: .today, provider: .all))
|
|
}
|
|
|
|
}
|