Skip to content

Commit 0a566b9

Browse files
authored
Add k6 performance test scenarios (#957)
* Configure webhook receiver endpoint * Add YT01 as selectable Bruno environment * Set up performance test helpers * Define test scenarios for fixed rate/total * Fix error count data metric * Provide delete SQL for subscription * Include YT01 in baseurls * Fix errors threshold instead of rate
1 parent 06cd6c3 commit 0a566b9

File tree

5 files changed

+407
-0
lines changed

5 files changed

+407
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
vars {
2+
Environment: yt01
3+
BaseUrl: https://platform.{{Environment}}.altinn.cloud
4+
PlatformHostUrl: {{BaseUrl}}
5+
}
6+
vars:secret [
7+
PlatformToken
8+
]

test/k6/src/config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const baseUrls = {
33
at22: "at22.altinn.cloud",
44
at23: "at23.altinn.cloud",
55
at24: "at24.altinn.cloud",
6+
yt01: "yt01.altinn.cloud",
67
tt02: "tt02.altinn.no",
78
prod: "altinn.no",
89
};
@@ -46,6 +47,8 @@ export const platformEvents = {
4647
"https://platform." + baseUrl + "/events/api/v1/app/",
4748
subscriptions:
4849
"https://platform." + baseUrl + "/events/api/v1/subscriptions/",
50+
webhookReceiver:
51+
"https://platform." + baseUrl + "/events/api/v1/tests/webhookreceiver",
4952
};
5053

5154
export const platformAuthentication = {
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
Performance test: fixed arrival rate
3+
4+
Fires exactly `targetRps` event POST requests per second for `duration`,
5+
regardless of how long each request takes. This decouples load generation
6+
from response time, which is the correct model for finding the system's
7+
throughput ceiling.
8+
9+
If k6 cannot start iterations fast enough — because the system is overloaded,
10+
VUs are exhausted, or registration is too slow — `dropped_iterations` climbs
11+
above 0, telling you the target rate was not sustained.
12+
13+
How to find the ceiling:
14+
Start low (e.g. -e targetRps=10) and increase until you see either
15+
dropped_iterations > 0 or a sharp spike in p(95) POST latency.
16+
That inflection point is your system's throughput ceiling.
17+
18+
After the test, handleSummary() prints SQL queries with timestamps filled in:
19+
- SQL 1 ingest vs outbound counts (registered, queued, webhook responses)
20+
- SQL 2 pipeline latency (registration → OutboundQueue lag)
21+
- SQL 3 throughput per 5s bucket (registration, queuing, webhook delivery)
22+
23+
Command:
24+
podman compose run k6 run /src/tests/performance/fixed-rate.js \
25+
-e altinn_env=yt01 \
26+
-e tokenGeneratorUserName=autotest \
27+
-e tokenGeneratorUserPwd=*** \
28+
-e runId=$(date +%Y%m%d-%H%M%S) \
29+
-e targetRps=20 \
30+
-e duration=2m \
31+
-e maxVus=50 \
32+
-e queryOffsetMinutes=15
33+
34+
Tuning preAllocatedVUs:
35+
k6 pre-warms this many VUs before the test starts. The rule of thumb is
36+
preAllocatedVUs ≈ targetRps × expected_p95_latency_in_seconds.
37+
This script defaults to targetRps × 2 (assumes up to 2s per request),
38+
capped by maxVus. Override maxVus if you need more headroom.
39+
*/
40+
41+
import {
42+
runId, performanceSetup, postCloudEvent, performanceTeardown,
43+
warnIfUntagged, getTimeWindow, getBaseMetrics, buildSummary,
44+
} from "./helpers.js";
45+
46+
const eventType = `performancetest.fixed-rate.${runId}`;
47+
const targetRps = Number.parseInt(__ENV.targetRps || "20", 10);
48+
const duration = __ENV.duration || "2m";
49+
const maxVus = Number.parseInt(__ENV.maxVus || "50", 10);
50+
51+
// Pre-allocate enough VUs to sustain targetRps assuming up to ~2s per request.
52+
// k6 will spin up more (up to maxVus) if needed mid-test.
53+
const preAllocatedVUs = Math.min(targetRps * 2, maxVus);
54+
55+
warnIfUntagged();
56+
57+
export const options = {
58+
thresholds: {
59+
errors: ["count<1"],
60+
http_req_duration: ["p(95)<5000"],
61+
dropped_iterations: ["count<1"],
62+
},
63+
scenarios: {
64+
fixed_rate: {
65+
executor: "constant-arrival-rate",
66+
rate: targetRps,
67+
timeUnit: "1s",
68+
duration: duration,
69+
preAllocatedVUs: preAllocatedVUs,
70+
maxVUs: maxVus,
71+
},
72+
},
73+
};
74+
75+
export function setup() {
76+
return performanceSetup(`Target rate: ${targetRps} events/s for ${duration} (preAllocated: ${preAllocatedVUs}, max: ${maxVus} VUs)`);
77+
}
78+
79+
export default function runTests(data) {
80+
postCloudEvent(eventType, data.token);
81+
}
82+
83+
export function teardown(data) {
84+
performanceTeardown(data);
85+
}
86+
87+
export function handleSummary(data) {
88+
const { durationSec } = getTimeWindow(data);
89+
const { successCount, errorCount, p95Ms } = getBaseMetrics(data);
90+
const droppedCount = data.metrics["dropped_iterations"]?.values?.count ?? 0;
91+
const effectiveRps = durationSec > 0 ? (successCount / durationSec).toFixed(1) : "N/A";
92+
const targetMet = droppedCount === 0 ? "YES" : `NO — ${droppedCount} iterations dropped`;
93+
94+
return buildSummary("Fixed-Rate Throughput Test — Summary ║", [
95+
" k6 results:",
96+
` Target rate : ${targetRps} events/s`,
97+
` Effective rate : ${effectiveRps} events/s`,
98+
` Target rate sustained : ${targetMet}`,
99+
` Events posted (HTTP 200) : ${successCount}`,
100+
` Errors : ${errorCount}`,
101+
` Dropped iterations : ${droppedCount}`,
102+
` p(95) POST latency : ${p95Ms.toFixed(0)} ms`,
103+
], eventType, data);
104+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Performance test: fixed total events (shared-iterations)
3+
4+
Sends exactly `totalEvents` events as fast as possible, shared across `vus` VUs.
5+
The test ends when all iterations are consumed — not after a fixed duration.
6+
7+
Key metrics to compare between runs:
8+
- Test duration (how long to post all events)
9+
- Effective POST rate (events/s calculated from duration)
10+
- p(95) POST latency (registration speed)
11+
- SQL 1 counts (how many made it through the pipeline)
12+
- SQL 2 pipeline latency (registration → OutboundQueue lag)
13+
- SQL 3 throughput per 5s bucket (registration, queuing, webhook delivery)
14+
15+
Command:
16+
podman compose run k6 run /src/tests/performance/fixed-total.js \
17+
-e altinn_env=yt01 \
18+
-e tokenGeneratorUserName=autotest \
19+
-e tokenGeneratorUserPwd=*** \
20+
-e runId=$(date +%Y%m%d-%H%M%S) \
21+
-e totalEvents=500 \
22+
-e vus=10 \
23+
-e queryOffsetMinutes=15
24+
*/
25+
26+
import {
27+
runId, performanceSetup, postCloudEvent, performanceTeardown,
28+
warnIfUntagged, getTimeWindow, getBaseMetrics, buildSummary,
29+
} from "./helpers.js";
30+
31+
const eventType = `performancetest.fixed-total.${runId}`;
32+
const totalEvents = Number.parseInt(__ENV.totalEvents || "500", 10);
33+
const vus = Number.parseInt(__ENV.vus || "10", 10);
34+
35+
warnIfUntagged();
36+
37+
export const options = {
38+
thresholds: {
39+
errors: ["count<1"],
40+
http_req_duration: ["p(95)<5000"],
41+
},
42+
scenarios: {
43+
fixed_total: {
44+
executor: "shared-iterations",
45+
vus: vus,
46+
iterations: totalEvents,
47+
maxDuration: "30m", // safety cap — increase if posting is very slow
48+
},
49+
},
50+
};
51+
52+
export function setup() {
53+
return performanceSetup(`Will post ${totalEvents} events across ${vus} VUs`);
54+
}
55+
56+
export default function runTests(data) {
57+
postCloudEvent(eventType, data.token);
58+
}
59+
60+
export function teardown(data) {
61+
performanceTeardown(data);
62+
}
63+
64+
export function handleSummary(data) {
65+
const { durationSec } = getTimeWindow(data);
66+
const { successCount, errorCount, p95Ms } = getBaseMetrics(data);
67+
const effectiveRate = durationSec > 0 ? (successCount / durationSec).toFixed(1) : "N/A";
68+
69+
return buildSummary("Fixed-Total Throughput Test — Summary ║", [
70+
" k6 results (what was sent):",
71+
` Target events : ${totalEvents}`,
72+
` Events posted (HTTP 200) : ${successCount}`,
73+
` Errors : ${errorCount}`,
74+
` Test duration : ${durationSec.toFixed(1)} s`,
75+
` Effective POST rate : ${effectiveRate} events/s`,
76+
` p(95) POST latency : ${p95Ms.toFixed(0)} ms`,
77+
], eventType, data);
78+
}

0 commit comments

Comments
 (0)