feat(backends,api,ui): process trees with cpu and stderr per session, interrupt, close and kill from the system page
This commit is contained in:
1 parent
9875f08016
commit
712c24de4e
12 files changed
+996
-127
No files matched your search
@@ -396,6 +396,54 @@ async def test_describe_snapshots_open_tools_and_records_rate_limit(
|
||||
assert page["offset"] == 0 and len(page["entries"]) == 1
|
||||
|
||||
|
||||
async def test_sessions_show_their_processes_and_take_orders(world: World) -> None:
|
||||
world.backend._factory = ToolClient # noqa: SLF001
|
||||
api = Api(world)
|
||||
api.store.grant("api-only", "weak", scope="api")
|
||||
weak = {"Authorization": "Bearer weak"}
|
||||
conv = await world.conversations.create(kind="master", agent="a", origin="test")
|
||||
key = conv.external_id
|
||||
ScriptedClient.hold = asyncio.Event()
|
||||
await world.conversations.post(conv, "go")
|
||||
await asyncio.sleep(0.3)
|
||||
census = await api.get("/sessions")
|
||||
(row,) = census["sessions"]
|
||||
assert row["key"] == key and row["busy"]
|
||||
assert row["processes"] == [] and row["cpu"] is None
|
||||
assert isinstance(census["others"], list)
|
||||
live = world.pool.get(key)
|
||||
assert live is not None
|
||||
live.stderr.append("warning: something")
|
||||
stderr = await api.get(f"/sessions/{key}/stderr")
|
||||
assert stderr["lines"] == ["warning: something"]
|
||||
for path in (f"/sessions/{key}/close", "/processes/1/kill"):
|
||||
assert (await api.http.post(path, headers=weak)).status_code == 403
|
||||
assert (
|
||||
await api.http.get(f"/sessions/{key}/stderr", headers=weak)
|
||||
).status_code == 403
|
||||
|
||||
closed = await api.http.post(f"/sessions/{key}/close", headers=HEADERS)
|
||||
assert closed.json() == {"key": key, "closed": True}
|
||||
assert world.pool.get(key) is None
|
||||
deadline = asyncio.get_running_loop().time() + 5
|
||||
while ("user", "failed") not in await world.statuses(conv):
|
||||
assert asyncio.get_running_loop().time() < deadline, "the cut turn hangs"
|
||||
await asyncio.sleep(0.02)
|
||||
again = await api.http.post(f"/sessions/{key}/close", headers=HEADERS)
|
||||
assert again.status_code == 404
|
||||
gone = await api.http.post("/processes/999999999/kill", headers=HEADERS)
|
||||
assert gone.status_code == 404
|
||||
|
||||
ScriptedClient.hold = asyncio.Event()
|
||||
await world.conversations.post(conv, "once more")
|
||||
await asyncio.sleep(0.3)
|
||||
interrupted = await api.http.post(f"/sessions/{key}/interrupt", headers=weak)
|
||||
assert interrupted.json() == {"key": key, "interrupted": True}
|
||||
assert ScriptedClient.instances[-1].interrupted
|
||||
kinds = [r["kind"] for r in (await api.get("/audit"))["records"]]
|
||||
assert kinds == ["session_interrupt", "session_close"]
|
||||
|
||||
|
||||
async def test_tokens_and_audit_need_admin_scope(world: World) -> None:
|
||||
api = Api(world)
|
||||
api.store.grant("api-only", "weak", scope="api")
|
||||
|
||||
Reference in new issue
Block a user