74 lines
5.2 KiB
TypeScript
74 lines
5.2 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import { randomUUID } from "node:crypto"
|
|
import type { PoolClient } from "pg"
|
|
import { pool, createPool } from "../../db/index.js"
|
|
import { controllerProfileCurrent, publishControllerState, saveControllerProfileCas, withControllerProfileLease } from "./routing-controller-fence.js"
|
|
|
|
/** Disposable SQL only; no RouterOS/native calls. Copies table constraints/defaults without foreign keys. */
|
|
export async function acceptRoutingControllerCas() {
|
|
const schema = "controller_cas_" + randomUUID().replaceAll("-", "")
|
|
const database = createPool(4)
|
|
await pool.query(`CREATE SCHEMA ${schema}`)
|
|
let human: PoolClient | undefined
|
|
try {
|
|
await pool.query(`CREATE TABLE ${schema}.mcp_routing_profiles (LIKE public.mcp_routing_profiles INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES)`)
|
|
human = await database.connect()
|
|
await human.query(`SET search_path TO ${schema},public`)
|
|
const input = { profileId: randomUUID(), connectionId: randomUUID(), expectedVersion: null as number | null,
|
|
profile: { marker: "first-human-grant" }, enabled: true, expiresAt: new Date(Date.now() + 600000).toISOString(),
|
|
credentialId: randomUUID(), generation: "original-generation", policyVersion: 1 }
|
|
assert.equal((await saveControllerProfileCas(human, input))?.version, 1)
|
|
assert.equal(await saveControllerProfileCas(human, input), undefined, "same-owner create collision must not overwrite")
|
|
assert.equal(await saveControllerProfileCas(human, { ...input, connectionId: randomUUID() }), undefined)
|
|
const previousSwitch = new Date(Date.now() - 1000).toISOString()
|
|
await human.query("UPDATE mcp_routing_profiles SET state=$2::jsonb WHERE id=$1", [input.profileId,
|
|
JSON.stringify({ switches: [previousSwitch], lastSwitchAt: previousSwitch, marker: "old-controller-state" })])
|
|
|
|
const fence = { id: input.profileId, connection_id: input.connectionId, version: 1 }
|
|
let entered!: () => void, resume!: () => void
|
|
const started = new Promise<void>(resolve => { entered = resolve })
|
|
const blocked = new Promise<void>(resolve => { resume = resolve })
|
|
let competitorEntered = false
|
|
const tick = withControllerProfileLease(database, input.profileId, async lease => {
|
|
await lease.query(`SET search_path TO ${schema},public`)
|
|
assert.equal(await controllerProfileCurrent(lease, fence), true)
|
|
entered(); await blocked
|
|
assert.equal(await controllerProfileCurrent(lease, fence), false)
|
|
assert.equal(await publishControllerState(lease, fence, { marker: "stale-tick" }), false)
|
|
assert.equal(await publishControllerState(lease, fence, { pausedReason: "stale-stop" }, true), false)
|
|
})
|
|
await started
|
|
try {
|
|
await withControllerProfileLease(database, input.profileId, async () => { competitorEntered = true })
|
|
assert.equal(competitorEntered, false, "second tick cannot enter the same profile")
|
|
const changed = { ...input, expectedVersion: 1, profile: { marker: "new-human-grant" }, generation: "new-generation", credentialId: randomUUID() }
|
|
assert.equal((await saveControllerProfileCas(human, changed))?.version, 2)
|
|
assert.equal(await saveControllerProfileCas(human, changed), undefined, "stale human save must fail CAS")
|
|
} finally { resume(); await tick }
|
|
const saved = (await human.query("SELECT * FROM mcp_routing_profiles WHERE id=$1", [input.profileId])).rows[0]
|
|
assert.equal(saved.enabled, true); assert.equal(saved.version, 2)
|
|
assert.deepEqual(saved.config, { marker: "new-human-grant" })
|
|
assert.deepEqual(saved.state, { switches: [previousSwitch], lastSwitchAt: previousSwitch }, "Human save preserves switch-rate history but replaces prior controller state")
|
|
assert.equal(saved.generation, "new-generation")
|
|
|
|
const current = { ...fence, version: 2 }
|
|
assert.equal(await publishControllerState(human, current, { marker: "fresh-tick" }), true)
|
|
// Emergency/portal pauses currently disable directly, without incrementing version.
|
|
await human.query("UPDATE mcp_routing_profiles SET enabled=false,state=$2::jsonb WHERE id=$1", [input.profileId, JSON.stringify({ pausedReason: "human-emergency-pause" })])
|
|
assert.equal(await controllerProfileCurrent(human, current), false)
|
|
assert.equal(await publishControllerState(human, current, { marker: "stale-after-pause" }), false)
|
|
assert.equal(await publishControllerState(human, current, { pausedReason: "stale-stop" }, true), false)
|
|
assert.deepEqual((await human.query("SELECT state FROM mcp_routing_profiles WHERE id=$1", [input.profileId])).rows[0].state, { pausedReason: "human-emergency-pause" })
|
|
|
|
await assert.rejects(withControllerProfileLease(database, input.profileId, async () => { throw new Error("fixture failure") }), /fixture failure/)
|
|
let released = false
|
|
await withControllerProfileLease(database, input.profileId, async () => { released = true })
|
|
assert.equal(released, true, "throwing tick releases its session lock")
|
|
return { accepted: true, concurrentTicks: "one-owner", staleStateWrites: 0, staleSaveWrites: 0, createCollisionWrites: 0, nativeRequests: 0 }
|
|
} finally {
|
|
human?.release()
|
|
await database.end()
|
|
await pool.query(`DROP SCHEMA ${schema} CASCADE`)
|
|
}
|
|
}
|