fix(e2e): bound plugin update log assertions

This commit is contained in:
Vincent Koc
2026-06-07 04:40:38 +02:00
parent e32707458d
commit bcfd7164de
2 changed files with 74 additions and 3 deletions

View File

@@ -8,11 +8,14 @@ import {
readPluginInstallRecords,
writePluginInstallIndexForE2E,
} from "../plugin-index-sqlite.mjs";
import { readTextFileTail } from "../text-file-utils.mjs";
const command = process.argv[2];
const scratchRoot = process.env.OPENCLAW_PLUGINS_TMP_DIR || os.tmpdir();
const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
const scratchFile = (name) => path.join(scratchRoot, name);
const ERROR_DETAIL_TAIL_BYTES = 16 * 1024;
const LOG_SCAN_CHUNK_BYTES = 64 * 1024;
function readClawHubPreflightLimits() {
return {
@@ -114,6 +117,40 @@ function pathsEqual(left, right) {
return comparablePath(left) === comparablePath(right);
}
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(LOG_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(0, needle.length - 1));
}
return false;
} finally {
fs.closeSync(fd);
}
}
function getInstallRecords() {
const configPath = openClawConfigPath();
const config = readOpenClawConfig();
@@ -288,10 +325,10 @@ function assertSimplePlugin(jsonFile, inspectFile, pluginId, method) {
}
function assertUpdateOutput(logFile, expectedSnippet) {
const output = fs.readFileSync(logFile, "utf8");
if (!output.includes(expectedSnippet)) {
if (!fileContainsText(logFile, expectedSnippet)) {
const outputTail = readTextFileTail(logFile, ERROR_DETAIL_TAIL_BYTES);
throw new Error(
`expected update output to include ${JSON.stringify(expectedSnippet)}:\n${output}`,
`expected update output to include ${JSON.stringify(expectedSnippet)}. Output tail:\n${outputTail}`,
);
}
}

View File

@@ -208,6 +208,40 @@ test -d "$OPENCLAW_PLUGINS_TMP_DIR"
}
});
it("scans plugin update logs without echoing whole files on failure", async () => {
const root = mkdtempSync(path.join(tmpdir(), "openclaw-plugin-update-log-"));
try {
const passRoot = path.join(root, "pass");
mkdirSync(passRoot, { recursive: true });
writeFileSync(
path.join(passRoot, "plugins-dir-update.log"),
`Skipping "demo-plugin-dir" (source: path).\n${"x".repeat(256 * 1024)}`,
"utf8",
);
const pass = await runAssertionAsync(["plugin-dir-update-skipped"], {
OPENCLAW_PLUGINS_TMP_DIR: passRoot,
});
expect(pass.status).toBe(0);
const failRoot = path.join(root, "fail");
mkdirSync(failRoot, { recursive: true });
writeFileSync(
path.join(failRoot, "plugins-dir-update.log"),
`${"x".repeat(256 * 1024)}\nmissing marker tail`,
"utf8",
);
const fail = await runAssertionAsync(["plugin-dir-update-skipped"], {
OPENCLAW_PLUGINS_TMP_DIR: failRoot,
});
expect(fail.status).toBe(1);
expect(fail.stderr).toContain("Output tail:");
expect(fail.stderr).toContain("missing marker tail");
expect(fail.stderr.length).toBeLessThan(20 * 1024);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
it("cleans npm fixture registry children when readiness times out", () => {
const root = mkdtempSync(path.join(tmpdir(), "openclaw-plugin-npm-fixture-cleanup-"));
try {