Files
roboco/tests/integration/test_dashboard_service.py
T
Renn F 64c48356d0 test: lift coverage 41% → 76% (+1068 tests across 36 files)
Service-level tests now exercise provider, permissions, project, journal,
messaging, work_session, metrics, kanban, extraction, learning, notification,
dashboard, llm_routing, a2a, task, repository_base, audit, db_seed,
branch_name, indexed_document, query_helpers, agent. API route tests cover
provider, journal, project, sessions, dashboard, work_session, tasks, a2a,
groups, notifications, agents, channels, messages, kanban, api_resources.
Pure-function helpers covered: handlers, deps_helpers, middleware,
middleware_docs, transcription, pr templates, agents_config, errors,
logging, journal/notification/channel/a2a access, task_lifecycle,
streaming, converters, crypto, schemas (common + websocket), events,
permissions extras.

pyproject ruff per-file-ignores extended for tests so PLR2004 (status code
magic values), PLC0415 (lazy imports), PLR0913 (fixture params), ARG001
(unused fixture deps), SIM105, and E501 don't fight test idioms.
2026-05-06 00:32:52 +02:00

281 lines
8.3 KiB
Python

"""DashboardService coverage — flags, reports, channel feeds, audit queue."""
from __future__ import annotations
from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
import pytest_asyncio
from roboco.db.tables import AgentTable, ChannelTable, ProjectTable, TaskTable
from roboco.models import AgentRole, AgentStatus, Team
from roboco.models.base import (
ChannelType,
TaskNature,
TaskStatus,
TaskType,
)
from roboco.models.dashboard import CreateFlagParams
from roboco.services.dashboard import DashboardService, reset_storage
if TYPE_CHECKING:
from collections.abc import AsyncIterator
from sqlalchemy.ext.asyncio import AsyncSession
@pytest_asyncio.fixture
async def dash_setup(
db_session: AsyncSession,
) -> AsyncIterator[dict]:
reset_storage()
agent = AgentTable(
id=uuid4(),
name="Dev",
slug=f"be-dev-{uuid4().hex[:8]}",
role=AgentRole.DEVELOPER,
team=Team.BACKEND,
status=AgentStatus.ACTIVE,
model_config={},
system_prompt="dev",
capabilities=[],
permissions={},
metrics={},
)
db_session.add(agent)
await db_session.flush()
project = ProjectTable(
id=uuid4(),
name="D-Proj",
slug=f"d-proj-{uuid4().hex[:8]}",
git_url="https://example.com/r.git",
assigned_cell=Team.BACKEND,
created_by=agent.id,
)
db_session.add(project)
await db_session.flush()
yield {
"svc": DashboardService(db_session),
"agent_id": agent.id,
"project_id": project.id,
}
# ---------------------------------------------------------------------------
# Flags
# ---------------------------------------------------------------------------
def test_create_flag(dash_setup: dict) -> None:
svc = dash_setup["svc"]
flag = svc.create_flag(
CreateFlagParams(
severity="urgent",
category="quality",
title="t",
description="d",
)
)
assert flag.severity == "urgent"
fetched = svc.get_flag(flag.id)
assert fetched is not None
assert fetched.id == flag.id
def test_get_flags_filters_unresolved(dash_setup: dict) -> None:
svc = dash_setup["svc"]
a = svc.create_flag(
CreateFlagParams(severity="urgent", category="c", title="a", description="d")
)
svc.resolve_flag(a.id, notes="fixed")
unresolved = svc.get_flags(resolved=False)
assert all(f.id != a.id for f in unresolved)
resolved = svc.get_flags(resolved=True)
assert any(f.id == a.id for f in resolved)
def test_get_flags_filters_by_severity(dash_setup: dict) -> None:
svc = dash_setup["svc"]
svc.create_flag(
CreateFlagParams(severity="urgent", category="c", title="a", description="d")
)
svc.create_flag(
CreateFlagParams(severity="warning", category="c", title="b", description="d")
)
urgent_only = svc.get_flags(severity="urgent")
assert all(f.severity == "urgent" for f in urgent_only)
def test_resolve_flag_returns_false_for_missing(dash_setup: dict) -> None:
svc = dash_setup["svc"]
assert svc.resolve_flag(uuid4()) is False
def test_get_flag_returns_none_for_missing(dash_setup: dict) -> None:
svc = dash_setup["svc"]
assert svc.get_flag(uuid4()) is None
def test_count_unresolved_flags(dash_setup: dict) -> None:
svc = dash_setup["svc"]
svc.create_flag(
CreateFlagParams(severity="urgent", category="c", title="a", description="d")
)
svc.create_flag(
CreateFlagParams(severity="urgent", category="c", title="b", description="d")
)
assert svc.count_unresolved_flags("urgent") == 2
assert svc.count_unresolved_flags("warning") == 0
# ---------------------------------------------------------------------------
# Reports
# ---------------------------------------------------------------------------
def test_create_report(dash_setup: dict) -> None:
svc = dash_setup["svc"]
report = svc.create_report(
report_type="weekly", title="t", summary="s", sections=None
)
assert report.report_type == "weekly"
assert svc.get_report(report.id) is not None
def test_get_reports_filters(dash_setup: dict) -> None:
svc = dash_setup["svc"]
svc.create_report(report_type="weekly", title="a", summary="s")
svc.create_report(report_type="incident", title="b", summary="s")
weekly = svc.get_reports(report_type="weekly")
assert all(r.report_type == "weekly" for r in weekly)
def test_send_report(dash_setup: dict) -> None:
svc = dash_setup["svc"]
r = svc.create_report(report_type="weekly", title="t", summary="s")
assert svc.send_report(r.id) is True
fetched = svc.get_report(r.id)
assert fetched is not None
assert fetched.sent_at is not None
def test_send_report_returns_false_for_missing(dash_setup: dict) -> None:
svc = dash_setup["svc"]
assert svc.send_report(uuid4()) is False
def test_get_last_report_time_none_if_no_reports(dash_setup: dict) -> None:
svc = dash_setup["svc"]
assert svc.get_last_report_time() is None
def test_get_last_report_time_returns_most_recent(dash_setup: dict) -> None:
svc = dash_setup["svc"]
r = svc.create_report(report_type="weekly", title="t", summary="s")
svc.send_report(r.id)
assert svc.get_last_report_time() is not None
def test_get_report_returns_none_for_missing(dash_setup: dict) -> None:
svc = dash_setup["svc"]
assert svc.get_report(uuid4()) is None
# ---------------------------------------------------------------------------
# Channel feeds
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_get_channel_feeds(db_session: AsyncSession, dash_setup: dict) -> None:
svc = dash_setup["svc"]
ch = ChannelTable(
id=uuid4(),
name="ch",
slug=f"ch-{uuid4().hex[:6]}",
type=ChannelType.CELL,
)
db_session.add(ch)
await db_session.flush()
feeds = await svc.get_channel_feeds()
assert any(f.id == ch.id for f in feeds)
@pytest.mark.asyncio
async def test_compute_channel_status_offline_when_no_activity(
dash_setup: dict,
) -> None:
svc = dash_setup["svc"]
assert svc._compute_channel_status(None) == "offline"
# ---------------------------------------------------------------------------
# Audit queue
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_get_audit_queue_includes_blocked_and_qa(
db_session: AsyncSession, dash_setup: dict
) -> None:
svc = dash_setup["svc"]
aid = dash_setup["agent_id"]
pid = dash_setup["project_id"]
blocked = TaskTable(
id=uuid4(),
title="t-blocked",
description="d",
acceptance_criteria=["ac"],
status=TaskStatus.BLOCKED,
priority=2,
task_type=TaskType.CODE,
nature=TaskNature.TECHNICAL,
project_id=pid,
created_by=aid,
team=Team.BACKEND,
)
awaiting_qa = TaskTable(
id=uuid4(),
title="t-qa",
description="d",
acceptance_criteria=["ac"],
status=TaskStatus.AWAITING_QA,
priority=2,
task_type=TaskType.CODE,
nature=TaskNature.TECHNICAL,
project_id=pid,
created_by=aid,
team=Team.BACKEND,
)
db_session.add_all([blocked, awaiting_qa])
await db_session.flush()
queue = await svc.get_audit_queue()
types = {item.type for item in queue}
assert "blocked_task" in types
assert "qa_review" in types
# ---------------------------------------------------------------------------
# Roadmap progress (defensive on empty DB — division-by-zero safe path)
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_get_roadmap_progress_safe_on_empty(dash_setup: dict) -> None:
svc = dash_setup["svc"]
progress = await svc.get_roadmap_progress()
assert "current_quarter_progress" in progress
# ---------------------------------------------------------------------------
# Auditor alerts
# ---------------------------------------------------------------------------
def test_get_auditor_alerts_returns_dict(dash_setup: dict) -> None:
svc = dash_setup["svc"]
alerts = svc.get_auditor_alerts()
assert "urgent_count" in alerts
assert "warning_count" in alerts