Kairo-Jinkendo/backend/tests/test_ap09_operating_model.py
Lars a025542545
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Test Suite / pytest-backend (push) Successful in 1m6s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 21s
Test Suite / playwright-smoke (push) Successful in 14s
AP0.9: Operating Model Extension II (Evidence, Decision, Review, Recurring, due_at)
Schließt den zweiten OM-Slice entlang der Roadmap: neue Entitäten parallel im Vorhaben, erweiterte Action-Status/Fälligkeit und Attention-Regeln 7–9.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 15:27:03 +02:00

166 lines
5.4 KiB
Python

"""AP0.9 — Operating Model Extension II tests."""
from __future__ import annotations
from datetime import datetime, timedelta, timezone
from tests.factories import provision_user_in_tenant
from tests.test_initiatives_actions import (
_auth,
_create_action,
_create_initiative,
_login,
)
def _create_evidence(client, token, initiative_id, **kwargs):
body = {"title": "Evidence Test", **kwargs}
return client.post(
f"/api/initiatives/{initiative_id}/evidence",
json=body,
headers=_auth(token),
)
def _create_decision(client, token, initiative_id, **kwargs):
body = {"title": "Decision Test", **kwargs}
return client.post(
f"/api/initiatives/{initiative_id}/decisions",
json=body,
headers=_auth(token),
)
def _create_review(client, token, initiative_id, **kwargs):
body = {"title": "Review Test", **kwargs}
return client.post(
f"/api/initiatives/{initiative_id}/reviews",
json=body,
headers=_auth(token),
)
def _create_recurring(client, token, initiative_id, **kwargs):
body = {"title": "Recurring Test", **kwargs}
return client.post(
f"/api/initiatives/{initiative_id}/recurring",
json=body,
headers=_auth(token),
)
def test_action_ready_status_and_due_at(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
due = (datetime.now(timezone.utc) - timedelta(days=1)).isoformat()
created = client.post(
f"/api/initiatives/{initiative_id}/actions",
json={"title": "Due Action", "status": "ready", "due_at": due},
headers=_auth(token),
)
assert created.status_code == 201
action = created.json()
assert action["status"] == "ready"
assert action["due_at"] is not None
def test_attention_overdue_action(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
action = _create_action(client, token, initiative_id, title="Overdue").json()
past = (datetime.now(timezone.utc) - timedelta(hours=2)).isoformat()
client.patch(
f"/api/actions/{action['id']}",
json={"due_at": past},
headers=_auth(token),
)
res = client.get("/api/workspace/attention", headers=_auth(token))
assert res.status_code == 200
assert any(i["kind"] == "overdue_action" for i in res.json())
def test_attention_review_due(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
past = (datetime.now(timezone.utc) - timedelta(hours=1)).isoformat()
created = _create_review(
client, token, initiative_id, status="planned", due_at=past
)
assert created.status_code == 201
res = client.get("/api/workspace/attention", headers=_auth(token))
assert res.status_code == 200
assert any(i["kind"] == "review_due" for i in res.json())
def test_attention_recurring_due(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
past = (datetime.now(timezone.utc) - timedelta(hours=1)).isoformat()
created = _create_recurring(
client, token, initiative_id, status="active", next_due_at=past
)
assert created.status_code == 201
res = client.get("/api/workspace/attention", headers=_auth(token))
assert res.status_code == 200
assert any(i["kind"] == "recurring_due" for i in res.json())
def test_evidence_crud(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
created = _create_evidence(client, token, initiative_id)
assert created.status_code == 201
ev_id = created.json()["id"]
listed = client.get(
f"/api/initiatives/{initiative_id}/evidence", headers=_auth(token)
)
assert listed.status_code == 200
assert len(listed.json()) == 1
deleted = client.delete(f"/api/evidence/{ev_id}", headers=_auth(token))
assert deleted.status_code == 204
def test_decision_crud(client):
user = provision_user_in_tenant(tenant_role="member")
token = _login(client, user)
initiative_id = _create_initiative(client, token).json()["id"]
created = _create_decision(client, token, initiative_id, status="proposed")
assert created.status_code == 201
dec_id = created.json()["id"]
patched = client.patch(
f"/api/decisions/{dec_id}",
json={"status": "decided", "outcome": "Ja"},
headers=_auth(token),
)
assert patched.status_code == 200
assert patched.json()["status"] == "decided"
def test_member_has_ap09_capabilities(client):
member = provision_user_in_tenant(tenant_role="member")
token = _login(client, member)
ctx = client.get("/api/me/context", headers=_auth(token)).json()
caps = ctx["capabilities"]
for key in (
"kairo.evidence.read",
"kairo.evidence.manage",
"kairo.decision.read",
"kairo.decision.manage",
"kairo.review.read",
"kairo.review.manage",
"kairo.recurring.read",
"kairo.recurring.manage",
):
assert key in caps