433 lines · 16.4 KB · Swift
RawDownload
import Foundationimport Testing@testable import CodexBarCLI@testable import CodexBarCore @Suite(.serialized)struct CLIOpenAIDashboardCacheTests {    @Test    func `cached dashboard restores when authority allows cached reuse`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(            email: "owner@example.com",            accountId: "acct-owner")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-owner"),                    normalizedEmail: "owner@example.com"),            ])        let dashboard = self.makeDashboard(email: "owner@example.com")        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "stale-route@example.com",            snapshot: dashboard))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: nil),            sourceLabel: "openai-web",            context: context)         #expect(restored == dashboard)    }     @Test    func `cached dashboard returns nil on display only and clears cache`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(email: "shared@example.com")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-alpha"),                    normalizedEmail: "shared@example.com"),                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-beta"),                    normalizedEmail: "shared@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "shared@example.com",            snapshot: self.makeDashboard(email: "shared@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "shared@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard returns nil on fail closed and clears cache`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(            email: "owner@example.com",            accountId: "acct-owner")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-other"),                    normalizedEmail: "owner@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "owner@example.com",            snapshot: self.makeDashboard(email: "owner@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard wrong email returns nil and clears cache`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(            email: "owner@example.com",            accountId: "acct-owner")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-owner"),                    normalizedEmail: "owner@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "other@example.com",            snapshot: self.makeDashboard(email: "other@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard provider account without scoped auth email fails closed`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(email: nil, accountId: "acct-owner")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-alpha"),                    normalizedEmail: "shared@example.com"),                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-beta"),                    normalizedEmail: "shared@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "shared@example.com",            snapshot: self.makeDashboard(email: "shared@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "shared@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard unresolved trusted continuity with competing owner returns nil`() {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let emptyHome = self.makeEmptyHome()        defer { try? FileManager.default.removeItem(at: emptyHome) }        let context = self.makeContext(            authHome: emptyHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-alpha"),                    normalizedEmail: "shared@example.com"),                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-beta"),                    normalizedEmail: "shared@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "shared@example.com",            snapshot: self.makeDashboard(email: "shared@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "shared@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard trusts codex cli usage continuity`() {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let emptyHome = self.makeEmptyHome()        defer { try? FileManager.default.removeItem(at: emptyHome) }        let context = self.makeContext(            authHome: emptyHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-owner"),                    normalizedEmail: "owner@example.com"),            ])        let dashboard = self.makeDashboard(email: "owner@example.com")        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "stale-route@example.com",            snapshot: dashboard))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == dashboard)    }     @Test    func `cached dashboard trusts oauth usage continuity`() {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let emptyHome = self.makeEmptyHome()        defer { try? FileManager.default.removeItem(at: emptyHome) }        let context = self.makeContext(            authHome: emptyHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-owner"),                    normalizedEmail: "owner@example.com"),            ])        let dashboard = self.makeDashboard(email: "owner@example.com")        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "stale-route@example.com",            snapshot: dashboard))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "oauth",            context: context)         #expect(restored == dashboard)    }     @Test    func `cached dashboard does not trust open A I web usage continuity`() {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let emptyHome = self.makeEmptyHome()        defer { try? FileManager.default.removeItem(at: emptyHome) }        let context = self.makeContext(            authHome: emptyHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-owner"),                    normalizedEmail: "owner@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "owner@example.com",            snapshot: self.makeDashboard(email: "owner@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "openai-web",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     @Test    func `cached dashboard ignores cached account email equality when authority rejects`() throws {        OpenAIDashboardCacheStore.clear()        defer { OpenAIDashboardCacheStore.clear() }         let authHome = try self.makeAuthHome(            email: "owner@example.com",            accountId: "acct-owner")        defer { try? FileManager.default.removeItem(at: authHome) }         let context = self.makeContext(            authHome: authHome,            knownOwners: [                CodexDashboardKnownOwnerCandidate(                    identity: .providerAccount(id: "acct-other"),                    normalizedEmail: "owner@example.com"),            ])        OpenAIDashboardCacheStore.save(OpenAIDashboardCache(            accountEmail: "owner@example.com",            snapshot: self.makeDashboard(email: "owner@example.com")))         let restored = CodexBarCLI.loadOpenAIDashboardIfAvailable(            usage: self.makeUsage(email: "owner@example.com"),            sourceLabel: "codex-cli",            context: context)         #expect(restored == nil)        #expect(OpenAIDashboardCacheStore.load() == nil)    }     private func makeContext(        authHome: URL?,        knownOwners: [CodexDashboardKnownOwnerCandidate]) -> ProviderFetchContext    {        let env = authHome.map { ["CODEX_HOME": $0.path] } ?? [:]        let browserDetection = BrowserDetection(cacheTTL: 0)        return ProviderFetchContext(            runtime: .cli,            sourceMode: .auto,            includeCredits: true,            webTimeout: 60,            webDebugDumpHTML: false,            verbose: false,            env: env,            settings: ProviderSettingsSnapshot.make(                codex: .init(                    usageDataSource: .auto,                    cookieSource: .auto,                    manualCookieHeader: nil,                    dashboardAuthorityKnownOwners: knownOwners)),            fetcher: UsageFetcher(environment: env),            claudeFetcher: ClaudeUsageFetcher(browserDetection: browserDetection),            browserDetection: browserDetection)    }     private func makeUsage(email: String?) -> UsageSnapshot {        UsageSnapshot(            primary: RateWindow(                usedPercent: 10,                windowMinutes: 300,                resetsAt: Date(timeIntervalSince1970: 7200),                resetDescription: nil),            secondary: nil,            updatedAt: Date(timeIntervalSince1970: 2000),            identity: ProviderIdentitySnapshot(                providerID: .codex,                accountEmail: email,                accountOrganization: nil,                loginMethod: nil))    }     private func makeDashboard(email: String) -> OpenAIDashboardSnapshot {        let creditEvents = [            CreditEvent(                date: Date(timeIntervalSince1970: 1000),                service: "codex",                creditsUsed: 3),        ]        return OpenAIDashboardSnapshot(            signedInEmail: email,            codeReviewRemainingPercent: 75,            codeReviewLimit: RateWindow(                usedPercent: 25,                windowMinutes: 60,                resetsAt: Date(timeIntervalSince1970: 3600),                resetDescription: nil),            creditEvents: creditEvents,            dailyBreakdown: OpenAIDashboardSnapshot.makeDailyBreakdown(from: creditEvents, maxDays: 30),            usageBreakdown: [],            creditsPurchaseURL: nil,            primaryLimit: RateWindow(                usedPercent: 10,                windowMinutes: 300,                resetsAt: Date(timeIntervalSince1970: 7200),                resetDescription: nil),            secondaryLimit: nil,            creditsRemaining: 42,            accountPlan: "pro",            updatedAt: Date(timeIntervalSince1970: 2000))    }     private func makeAuthHome(email: String?, accountId: String? = nil) throws -> URL {        let homeURL = FileManager.default.temporaryDirectory.appendingPathComponent(            UUID().uuidString,            isDirectory: true)        try self.writeCodexAuthFile(homeURL: homeURL, email: email, accountId: accountId)        return homeURL    }     private func makeEmptyHome() -> URL {        let homeURL = FileManager.default.temporaryDirectory.appendingPathComponent(            UUID().uuidString,            isDirectory: true)        try? FileManager.default.createDirectory(at: homeURL, withIntermediateDirectories: true)        return homeURL    }     private func writeCodexAuthFile(        homeURL: URL,        email: String?,        accountId: String?) throws    {        try FileManager.default.createDirectory(at: homeURL, withIntermediateDirectories: true)        var tokens: [String: Any] = [            "accessToken": "access-token",            "refreshToken": "refresh-token",            "idToken": Self.fakeJWT(email: email, accountId: accountId),        ]        if let accountId {            tokens["accountId"] = accountId        }        let auth = ["tokens": tokens]        let data = try JSONSerialization.data(withJSONObject: auth)        try data.write(to: homeURL.appendingPathComponent("auth.json"))    }     private static func fakeJWT(email: String?, accountId: String?) -> String {        let header = (try? JSONSerialization.data(withJSONObject: ["alg": "none"])) ?? Data()        var authClaims: [String: Any] = [            "chatgpt_plan_type": "pro",        ]        if let accountId {            authClaims["chatgpt_account_id"] = accountId        }        var claims: [String: Any] = [            "chatgpt_plan_type": "pro",            "https://api.openai.com/auth": authClaims,        ]        if let email {            claims["email"] = email        }        let payload = (try? JSONSerialization.data(withJSONObject: claims)) ?? Data()         func base64URL(_ data: Data) -> String {            data.base64EncodedString()                .replacingOccurrences(of: "=", with: "")                .replacingOccurrences(of: "+", with: "-")                .replacingOccurrences(of: "/", with: "_")        }         return "\(base64URL(header)).\(base64URL(payload))."    }}