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

133 lines
5.4 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@Suite(.serialized)
struct CodexSystemAccountObserverTests {
@Test
func `observer reads ambient CODEX_HOME when present`() throws {
let home = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: home) }
try Self.writeCodexAuthFile(
homeURL: home,
email: " LIVE@Example.com ",
plan: "pro",
accountId: "account-live")
let observer = DefaultCodexSystemAccountObserver()
let account = try observer.loadSystemAccount(environment: ["CODEX_HOME": home.path])
#expect(account?.email == "live@example.com")
#expect(account?.codexHomePath == home.path)
#expect(account?.identity == .providerAccount(id: "account-live"))
}
@Test
func `observer falls back to nil when ambient home has no readable email`() throws {
let home = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: home) }
try FileManager.default.createDirectory(at: home, withIntermediateDirectories: true)
let observer = DefaultCodexSystemAccountObserver()
let account = try observer.loadSystemAccount(environment: ["CODEX_HOME": home.path])
#expect(account == nil)
}
@Test
func `observer records observation timestamp`() throws {
let home = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: home) }
try Self.writeCodexAuthFile(homeURL: home, email: "user@example.com", plan: "team")
let before = Date()
let observer = DefaultCodexSystemAccountObserver()
let account = try observer.loadSystemAccount(environment: ["CODEX_HOME": home.path])
let observed = try #require(account)
#expect(observed.observedAt >= before)
}
@Test
func `observer preserves provider account identity from scoped auth`() throws {
let home = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: home) }
try Self.writeCodexAuthFile(
homeURL: home,
email: "user@example.com",
plan: "team",
accountId: "account-live-123")
let observer = DefaultCodexSystemAccountObserver()
let account = try #require(try observer.loadSystemAccount(environment: ["CODEX_HOME": home.path]))
#expect(account.identity == .providerAccount(id: "account-live-123"))
}
@Test
func `observer uses cached workspace label for provider account`() throws {
let home = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
let cacheURL = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-openai-workspaces-\(UUID().uuidString).json")
defer {
try? FileManager.default.removeItem(at: home)
try? FileManager.default.removeItem(at: cacheURL)
}
try Self.writeCodexAuthFile(
homeURL: home,
email: "user@example.com",
plan: "team",
accountId: "account-live-123")
try CodexOpenAIWorkspaceIdentityCache.withFileURLOverrideForTesting(cacheURL) {
try CodexOpenAIWorkspaceIdentityCache().store(CodexOpenAIWorkspaceIdentity(
workspaceAccountID: "account-live-123",
workspaceLabel: "Team Alpha"))
let observer = DefaultCodexSystemAccountObserver()
let account = try #require(try observer.loadSystemAccount(environment: ["CODEX_HOME": home.path]))
#expect(account.workspaceAccountID == "account-live-123")
#expect(account.workspaceLabel == "Team Alpha")
}
}
private static func writeCodexAuthFile(
homeURL: URL,
email: String,
plan: String,
accountId: String? = nil) throws
{
try FileManager.default.createDirectory(at: homeURL, withIntermediateDirectories: true)
var tokens: [String: Any] = [
"accessToken": "access-token",
"refreshToken": "refresh-token",
"idToken": Self.fakeJWT(email: email, plan: plan),
]
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, plan: String) -> String {
let header = (try? JSONSerialization.data(withJSONObject: ["alg": "none"])) ?? Data()
let payload = (try? JSONSerialization.data(withJSONObject: [
"email": email,
"chatgpt_plan_type": plan,
])) ?? Data()
func base64URL(_ data: Data) -> String {
data.base64EncodedString()
.replacingOccurrences(of: "=", with: "")
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
}
return "\(base64URL(header)).\(base64URL(payload))."
}
}