testsAndMisc/python_pkg/token_dashboard/tests/test_ingest.py
Krzysztof kuhy Rudnicki 1ba202c567
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
token_dashboard: ingester core + detail tables (calls, marks, turn_detail, ab_rows) for the control-panel dashboard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JThjboXTeZ3yJPBzxMx5wS
2026-10-18 14:45:06 +02:00

182 lines
5.7 KiB
Python

from __future__ import annotations
import json
import sqlite3
from typing import TYPE_CHECKING
import pytest
from python_pkg.token_dashboard import ingest
from python_pkg.token_dashboard.tests.conftest import (
assistant,
prompt,
result,
usd_opus_output,
use,
write,
)
if TYPE_CHECKING:
from collections.abc import Callable, Iterator
from pathlib import Path
def _tree(root: Path) -> None:
agent = use("ta", "Agent", description="Find x", subagent_type="Explore")
write(
root / "proj" / "s1.jsonl",
[
prompt("first", 0),
assistant("m1", 10, blocks=[agent]),
result("ta", 11, "launched", toolUseResult={"agentId": "abc"}),
assistant("m2", 20),
prompt("second", 1000),
assistant("m3", 1010, blocks=[{"type": "text", "text": "DONE: x"}]),
],
)
subdir = root / "proj" / "s1" / "subagents"
write(subdir / "agent-abc.jsonl", [prompt("task", 12), assistant("a1", 200)])
(subdir / "agent-abc.meta.json").write_text(
json.dumps({"agentType": "Explore", "description": "Find x"}),
encoding="utf-8",
)
# An agent that outlived /clear: nothing in s1 spawned it.
write(subdir / "agent-zzz.jsonl", [prompt("orphan", 30), assistant("z1", 40)])
def _run(tmp_path: Path, budget: float = 30.0) -> ingest.Outcome:
return ingest.run(
root=tmp_path / "projects",
db_path=tmp_path / "t.sqlite",
report_dir=tmp_path / "report",
budget_s=budget,
)
@pytest.fixture
def db(tmp_path: Path) -> Iterator[Callable[[], sqlite3.Connection]]:
opened: list[sqlite3.Connection] = []
def _open() -> sqlite3.Connection:
opened.append(sqlite3.connect(tmp_path / "t.sqlite"))
return opened[-1]
yield _open
for conn in opened:
conn.close()
def test_session_cost_reconciles_to_prompts_plus_unattributed(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
_tree(tmp_path / "projects")
outcome = _run(tmp_path)
assert outcome.complete
conn = db()
usd, active_s, wall_s, tag = conn.execute(
"SELECT usd, active_s, wall_s, final_tag FROM session_summary WHERE key='s1'"
).fetchone()
assert usd == pytest.approx(usd_opus_output(1000) * 5)
prompts = conn.execute(
"SELECT idx, usd_own + usd_sub FROM prompt_summary WHERE key='s1' ORDER BY idx"
).fetchall()
unattributed = conn.execute(
"SELECT SUM(usd) FROM subagent_link WHERE main_key='s1' AND prompt_idx IS NULL"
).fetchone()[0]
assert sum(v for _, v in prompts) + unattributed == pytest.approx(usd)
# Prompt 0 carries its own two turns plus the Explore agent it spawned.
assert prompts[0][1] == pytest.approx(usd_opus_output(1000) * 3)
assert wall_s == 1010
# Union of main + subagent activity: 0..200 bridged, then 1000..1010.
assert active_s == pytest.approx(210)
assert tag == "DONE"
def test_subagent_links_to_its_prompt_via_agent_id(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
_tree(tmp_path / "projects")
_run(tmp_path)
rows = dict(
db().execute("SELECT sub_key, prompt_idx FROM subagent_link").fetchall()
)
assert rows == {"s1/agent-abc": 0, "s1/agent-zzz": None}
def test_rerun_skips_unchanged_and_rows_outlive_deleted_files(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
_tree(tmp_path / "projects")
_run(tmp_path)
assert _run(tmp_path).parsed == 0
(tmp_path / "projects" / "proj" / "s1.jsonl").unlink()
_run(tmp_path)
count = db().execute("SELECT COUNT(*) FROM turns").fetchone()[0]
assert count == 5
def test_changed_file_is_reparsed_without_duplicating_rows(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
_tree(tmp_path / "projects")
_run(tmp_path)
path = tmp_path / "projects" / "proj" / "s1.jsonl"
with path.open("a", encoding="utf-8") as handle:
handle.write(json.dumps(assistant("m4", 1020)) + "\n")
assert _run(tmp_path).parsed == 1
count = db().execute("SELECT COUNT(*) FROM turns").fetchone()[0]
assert count == 6
def test_zero_budget_leaves_work_pending_and_resumes(tmp_path: Path) -> None:
_tree(tmp_path / "projects")
first = _run(tmp_path, budget=0.0)
assert not first.complete
assert first.parsed == 1 # always makes progress
rest = _run(tmp_path)
assert rest.complete
assert first.parsed + rest.parsed == 3
def test_daily_rollup_matches_turns(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
_tree(tmp_path / "projects")
_run(tmp_path)
conn = db()
total, calls, sub = conn.execute(
"SELECT SUM(usd), SUM(calls), SUM(usd_sub) FROM daily"
).fetchone()
assert total == pytest.approx(usd_opus_output(1000) * 5)
assert calls == 5
assert sub == pytest.approx(usd_opus_output(1000) * 2)
def test_cli_exit_codes(tmp_path: Path) -> None:
_tree(tmp_path / "projects")
args = [
"--root",
str(tmp_path / "projects"),
"--db",
str(tmp_path / "t.sqlite"),
"--report-dir",
str(tmp_path / "report"),
]
assert ingest.main([*args, "--budget", "0"]) == ingest.EXIT_PENDING
assert ingest.main(args) == 0
def test_session_with_no_prompts_and_no_main_file(
tmp_path: Path, db: Callable[[], sqlite3.Connection]
) -> None:
sub = tmp_path / "projects" / "proj" / "gone" / "subagents" / "agent-q.jsonl"
write(sub, [assistant("q1", 5), assistant("q2", 6)])
assert _run(tmp_path).complete
usd, prompts = (
db()
.execute("SELECT usd, prompts FROM session_summary WHERE key='gone'")
.fetchone()
)
assert usd == pytest.approx(usd_opus_output(1000) * 2)
assert prompts == 0