diff --git a/scripts/e2e/kitchen-sink-rpc-walk.mjs b/scripts/e2e/kitchen-sink-rpc-walk.mjs index ec626ae9f253..dde680142221 100644 --- a/scripts/e2e/kitchen-sink-rpc-walk.mjs +++ b/scripts/e2e/kitchen-sink-rpc-walk.mjs @@ -1599,13 +1599,18 @@ function assertProcessResourceCeiling(sample, { label, maxRssMiB, requireSample } return; } + if (!Number.isFinite(sample.rssMiB) || sample.rssMiB <= 0) { + throw new Error(`${label} RSS sample was invalid: ${String(sample.rssMiB)} MiB`); + } + const aggregateRssMiB = sample.aggregateRssMiB ?? sample.rssMiB; + if (!Number.isFinite(aggregateRssMiB) || aggregateRssMiB <= 0) { + throw new Error(`${label} aggregate RSS sample was invalid: ${String(aggregateRssMiB)} MiB`); + } if (sample.rssMiB > maxRssMiB) { throw new Error(`${label} RSS exceeded ${maxRssMiB} MiB: ${sample.rssMiB} MiB`); } - if ((sample.aggregateRssMiB ?? sample.rssMiB) > maxRssMiB) { - throw new Error( - `${label} aggregate RSS exceeded ${maxRssMiB} MiB: ${sample.aggregateRssMiB} MiB`, - ); + if (aggregateRssMiB > maxRssMiB) { + throw new Error(`${label} aggregate RSS exceeded ${maxRssMiB} MiB: ${aggregateRssMiB} MiB`); } } diff --git a/scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs b/scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs index 710d80e0394a..27d7b265c105 100644 --- a/scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs +++ b/scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs @@ -55,6 +55,11 @@ function assertSampleValue(value, raw, name, labelLocal) { `docker stats sample for ${labelLocal} had invalid ${name}: ${JSON.stringify(raw)}`, ); } + if (name === "MemUsage" && value <= 0) { + throw new Error( + `docker stats sample for ${labelLocal} had non-positive ${name}: ${JSON.stringify(raw)}`, + ); + } } async function scanStatsFileLines(file, onLine) { diff --git a/test/scripts/docker-stats-resource-ceiling.test.ts b/test/scripts/docker-stats-resource-ceiling.test.ts index d3ca1b334ccb..ec94b4cacf28 100644 --- a/test/scripts/docker-stats-resource-ceiling.test.ts +++ b/test/scripts/docker-stats-resource-ceiling.test.ts @@ -89,4 +89,11 @@ describe("scripts/e2e/lib/docker-stats/assert-resource-ceiling.mjs", () => { expect(result.status).toBe(0); expect(result.stdout).toContain("samples=1"); }); + + it("rejects zero-memory Docker stats samples as invalid proof", () => { + const result = runAssert(writeStats('{"MemUsage":"0B / 2GiB","CPUPerc":"0.0%"}\n')); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("had non-positive MemUsage"); + }); }); diff --git a/test/scripts/kitchen-sink-rpc-walk.test.ts b/test/scripts/kitchen-sink-rpc-walk.test.ts index bc4608e6337f..de722520942a 100644 --- a/test/scripts/kitchen-sink-rpc-walk.test.ts +++ b/test/scripts/kitchen-sink-rpc-walk.test.ts @@ -1188,6 +1188,15 @@ describe("kitchen-sink RPC process sampling", () => { expect(() => assertResourceCeiling(null)).toThrow("gateway RSS sample was not captured"); }); + it("fails zero-valued process RSS samples", () => { + expect(() => assertResourceCeiling({ rssMiB: 0 })).toThrow( + "gateway RSS sample was invalid: 0 MiB", + ); + expect(() => assertCommandResourceCeiling({ aggregateRssMiB: 0, rssMiB: 128 })).toThrow( + "command aggregate RSS sample was invalid: 0 MiB", + ); + }); + it("fails missing command samples and command RSS spikes", () => { expect(() => assertCommandResourceCeiling(null)).toThrow("command RSS sample was not captured"); expect(() => assertCommandResourceCeiling({ aggregateRssMiB: 8193, rssMiB: 1024 })).toThrow(