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

1056 lines
44 KiB
Swift

import Foundation
import Testing
@testable import CodexBar
@testable import CodexBarCLI
@testable import CodexBarCore
#if os(macOS)
import SweetCookieKit
#endif
struct QoderProviderBehaviorTests {
@MainActor
private final class SessionQuotaNotifierSpy: SessionQuotaNotifying {
private(set) var posts: [(transition: SessionQuotaTransition, provider: UsageProvider)] = []
private(set) var quotaWarningPosts: [(
event: QuotaWarningEvent,
provider: UsageProvider,
soundEnabled: Bool,
onScreenAlertEnabled: Bool)] = []
func post(transition: SessionQuotaTransition, provider: UsageProvider, badge _: NSNumber?) {
self.posts.append((transition: transition, provider: provider))
}
func postQuotaWarning(
event: QuotaWarningEvent,
provider: UsageProvider,
soundEnabled: Bool,
onScreenAlertEnabled: Bool)
{
self.quotaWarningPosts.append((
event: event,
provider: provider,
soundEnabled: soundEnabled,
onScreenAlertEnabled: onScreenAlertEnabled))
}
}
private struct StubClaudeFetcher: ClaudeUsageFetching {
func loadLatestUsage(model _: String) async throws -> ClaudeUsageSnapshot {
throw ClaudeUsageError.parseFailed("stub")
}
func debugRawProbe(model _: String) async -> String {
"stub"
}
func detectVersion() -> String? {
nil
}
}
private final class Recorder: @unchecked Sendable {
private let lock = NSLock()
private var cookieHeaders: [String] = []
private var skippedLabels: [Set<String>] = []
private var sites: [QoderWebSite] = []
private var site: QoderWebSite?
func appendCookieHeader(_ value: String) {
self.lock.withLock {
self.cookieHeaders.append(value)
}
}
func appendSkippedLabels(_ value: Set<String>) {
self.lock.withLock {
self.skippedLabels.append(value)
}
}
func setSite(_ value: QoderWebSite) {
self.lock.withLock {
self.site = value
}
}
func appendSite(_ value: QoderWebSite) {
self.lock.withLock {
self.sites.append(value)
self.site = value
}
}
func cookieHeadersSnapshot() -> [String] {
self.lock.withLock { self.cookieHeaders }
}
func skippedLabelsSnapshot() -> [Set<String>] {
self.lock.withLock { self.skippedLabels }
}
func siteSnapshot() -> QoderWebSite? {
self.lock.withLock { self.site }
}
func sitesSnapshot() -> [QoderWebSite] {
self.lock.withLock { self.sites }
}
}
@Test
func `token account selection forces manual cookie source in CLI settings snapshot`() throws {
let accounts = ProviderTokenAccountData(
version: 1,
accounts: [
ProviderTokenAccount(
id: UUID(),
label: "Qoder",
token: "sid=qoder-account-token",
addedAt: 0,
lastUsed: nil),
],
activeIndex: 0)
let config = CodexBarConfig(providers: [
ProviderConfig(
id: .qoder,
cookieSource: .auto,
tokenAccounts: accounts),
])
let selection = TokenAccountCLISelection(label: nil, index: nil, allAccounts: false)
let tokenContext = try TokenAccountCLIContext(selection: selection, config: config, verbose: false)
let account = try #require(tokenContext.resolvedAccounts(for: .qoder).first)
let snapshot = try #require(tokenContext.settingsSnapshot(for: .qoder, account: account))
let qoderSettings = try #require(snapshot.qoder)
#expect(qoderSettings.cookieSource == .manual)
#expect(qoderSettings.manualCookieHeader == "sid=qoder-account-token")
}
@Test
func `model shows credit total only as primary detail when reset date missing`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.qoder])
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 25,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "125 / 500 credits"),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .qoder,
accountEmail: nil,
accountOrganization: nil,
loginMethod: nil))
let model = UsageMenuCardView.Model.make(.init(
provider: .qoder,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let primary = try #require(model.metrics.first)
#expect(primary.resetText == nil)
#expect(primary.detailText == "125 / 500 credits")
#expect(model.creditsText == nil)
#expect(model.creditsHintText == nil)
}
@Test
func `model shows reset countdown with credit detail`() throws {
let now = Date(timeIntervalSince1970: 1_719_206_400)
let snapshot = QoderUsageSnapshot(
usedCredits: 125,
totalCredits: 500,
remainingCredits: 375,
usagePercentage: 25,
unit: "credit",
resetsAt: now.addingTimeInterval(86400),
updatedAt: now).toUsageSnapshot()
let metadata = try #require(ProviderDefaults.metadata[.qoder])
let model = UsageMenuCardView.Model.make(.init(
provider: .qoder,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let primary = try #require(model.metrics.first)
#expect(primary.resetText != nil)
#expect(primary.detailText == "125 / 500 credits")
}
@MainActor
@Test
func `standard menu shows credit total as detail instead of reset line`() throws {
let suite = "QoderProviderBehaviorTests-menu-detail"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
let settings = SettingsStore(
userDefaults: defaults,
configStore: testConfigStore(suiteName: suite),
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore())
settings.statusChecksEnabled = false
settings.usageBarsShowUsed = false
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings)
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 25,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "125 / 500 credits"),
secondary: nil,
tertiary: nil,
updatedAt: Date(),
identity: ProviderIdentitySnapshot(
providerID: .qoder,
accountEmail: nil,
accountOrganization: nil,
loginMethod: nil))
store._setSnapshotForTesting(snapshot, provider: .qoder)
let descriptor = MenuDescriptor.build(
provider: .qoder,
store: store,
settings: settings,
account: AccountInfo(email: nil, plan: nil),
updateReady: false,
includeContextualActions: false)
let textLines = descriptor.sections
.flatMap(\.entries)
.compactMap { entry -> String? in
guard case let .text(text, _) = entry else { return nil }
return text
}
#expect(textLines.contains("125 / 500 credits"))
#expect(!textLines.contains(where: { $0.contains("Resets 125 / 500 credits") }))
}
}
struct QoderManualCookieRoutingTests {
@Test
func `manual cookie header can route to Qoder China site`() {
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=abc") == .international)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=qoder.com.cn-looking-value") == .international)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "sid=abc; note=curl https://qoder.com.cn") == .international)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "sid=abc; redirect=https://example.com/curl") == .international)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=abc; Domain=.qoder.com.cn") == .china)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=abc; Domain=qoder.com.cn") == .china)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=abc; Domain=www.qoder.com.cn") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl https://qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "HTTPS_PROXY=http://127.0.0.1:8080 curl https://qoder.com.cn") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"HTTPS_PROXY=http://127.0.0.1:8080 \\\ncurl https://qoder.com.cn -H 'Cookie: sid=abc'") ==
.china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "\\\ncurl https://qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "\\\r\ncurl https://qoder.com -H 'Cookie: sid=abc'") == .international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H 'Origin: https://qoder.com' " +
"-H 'Referer: https://qoder.com/account/usage' -H 'Cookie: sid=abc'") == .international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Origin: https://qoder.com.cn' " +
"-H 'Referer: https://qoder.com.cn/account/usage' -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl https://www.qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl --url https://qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl --url https://qoder.com --data 'x=1; Domain=qoder.com.cn'") ==
.international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --data 'GET /account/usage HTTP/1.1\nHost: qoder.com.cn'") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "GET https://qoder.com.cn/account/usage") == .china)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn") ==
.china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: www.qoder.com.cn") ==
.china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn:443") ==
.china)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn:evil") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn:") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn:65536") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com.cn:443:444") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: qoder.com") ==
.international)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "TRACE /account/usage HTTP/1.1\nHost: qoder.com.cn") ==
nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "CONNECT qoder.com.cn:443 HTTP/1.1") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "BREW /account/usage HTTP/1.1\nHost: qoder.com.cn") ==
nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl -H 'Referer: https://qoder.com.cn/account/usage' https://qoder.com -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl --proxy-header 'X: https://qoder.com.cn' https://qoder.com -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "curl -X GET https://qoder.com.cn") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sudo curl https://qoder.com.cn") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "sid=abc; curl https://qoder.com.cn") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl https://qoder.com/account https://qoder.com/profile") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl --url https://qoder.com/account https://qoder.com/profile") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl https://qoder.com https://qoder.com.cn -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "curl https://example.com -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET https://qoder.com/account/usage HTTP/1.1\nHost: qoder.com.cn") == nil)
#expect(QoderWebFetchStrategy
.site(forManualCookieHeader: "GET https://qoder.com/account/usage HTTP/1.1\nHost: example.com") == nil)
#expect(QoderWebFetchStrategy.site(forManualCookieHeader: "GET /account/usage HTTP/1.1\nHost: example.com") ==
nil)
}
@Test
func `manual curl Host headers must match authoritative Qoder target`() {
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H 'Host: qoder.com' -H 'Cookie: sid=abc'") == .international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host: www.qoder.com.cn:443' -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -sH 'Host: qoder.com.cn' -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -fsSLHHost:qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -HHost:qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn --header=Host:qoder.com.cn -H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn \\\n-H 'Host: qoder.com.cn' \\\r\n-H 'Cookie: sid=abc'") == .china)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H 'Host: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host: qoder.com' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host: qoder.com.cn:evil' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host: qoder.com.cn' -H 'Host: qoder.com' -H 'Cookie: sid=abc'") ==
nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -sH 'Host: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -fsSLHHost:qoder.com.cn -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -HHost:qoder.com.cn -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -XH 'Host: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H @headers.txt -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --header @- -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host:' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -H 'Host;' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn --header=Host\\; -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -sHHost\\; -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn -K qoder.curlrc -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn --config qoder.curlrc -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn --config=qoder.curlrc -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --variable site=qoder.com.cn --expand-header 'Host: {{site}}' " +
"-H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --variable site=qoder.com.cn --expand-url 'https://{{site}}' " +
"-H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn --expand-config '{{config}}' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn ; echo -H 'Cookie: sid=global'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn | cat -H 'Cookie: sid=global'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com.cn > headers.txt -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com && echo done -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl 'https://qoder.com/account/usage?a=1&b=2;next=ok' -H 'Cookie: sid=abc'") ==
.international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H 'X-Note: a;b|c&d=<e>' -H 'Cookie: sid=abc'") == .international)
}
@Test
func `manual curl rejects shell synthesis and injected controls`() {
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --location-trusted -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A $'agent\r\nHost: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com --referer $'https://qoder.com\r\nHost: qoder.com.cn' " +
"-H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A \\'$'agent\\r\\nHost: qoder.com.cn'\\' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A \\'$'agent\r\nHost: qoder.com.cn'\\' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H 'User-Agent: agent\\\nHost: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A $'agent\\r\\nHost: qoder.com.cn' -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A $(printf agent) -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A `printf agent` -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A $AGENT -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"\"curl\" https://qoder.com.cn -A $AGENT -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"'/usr/bin/curl' https://qoder.com.cn -A $AGENT -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"\\curl https://qoder.com.cn -A $AGENT -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"QODER_AGENT=$AGENT \\\ncurl https://qoder.com.cn -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H \"User-Agent: $AGENT\" -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A $\"agent\" -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -H @<(printf 'Host: qoder.com.cn') -H 'Cookie: sid=abc'") == nil)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A \\'literal\\' -H 'Cookie: sid=abc'") == .international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A \\\"literal\\\" -H 'Cookie: sid=abc'") == .international)
#expect(QoderWebFetchStrategy
.site(
forManualCookieHeader:
"curl https://qoder.com -A literal\\\\slash -H 'Cookie: sid=abc'") == .international)
}
}
extension QoderProviderBehaviorTests {
#if os(macOS)
@Test
func `importer exact domain filter keeps China cookies out of global sessions`() {
let records = [
Self.cookieRecord(domain: "qoder.com", name: "global", value: "1"),
Self.cookieRecord(domain: ".qoder.com.cn", name: "china", value: "1"),
Self.cookieRecord(domain: "www.qoder.com.cn", name: "china-www", value: "1"),
]
let filtered = QoderCookieImporter.records(records, for: .international)
#expect(QoderCookieImporter.cookieQuery(for: .international).domainMatch == .exact)
#expect(filtered.map(\.name) == ["global"])
}
@Test
func `importer exact domain filter keeps global cookies out of China sessions`() {
let records = [
Self.cookieRecord(domain: ".qoder.com", name: "global", value: "1"),
Self.cookieRecord(domain: "qoder.com.cn", name: "china", value: "1"),
Self.cookieRecord(domain: ".www.qoder.com.cn", name: "china-www", value: "1"),
]
let filtered = QoderCookieImporter.records(records, for: .china)
#expect(QoderCookieImporter.cookieQuery(for: .china).domainMatch == .exact)
#expect(filtered.map(\.name) == ["china", "china-www"])
}
#endif
@Test
func `auto cookie fetch retries every imported candidate before succeeding`() async throws {
let candidates = [
QoderResolvedCookie(cookieHeader: "sid=expired-one", sourceLabel: "Chrome Default / qoder.com"),
QoderResolvedCookie(cookieHeader: "sid=expired-two", sourceLabel: "Chrome Profile 2 / qoder.com.cn"),
QoderResolvedCookie(cookieHeader: "sid=valid", sourceLabel: "Chrome Profile 3 / qoder.com.cn"),
]
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { cookieHeader, _, _ in
recorder.appendCookieHeader(cookieHeader)
if cookieHeader != "sid=valid" {
throw QoderUsageError.invalidCredentials
}
return QoderUsageSnapshot(
usedCredits: 125,
totalCredits: 500,
remainingCredits: 375,
usagePercentage: 25,
unit: "credit")
},
cookieResolver: { _, _, skippedLabels in
recorder.appendSkippedLabels(skippedLabels)
return candidates.first { !skippedLabels.contains($0.sourceLabel) }
})
let result = try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(cookieSource: .auto, manualCookieHeader: nil))))
#expect(recorder.cookieHeadersSnapshot() == ["sid=expired-one", "sid=expired-two", "sid=valid"])
#expect(recorder.skippedLabelsSnapshot() == [
Set<String>(),
["Chrome Default / qoder.com"],
["Chrome Default / qoder.com", "Chrome Profile 2 / qoder.com.cn"],
])
#expect(result.sourceLabel == "Chrome Profile 3 / qoder.com.cn")
#expect(result.usage.primary?.resetDescription == "125 / 500 credits")
}
@Test
func `auto cookie source label trusts authoritative suffix over browser label text`() async throws {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.appendSite(site)
return QoderUsageSnapshot(
usedCredits: 125,
totalCredits: 500,
remainingCredits: 375,
usagePercentage: 25,
unit: "credit")
},
cookieResolver: { _, _, _ in
QoderResolvedCookie(
cookieHeader: "sid=global",
sourceLabel: "Chrome Profile qoder.com.cn / qoder.com")
})
let result = try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(cookieSource: .auto, manualCookieHeader: nil))))
#expect(recorder.sitesSnapshot() == [.international])
#expect(result.sourceLabel == "Chrome Profile qoder.com.cn / qoder.com")
}
@Test
func `auto cookie fetch retries freshly imported session after stale cache`() async throws {
let sourceLabel = "Chrome Default / qoder.com"
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { cookieHeader, _, _ in
recorder.appendCookieHeader(cookieHeader)
if cookieHeader == "sid=expired-cache" {
throw QoderUsageError.invalidCredentials
}
return QoderUsageSnapshot(
usedCredits: 125,
totalCredits: 500,
remainingCredits: 375,
usagePercentage: 25,
unit: "credit")
},
cookieResolver: { _, allowCached, skippedLabels in
recorder.appendSkippedLabels(skippedLabels)
if allowCached {
return QoderResolvedCookie(
cookieHeader: "sid=expired-cache",
sourceLabel: sourceLabel,
isFromCache: true)
}
return QoderResolvedCookie(cookieHeader: "sid=fresh", sourceLabel: sourceLabel)
})
let result = try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(cookieSource: .auto, manualCookieHeader: nil))))
#expect(recorder.cookieHeadersSnapshot() == ["sid=expired-cache", "sid=fresh"])
#expect(recorder.skippedLabelsSnapshot() == [Set<String>(), Set<String>()])
#expect(result.sourceLabel == sourceLabel)
}
@Test
func `manual cookie fetch uses China endpoint when header identifies China site`() async throws {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.setSite(site)
return QoderUsageSnapshot(
usedCredits: 0,
totalCredits: 300,
remainingCredits: 300,
usagePercentage: 0,
unit: "credit")
})
let result = try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "curl https://qoder.com.cn -H 'Cookie: sid=china'"))))
#expect(recorder.siteSnapshot() == .china)
#expect(result.sourceLabel == "manual / qoder.com.cn")
}
@Test
func `manual cookie value that looks like China domain stays on global endpoint`() async throws {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.appendSite(site)
return QoderUsageSnapshot(
usedCredits: 0,
totalCredits: 300,
remainingCredits: 300,
usagePercentage: 0,
unit: "credit")
})
let result = try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "sid=qoder.com.cn-looking-value"))))
#expect(recorder.sitesSnapshot() == [.international])
#expect(result.sourceLabel == "manual / qoder.com")
}
@Test
func `manual request-like cookie with ambiguous target fails before request`() async {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.appendSite(site)
return QoderUsageSnapshot(
usedCredits: 0,
totalCredits: 300,
remainingCredits: 300,
usagePercentage: 0,
unit: "credit")
})
await #expect(throws: QoderUsageError.invalidCredentials) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "curl --proxy-header 'X: https://qoder.com.cn' https://qoder.com"))))
}
#expect(recorder.sitesSnapshot().isEmpty)
}
@Test
func `manual curl with appended command does not resolve cookie or send request`() async {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { cookieHeader, site, _ in
recorder.appendCookieHeader(cookieHeader)
recorder.appendSite(site)
return QoderUsageSnapshot(
usedCredits: 0,
totalCredits: 300,
remainingCredits: 300,
usagePercentage: 0,
unit: "credit")
})
await #expect(throws: QoderUsageError.invalidCredentials) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "curl https://qoder.com.cn ; echo -H 'Cookie: sid=global'"))))
}
#expect(recorder.cookieHeadersSnapshot().isEmpty)
#expect(recorder.sitesSnapshot().isEmpty)
}
@Test
func `manual plain cookie fetch does not retry China after global auth failure`() async {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.appendSite(site)
throw QoderUsageError.invalidCredentials
})
await #expect(throws: QoderUsageError.invalidCredentials) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "sid=plain-cookie"))))
}
#expect(recorder.sitesSnapshot() == [.international])
}
@Test
func `manual plain cookie fetch does not retry China after global network failure`() async {
let recorder = Recorder()
let strategy = QoderWebFetchStrategy(
usageLoader: { _, site, _ in
recorder.appendSite(site)
throw QoderUsageError.networkError("timed out")
})
await #expect(throws: QoderUsageError.networkError("timed out")) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "sid=plain-cookie"))))
}
#expect(recorder.sitesSnapshot() == [.international])
}
@Test
func `auto cookie fetch preserves invalid credentials when fresh import is exhausted`() async {
let strategy = QoderWebFetchStrategy(
usageLoader: { _, _, _ in
throw QoderUsageError.invalidCredentials
},
cookieResolver: { _, allowCached, _ in
if allowCached {
return QoderResolvedCookie(
cookieHeader: "sid=expired-cache",
sourceLabel: "Chrome Default / qoder.com",
isFromCache: true)
}
throw QoderUsageError.missingCredentials
})
await #expect(throws: QoderUsageError.invalidCredentials) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .auto,
manualCookieHeader: nil))))
}
}
@Test
func `auto cookie fetch preserves terminal non auth error when fresh import is exhausted`() async {
let strategy = QoderWebFetchStrategy(
usageLoader: { _, _, _ in
throw QoderUsageError.networkError("global timed out")
},
cookieResolver: { _, allowCached, _ in
if allowCached {
return QoderResolvedCookie(
cookieHeader: "sid=stale-cache",
sourceLabel: "Chrome Default / qoder.com",
isFromCache: true)
}
throw QoderUsageError.missingCredentials
})
await #expect(throws: QoderUsageError.networkError("global timed out")) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .auto,
manualCookieHeader: nil))))
}
}
@Test
func `auto cookie fetch preserves terminal non auth error when later candidate also fails`() async {
let candidates = [
QoderResolvedCookie(cookieHeader: "sid=global", sourceLabel: "Chrome Default / qoder.com"),
QoderResolvedCookie(cookieHeader: "sid=china", sourceLabel: "Chrome Default / qoder.com.cn"),
]
let strategy = QoderWebFetchStrategy(
usageLoader: { cookieHeader, _, _ in
if cookieHeader == "sid=global" {
throw QoderUsageError.networkError("timed out")
}
throw QoderUsageError.apiError(503)
},
cookieResolver: { _, _, skippedLabels in
candidates.first { !skippedLabels.contains($0.sourceLabel) }
})
await #expect(throws: QoderUsageError.apiError(503)) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .auto,
manualCookieHeader: nil))))
}
}
@Test
func `auto cookie fetch preserves later non auth error after auth failure`() async {
let candidates = [
QoderResolvedCookie(cookieHeader: "sid=global", sourceLabel: "Chrome Default / qoder.com"),
QoderResolvedCookie(cookieHeader: "sid=china", sourceLabel: "Chrome Default / qoder.com.cn"),
]
let strategy = QoderWebFetchStrategy(
usageLoader: { cookieHeader, _, _ in
if cookieHeader == "sid=global" {
throw QoderUsageError.invalidCredentials
}
throw QoderUsageError.networkError("china timed out")
},
cookieResolver: { _, _, skippedLabels in
candidates.first { !skippedLabels.contains($0.sourceLabel) }
})
await #expect(throws: QoderUsageError.networkError("china timed out")) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .auto,
manualCookieHeader: nil))))
}
}
@Test
func `manual plain cookie fetch reports invalid credentials when every candidate is auth failure`() async {
let strategy = QoderWebFetchStrategy(
usageLoader: { _, _, _ in
throw QoderUsageError.invalidCredentials
})
await #expect(throws: QoderUsageError.invalidCredentials) {
try await strategy.fetch(self.makeContext(settings: .make(
qoder: .init(
cookieSource: .manual,
manualCookieHeader: "sid=plain-cookie"))))
}
}
@Test
@MainActor
func `monthly credits keep nil cadence and do not emit quota notifications`() throws {
let suiteName = "QoderProviderBehaviorTests-quota-notifications"
let defaults = try #require(UserDefaults(suiteName: suiteName))
defaults.removePersistentDomain(forName: suiteName)
let settings = SettingsStore(
userDefaults: defaults,
configStore: testConfigStore(suiteName: suiteName),
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore())
settings.refreshFrequency = .manual
settings.statusChecksEnabled = false
settings.sessionQuotaNotificationsEnabled = true
settings.quotaWarningNotificationsEnabled = true
settings.quotaWarningThresholds = [50, 20]
let notifier = SessionQuotaNotifierSpy()
let store = UsageStore(
fetcher: UsageFetcher(),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings,
sessionQuotaNotifier: notifier)
let depletedSnapshot = QoderUsageSnapshot(
usedCredits: 500,
totalCredits: 500,
remainingCredits: 0,
usagePercentage: 100,
unit: "credit",
resetsAt: Date().addingTimeInterval(30 * 24 * 60 * 60))
.toUsageSnapshot()
let restoredSnapshot = QoderUsageSnapshot(
usedCredits: 100,
totalCredits: 500,
remainingCredits: 400,
usagePercentage: 20,
unit: "credit",
resetsAt: Date().addingTimeInterval(30 * 24 * 60 * 60))
.toUsageSnapshot()
let restoredPrimary = try #require(restoredSnapshot.primary)
#expect(depletedSnapshot.primary?.windowMinutes == nil)
#expect(restoredPrimary.windowMinutes == nil)
#expect(store.weeklyPace(provider: .qoder, window: restoredPrimary, now: Date()) == nil)
for snapshot in [depletedSnapshot, restoredSnapshot] {
store.handleSessionQuotaTransition(provider: .qoder, snapshot: snapshot)
store.handleQuotaWarningTransitions(provider: .qoder, snapshot: snapshot)
}
#expect(notifier.posts.isEmpty)
#expect(notifier.quotaWarningPosts.isEmpty)
}
private func makeContext(settings: ProviderSettingsSnapshot?) -> ProviderFetchContext {
let env: [String: String] = [:]
return ProviderFetchContext(
runtime: .app,
sourceMode: .auto,
includeCredits: false,
webTimeout: 1,
webDebugDumpHTML: false,
verbose: false,
env: env,
settings: settings,
fetcher: UsageFetcher(environment: env),
claudeFetcher: StubClaudeFetcher(),
browserDetection: BrowserDetection(cacheTTL: 0))
}
#if os(macOS)
private static func cookieRecord(domain: String, name: String, value: String) -> BrowserCookieRecord {
BrowserCookieRecord(
domain: domain,
name: name,
path: "/",
value: value,
expires: Date(timeIntervalSince1970: 1_900_000_000),
isSecure: true,
isHTTPOnly: true)
}
#endif
}