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

236 lines
8.1 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
struct LiteLLMMenuCardModelTests {
@Test
func `litellm budget rows show spend detail with reset time`() throws {
let now = Date(timeIntervalSince1970: 0)
let metadata = try #require(ProviderDefaults.metadata[.litellm])
let json = """
{
"user_id": "user-123",
"user_info": {
"user_id": "user-123",
"max_budget": 900.0,
"spend": 403.99,
"budget_reset_at": "1970-01-07T00:00:00Z"
},
"teams": [
{
"team_alias": "Platform",
"team_id": "team-123",
"max_budget": 1000.0,
"spend": 70.0,
"budget_duration": "30d",
"budget_reset_at": "1970-01-07T00:00:00Z"
}
]
}
"""
let snapshot = try LiteLLMUsageFetcher._parseUserInfoForTesting(
Data(json.utf8),
keyInfo: LiteLLMKeyInfoSnapshot(
userID: "user-123",
teamID: "team-123",
keyName: nil,
spendUSD: 403.99,
expiresAt: nil),
updatedAt: now)
.toUsageSnapshot()
let model = UsageMenuCardView.Model.make(.init(
provider: .litellm,
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 personal = try #require(model.metrics.first { $0.id == "primary" })
#expect(personal.title == "Personal budget")
#expect(personal.percentLabel == "55% left")
#expect(personal.resetText?.hasPrefix("Resets") == true)
#expect(personal.detailText == "$403.99 / $900.00")
let team = try #require(model.metrics.first { $0.id == "secondary" })
#expect(team.title == "Team budget")
#expect(team.percentLabel == "93% left")
#expect(team.resetText?.hasPrefix("Resets") == true)
#expect(team.detailText == "Team Platform: $70.00 / $1,000.00")
#expect(model.providerCost == nil)
}
@Test
func `litellm budget row details redact team aliases when hiding personal info`() throws {
let teamAlias = "Private Workspace"
let model = try self.redactedTeamAliasModel(teamAlias)
let team = try #require(model.metrics.first { $0.id == "secondary" })
#expect(team.detailText == "Team: $70.00 / $1,000.00")
#expect(team.detailText?.contains(teamAlias) == false)
}
@Test
func `litellm budget row details redact email team aliases when hiding personal info`() throws {
let teamAlias = "workspace@example.com"
let model = try self.redactedTeamAliasModel(teamAlias)
let team = try #require(model.metrics.first { $0.id == "secondary" })
#expect(team.detailText == "Team: $70.00 / $1,000.00")
#expect(team.detailText?.contains(teamAlias) == false)
#expect(team.detailText?.contains("Hidden") == false)
}
@Test
func `litellm team-only budget stays on the team row`() throws {
let now = Date(timeIntervalSince1970: 0)
let metadata = try #require(ProviderDefaults.metadata[.litellm])
let snapshot = UsageSnapshot(
primary: nil,
secondary: RateWindow(
usedPercent: 25,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(7 * 24 * 60 * 60),
resetDescription: "Team Platform: $250.00 / $1,000.00"),
providerCost: ProviderCostSnapshot(
used: 250,
limit: 1000,
currencyCode: "USD",
period: "Team budget",
updatedAt: now),
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .litellm,
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))
#expect(model.metrics.map(\.id) == ["secondary"])
#expect(model.metrics.first?.detailText == "Team Platform: $250.00 / $1,000.00")
#expect(model.providerCost == nil)
}
@Test
func `litellm spend without budget remains visible`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.litellm])
let snapshot = UsageSnapshot(
primary: nil,
secondary: nil,
providerCost: ProviderCostSnapshot(
used: 12.5,
limit: 0,
currencyCode: "USD",
period: "Personal spend",
updatedAt: now),
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .litellm,
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))
#expect(model.providerCost?.title == "API spend")
#expect(model.providerCost?.spendLine == "Personal spend: $12.50")
#expect(model.providerCost?.percentUsed == nil)
}
private func redactedTeamAliasModel(_ teamAlias: String) throws -> UsageMenuCardView.Model {
let now = Date(timeIntervalSince1970: 0)
let metadata = try #require(ProviderDefaults.metadata[.litellm])
let json = """
{
"user_id": "user-123",
"user_info": {
"user_id": "user-123",
"max_budget": 900.0,
"spend": 403.99
},
"teams": [
{
"team_alias": "\(teamAlias)",
"team_id": "team-123",
"max_budget": 1000.0,
"spend": 70.0
}
]
}
"""
let snapshot = try LiteLLMUsageFetcher._parseUserInfoForTesting(
Data(json.utf8),
keyInfo: LiteLLMKeyInfoSnapshot(
userID: "user-123",
teamID: "team-123",
keyName: nil,
spendUSD: 403.99,
expiresAt: nil),
updatedAt: now)
.toUsageSnapshot()
return UsageMenuCardView.Model.make(.init(
provider: .litellm,
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: true,
now: now))
}
}