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
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>
166 lines
5.4 KiB
Python
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
|