test(platform): add unit tests for platform cost helpers and data layer

Extract pure helper functions (formatMicrodollars, formatTokens,
formatDuration, estimateCostForRow, trackingValue, toDateOrUndefined)
from PlatformCostContent.tsx into helpers.ts for testability. Add 26
vitest cases covering all formatting and cost-estimation branches.

Add backend tests for _build_where and _json_or_none in
platform_cost.py (11 pytest cases covering filter combinations).
This commit is contained in:
Zamil Majdy
2026-04-03 14:15:28 +02:00
parent 759effab60
commit 960f893295
5 changed files with 369 additions and 84 deletions

View File

@@ -0,0 +1,71 @@
"""Unit tests for pure helpers in platform_cost module."""
from datetime import datetime, timezone
from .platform_cost import _build_where, _json_or_none
class TestJsonOrNone:
def test_returns_none_for_none(self):
assert _json_or_none(None) is None
def test_returns_json_string_for_dict(self):
result = _json_or_none({"key": "value", "num": 42})
assert result is not None
assert '"key"' in result
assert '"value"' in result
def test_returns_json_for_empty_dict(self):
assert _json_or_none({}) == "{}"
class TestBuildWhere:
def test_no_filters_returns_true(self):
sql, params = _build_where(None, None, None, None)
assert sql == "TRUE"
assert params == []
def test_start_only(self):
dt = datetime(2026, 1, 1, tzinfo=timezone.utc)
sql, params = _build_where(dt, None, None, None)
assert '"createdAt" >= $1::timestamptz' in sql
assert params == [dt]
def test_end_only(self):
dt = datetime(2026, 6, 1, tzinfo=timezone.utc)
sql, params = _build_where(None, dt, None, None)
assert '"createdAt" <= $1::timestamptz' in sql
assert params == [dt]
def test_provider_only(self):
sql, params = _build_where(None, None, "openai", None)
assert 'LOWER("provider") = LOWER($1)' in sql
assert params == ["openai"]
def test_user_id_only(self):
sql, params = _build_where(None, None, None, "user-123")
assert '"userId" = $1' in sql
assert params == ["user-123"]
def test_all_filters(self):
start = datetime(2026, 1, 1, tzinfo=timezone.utc)
end = datetime(2026, 6, 1, tzinfo=timezone.utc)
sql, params = _build_where(start, end, "anthropic", "u1")
assert "$1" in sql
assert "$2" in sql
assert "$3" in sql
assert "$4" in sql
assert len(params) == 4
assert params == [start, end, "anthropic", "u1"]
def test_table_alias(self):
dt = datetime(2026, 1, 1, tzinfo=timezone.utc)
sql, params = _build_where(dt, None, None, None, table_alias="p")
assert 'p."createdAt"' in sql
assert params == [dt]
def test_clauses_joined_with_and(self):
start = datetime(2026, 1, 1, tzinfo=timezone.utc)
end = datetime(2026, 6, 1, tzinfo=timezone.utc)
sql, _ = _build_where(start, end, None, None)
assert " AND " in sql

View File

