chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CodexBarCore
|
||||
|
||||
@Suite(.serialized)
|
||||
struct ClaudeOAuthDelegatedRefreshLinuxTests {
|
||||
private actor Counter {
|
||||
private var value = 0
|
||||
|
||||
func increment() {
|
||||
self.value += 1
|
||||
}
|
||||
|
||||
func current() -> Int {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
private actor VersionDetectionCapture {
|
||||
private var value: Bool?
|
||||
|
||||
func record(_ value: Bool) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
func current() -> Bool? {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func cliOAuthSkipsVersionDetectionWhileAppPreservesIt() async throws {
|
||||
#expect(try await self.detectsClaudeVersion(runtime: .cli) == false)
|
||||
#expect(try await self.detectsClaudeVersion(runtime: .app) == true)
|
||||
}
|
||||
|
||||
@Test
|
||||
func cliOAuthDoesNotDelegateRefreshEvenForUserAction() async {
|
||||
let result = await self.runDelegatedRefresh(
|
||||
runtime: .cli,
|
||||
interaction: .userInitiated,
|
||||
promptMode: .always)
|
||||
|
||||
#expect(result.attempts == 0)
|
||||
#expect(result.message.contains("CodexBar CLI does not launch Claude"))
|
||||
}
|
||||
|
||||
@Test
|
||||
func appOAuthPreservesUserInitiatedDelegatedRefresh() async {
|
||||
let result = await self.runDelegatedRefresh(
|
||||
runtime: .app,
|
||||
interaction: .userInitiated,
|
||||
promptMode: .onlyOnUserAction)
|
||||
|
||||
#expect(result.attempts == 1)
|
||||
#expect(result.message.contains("still unavailable after delegated Claude CLI refresh"))
|
||||
}
|
||||
|
||||
@Test
|
||||
func appOAuthBackgroundRespectsPlatformKeychainPromptPolicy() async {
|
||||
let result = await self.runDelegatedRefresh(
|
||||
runtime: .app,
|
||||
interaction: .background,
|
||||
promptMode: .onlyOnUserAction)
|
||||
|
||||
#expect(result.attempts == 0)
|
||||
#expect(result.message.contains("background repair is suppressed"))
|
||||
}
|
||||
|
||||
private func runDelegatedRefresh(
|
||||
runtime: ProviderRuntime,
|
||||
interaction: ProviderInteraction,
|
||||
promptMode: ClaudeOAuthKeychainPromptMode) async -> (attempts: Int, message: String)
|
||||
{
|
||||
let counter = Counter()
|
||||
let fetcher = ClaudeUsageFetcher(
|
||||
browserDetection: BrowserDetection(cacheTTL: 0),
|
||||
environment: [:],
|
||||
runtime: runtime,
|
||||
dataSource: .oauth)
|
||||
let credentialsOverride: @Sendable (
|
||||
[String: String],
|
||||
Bool,
|
||||
Bool) async throws -> ClaudeOAuthCredentials = { _, _, _ in
|
||||
throw ClaudeOAuthCredentialsError.refreshDelegatedToClaudeCLI
|
||||
}
|
||||
let delegatedOverride: @Sendable (
|
||||
Date,
|
||||
TimeInterval,
|
||||
[String: String]) async -> ClaudeOAuthDelegatedRefreshCoordinator.Outcome = { _, _, _ in
|
||||
await counter.increment()
|
||||
return .attemptedSucceeded
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try await ClaudeOAuthKeychainPromptPreference.withTaskOverrideForTesting(promptMode) {
|
||||
try await ProviderInteractionContext.$current.withValue(interaction) {
|
||||
try await ClaudeUsageFetcher.$loadOAuthCredentialsOverride
|
||||
.withValue(credentialsOverride) {
|
||||
try await ClaudeUsageFetcher.$delegatedRefreshAttemptOverride
|
||||
.withValue(delegatedOverride) {
|
||||
try await fetcher.loadLatestUsage(model: "sonnet")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Issue.record("Expected delegated-refresh path to fail with mocked stale credentials")
|
||||
return (await counter.current(), "")
|
||||
} catch let error as ClaudeUsageError {
|
||||
guard case let .oauthFailed(message) = error else {
|
||||
Issue.record("Expected ClaudeUsageError.oauthFailed, got \(error)")
|
||||
return (await counter.current(), "")
|
||||
}
|
||||
return (await counter.current(), message)
|
||||
} catch {
|
||||
Issue.record("Expected ClaudeUsageError, got \(error)")
|
||||
return (await counter.current(), "")
|
||||
}
|
||||
}
|
||||
|
||||
private func detectsClaudeVersion(runtime: ProviderRuntime) async throws -> Bool {
|
||||
let capture = VersionDetectionCapture()
|
||||
let fetcher = ClaudeUsageFetcher(
|
||||
browserDetection: BrowserDetection(cacheTTL: 0),
|
||||
environment: [:],
|
||||
runtime: runtime,
|
||||
dataSource: .oauth)
|
||||
let credentialsOverride: @Sendable (
|
||||
[String: String],
|
||||
Bool,
|
||||
Bool) async throws -> ClaudeOAuthCredentials = { _, _, _ in
|
||||
ClaudeOAuthCredentials(
|
||||
accessToken: "access-token",
|
||||
refreshToken: nil,
|
||||
expiresAt: Date(timeIntervalSinceNow: 3600),
|
||||
scopes: ["user:profile"],
|
||||
rateLimitTier: nil)
|
||||
}
|
||||
let fetchOverride: @Sendable (String, Bool) async throws -> OAuthUsageResponse = {
|
||||
_, detectClaudeVersion in
|
||||
await capture.record(detectClaudeVersion)
|
||||
return try Self.makeOAuthUsageResponse()
|
||||
}
|
||||
|
||||
_ = try await ClaudeUsageFetcher.$loadOAuthCredentialsOverride.withValue(credentialsOverride) {
|
||||
try await ClaudeUsageFetcher.$fetchOAuthUsageOverride.withValue(fetchOverride) {
|
||||
try await fetcher.loadLatestUsage(model: "sonnet")
|
||||
}
|
||||
}
|
||||
|
||||
guard let value = await capture.current() else {
|
||||
Issue.record("Expected OAuth fetch to report its version-detection policy")
|
||||
return false
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private static func makeOAuthUsageResponse() throws -> OAuthUsageResponse {
|
||||
let json = """
|
||||
{
|
||||
"five_hour": { "utilization": 7, "resets_at": "2025-12-23T16:00:00.000Z" },
|
||||
"seven_day": { "utilization": 21, "resets_at": "2025-12-29T23:00:00.000Z" }
|
||||
}
|
||||
"""
|
||||
return try ClaudeOAuthUsageFetcher._decodeUsageResponseForTesting(Data(json.utf8))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user