Files
cowork-local/tests/unit/test_dashboard_query_service.py
T

108 lines
3.7 KiB
Python

"""EPIC R08-T13: DashboardQueryService — no Qt.
``core/usage_tracker.py::USAGE_DIR`` is a module-level constant (not
injectable per-call except through an explicit ``directory=`` kwarg
``load_events`` alone accepts) — this is a pre-existing testability gap the
original ``ui/dashboard_tab.py`` also had (it had zero tests before this
task). Monkeypatching the module attribute is what lets these tests write
usage events without touching the real ``~/.cowork_local/usage/``.
"""
from __future__ import annotations
import json
from datetime import date, timedelta
import pytest
from cowork_local.application.monitoring import DashboardQueryService
from cowork_local.config import AppConfig
from cowork_local.core import usage_tracker as ut
from cowork_local.state import AppContext
@pytest.fixture
def usage_dir(tmp_path, monkeypatch):
import sys
d = tmp_path / "usage"
for mod in list(sys.modules.values()):
if mod is not None and getattr(mod, "__name__", "").endswith("usage_tracker") and hasattr(mod, "USAGE_DIR"):
monkeypatch.setattr(mod, "USAGE_DIR", d)
monkeypatch.setattr(ut, "USAGE_DIR", d)
return d
@pytest.fixture
def ctx(tmp_path):
return AppContext(AppConfig.load(tmp_path / "config.json"))
def _write_event(usage_dir, day: date, **overrides):
usage_dir.mkdir(parents=True, exist_ok=True)
event = {
"ts": f"{day.isoformat()}T10:00:00", "source": "cowork", "label": "Test chat",
"provider": "anthropic", "model": "claude-sonnet-4-6",
"in": 100, "out": 50, "cache": 0, "estimated": False,
"account": "", "machine": "",
}
event.update(overrides)
path = usage_dir / f"{day.isoformat()}.jsonl"
with path.open("a", encoding="utf-8") as f:
f.write(json.dumps(event) + "\n")
def test_period_range_is_inclusive_end(usage_dir, ctx):
query = DashboardQueryService(ctx, directory=usage_dir)
start, end = query.period_range("week", 0)
assert start <= end
def test_summary_aggregates_events_in_range(usage_dir, ctx):
test_day = date(2025, 6, 15)
_write_event(usage_dir, test_day, **{"in": 100, "out": 50})
_write_event(usage_dir, test_day - timedelta(days=400), **{"in": 999, "out": 999}) # out of range
query = DashboardQueryService(ctx, directory=usage_dir)
summary = query.summary(test_day, test_day)
assert len(summary["events"]) == 1
assert summary["stats"]["in"] == 100
assert summary["stats"]["out"] == 50
assert summary["total_cost"] >= 0
def test_summary_empty_range_has_no_events(usage_dir, ctx):
query = DashboardQueryService(ctx, directory=usage_dir)
summary = query.summary(date(2020, 1, 1), date(2020, 1, 1))
assert summary["events"] == []
assert summary["stats"]["total"] == 0
def test_pricing_returns_a_dict_with_currency(usage_dir, ctx):
query = DashboardQueryService(ctx, directory=usage_dir)
pricing = query.pricing()
assert "currency" in pricing
def test_chart_series_returns_points_for_the_granularity(usage_dir, ctx):
today = date.today()
_write_event(usage_dir, today)
query = DashboardQueryService(ctx, directory=usage_dir)
pts = query.chart_series("week", 0, "tokens")
assert len(pts) == 7 # week view = 7 days
assert all(isinstance(p, tuple) and len(p) == 2 for p in pts)
def test_budget_status_none_when_no_budget_set(usage_dir, ctx):
query = DashboardQueryService(ctx, directory=usage_dir)
assert query.budget_status() is None
def test_set_budget_then_status_reflects_it(usage_dir, ctx):
query = DashboardQueryService(ctx, directory=usage_dir)
query.set_budget(100.0, "USD")
status = query.budget_status()
assert status is not None
assert status["amount_usd"] == pytest.approx(100.0)