mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-29 17:41:26 +00:00
fix(qqbot): bound tail log reads to actual bytes returned by fs.readSync (#108955)
* fix(qqbot): bound tail log reads to actual bytes returned by fs.readSync * fix(qqbot): satisfy knip deadcode check for testing export Add __testing re-export and test-api.ts barrel so knip traces the testing export through a recognized entry point. * fix(qqbot): restore testing export alongside __testing re-export Both exports are needed: testing for proof scripts, __testing for knip tracing. * fix(qqbot): remove unused __testing re-export from log-helpers test-api.ts already imports testing and re-exports as __testing. The extra re-export in log-helpers.ts was unused by production code. * fix(qqbot): retry short log tail reads * test(qqbot): keep short-read seam private Co-authored-by: RileyJJY <100176083+RileyJJY@users.noreply.github.com> * test(qqbot): exercise short reads through log export Co-authored-by: RileyJJY <0668000974@xydigit.com> --------- Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: RileyJJY <100176083+RileyJJY@users.noreply.github.com>
This commit is contained in:
@@ -35,6 +35,7 @@ describe("buildBotLogsResult", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
});
|
||||
@@ -59,4 +60,39 @@ describe("buildBotLogsResult", () => {
|
||||
expect(fs.readFileSync(first.filePath, "utf8")).toContain("line 1");
|
||||
expect(fs.readFileSync(second.filePath, "utf8")).toContain("line 2");
|
||||
});
|
||||
|
||||
it("completes short fs.readSync tail windows before selecting lines", () => {
|
||||
const logDir = path.join(tempHome, ".openclaw", "logs");
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
const logFile = path.join(logDir, "gateway.log");
|
||||
const lines = Array.from(
|
||||
{ length: 40 },
|
||||
(_, index) => `line ${String(index + 1).padStart(2, "0")}`,
|
||||
);
|
||||
const contents = `${lines.join("\n")}\n`;
|
||||
fs.writeFileSync(logFile, contents, "utf8");
|
||||
|
||||
const realReadSync = fs.readSync.bind(fs) as typeof fs.readSync;
|
||||
const readSpy = vi.spyOn(fs, "readSync").mockImplementation(((
|
||||
fd: number,
|
||||
buffer: NodeJS.ArrayBufferView,
|
||||
offset: number,
|
||||
length: number,
|
||||
position: number | null,
|
||||
) => {
|
||||
return realReadSync(fd, buffer, offset, Math.min(length, 7), position);
|
||||
}) as typeof fs.readSync);
|
||||
|
||||
const result = buildBotLogsResult();
|
||||
|
||||
expect(readSpy.mock.calls.length).toBeGreaterThan(1);
|
||||
expect(typeof result).toBe("object");
|
||||
if (!result || typeof result === "string") {
|
||||
throw new Error("expected file upload result");
|
||||
}
|
||||
const exportedLogs = fs.readFileSync(result.filePath, "utf8");
|
||||
expect(exportedLogs).toContain("line 01");
|
||||
expect(exportedLogs).toContain("line 40");
|
||||
expect(exportedLogs).not.toContain("\0");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -230,11 +230,25 @@ function tailFileLines(
|
||||
const readSize = Math.min(CHUNK_SIZE, position);
|
||||
position -= readSize;
|
||||
const buf = Buffer.alloc(readSize);
|
||||
fs.readSync(fd, buf, 0, readSize, position);
|
||||
chunks.unshift(buf);
|
||||
bytesRead += readSize;
|
||||
let actualRead = 0;
|
||||
while (actualRead < readSize) {
|
||||
const justRead = fs.readSync(
|
||||
fd,
|
||||
buf,
|
||||
actualRead,
|
||||
readSize - actualRead,
|
||||
position + actualRead,
|
||||
);
|
||||
if (justRead === 0) {
|
||||
throw new Error(`Could not complete log read for ${filePath}`);
|
||||
}
|
||||
actualRead += justRead;
|
||||
}
|
||||
|
||||
for (let i = 0; i < readSize; i++) {
|
||||
chunks.unshift(buf);
|
||||
bytesRead += actualRead;
|
||||
|
||||
for (let i = 0; i < actualRead; i++) {
|
||||
if (buf[i] === 0x0a) {
|
||||
newlineCount++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user