Files
the-custodian/workplans/CUST-WP-0020-test-suite.md
tegwick ec92c8e95e feat(tests): pytest-asyncio test suite — 119 tests across 3 modules
Infrastructure (T01):
- tests/conftest.py: sync schema setup (psycopg2), per-test table
  truncation, async ASGI client with get_session override
- pyproject.toml: [tool.pytest.ini_options] asyncio_mode=auto
- Makefile: make test target with TEST_DATABASE_URL

Core router tests (T02): 19 tests
- domains, topics, workstreams, tasks, decisions + state summary
- Caught real bug: topic router missing duplicate-slug 409 guard (fixed)

TD/EP/Contributions/SBOM tests (T03): 10 tests
- CRUD + status transitions + lifecycle guard + SBOM ingest

MCP smoke tests (T04): 12 tests
- get_state_summary, create_task, update_task_status,
  add_progress_event, flag_for_human HTTP shapes

CI gate (T05): make test documented in CLAUDE.md session protocol

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:00:06 +01:00

3.3 KiB

id, type, title, domain, status, owner, topic_slug, created, updated, state_hub_workstream_id
id type title domain status owner topic_slug created updated state_hub_workstream_id
CUST-WP-0020 workplan State Hub — pytest Test Suite custodian done custodian custodian 2026-03-18 2026-03-18 56379f10-bad9-49b4-bbd0-e4a0de5c6a81

State Hub — pytest Test Suite

Summary

The API, MCP server, seed script, and migration scripts currently have zero automated test coverage (TD-CUST-014). Regressions are caught at runtime. This workplan introduces a pytest-asyncio test suite using HTTPX's async test client against a real test database (no mocking — see ADR below).

ADR

Do NOT mock the database in these tests. The state-hub has had past incidents where mocked tests passed but the real DB diverged (see memory: feedback on not mocking the database). Use a real PostgreSQL test database via TEST_DATABASE_URL env var (docker-compose already provides postgres).


Tasks

T01 — Test infrastructure: pytest-asyncio + async HTTP client + fixtures

id: CUST-WP-0020-T01
status: done
priority: high
state_hub_task_id: "35a52abb-15b1-4c12-b1c6-5e321377ddfa"
  • Add pytest, pytest-asyncio, httpx to state-hub/pyproject.toml dev deps
  • Create state-hub/tests/conftest.py:
    • engine fixture: creates a fresh async engine against TEST_DATABASE_URL
    • db fixture: runs alembic upgrade head then alembic downgrade base around each test session (or truncates tables between tests)
    • client fixture: httpx.AsyncClient pointed at the test app instance
  • Create state-hub/tests/__init__.py
  • Add make test target in state-hub/Makefile

T02 — Core router tests: topics, workstreams, tasks, decisions

id: CUST-WP-0020-T02
status: done
priority: high
state_hub_task_id: "85b0b6e2-d66b-4619-8e1f-2056862a0d97"

Coverage targets (happy path + key error cases):

  • POST /topics/ → 201, duplicate slug → 409
  • POST /workstreams/ + GET /workstreams/?topic_id= + status transitions
  • POST /tasks/ + GET /tasks/?workstream_id= + needs_human flag
  • POST /decisions/ + PATCH /{id}/resolve/
  • GET /state/summary → returns expected shape with counts

T03 — TD, EP, contributions router tests

id: CUST-WP-0020-T03
status: done
priority: medium
state_hub_task_id: "41106482-5b1c-4ee9-8979-377595f704b9"
  • TD CRUD + workflow status transitions + notes endpoints
  • EP CRUD + status transitions
  • Contribution lifecycle guard (invalid transitions → 422)
  • SBOM ingest + /sbom/snapshots/ aggregation

T04 — MCP server smoke tests

id: CUST-WP-0020-T04
status: done
priority: medium
state_hub_task_id: "6fa30dd1-065d-4158-8ef9-ed5ff7001083"

For each MCP tool, call the underlying HTTP helper against the test client and assert the result shape. No need to test the MCP stdio protocol itself — just the HTTP-level correctness. Focus on: get_state_summary, create_task, update_task_status, add_progress_event, flag_for_human.


T05 — CI: add pytest to pre-commit or Makefile gate

id: CUST-WP-0020-T05
status: done
priority: low
state_hub_task_id: "5d206df8-c902-4c5b-8a0b-58b600480c0f"

Add make test as a step in any existing CI pipeline, or document the manual pre-push gate in CLAUDE.md. Ensure TEST_DATABASE_URL is set to the docker-compose postgres instance in the local dev workflow.