fix(tests): pytest nach Kernel Spine und Starter-Kit bereinigen
Some checks failed
Deploy Development / deploy (push) Successful in 45s
Test Suite / pytest-backend (push) Failing after 3m33s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 3s
Test Suite / compose-smoke (push) Has been skipped
Some checks failed
Deploy Development / deploy (push) Successful in 45s
Test Suite / pytest-backend (push) Failing after 3m33s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 3s
Test Suite / compose-smoke (push) Has been skipped
list_compatible_methods nur Primary-Methoden; Agile-Graph auf Sprint-Scope; Tests ohne Starter-Action-Kollision; TenantContext-Factory fuer Kernel-Tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
75a6a63665
commit
0443b734c1
|
|
@ -56,7 +56,8 @@ def list_compatible_methods(
|
||||||
return tuple(
|
return tuple(
|
||||||
m
|
m
|
||||||
for m in _METHODS.values()
|
for m in _METHODS.values()
|
||||||
if method_compatible_with_archetype(
|
if m.method_role == "primary"
|
||||||
|
and method_compatible_with_archetype(
|
||||||
m, archetype_key, om_capabilities=om_capabilities
|
m, archetype_key, om_capabilities=om_capabilities
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ class AgileIterationStrategy:
|
||||||
cycle_id = str(active["id"])
|
cycle_id = str(active["id"])
|
||||||
|
|
||||||
from services import actions as action_service
|
from services import actions as action_service
|
||||||
from steering.graph.execution_engine import load_initiative_execution_graph_state
|
|
||||||
|
|
||||||
actions = action_service.list_actions_for_initiative(
|
actions = action_service.list_actions_for_initiative(
|
||||||
tenant_id=ctx.tenant_id, initiative_id=initiative_id
|
tenant_id=ctx.tenant_id, initiative_id=initiative_id
|
||||||
|
|
@ -73,9 +72,22 @@ class AgileIterationStrategy:
|
||||||
if not scoped:
|
if not scoped:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
graph_state = load_initiative_execution_graph_state(
|
scoped_ids = {str(action["id"]) for action in scoped}
|
||||||
tenant_id=ctx.tenant_id,
|
from services import execution_plan as execution_plan_service
|
||||||
initiative_id=initiative_id,
|
from steering.graph.execution_engine import compute_execution_graph_state
|
||||||
|
|
||||||
|
dependencies = execution_plan_service.list_dependencies_for_initiative(
|
||||||
|
tenant_id=ctx.tenant_id, initiative_id=initiative_id
|
||||||
|
)
|
||||||
|
internal_dependencies = [
|
||||||
|
dep
|
||||||
|
for dep in dependencies
|
||||||
|
if str(dep["predecessor_action_id"]) in scoped_ids
|
||||||
|
and str(dep["successor_action_id"]) in scoped_ids
|
||||||
|
]
|
||||||
|
graph_state = compute_execution_graph_state(
|
||||||
|
actions=scoped,
|
||||||
|
dependencies=internal_dependencies,
|
||||||
scope_roadmap_item_id=gate_scope,
|
scope_roadmap_item_id=gate_scope,
|
||||||
)
|
)
|
||||||
ready = build_execution_ready_candidates(
|
ready = build_execution_ready_candidates(
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,54 @@ def add_membership(*, tenant_id: str, user_id: str, tenant_role: str = "member")
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def tenant_context_from_user(user: dict):
|
||||||
|
"""Build TenantContext for direct service/kernel calls in tests."""
|
||||||
|
from psycopg2.extras import RealDictCursor
|
||||||
|
|
||||||
|
from rights_registry import load_grants_for_roles
|
||||||
|
from tenant_context import TenantContext
|
||||||
|
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT t.id, t.slug, t.name, tm.tenant_role
|
||||||
|
FROM tenant_memberships tm
|
||||||
|
JOIN tenants t ON t.id = tm.tenant_id
|
||||||
|
WHERE tm.user_id = %s AND tm.tenant_id = %s
|
||||||
|
""",
|
||||||
|
(user["id"], user["tenant_id"]),
|
||||||
|
)
|
||||||
|
membership = cur.fetchone()
|
||||||
|
if not membership:
|
||||||
|
raise ValueError("Test user has no tenant membership")
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
tenant_role = membership["tenant_role"]
|
||||||
|
caps = frozenset(
|
||||||
|
load_grants_for_roles(
|
||||||
|
portal_role=user["portal_role"],
|
||||||
|
tenant_role=tenant_role,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return TenantContext(
|
||||||
|
user_id=user["id"],
|
||||||
|
email=user["email"],
|
||||||
|
display_name=user["display_name"],
|
||||||
|
portal_role=user["portal_role"],
|
||||||
|
tenant_id=str(membership["id"]),
|
||||||
|
tenant_slug=membership["slug"],
|
||||||
|
tenant_name=membership["name"],
|
||||||
|
tenant_role=tenant_role,
|
||||||
|
actor_id=user.get("actor_id"),
|
||||||
|
actor_type="human" if user.get("actor_id") else None,
|
||||||
|
session_token="test-session",
|
||||||
|
capabilities=caps,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def provision_user_in_tenant(
|
def provision_user_in_tenant(
|
||||||
*,
|
*,
|
||||||
tenant_role: str = "member",
|
tenant_role: str = "member",
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ def test_linear_critical_path_and_next_action(client):
|
||||||
token,
|
token,
|
||||||
title="Neue Küche",
|
title="Neue Küche",
|
||||||
archetype_key="initiative.linear_project",
|
archetype_key="initiative.linear_project",
|
||||||
|
apply_starter_kit=False,
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,25 @@ from tests.factories import provision_user_in_tenant
|
||||||
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
||||||
|
|
||||||
|
|
||||||
|
_STARTER_ACTION_TITLE = "Erster Schritt — Planung konkretisieren"
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_starter_action(client, token, initiative_id):
|
||||||
|
actions = client.get(
|
||||||
|
f"/api/initiatives/{initiative_id}/actions",
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert actions.status_code == 200
|
||||||
|
for action in actions.json():
|
||||||
|
if action.get("title") == _STARTER_ACTION_TITLE:
|
||||||
|
deleted = client.delete(
|
||||||
|
f"/api/actions/{action['id']}",
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert deleted.status_code == 204
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def _gate_ids(client, token, initiative_id):
|
def _gate_ids(client, token, initiative_id):
|
||||||
roadmap = client.get(
|
roadmap = client.get(
|
||||||
f"/api/initiatives/{initiative_id}/roadmap/items",
|
f"/api/initiatives/{initiative_id}/roadmap/items",
|
||||||
|
|
@ -30,6 +49,7 @@ def test_sequential_next_action_only_in_active_gate_horizon(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
g1_id, g2_id = _gate_ids(client, token, initiative_id)
|
g1_id, g2_id = _gate_ids(client, token, initiative_id)
|
||||||
|
_remove_starter_action(client, token, initiative_id)
|
||||||
|
|
||||||
off_horizon = client.post(
|
off_horizon = client.post(
|
||||||
f"/api/initiatives/{initiative_id}/actions",
|
f"/api/initiatives/{initiative_id}/actions",
|
||||||
|
|
@ -77,6 +97,7 @@ def test_agile_on_linear_delegates_primary_without_active_sprint(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
g1_id, _ = _gate_ids(client, token, initiative_id)
|
g1_id, _ = _gate_ids(client, token, initiative_id)
|
||||||
|
_remove_starter_action(client, token, initiative_id)
|
||||||
|
|
||||||
action = client.post(
|
action = client.post(
|
||||||
f"/api/initiatives/{initiative_id}/actions",
|
f"/api/initiatives/{initiative_id}/actions",
|
||||||
|
|
@ -115,6 +136,7 @@ def test_agile_on_linear_sprint_intersects_gate_horizon(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
g1_id, _ = _gate_ids(client, token, initiative_id)
|
g1_id, _ = _gate_ids(client, token, initiative_id)
|
||||||
|
_remove_starter_action(client, token, initiative_id)
|
||||||
|
|
||||||
cycle = client.post(
|
cycle = client.post(
|
||||||
f"/api/initiatives/{initiative_id}/work-cycles",
|
f"/api/initiatives/{initiative_id}/work-cycles",
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,9 @@ def test_steering_methods_filtered_by_archetype(client):
|
||||||
|
|
||||||
|
|
||||||
def test_queue_pull_rejected_on_linear(client):
|
def test_queue_pull_rejected_on_linear(client):
|
||||||
|
from tests.factories import provision_user_in_tenant
|
||||||
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
||||||
|
|
||||||
user = provision_user_in_tenant(tenant_role="member")
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
token = _login(client, user)
|
token = _login(client, user)
|
||||||
|
|
||||||
|
|
@ -145,6 +148,9 @@ def test_queue_pull_rejected_on_linear(client):
|
||||||
|
|
||||||
|
|
||||||
def test_operating_context_composable_modifiers_linear(client):
|
def test_operating_context_composable_modifiers_linear(client):
|
||||||
|
from tests.factories import provision_user_in_tenant
|
||||||
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
||||||
|
|
||||||
user = provision_user_in_tenant(tenant_role="member")
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
token = _login(client, user)
|
token = _login(client, user)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from steering.kernel import apply_steering_event, evaluate_steering
|
from steering.kernel import apply_steering_event, evaluate_steering
|
||||||
from steering.kernel.binding import resolve_steering_binding
|
from steering.kernel.binding import resolve_steering_binding
|
||||||
from tests.factories import provision_user_in_tenant
|
from tests.factories import provision_user_in_tenant, tenant_context_from_user
|
||||||
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -20,9 +20,7 @@ def test_evaluate_steering_linear_binding(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
from tenant_context import TenantContext
|
ctx = tenant_context_from_user(user)
|
||||||
|
|
||||||
ctx = TenantContext(tenant_id=user["tenant_id"], user_id=user["id"])
|
|
||||||
binding = resolve_steering_binding(ctx, initiative_id)
|
binding = resolve_steering_binding(ctx, initiative_id)
|
||||||
assert binding.primary_method_key == "sequential_dependency"
|
assert binding.primary_method_key == "sequential_dependency"
|
||||||
assert binding.composition_modifier is None
|
assert binding.composition_modifier is None
|
||||||
|
|
@ -41,9 +39,7 @@ def test_evaluate_steering_returns_horizon_and_next(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
from tenant_context import TenantContext
|
ctx = tenant_context_from_user(user)
|
||||||
|
|
||||||
ctx = TenantContext(tenant_id=user["tenant_id"], user_id=user["id"])
|
|
||||||
evaluation = evaluate_steering(ctx, initiative_id=initiative_id)
|
evaluation = evaluate_steering(ctx, initiative_id=initiative_id)
|
||||||
assert evaluation.data_source == "steering_kernel_v0.1.1"
|
assert evaluation.data_source == "steering_kernel_v0.1.1"
|
||||||
assert evaluation.lifecycle.slot_map.get("action_selection") == "active"
|
assert evaluation.lifecycle.slot_map.get("action_selection") == "active"
|
||||||
|
|
@ -97,9 +93,7 @@ def test_apply_steering_event_stub(client):
|
||||||
)
|
)
|
||||||
initiative_id = created.json()["id"]
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
from tenant_context import TenantContext
|
ctx = tenant_context_from_user(user)
|
||||||
|
|
||||||
ctx = TenantContext(tenant_id=user["tenant_id"], user_id=user["id"])
|
|
||||||
result = apply_steering_event(
|
result = apply_steering_event(
|
||||||
ctx,
|
ctx,
|
||||||
initiative_id=initiative_id,
|
initiative_id=initiative_id,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user