diff --git a/scripts/e2e/kitchen-sink-rpc-walk.mjs b/scripts/e2e/kitchen-sink-rpc-walk.mjs index 37994c23caf9..a5d584a9e506 100644 --- a/scripts/e2e/kitchen-sink-rpc-walk.mjs +++ b/scripts/e2e/kitchen-sink-rpc-walk.mjs @@ -1740,7 +1740,7 @@ function parsePosixProcessRows(stdout) { const processId = Number.parseInt(pidRaw, 10); const parentProcessId = Number.parseInt(ppidRaw, 10); const rssKb = Number.parseInt(rssKbRaw, 10); - const cpuPercent = Number.parseFloat(cpuRaw); + const cpuPercent = parsePosixCpuPercent(cpuRaw); if ( !Number.isInteger(processId) || !Number.isInteger(parentProcessId) || @@ -1752,13 +1752,22 @@ function parsePosixProcessRows(stdout) { processId, parentProcessId, rssKb, - cpuPercent: Number.isFinite(cpuPercent) ? cpuPercent : null, + cpuPercent, command: command ?? "", }; }) .filter(Boolean); } +function parsePosixCpuPercent(raw) { + const text = String(raw ?? "").trim(); + if (!/^(?:0|[1-9]\d*)(?:\.\d+)?$/u.test(text)) { + return null; + } + const parsed = Number(text); + return Number.isFinite(parsed) ? parsed : null; +} + function collectPosixProcessTree(rows, rootPid) { const byParent = new Map(); for (const row of rows) { diff --git a/test/scripts/kitchen-sink-rpc-walk.test.ts b/test/scripts/kitchen-sink-rpc-walk.test.ts index ff94c0a64d16..489577f0f84a 100644 --- a/test/scripts/kitchen-sink-rpc-walk.test.ts +++ b/test/scripts/kitchen-sink-rpc-walk.test.ts @@ -1412,6 +1412,23 @@ describe("kitchen-sink RPC process sampling", () => { }); }); + it("does not truncate malformed POSIX CPU samples", async () => { + const sample = await sampleProcess(4321, { + platform: "linux", + runCommand: async () => ({ + stdout: " 4321 1 262144 12.5.6 node dist/index.js gateway --port 19080", + stderr: "", + }), + }); + + expect(sample).toEqual({ + aggregateRssMiB: 256, + cpuPercent: null, + processId: 4321, + rssMiB: 256, + }); + }); + it("samples the POSIX gateway child instead of the pnpm launcher", async () => { const sample = await sampleProcess(4321, { platform: "linux",