fix(e2e): stream docker stats resource scans

This commit is contained in:
Vincent Koc
2026-06-04 08:52:42 +02:00
parent 0d109750ae
commit 5c08fb225a
2 changed files with 36 additions and 10 deletions

View File

@@ -1,4 +1,5 @@
import fs from "node:fs";
import { createInterface } from "node:readline";
const [statsFile, maxMemoryRaw, maxCpuRaw, label = "docker"] = process.argv.slice(2);
const maxMemoryMiB = Number(maxMemoryRaw);
@@ -55,9 +56,19 @@ function assertSampleValue(value, raw, name, labelLocal) {
}
}
const lines = fs.existsSync(statsFile)
? fs.readFileSync(statsFile, "utf8").split(/\r?\n/u).filter(Boolean)
: [];
async function scanStatsFileLines(file, onLine) {
if (!fs.existsSync(file)) {
return;
}
const input = fs.createReadStream(file, { encoding: "utf8" });
const lines = createInterface({ crlfDelay: Infinity, input });
for await (const line of lines) {
if (line) {
onLine(line);
}
}
}
let maxObservedMemoryMiB = 0;
let maxObservedCpuPercent = 0;
let parsedSamples = 0;
@@ -65,7 +76,7 @@ let parsedSamples = 0;
assertFiniteLimit(maxMemoryMiB, maxMemoryRaw, "max memory MiB");
assertFiniteLimit(maxCpuPercent, maxCpuRaw, "max CPU percent");
for (const line of lines) {
await scanStatsFileLines(statsFile, (line) => {
let parsed;
try {
parsed = JSON.parse(line);
@@ -79,7 +90,7 @@ for (const line of lines) {
parsedSamples += 1;
maxObservedMemoryMiB = Math.max(maxObservedMemoryMiB, observedMemoryMiB);
maxObservedCpuPercent = Math.max(maxObservedCpuPercent, observedCpuPercent);
}
});
console.log(
`${label} resource peak: memory=${maxObservedMemoryMiB.toFixed(1)}MiB cpu=${maxObservedCpuPercent.toFixed(1)}% samples=${parsedSamples}`,

View File

@@ -1,5 +1,5 @@
import { spawnSync } from "node:child_process";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
@@ -16,9 +16,13 @@ function writeStats(contents: string): string {
}
function runAssert(statsFile: string, maxMemoryMiB = "512", maxCpuPercent = "100") {
return spawnSync(process.execPath, [SCRIPT_PATH, statsFile, maxMemoryMiB, maxCpuPercent, "test"], {
encoding: "utf8",
});
return spawnSync(
process.execPath,
[SCRIPT_PATH, statsFile, maxMemoryMiB, maxCpuPercent, "test"],
{
encoding: "utf8",
},
);
}
afterEach(() => {
@@ -36,7 +40,10 @@ describe("scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs", () => {
});
it("rejects invalid resource limits instead of disabling the ceiling", () => {
const result = runAssert(writeStats('{"MemUsage":"128MiB / 2GiB","CPUPerc":"25.0%"}\n'), "nope");
const result = runAssert(
writeStats('{"MemUsage":"128MiB / 2GiB","CPUPerc":"25.0%"}\n'),
"nope",
);
expect(result.status).not.toBe(0);
expect(result.stderr).toContain("max memory MiB must be a finite non-negative number");
@@ -67,6 +74,14 @@ describe("scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs", () => {
expect(result.stdout).toContain("samples=1");
});
it("streams stats logs instead of slurping them into memory", () => {
const source = readFileSync(SCRIPT_PATH, "utf8");
expect(source).toContain("createReadStream");
expect(source).not.toContain("readFileSync(statsFile");
expect(source).not.toContain("split(/\\r?\\n/u)");
});
it("accepts byte-unit Docker memory samples", () => {
const result = runAssert(writeStats('{"MemUsage":"512B / 2GiB","CPUPerc":"0.5%"}\n'));