175 lines · 7.3 KB · Swift
RawDownload
import Foundationimport Testing@testable import CodexBar@testable import CodexBarCore struct ClaudeWebRefreshResilienceTests {    @Test    func `web unauthorized respects failure gate while keeping prior Claude snapshot`() async throws {        try await ClaudeOAuthCredentialsStore.withIsolatedCredentialsFileTrackingForTesting {            let tempDir = FileManager.default.temporaryDirectory                .appendingPathComponent(UUID().uuidString, isDirectory: true)            try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)            let fileURL = tempDir.appendingPathComponent("missing-credentials.json")             try await ClaudeOAuthCredentialsStore.withCredentialsURLOverrideForTesting(fileURL) {                let prior = Self.makePriorSnapshot()                let store = try await MainActor.run {                    try Self.makeStore(                        suite: "ClaudeWebRefreshResilienceTests-web-unauthorized",                        prior: prior)                }                 await store.refreshProvider(.claude)                let firstResult = await MainActor.run {                    (                        updatedAt: store.snapshot(for: .claude)?.updatedAt,                        hasError: store.error(for: .claude) != nil)                }                 #expect(firstResult.updatedAt == prior.updatedAt)                #expect(!firstResult.hasError)                 await store.refreshProvider(.claude)                let secondResult = await MainActor.run {                    (                        updatedAt: store.snapshot(for: .claude)?.updatedAt,                        error: store.error(for: .claude))                }                 #expect(secondResult.updatedAt == prior.updatedAt)                #expect(secondResult.error == ClaudeWebAPIFetcher.FetchError.unauthorized.localizedDescription)            }        }    }     @Test    func `web unauthorized without prior Claude snapshot still surfaces failure`() async throws {        try await ClaudeOAuthCredentialsStore.withIsolatedCredentialsFileTrackingForTesting {            let tempDir = FileManager.default.temporaryDirectory                .appendingPathComponent(UUID().uuidString, isDirectory: true)            try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)            let fileURL = tempDir.appendingPathComponent("missing-credentials.json")             try await ClaudeOAuthCredentialsStore.withCredentialsURLOverrideForTesting(fileURL) {                let store = try await MainActor.run {                    try Self.makeStore(                        suite: "ClaudeWebRefreshResilienceTests-web-unauthorized-no-prior",                        prior: nil)                }                 await store.refreshProvider(.claude)                let result = await MainActor.run {                    (                        hasSnapshot: store.snapshot(for: .claude) != nil,                        error: store.error(for: .claude))                }                 #expect(!result.hasSnapshot)                #expect(result.error == ClaudeWebAPIFetcher.FetchError.unauthorized.localizedDescription)            }        }    }     @MainActor    private static func makeStore(suite: String, prior: UsageSnapshot?) throws -> UsageStore {        let settings = self.makeSettingsStore(suite: suite)        settings.refreshFrequency = .manual        settings.statusChecksEnabled = false        settings.claudeUsageDataSource = .web         let metadata = ProviderRegistry.shared.metadata        for provider in UsageProvider.allCases {            try settings.setProviderEnabled(                provider: provider,                metadata: #require(metadata[provider]),                enabled: provider == .claude)        }         let store = UsageStore(            fetcher: UsageFetcher(environment: [:]),            browserDetection: BrowserDetection(cacheTTL: 0),            settings: settings,            startupBehavior: .testing,            environmentBase: [:])        if let prior {            store._setSnapshotForTesting(prior, provider: .claude)        }         let baseSpec = try #require(store.providerSpecs[.claude])        let descriptor = ProviderDescriptor(            id: .claude,            metadata: baseSpec.descriptor.metadata,            branding: baseSpec.descriptor.branding,            tokenCost: baseSpec.descriptor.tokenCost,            fetchPlan: ProviderFetchPlan(                sourceModes: [.web],                pipeline: ProviderFetchPipeline { _ in [ClaudeWebUnauthorizedFetchStrategy()] }),            cli: baseSpec.descriptor.cli)        store.providerSpecs[.claude] = ProviderSpec(            style: baseSpec.style,            isEnabled: baseSpec.isEnabled,            descriptor: descriptor,            makeFetchContext: baseSpec.makeFetchContext)        return store    }     private static func makePriorSnapshot() -> UsageSnapshot {        UsageSnapshot(            primary: RateWindow(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: nil),            secondary: RateWindow(                usedPercent: 34,                windowMinutes: 10080,                resetsAt: nil,                resetDescription: nil),            updatedAt: Date(timeIntervalSince1970: 1_800_000_000),            identity: ProviderIdentitySnapshot(                providerID: .claude,                accountEmail: "claude@example.com",                accountOrganization: nil,                loginMethod: "Pro"))    }     @MainActor    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 struct ClaudeWebUnauthorizedFetchStrategy: ProviderFetchStrategy {    let id = "test.claude-web-unauthorized"    let kind: ProviderFetchKind = .web     func isAvailable(_: ProviderFetchContext) async -> Bool {        true    }     func fetch(_: ProviderFetchContext) async throws -> ProviderFetchResult {        throw ClaudeWebAPIFetcher.FetchError.unauthorized    }     func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {        false    }}