@@ -0,0 +1,206 @@
import { describe, expect, it } from "vitest";
import type { ProviderCostSummary } from "@/app/api/__generated__/models/providerCostSummary";
import {
toDateOrUndefined,
formatMicrodollars,
formatTokens,
formatDuration,
estimateCostForRow,
trackingValue,
} from "../helpers";
function makeRow(overrides: Partial<ProviderCostSummary>): ProviderCostSummary {
return {
provider: "openai",
tracking_type: null,
total_cost_microdollars: 0,
total_input_tokens: 0,
total_output_tokens: 0,
total_duration_seconds: 0,
request_count: 0,
...overrides,
};
}
describe("toDateOrUndefined", () => {
it("returns undefined for empty string", () => {
expect(toDateOrUndefined("")).toBeUndefined();
});
it("returns undefined for undefined", () => {
expect(toDateOrUndefined(undefined)).toBeUndefined();
});
it("returns undefined for invalid date string", () => {
expect(toDateOrUndefined("not-a-date")).toBeUndefined();
});
it("returns a Date for a valid ISO string", () => {
const result = toDateOrUndefined("2026-01-15T00:00:00Z");
expect(result).toBeInstanceOf(Date);
expect(result!.toISOString()).toBe("2026-01-15T00:00:00.000Z");
});
});
describe("formatMicrodollars", () => {
it("formats zero", () => {
expect(formatMicrodollars(0)).toBe("$0.0000");
});
it("formats a small amount", () => {
expect(formatMicrodollars(50_000)).toBe("$0.0500");
});
it("formats one dollar", () => {
expect(formatMicrodollars(1_000_000)).toBe("$1.0000");
});
});
describe("formatTokens", () => {
it("formats small numbers as-is", () => {
expect(formatTokens(500)).toBe("500");
});
it("formats thousands with K suffix", () => {
expect(formatTokens(1_500)).toBe("1.5K");
});
it("formats millions with M suffix", () => {
expect(formatTokens(2_500_000)).toBe("2.5M");
});
});
describe("formatDuration", () => {
it("formats seconds", () => {
expect(formatDuration(30)).toBe("30.0s");
});
it("formats minutes", () => {
expect(formatDuration(90)).toBe("1.5m");
});
it("formats hours", () => {
expect(formatDuration(5400)).toBe("1.5h");
});
});
describe("estimateCostForRow", () => {
it("returns microdollars directly for cost_usd tracking", () => {
const row = makeRow({
tracking_type: "cost_usd",
total_cost_microdollars: 500_000,
});
expect(estimateCostForRow(row, {})).toBe(500_000);
});
it("returns reported cost for token tracking when cost > 0", () => {
const row = makeRow({
tracking_type: "tokens",
total_cost_microdollars: 100_000,
total_input_tokens: 1000,
total_output_tokens: 500,
});
expect(estimateCostForRow(row, {})).toBe(100_000);
});
it("estimates cost from default rate for token tracking with zero cost", () => {
const row = makeRow({
provider: "openai",
tracking_type: "tokens",
total_cost_microdollars: 0,
total_input_tokens: 500,
total_output_tokens: 500,
});
// 1000 tokens / 1000 * 0.005 USD * 1_000_000 = 5000
expect(estimateCostForRow(row, {})).toBe(5000);
});
it("returns null for unknown token provider with zero cost", () => {
const row = makeRow({
provider: "unknown_provider",
tracking_type: "tokens",
total_cost_microdollars: 0,
});
expect(estimateCostForRow(row, {})).toBeNull();
});
it("uses per-run override when provided", () => {
const row = makeRow({
provider: "google_maps",
tracking_type: "per_run",
request_count: 10,
});
// override = 0.05 * 10 * 1_000_000 = 500_000
expect(estimateCostForRow(row, { google_maps: 0.05 })).toBe(500_000);
});
it("uses default per-run cost when no override", () => {
const row = makeRow({
provider: "google_maps",
tracking_type: null,
request_count: 5,
});
// 0.032 * 5 * 1_000_000 = 160_000
expect(estimateCostForRow(row, {})).toBe(160_000);
});
it("returns null for unknown per_run provider", () => {
const row = makeRow({
provider: "totally_unknown",
tracking_type: "per_run",
request_count: 3,
});
expect(estimateCostForRow(row, {})).toBeNull();
});
it("returns cost for other tracking types when cost > 0", () => {
const row = makeRow({
tracking_type: "duration_seconds",
total_cost_microdollars: 42_000,
});
expect(estimateCostForRow(row, {})).toBe(42_000);
});
it("returns null for other tracking types when cost is 0", () => {
const row = makeRow({
tracking_type: "duration_seconds",
total_cost_microdollars: 0,
});
expect(estimateCostForRow(row, {})).toBeNull();
});
});
describe("trackingValue", () => {
it("returns formatted microdollars for cost_usd", () => {
const row = makeRow({
tracking_type: "cost_usd",
total_cost_microdollars: 1_000_000,
});
expect(trackingValue(row)).toBe("$1.0000");
});
it("returns formatted token count for tokens", () => {
const row = makeRow({
tracking_type: "tokens",
total_input_tokens: 500,
total_output_tokens: 500,
});
expect(trackingValue(row)).toBe("1.0K");
});
it("returns formatted duration for duration_seconds", () => {
const row = makeRow({
tracking_type: "duration_seconds",
total_duration_seconds: 120,
});
expect(trackingValue(row)).toBe("2.0m");
});
it("returns run count for per_run (default tracking)", () => {
const row = makeRow({
tracking_type: null,
request_count: 42,
});
expect(trackingValue(row)).toBe("42 runs");
});
});

