"""The composition boots, its bricks answer through HTTP together, and a signed-in caller can read each one."""
import inspect
import pathlib
from contextlib import ExitStack
import anyio
import httpx
from sqlalchemy import create_engine
from erp_platform import compose, seam
from erp_platform.scenarios import Catalogue
from erp_platform.scenarios.inprocess import stage
COMPOSE = pathlib.Path(__file__).resolve().parent.parent / "compose.yaml"
def test_composition_boots_and_every_brick_answers_a_signed_in_read(tmp_path):
comp = compose.load(COMPOSE)
assert compose.check(comp)["problems"] == []
engine = create_engine(f"sqlite:///{tmp_path / 'bucket.db'}", connect_args={"check_same_thread": False})
perms = sorted({u.permission for m in comp.members for u in m.brick.use_cases if u.permission})
me = {"sub": "tester.1", "email": "tester@test", "app_roles": ["tester"], "permissions": perms}
async def get(app, path):
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://t") as c:
return await c.get(path, headers=seam.gateway_headers(me))
with ExitStack() as st:
app = stage(Catalogue("t", compose=comp, roles=None), st, lambda name: engine).app
assert anyio.run(get, app, "/healthz").status_code == 200
for m in comp.members:
reads = [u for u in m.brick.use_cases if u.kind == "query" and u.method == "GET" and u.tool
and not u.path_params and all(d is not inspect.Parameter.empty for _, _, d in u.inputs)]
assert reads, f"{m.name}: no plain read use case to call"
# The first plain read may refuse an empty question (activity's GET /contacts wants a bp_id or an
# email: 422). A refusal is the use case answering; a 5xx is the composition broken. So: no read
# may 5xx, and at least one must answer 200.
answers = []
for u in reads:
r = anyio.run(get, app, f"/{m.name}{u.path}")
assert r.status_code < 500, f"{m.name} {u.path}: {r.status_code} {r.text[:200]}"
answers.append(f"{u.path} {r.status_code}")
if r.status_code == 200:
break
else:
raise AssertionError(f"{m.name}: no plain read answered 200 ({', '.join(answers)})")