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

275 lines
10 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@testable import CodexBarCLI
struct ClawRouterUsageFetcherTests {
@Test
func `parses monthly budget and provider agnostic usage`() throws {
let parsed = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.budgetedResponse.utf8),
updatedAt: Date(timeIntervalSince1970: 1))
#expect(parsed.budgetLimitUSD == 25)
#expect(parsed.budgetSpentUSD == 0.006)
#expect(parsed.budgetRemainingUSD == 24.994)
#expect(parsed.requestCount == 6)
#expect(parsed.totalTokens == 54191)
#expect(parsed.providers.map(\.provider) == ["openai", "anthropic"])
let snapshot = parsed.toUsageSnapshot()
#expect(snapshot.identity?.providerID == .clawrouter)
#expect(snapshot.primary?.usedPercent == 0.024)
#expect(snapshot.secondary == nil)
#expect(snapshot.providerCost?.used == 0.006)
#expect(snapshot.providerCost?.limit == 25)
#expect(snapshot.clawRouterUsage?.providers.map(\.provider) == ["openai", "anthropic"])
#expect(snapshot.dataConfidence == .exact)
let reset = try #require(snapshot.primary?.resetsAt)
let expected = try #require(DateComponents(
calendar: Calendar(identifier: .gregorian),
timeZone: TimeZone(secondsFromGMT: 0),
year: 2026,
month: 8,
day: 1).date)
#expect(reset == expected)
}
@Test
func `supports unmetered policies and arbitrary providers`() throws {
let parsed = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.unmeteredResponse.utf8),
updatedAt: Date(timeIntervalSince1970: 1))
let snapshot = parsed.toUsageSnapshot()
#expect(!parsed.budgetConfigured)
#expect(parsed.providers.map(\.provider) == ["replicate", "tavily"])
#expect(snapshot.primary == nil)
#expect(snapshot.identity?.loginMethod == "Unmetered")
#expect(snapshot.providerCost?.used == 1.25)
#expect(snapshot.providerCost?.limit == 0)
}
@Test
func `usage URL accepts root and versioned base URLs`() throws {
#expect(
try ClawRouterUsageFetcher._usageURLForTesting(
baseURL: #require(URL(string: "https://router.example.com"))).absoluteString ==
"https://router.example.com/v1/usage")
#expect(
try ClawRouterUsageFetcher._usageURLForTesting(
baseURL: #require(URL(string: "https://router.example.com/v1"))).absoluteString ==
"https://router.example.com/v1/usage")
}
@Test
func `fetch sends bearer key and maps authorization failure`() async throws {
let transport = ProviderHTTPTransportStub { request in
#expect(request.url?.absoluteString == "https://router.example.com/v1/usage")
#expect(request.httpMethod == "GET")
#expect(request.value(forHTTPHeaderField: "Authorization") == "Bearer smoke-key")
let response = try #require(HTTPURLResponse(
url: request.url!,
statusCode: 401,
httpVersion: nil,
headerFields: nil))
return (Data(), response)
}
await #expect(throws: ClawRouterUsageError.invalidCredentials) {
_ = try await ClawRouterUsageFetcher.fetchUsage(
apiKey: "smoke-key",
baseURL: #require(URL(string: "https://router.example.com")),
transport: transport)
}
}
@Test
func `config projects API key and optional base URL`() {
let config = ProviderConfig(
id: .clawrouter,
apiKey: "router-token",
enterpriseHost: "https://router.example.com")
let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(
base: [:],
provider: .clawrouter,
config: config)
#expect(environment[ClawRouterSettingsReader.apiKeyEnvironmentKey] == "router-token")
#expect(environment[ClawRouterSettingsReader.baseURLEnvironmentKey] == "https://router.example.com")
#expect(ProviderTokenResolver.clawRouterToken(environment: environment) == "router-token")
}
@Test
func `endpoint override is HTTPS only`() throws {
let key = ClawRouterSettingsReader.baseURLEnvironmentKey
try ClawRouterSettingsReader.validateEndpointOverride(environment: [key: "router.example.com/v1"])
#expect(ClawRouterSettingsReader.baseURL(environment: [key: "router.example.com/v1"]).absoluteString ==
"https://router.example.com/v1")
#expect(throws: ClawRouterSettingsError.invalidEndpointOverride(key)) {
try ClawRouterSettingsReader.validateEndpointOverride(environment: [key: "http://router.example.com"])
}
}
@Test
@MainActor
func `descriptor and settings are registered`() throws {
let descriptor = ProviderDescriptorRegistry.descriptor(for: .clawrouter)
#expect(descriptor.metadata.displayName == "ClawRouter")
#expect(descriptor.cli.aliases.contains("claw-router"))
let implementation = try #require(ProviderImplementationRegistry.implementation(for: .clawrouter))
#expect(implementation.id == .clawrouter)
}
@Test
func `usage snapshot preserves ClawRouter detail when cached`() throws {
let parsed = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.budgetedResponse.utf8),
updatedAt: Date(timeIntervalSince1970: 1))
let encoded = try JSONEncoder().encode(parsed.toUsageSnapshot())
let decoded = try JSONDecoder().decode(UsageSnapshot.self, from: encoded)
#expect(decoded.clawRouterUsage == parsed)
#expect(decoded.identity?.providerID == .clawrouter)
}
@Test
func `text CLI renders budgeted spend and routed usage`() throws {
let parsed = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.budgetedResponse.utf8),
updatedAt: Date(timeIntervalSince1970: 1))
let output = Self.renderText(parsed.toUsageSnapshot())
#expect(output.contains("Spend: $0.01 / $25.00"))
#expect(output.contains("Usage: 6 requests · 54K tokens"))
#expect(output.contains("Results: 5 succeeded · 1 failed"))
#expect(output.contains("Routed providers: openai: 4 · anthropic: 2"))
}
@Test
func `text CLI renders unmetered and zero spend without a zero limit`() throws {
let unmetered = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.unmeteredResponse.utf8),
updatedAt: Date(timeIntervalSince1970: 1))
let zeroSpend = try ClawRouterUsageFetcher._parseSnapshotForTesting(
Data(Self.unmeteredResponse.replacingOccurrences(of: "1250000", with: "0").utf8),
updatedAt: Date(timeIntervalSince1970: 1))
let unmeteredOutput = Self.renderText(unmetered.toUsageSnapshot())
let zeroSpendOutput = Self.renderText(zeroSpend.toUsageSnapshot())
#expect(unmeteredOutput.contains("Spend: $1.25"))
#expect(unmeteredOutput.contains("Usage: 3 requests · 0 tokens"))
#expect(!unmeteredOutput.contains(" / 0.0"))
#expect(zeroSpendOutput.contains("Spend: $0.00"))
#expect(zeroSpendOutput.contains("Usage: 3 requests · 0 tokens"))
#expect(!zeroSpendOutput.contains(" / 0.0"))
}
private static func renderText(_ snapshot: UsageSnapshot) -> String {
CLIRenderer.renderText(
provider: .clawrouter,
snapshot: snapshot,
credits: nil,
context: RenderContext(
header: "ClawRouter (api)",
status: nil,
useColor: false,
resetStyle: .countdown))
}
private static let budgetedResponse = """
{
"policyId": "openclaw-smoke",
"budget": {
"configured": true,
"ledger": "durable_object",
"windowKey": "openclaw/openclaw-smoke/2026-07",
"limitMicros": 25000000,
"spentMicros": 6000,
"remainingMicros": 24994000
},
"usage": {
"ledger": "ready",
"summary": {
"requestCount": 6,
"successCount": 5,
"errorCount": 1,
"inputTokens": 50000,
"outputTokens": 4191,
"totalTokens": 54191,
"actualCostMicros": 6000
},
"providers": [
{
"provider": "anthropic",
"requestCount": 2,
"successCount": 2,
"errorCount": 0,
"totalTokens": 12191,
"actualCostMicros": 2000
},
{
"provider": "openai",
"requestCount": 4,
"successCount": 3,
"errorCount": 1,
"totalTokens": 42000,
"actualCostMicros": 4000
}
],
"events": []
}
}
"""
private static let unmeteredResponse = """
{
"policyId": "any-provider-policy",
"budget": {
"configured": false,
"ledger": "unmetered",
"windowKey": null,
"limitMicros": null,
"spentMicros": null,
"remainingMicros": null
},
"usage": {
"ledger": "ready",
"summary": {
"requestCount": 3,
"successCount": 3,
"errorCount": 0,
"inputTokens": 0,
"outputTokens": 0,
"totalTokens": 0,
"actualCostMicros": 1250000
},
"providers": [
{
"provider": "tavily",
"requestCount": 2,
"successCount": 2,
"errorCount": 0,
"totalTokens": 0,
"actualCostMicros": 250000
},
{
"provider": "replicate",
"requestCount": 1,
"successCount": 1,
"errorCount": 0,
"totalTokens": 0,
"actualCostMicros": 1000000
}
],
"events": []
}
}
"""
}