mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(e2e): bound release journey output assertions
This commit is contained in:
@@ -8,6 +8,11 @@ import {
|
||||
import { readBoundedResponseText as readBoundedResponseTextWithLimit } from "../bounded-response-text.mjs";
|
||||
import { applyMockOpenAiModelConfig } from "../fixtures/mock-openai-config.mjs";
|
||||
import { readPluginInstallRecords } from "../plugin-index-sqlite.mjs";
|
||||
import { readTextFileTail } from "../text-file-utils.mjs";
|
||||
|
||||
const SCAN_CHUNK_BYTES = 64 * 1024;
|
||||
const SCAN_CARRY_CHARS = 256;
|
||||
const ERROR_DETAIL_TAIL_BYTES = 16 * 1024;
|
||||
|
||||
function clickClackHttpTimeoutMs() {
|
||||
return readPositiveInt(process.env.OPENCLAW_RELEASE_USER_JOURNEY_HTTP_TIMEOUT_MS, 5000);
|
||||
@@ -33,6 +38,41 @@ function readPositiveInt(raw, fallback) {
|
||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
||||
}
|
||||
|
||||
function fileContainsText(file, needle) {
|
||||
let stat;
|
||||
try {
|
||||
stat = fs.statSync(file);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
if (!stat.isFile() || stat.size <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fd = fs.openSync(file, "r");
|
||||
try {
|
||||
const buffer = Buffer.alloc(Math.min(SCAN_CHUNK_BYTES, stat.size));
|
||||
let carry = "";
|
||||
let offset = 0;
|
||||
while (offset < stat.size) {
|
||||
const bytesToRead = Math.min(buffer.length, stat.size - offset);
|
||||
const bytesRead = fs.readSync(fd, buffer, 0, bytesToRead, offset);
|
||||
if (bytesRead <= 0) {
|
||||
break;
|
||||
}
|
||||
offset += bytesRead;
|
||||
const text = carry + buffer.subarray(0, bytesRead).toString("utf8");
|
||||
if (text.includes(needle)) {
|
||||
return true;
|
||||
}
|
||||
carry = text.slice(-Math.max(SCAN_CARRY_CHARS, needle.length - 1));
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
fs.closeSync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
async function withClickClackFixtureResponse(url, init, consume, options = {}) {
|
||||
const timeoutMs = options.timeoutMs ?? clickClackHttpTimeoutMs();
|
||||
const controller = new AbortController();
|
||||
@@ -134,8 +174,10 @@ function assertAgentTurn() {
|
||||
function assertFileContains() {
|
||||
const file = process.argv[3];
|
||||
const needle = process.argv[4];
|
||||
const raw = fs.readFileSync(file, "utf8");
|
||||
assert(raw.includes(needle), `${file} did not contain ${needle}. Output: ${raw}`);
|
||||
assert(
|
||||
fileContainsText(file, needle),
|
||||
`${file} did not contain ${needle}. Output tail: ${readTextFileTail(file, ERROR_DETAIL_TAIL_BYTES)}`,
|
||||
);
|
||||
}
|
||||
|
||||
function rememberPluginInstallPath() {
|
||||
|
||||
@@ -87,6 +87,55 @@ async function startTcpFixtureServer(handler: (socket: Socket) => void): Promise
|
||||
}
|
||||
|
||||
describe("release user journey assertions", () => {
|
||||
it("scans large files when checking release user journey output text", () => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "openclaw-release-user-assertions-"));
|
||||
const home = path.join(root, "home");
|
||||
const outputPath = path.join(root, "output.log");
|
||||
|
||||
try {
|
||||
const needlePrefix = "journey-plugin";
|
||||
writeFileSync(
|
||||
outputPath,
|
||||
`${"x".repeat(64 * 1024 - needlePrefix.length)}${needlePrefix}-a:pong\n`,
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const result = runAssertion(home, [
|
||||
"assert-file-contains",
|
||||
outputPath,
|
||||
"journey-plugin-a:pong",
|
||||
]);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stderr).toBe("");
|
||||
} finally {
|
||||
rmSync(root, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("bounds release user journey output assertion diagnostics", () => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "openclaw-release-user-assertions-"));
|
||||
const home = path.join(root, "home");
|
||||
const outputPath = path.join(root, "output.log");
|
||||
|
||||
try {
|
||||
writeFileSync(
|
||||
outputPath,
|
||||
`DO_NOT_DUMP_OLD_OUTPUT${"x".repeat(70 * 1024)}\nrecent output tail\n`,
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const result = runAssertion(home, ["assert-file-contains", outputPath, "missing"]);
|
||||
|
||||
expect(result.status).not.toBe(0);
|
||||
expect(result.stderr).toContain("Output tail:");
|
||||
expect(result.stderr).toContain("recent output tail");
|
||||
expect(result.stderr).not.toContain("DO_NOT_DUMP_OLD_OUTPUT");
|
||||
} finally {
|
||||
rmSync(root, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("fails when uninstall leaves the managed plugin directory behind", () => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "openclaw-release-user-assertions-"));
|
||||
const home = path.join(root, "home");
|
||||
|
||||
Reference in New Issue
Block a user