95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtemp, readFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { resolve } from "node:path";
|
|
import {
|
|
RuntimeEventPublisher,
|
|
createDiscordWebhookRuntimeEventSink,
|
|
createFileRuntimeEventSink,
|
|
} from "../src/telemetry/index.js";
|
|
|
|
test("runtime event file sink writes ndjson events", async () => {
|
|
const root = await mkdtemp(resolve(tmpdir(), "ai-ops-runtime-events-"));
|
|
const logPath = resolve(root, "runtime-events.ndjson");
|
|
const publisher = new RuntimeEventPublisher({
|
|
sinks: [createFileRuntimeEventSink(logPath)],
|
|
});
|
|
|
|
await publisher.publish({
|
|
type: "session.started",
|
|
severity: "info",
|
|
sessionId: "session-1",
|
|
message: "Session started.",
|
|
metadata: {
|
|
entryNodeId: "entry",
|
|
},
|
|
});
|
|
|
|
const lines = (await readFile(logPath, "utf8"))
|
|
.trim()
|
|
.split("\n")
|
|
.filter((line) => line.length > 0);
|
|
assert.equal(lines.length, 1);
|
|
const parsed = JSON.parse(lines[0] ?? "{}") as Record<string, unknown>;
|
|
assert.equal(parsed.type, "session.started");
|
|
assert.equal(parsed.severity, "info");
|
|
assert.equal(parsed.sessionId, "session-1");
|
|
});
|
|
|
|
test("discord runtime sink supports severity threshold and always-notify types", async () => {
|
|
const requests: Array<{
|
|
url: string;
|
|
body: Record<string, unknown>;
|
|
}> = [];
|
|
|
|
const discordSink = createDiscordWebhookRuntimeEventSink({
|
|
webhookUrl: "https://discord.example/webhook",
|
|
minSeverity: "critical",
|
|
alwaysNotifyTypes: ["session.started", "session.completed"],
|
|
fetchFn: async (url, init) => {
|
|
requests.push({
|
|
url: String(url),
|
|
body: JSON.parse(String(init?.body ?? "{}")) as Record<string, unknown>,
|
|
});
|
|
return new Response(null, { status: 204 });
|
|
},
|
|
});
|
|
|
|
const publisher = new RuntimeEventPublisher({
|
|
sinks: [discordSink],
|
|
});
|
|
|
|
await publisher.publish({
|
|
type: "session.started",
|
|
severity: "info",
|
|
sessionId: "session-1",
|
|
message: "Session started.",
|
|
});
|
|
await publisher.publish({
|
|
type: "node.attempt.completed",
|
|
severity: "warning",
|
|
sessionId: "session-1",
|
|
nodeId: "node-1",
|
|
attempt: 1,
|
|
message: "Validation failed.",
|
|
});
|
|
await publisher.publish({
|
|
type: "session.failed",
|
|
severity: "critical",
|
|
sessionId: "session-1",
|
|
message: "Session failed.",
|
|
});
|
|
|
|
assert.equal(requests.length, 2);
|
|
assert.equal(requests[0]?.url, "https://discord.example/webhook");
|
|
const firstPayload = requests[0]?.body;
|
|
assert.ok(firstPayload);
|
|
const firstEmbeds = firstPayload.embeds as Array<Record<string, unknown>>;
|
|
assert.equal(firstEmbeds[0]?.title, "session.started");
|
|
const secondPayload = requests[1]?.body;
|
|
assert.ok(secondPayload);
|
|
const secondEmbeds = secondPayload.embeds as Array<Record<string, unknown>>;
|
|
assert.equal(secondEmbeds[0]?.title, "session.failed");
|
|
});
|