Files
legion_kk/tests/unit/root-supervisor.test.ts
self 82f1dfe149 fix: guard duplicate daemon startup
Detect reachable daemon metadata before spawning a detached daemon so the CLI does not print a dead token when the GUI already owns the daemon.

Clarify daemon-required command errors when the daemon is reachable but no token is exported, and await engine disposal for local CLI shutdown.
2026-06-25 14:42:51 +02:00

135 lines
3.2 KiB
TypeScript

import assert from "node:assert/strict"
import test from "node:test"
import type { LegionLogAppendInput } from "../../src/main/legion-log-store"
import { RootSupervisor } from "../../src/engine/root-supervisor"
test("root supervisor starts children, degrades on non-critical failure, and stops in reverse", async () => {
const events: string[] = []
const logs: LegionLogAppendInput[] = []
const supervisor = new RootSupervisor({
recordSystemLog: async (entry) => {
logs.push(entry)
},
children: [
{
id: "first",
start: () => {
events.push("start:first")
},
stop: () => {
events.push("stop:first")
}
},
{
id: "second",
start: () => {
events.push("start:second")
throw new Error("second failed")
},
stop: () => {
events.push("stop:second")
}
},
{
id: "third",
start: () => {
events.push("start:third")
},
stop: () => {
events.push("stop:third")
}
}
]
})
await supervisor.start()
assert.equal(supervisor.getSnapshot().status, "degraded")
assert.deepEqual(
supervisor.getSnapshot().children.map((child) => [child.id, child.status]),
[
["first", "running"],
["second", "failed"],
["third", "running"]
]
)
assert.equal(logs[0]?.type, "legion.root.child_start.error")
await supervisor.stop()
assert.deepEqual(events, [
"start:first",
"start:second",
"start:third",
"stop:third",
"stop:second",
"stop:first"
])
assert.equal(supervisor.getSnapshot().status, "stopped")
})
test("root supervisor stops startup after critical child failure", async () => {
const events: string[] = []
const supervisor = new RootSupervisor({
children: [
{
id: "critical",
critical: true,
start: () => {
events.push("start:critical")
throw new Error("critical failed")
},
stop: () => {
events.push("stop:critical")
}
},
{
id: "next",
start: () => {
events.push("start:next")
},
stop: () => {
events.push("stop:next")
}
}
]
})
await assert.rejects(() => supervisor.start(), /critical failed/)
assert.deepEqual(events, ["start:critical"])
assert.equal(supervisor.getSnapshot().status, "failed")
})
test("root supervisor dispose waits for async child shutdown", async () => {
const events: string[] = []
let releaseStop!: () => void
const stopReleased = new Promise<void>((resolve) => {
releaseStop = resolve
})
const supervisor = new RootSupervisor({
children: [
{
id: "async",
start: () => {
events.push("start")
},
stop: async () => {
events.push("stop:start")
await stopReleased
events.push("stop:end")
}
}
]
})
await supervisor.start()
const disposed = supervisor.dispose()
await Promise.resolve()
assert.deepEqual(events, ["start", "stop:start"])
releaseStop()
await disposed
assert.deepEqual(events, ["start", "stop:start", "stop:end"])
assert.equal(supervisor.getSnapshot().status, "stopped")
})