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>
116 lines
3.3 KiB
Markdown
116 lines
3.3 KiB
Markdown
---
|
|
id: CUST-WP-0020
|
|
type: workplan
|
|
title: "State Hub — pytest Test Suite"
|
|
domain: custodian
|
|
status: done
|
|
owner: custodian
|
|
topic_slug: custodian
|
|
created: "2026-03-18"
|
|
updated: "2026-03-18"
|
|
state_hub_workstream_id: "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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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.
|