chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CodexBarCore
|
||||
|
||||
@Suite(.serialized)
|
||||
struct CodexOpenAIWorkspaceResolverTests {
|
||||
@Test
|
||||
func `resolver returns workspace identity and sends expected headers`() async throws {
|
||||
defer {
|
||||
CodexOpenAIWorkspaceStubURLProtocol.handler = nil
|
||||
CodexOpenAIWorkspaceStubURLProtocol.requests = []
|
||||
}
|
||||
CodexOpenAIWorkspaceStubURLProtocol.requests = []
|
||||
|
||||
CodexOpenAIWorkspaceStubURLProtocol.handler = { request in
|
||||
let requestURL = try #require(request.url)
|
||||
let response = HTTPURLResponse(
|
||||
url: requestURL,
|
||||
statusCode: 200,
|
||||
httpVersion: nil,
|
||||
headerFields: nil)!
|
||||
let data = Data("""
|
||||
{
|
||||
"items": [
|
||||
{ "id": "account-live", "name": "Team Alpha" }
|
||||
]
|
||||
}
|
||||
""".utf8)
|
||||
return (response, data)
|
||||
}
|
||||
|
||||
let config = URLSessionConfiguration.ephemeral
|
||||
config.protocolClasses = [CodexOpenAIWorkspaceStubURLProtocol.self]
|
||||
let session = URLSession(configuration: config)
|
||||
let credentials = CodexOAuthCredentials(
|
||||
accessToken: "access-token",
|
||||
refreshToken: "refresh-token",
|
||||
idToken: nil,
|
||||
accountId: " account-live ",
|
||||
lastRefresh: nil)
|
||||
|
||||
let identity = try await CodexOpenAIWorkspaceResolver.resolve(credentials: credentials, session: session)
|
||||
|
||||
#expect(identity == CodexOpenAIWorkspaceIdentity(
|
||||
workspaceAccountID: "account-live",
|
||||
workspaceLabel: "Team Alpha"))
|
||||
#expect(CodexOpenAIWorkspaceStubURLProtocol.requests.count == 1)
|
||||
#expect(CodexOpenAIWorkspaceStubURLProtocol.requests.first?.value(forHTTPHeaderField: "Authorization")
|
||||
== "Bearer access-token")
|
||||
#expect(CodexOpenAIWorkspaceStubURLProtocol.requests.first?.value(forHTTPHeaderField: "ChatGPT-Account-Id")
|
||||
== "account-live")
|
||||
#expect(CodexOpenAIWorkspaceStubURLProtocol.requests.first?.value(forHTTPHeaderField: "User-Agent")
|
||||
== "codex-cli")
|
||||
}
|
||||
|
||||
@Test
|
||||
func `resolver default uses isolated authenticated transport`() async throws {
|
||||
let transport = ProviderHTTPTransportStub { request in
|
||||
#expect(request.cachePolicy == .reloadIgnoringLocalCacheData)
|
||||
let url = try #require(request.url)
|
||||
let response = try #require(HTTPURLResponse(
|
||||
url: url,
|
||||
statusCode: 200,
|
||||
httpVersion: nil,
|
||||
headerFields: ["Cache-Control": "public, max-age=300"]))
|
||||
return (Data(#"{"items":[{"id":"account-live","name":"Team Alpha"}]}"#.utf8), response)
|
||||
}
|
||||
let credentials = CodexOAuthCredentials(
|
||||
accessToken: "test-a",
|
||||
refreshToken: "test-r",
|
||||
idToken: nil,
|
||||
accountId: "account-live",
|
||||
lastRefresh: nil)
|
||||
|
||||
let identity = try await CodexAuthenticatedHTTPTransport.$overrideForTesting.withValue(transport) {
|
||||
try await CodexOpenAIWorkspaceResolver.resolve(credentials: credentials)
|
||||
}
|
||||
|
||||
#expect(identity?.workspaceLabel == "Team Alpha")
|
||||
#expect(await transport.requests().count == 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
func `resolver returns personal when account name is empty`() async throws {
|
||||
defer {
|
||||
CodexOpenAIWorkspaceStubURLProtocol.handler = nil
|
||||
CodexOpenAIWorkspaceStubURLProtocol.requests = []
|
||||
}
|
||||
CodexOpenAIWorkspaceStubURLProtocol.requests = []
|
||||
|
||||
CodexOpenAIWorkspaceStubURLProtocol.handler = { request in
|
||||
let requestURL = try #require(request.url)
|
||||
let response = HTTPURLResponse(
|
||||
url: requestURL,
|
||||
statusCode: 200,
|
||||
httpVersion: nil,
|
||||
headerFields: nil)!
|
||||
let data = Data("""
|
||||
{
|
||||
"items": [
|
||||
{ "id": "account-live", "name": " " }
|
||||
]
|
||||
}
|
||||
""".utf8)
|
||||
return (response, data)
|
||||
}
|
||||
|
||||
let config = URLSessionConfiguration.ephemeral
|
||||
config.protocolClasses = [CodexOpenAIWorkspaceStubURLProtocol.self]
|
||||
let session = URLSession(configuration: config)
|
||||
let credentials = CodexOAuthCredentials(
|
||||
accessToken: "access-token",
|
||||
refreshToken: "refresh-token",
|
||||
idToken: nil,
|
||||
accountId: "account-live",
|
||||
lastRefresh: nil)
|
||||
|
||||
let identity = try await CodexOpenAIWorkspaceResolver.resolve(credentials: credentials, session: session)
|
||||
|
||||
#expect(identity?.workspaceLabel == "Personal")
|
||||
}
|
||||
|
||||
@Test
|
||||
func `workspace identity cache persists and normalizes workspace ids`() throws {
|
||||
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||
defer { try? FileManager.default.removeItem(at: root) }
|
||||
let fileURL = root.appendingPathComponent("codex-openai-workspaces.json")
|
||||
|
||||
try CodexOpenAIWorkspaceIdentityCache.withFileURLOverrideForTesting(fileURL) {
|
||||
let cache = CodexOpenAIWorkspaceIdentityCache()
|
||||
try cache.store(CodexOpenAIWorkspaceIdentity(
|
||||
workspaceAccountID: " Account-Live ",
|
||||
workspaceLabel: "Team Alpha"))
|
||||
|
||||
#expect(cache.workspaceLabel(for: "account-live") == "Team Alpha")
|
||||
#expect(cache.workspaceLabel(for: " ACCOUNT-LIVE ") == "Team Alpha")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class CodexOpenAIWorkspaceStubURLProtocol: URLProtocol {
|
||||
nonisolated(unsafe) static var requests: [URLRequest] = []
|
||||
nonisolated(unsafe) static var handler: (@Sendable (URLRequest) throws -> (HTTPURLResponse, Data))?
|
||||
|
||||
override static func canInit(with request: URLRequest) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override static func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||
request
|
||||
}
|
||||
|
||||
override func startLoading() {
|
||||
Self.requests.append(self.request)
|
||||
guard let handler = Self.handler else {
|
||||
self.client?.urlProtocol(self, didFailWithError: URLError(.badServerResponse))
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let (response, data) = try handler(self.request)
|
||||
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
|
||||
self.client?.urlProtocol(self, didLoad: data)
|
||||
self.client?.urlProtocolDidFinishLoading(self)
|
||||
} catch {
|
||||
self.client?.urlProtocol(self, didFailWithError: error)
|
||||
}
|
||||
}
|
||||
|
||||
override func stopLoading() {}
|
||||
}
|
||||
Reference in New Issue
Block a user