mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-29 23:08:46 +00:00
193 lines
6.4 KiB
TypeScript
193 lines
6.4 KiB
TypeScript
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
assertAgentReplyContainsMarker,
|
|
assertOpenAiRequestLogUsed,
|
|
extractAgentReplyTexts,
|
|
} from "../../scripts/e2e/lib/agent-turn-output.mjs";
|
|
|
|
describe("scripts/e2e/lib/agent-turn-output", () => {
|
|
it("extracts local and gateway agent reply payload text", () => {
|
|
expect(
|
|
extractAgentReplyTexts(
|
|
JSON.stringify({
|
|
payloads: [{ text: "OPENCLAW_E2E_OK_LOCAL" }],
|
|
meta: { finalAssistantVisibleText: "visible" },
|
|
}),
|
|
),
|
|
).toEqual(["visible", "OPENCLAW_E2E_OK_LOCAL"]);
|
|
|
|
expect(
|
|
extractAgentReplyTexts(
|
|
JSON.stringify({
|
|
result: {
|
|
payloads: [{ text: "OPENCLAW_E2E_OK_GATEWAY" }],
|
|
meta: { finalAssistantRawText: "raw" },
|
|
},
|
|
}),
|
|
),
|
|
).toEqual(["raw", "OPENCLAW_E2E_OK_GATEWAY"]);
|
|
});
|
|
|
|
it("reads compact JSON replies from combined stdout and stderr logs", () => {
|
|
expect(
|
|
extractAgentReplyTexts(
|
|
[
|
|
"warning: diagnostic on stderr",
|
|
JSON.stringify({ payloads: [{ text: "OPENCLAW_E2E_OK_COMBINED" }] }),
|
|
].join("\n"),
|
|
),
|
|
).toEqual(["OPENCLAW_E2E_OK_COMBINED"]);
|
|
});
|
|
|
|
it("reads pretty JSON replies from combined stdout and stderr logs", () => {
|
|
expect(
|
|
extractAgentReplyTexts(
|
|
[
|
|
"warning: diagnostic on stderr",
|
|
JSON.stringify(
|
|
{
|
|
payloads: [{ text: "OPENCLAW_E2E_OK_PRETTY" }],
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
].join("\n"),
|
|
),
|
|
).toEqual(["OPENCLAW_E2E_OK_PRETTY"]);
|
|
});
|
|
|
|
it("does not accept markers that only appear outside reply payloads", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-agent-output-"));
|
|
try {
|
|
const outputPath = join(dir, "agent.log");
|
|
writeFileSync(
|
|
outputPath,
|
|
[
|
|
"Return marker OPENCLAW_E2E_OK_PROMPT_ECHO",
|
|
JSON.stringify({ payloads: [{ text: "wrong reply" }] }),
|
|
].join("\n"),
|
|
);
|
|
|
|
expect(() =>
|
|
assertAgentReplyContainsMarker("OPENCLAW_E2E_OK_PROMPT_ECHO", outputPath),
|
|
).toThrow(/agent reply payload did not contain marker/u);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("bounds missing marker diagnostics to the recent output tail", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-agent-output-"));
|
|
try {
|
|
const outputPath = join(dir, "agent.log");
|
|
writeFileSync(
|
|
outputPath,
|
|
[
|
|
"DO_NOT_DUMP_OLD_OUTPUT",
|
|
"x".repeat(70 * 1024),
|
|
JSON.stringify({ payloads: [{ text: "wrong reply" }] }),
|
|
].join("\n"),
|
|
);
|
|
|
|
expect(() => assertAgentReplyContainsMarker("OPENCLAW_E2E_OK_MISSING", outputPath)).toThrow(
|
|
/agent reply payload did not contain marker/u,
|
|
);
|
|
try {
|
|
assertAgentReplyContainsMarker("OPENCLAW_E2E_OK_MISSING", outputPath);
|
|
} catch (error) {
|
|
expect(error).toBeInstanceOf(Error);
|
|
expect((error as Error).message).toContain("Output tail:");
|
|
expect((error as Error).message).toContain("wrong reply");
|
|
expect((error as Error).message).not.toContain("DO_NOT_DUMP_OLD_OUTPUT");
|
|
}
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("bounds large reply payload diagnostics", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-agent-output-"));
|
|
try {
|
|
const outputPath = join(dir, "agent.log");
|
|
writeFileSync(
|
|
outputPath,
|
|
JSON.stringify({
|
|
payloads: [
|
|
{
|
|
text: `DO_NOT_DUMP_OLD_REPLY${"x".repeat(70 * 1024)}recent reply tail`,
|
|
},
|
|
],
|
|
}),
|
|
);
|
|
|
|
try {
|
|
assertAgentReplyContainsMarker("OPENCLAW_E2E_OK_MISSING", outputPath);
|
|
} catch (error) {
|
|
expect(error).toBeInstanceOf(Error);
|
|
expect((error as Error).message).toContain("Reply payload summary:");
|
|
expect((error as Error).message).toContain("recent reply tail");
|
|
expect((error as Error).message).not.toContain("DO_NOT_DUMP_OLD_REPLY");
|
|
return;
|
|
}
|
|
throw new Error("expected missing marker assertion to fail");
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("checks that the mock OpenAI endpoint was actually hit", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-request-log-"));
|
|
try {
|
|
mkdirSync(dir, { recursive: true });
|
|
const logPath = join(dir, "requests.jsonl");
|
|
writeFileSync(logPath, `${JSON.stringify({ path: "/v1/responses" })}\n`);
|
|
expect(() => assertOpenAiRequestLogUsed(logPath)).not.toThrow();
|
|
|
|
writeFileSync(logPath, `${JSON.stringify({ path: "/health" })}\n`);
|
|
expect(() => assertOpenAiRequestLogUsed(logPath)).toThrow(/was not used/u);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("finds OpenAI request paths split across large log scan chunks", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-request-log-"));
|
|
try {
|
|
const logPath = join(dir, "requests.jsonl");
|
|
const pathPrefix = "/v1/res";
|
|
writeFileSync(logPath, `${"x".repeat(64 * 1024 - pathPrefix.length)}${pathPrefix}ponses\n`);
|
|
|
|
expect(() => assertOpenAiRequestLogUsed(logPath)).not.toThrow();
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("bounds missing OpenAI request diagnostics to the recent log tail", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "openclaw-e2e-request-log-"));
|
|
try {
|
|
const logPath = join(dir, "requests.jsonl");
|
|
writeFileSync(
|
|
logPath,
|
|
["DO_NOT_DUMP_OLD_REQUESTS", "x".repeat(70 * 1024), '{"path":"/health"}'].join("\n"),
|
|
);
|
|
|
|
try {
|
|
assertOpenAiRequestLogUsed(logPath, "mock server");
|
|
} catch (error) {
|
|
expect(error).toBeInstanceOf(Error);
|
|
expect((error as Error).message).toContain("mock server was not used");
|
|
expect((error as Error).message).toContain("Request log tail:");
|
|
expect((error as Error).message).not.toContain("DO_NOT_DUMP_OLD_REQUESTS");
|
|
return;
|
|
}
|
|
throw new Error("expected missing request log assertion to fail");
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|