122 lines
4.0 KiB
TypeScript
122 lines
4.0 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
|
|
let runtimeRoot = "";
|
|
let readState: (typeof import("../src/lib/boss-data"))["readState"];
|
|
let writeState: (typeof import("../src/lib/boss-data"))["writeState"];
|
|
let approveRepairTicket: (typeof import("../src/lib/boss-data"))["approveRepairTicket"];
|
|
let verifyRepairTicket: (typeof import("../src/lib/boss-data"))["verifyRepairTicket"];
|
|
let subscribeBossEvents: (typeof import("../src/lib/boss-events"))["subscribeBossEvents"];
|
|
|
|
async function setup() {
|
|
if (runtimeRoot) return;
|
|
|
|
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-ops-events-"));
|
|
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
|
|
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
|
|
|
|
const data = await import("../src/lib/boss-data.ts");
|
|
const events = await import("../src/lib/boss-events.ts");
|
|
readState = data.readState;
|
|
writeState = data.writeState;
|
|
approveRepairTicket = data.approveRepairTicket;
|
|
verifyRepairTicket = data.verifyRepairTicket;
|
|
subscribeBossEvents = events.subscribeBossEvents;
|
|
}
|
|
|
|
async function resetOpsState() {
|
|
const state = await readState();
|
|
state.opsFaults = [
|
|
{
|
|
faultId: "fault-win-camera",
|
|
faultKey: "WIN_CAMERA_UPLOAD_DELAY",
|
|
severity: "high",
|
|
status: "open",
|
|
nodeId: "mac-studio",
|
|
serviceName: "boss-local-agent",
|
|
projectId: "master-agent",
|
|
threadRef: "thread-ops-1",
|
|
traceId: "trace-ops-1",
|
|
runbookId: "runbook-camera-sync",
|
|
firstSeenAt: "2026-03-25T11:34:00+08:00",
|
|
lastSeenAt: "2026-03-25T11:58:00+08:00",
|
|
summary: "摄像头证据上传延迟。",
|
|
suggestedNextAction: "重试本地 agent 上传。",
|
|
autoRepairable: true,
|
|
},
|
|
];
|
|
state.opsRepairTickets = [
|
|
{
|
|
ticketId: "ticket-win-camera",
|
|
faultId: "fault-win-camera",
|
|
title: "重试摄像头证据上传",
|
|
approvalStatus: "approved",
|
|
executionStatus: "running",
|
|
requestedBy: "运维 Agent",
|
|
approvedBy: "主 Agent",
|
|
targetNodeId: "mac-studio",
|
|
actionSummary: "重新触发本地 agent 心跳和摄像头证据上传。",
|
|
resultSummary: "等待复验中。",
|
|
createdAt: "2026-03-25T11:42:00+08:00",
|
|
updatedAt: "2026-03-25T11:57:00+08:00",
|
|
},
|
|
];
|
|
state.opsRepairVerifications = [
|
|
{
|
|
verificationId: "verify-win-camera",
|
|
ticketId: "ticket-win-camera",
|
|
verifier: "运维审计 Agent",
|
|
status: "watching",
|
|
summary: "等待关键帧落库后关闭工单。",
|
|
verifiedAt: "2026-03-25T11:58:00+08:00",
|
|
},
|
|
];
|
|
await writeState(state);
|
|
}
|
|
|
|
test.beforeEach(async () => {
|
|
await setup();
|
|
await resetOpsState();
|
|
});
|
|
|
|
test.after(async () => {
|
|
if (runtimeRoot) {
|
|
await rm(runtimeRoot, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("approve repair ticket publishes project context risk event", async () => {
|
|
const events: Array<{ event: string; payload: { status?: string; note?: string } }> = [];
|
|
const unsubscribe = subscribeBossEvents((event, payload) => {
|
|
events.push({ event, payload });
|
|
});
|
|
|
|
await approveRepairTicket("ticket-win-camera");
|
|
unsubscribe();
|
|
|
|
const latest = events.at(-1);
|
|
assert.ok(latest);
|
|
assert.equal(latest.event, "project.context_risk.updated");
|
|
assert.equal(latest.payload.status, "approved");
|
|
assert.equal(latest.payload.note, "ticket-win-camera");
|
|
});
|
|
|
|
test("verify repair ticket publishes project context risk event", async () => {
|
|
const events: Array<{ event: string; payload: { status?: string; note?: string } }> = [];
|
|
const unsubscribe = subscribeBossEvents((event, payload) => {
|
|
events.push({ event, payload });
|
|
});
|
|
|
|
await verifyRepairTicket("ticket-win-camera");
|
|
unsubscribe();
|
|
|
|
const latest = events.at(-1);
|
|
assert.ok(latest);
|
|
assert.equal(latest.event, "project.context_risk.updated");
|
|
assert.equal(latest.payload.status, "verified");
|
|
assert.equal(latest.payload.note, "ticket-win-camera");
|
|
});
|