| |
| |
| |
| |
| |
| |
| import { test } from "node:test"; |
| import assert from "node:assert/strict"; |
| import { |
| isLegalTransition, |
| assertLegalTransition, |
| IllegalLifecycleTransitionError, |
| ALL_LIFECYCLE_STATES, |
| type CapabilityLifecycleState, |
| } from "../lifecycle.ts"; |
|
|
| const LEGAL: ReadonlyArray<[CapabilityLifecycleState, CapabilityLifecycleState]> = [ |
| ["created", "cold_start"], |
| ["cold_start", "graduated"], |
| ["cold_start", "degraded"], |
| ["graduated", "live"], |
| ["graduated", "degraded"], |
| ["live", "degraded"], |
| ["degraded", "cold_start"], |
| ["degraded", "live"], |
| ]; |
|
|
| test("lifecycle: isLegalTransition matches expected matrix", () => { |
| for (const [from, to] of LEGAL) { |
| assert.equal(isLegalTransition(from, to), true, `${from}→${to} should be legal`); |
| } |
| |
| for (const s of ALL_LIFECYCLE_STATES) { |
| assert.equal(isLegalTransition(s, s), false, `self ${s}→${s} should not be legal`); |
| } |
| |
| assert.equal(isLegalTransition("created", "live"), false); |
| assert.equal(isLegalTransition("created", "degraded"), false); |
| assert.equal(isLegalTransition("graduated", "cold_start"), false); |
| assert.equal(isLegalTransition("live", "created"), false); |
| }); |
|
|
| test("lifecycle: assertLegalTransition throws IllegalLifecycleTransitionError on bad jump", () => { |
| assert.throws( |
| () => assertLegalTransition("created", "live"), |
| (err: unknown) => err instanceof IllegalLifecycleTransitionError, |
| ); |
| }); |
|
|
| const SKIP_DB = !process.env["DATABASE_URL"]; |
|
|
| test( |
| "lifecycle: transitionTo persists capability_lifecycle_events row", |
| { skip: SKIP_DB && "DATABASE_URL not set" }, |
| async () => { |
| const { transitionTo } = await import("../lifecycle.ts"); |
| const { db, capabilityLifecycleEvents } = await import("@workspace/db"); |
| const { eq } = await import("drizzle-orm"); |
| const capabilityId = `cap_b1test_${Math.random().toString(16).slice(2, 8)}`; |
| const r = await transitionTo({ |
| capabilityId, |
| from: "created", |
| to: "cold_start", |
| reason: "b1_test", |
| payload: { foo: "bar" }, |
| }); |
| assert.ok(r.eventId); |
| const rows = await db |
| .select() |
| .from(capabilityLifecycleEvents) |
| .where(eq(capabilityLifecycleEvents.id, r.eventId)); |
| assert.equal(rows.length, 1); |
| assert.equal(rows[0]!.capabilityId, capabilityId); |
| assert.equal(rows[0]!.toState, "cold_start"); |
| assert.equal(rows[0]!.reason, "b1_test"); |
| |
| await db |
| .delete(capabilityLifecycleEvents) |
| .where(eq(capabilityLifecycleEvents.id, r.eventId)); |
| }, |
| ); |
|
|
| test( |
| "lifecycle: transitionTo throws on illegal transition (no row written)", |
| { skip: SKIP_DB && "DATABASE_URL not set" }, |
| async () => { |
| const { transitionTo } = await import("../lifecycle.ts"); |
| await assert.rejects( |
| () => |
| transitionTo({ |
| capabilityId: "cap_b1test_illegal", |
| from: "created", |
| to: "live", |
| reason: "should_fail", |
| }), |
| (err: unknown) => err instanceof IllegalLifecycleTransitionError, |
| ); |
| }, |
| ); |
|
|