View File

@@ -5,12 +5,7 @@ import {
getV2GetPlatformCostLogs,
} from "@/app/api/__generated__/endpoints/admin/admin";
import { okData } from "@/app/api/helpers";
function toDateOrUndefined(val?: string): Date | undefined {
if (!val) return undefined;
const d = new Date(val);
return isNaN(d.getTime()) ? undefined : d;
}
import { toDateOrUndefined } from "./helpers";
export async function getPlatformCostDashboard(params?: {
start?: string;

View File

@@ -7,6 +7,14 @@ import type { CostLogRow } from "@/app/api/__generated__/models/costLogRow";
import type { Pagination } from "@/app/api/__generated__/models/pagination";
import type { PlatformCostLogsResponse } from "@/app/api/__generated__/models/platformCostLogsResponse";
import { getPlatformCostDashboard, getPlatformCostLogs } from "../actions";
import {
DEFAULT_COST_PER_RUN,
estimateCostForRow,
formatDuration,
formatMicrodollars,
formatTokens,
trackingValue,
} from "../helpers";
import { useRouter, useSearchParams } from "next/navigation";
interface Props {
@@ -20,42 +28,6 @@ interface Props {
};
}
// Default per-run costs in USD (checked 2026-04-02)
const DEFAULT_COST_PER_RUN: Record<string, number> = {
google_maps: 0.032,
ideogram: 0.08,
nvidia: 0.0,
screenshotone: 0.01,
zerobounce: 0.008,
mem0: 0.01,
openweathermap: 0.0,
webshare_proxy: 0.0,
};
// Default cost per 1K tokens in USD for token-based providers without actual cost
const DEFAULT_COST_PER_1K_TOKENS: Record<string, number> = {
openai: 0.005,
anthropic: 0.008,
groq: 0.0003,
ollama: 0.0,
};
function formatMicrodollars(microdollars: number) {
return `$${(microdollars / 1_000_000).toFixed(4)}`;
}
function formatTokens(tokens: number) {
if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;
if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;
return tokens.toString();
}
function formatDuration(seconds: number) {
if (seconds >= 3600) return `${(seconds / 3600).toFixed(1)}h`;
if (seconds >= 60) return `${(seconds / 60).toFixed(1)}m`;
return `${seconds.toFixed(1)}s`;
}
function trackingBadge(trackingType: string | null | undefined) {
const colors: Record<string, string> = {
cost_usd:
@@ -81,48 +53,6 @@ function trackingBadge(trackingType: string | null | undefined) {
);
}
function estimateCostForRow(
row: ProviderCostSummary,
costPerRunOverrides: Record<string, number>,
) {
const tt = row.tracking_type || "per_run";
if (tt === "cost_usd") return row.total_cost_microdollars;
if (tt === "tokens") {
if (row.total_cost_microdollars > 0) return row.total_cost_microdollars;
const rate = DEFAULT_COST_PER_1K_TOKENS[row.provider] ?? null;
if (rate !== null) {
const totalTokens = row.total_input_tokens + row.total_output_tokens;
return Math.round((totalTokens / 1000) * rate * 1_000_000);
}
return null;
}
if (tt === "per_run") {
const rate =
costPerRunOverrides[row.provider] ??
DEFAULT_COST_PER_RUN[row.provider] ??
null;
if (rate !== null) return Math.round(rate * row.request_count * 1_000_000);
return null;
}
return row.total_cost_microdollars > 0 ? row.total_cost_microdollars : null;
}
function trackingValue(row: ProviderCostSummary) {
const tt = row.tracking_type || "per_run";
if (tt === "cost_usd") return formatMicrodollars(row.total_cost_microdollars);
if (tt === "tokens")
return formatTokens(row.total_input_tokens + row.total_output_tokens);
if (
tt === "duration_seconds" ||
tt === "sandbox_seconds" ||
tt === "walltime_seconds"
)
return formatDuration(row.total_duration_seconds || 0);
if (tt === "characters")
return formatTokens(row.total_input_tokens + row.total_output_tokens);
return row.request_count.toLocaleString() + " runs";
}
function PlatformCostContent({ searchParams }: Props) {
const router = useRouter();
const urlParams = useSearchParams();

View File

@@ -0,0 +1,83 @@
import type { ProviderCostSummary } from "@/app/api/__generated__/models/providerCostSummary";
export const DEFAULT_COST_PER_RUN: Record<string, number> = {
google_maps: 0.032,
ideogram: 0.08,
nvidia: 0.0,
screenshotone: 0.01,
zerobounce: 0.008,
mem0: 0.01,
openweathermap: 0.0,
webshare_proxy: 0.0,
};
export const DEFAULT_COST_PER_1K_TOKENS: Record<string, number> = {
openai: 0.005,
anthropic: 0.008,
groq: 0.0003,
ollama: 0.0,
};
export function toDateOrUndefined(val?: string): Date | undefined {
if (!val) return undefined;
const d = new Date(val);
return isNaN(d.getTime()) ? undefined : d;
}
export function formatMicrodollars(microdollars: number) {
return `$${(microdollars / 1_000_000).toFixed(4)}`;
}
export function formatTokens(tokens: number) {
if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;
if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;
return tokens.toString();
}
export function formatDuration(seconds: number) {
if (seconds >= 3600) return `${(seconds / 3600).toFixed(1)}h`;
if (seconds >= 60) return `${(seconds / 60).toFixed(1)}m`;
return `${seconds.toFixed(1)}s`;
}
export function estimateCostForRow(
row: ProviderCostSummary,
costPerRunOverrides: Record<string, number>,
) {
const tt = row.tracking_type || "per_run";
if (tt === "cost_usd") return row.total_cost_microdollars;
if (tt === "tokens") {
if (row.total_cost_microdollars > 0) return row.total_cost_microdollars;
const rate = DEFAULT_COST_PER_1K_TOKENS[row.provider] ?? null;
if (rate !== null) {
const totalTokens = row.total_input_tokens + row.total_output_tokens;
return Math.round((totalTokens / 1000) * rate * 1_000_000);
}
return null;
}
if (tt === "per_run") {
const rate =
costPerRunOverrides[row.provider] ??
DEFAULT_COST_PER_RUN[row.provider] ??
null;
if (rate !== null) return Math.round(rate * row.request_count * 1_000_000);
return null;
}
return row.total_cost_microdollars > 0 ? row.total_cost_microdollars : null;
}
export function trackingValue(row: ProviderCostSummary) {
const tt = row.tracking_type || "per_run";
if (tt === "cost_usd") return formatMicrodollars(row.total_cost_microdollars);
if (tt === "tokens")
return formatTokens(row.total_input_tokens + row.total_output_tokens);
if (
tt === "duration_seconds" ||
tt === "sandbox_seconds" ||
tt === "walltime_seconds"
)
return formatDuration(row.total_duration_seconds || 0);
if (tt === "characters")
return formatTokens(row.total_input_tokens + row.total_output_tokens);
return row.request_count.toLocaleString() + " runs";
}