Skip to content

Commit f60db79

Browse files
authored
[PM-19590] Add k6 load testing script for SyncController's /sync endpoint (#5508)
* Add k6 load testing script for sync endpoint * Refactor sync response validation to use lowercase keys * Remove access token validation from sync.js * Update http_req_duration threshold in sync.js from 400ms to 1200ms
1 parent ad05e3f commit f60db79

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

perf/load/sync.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import http from "k6/http";
2+
import { check, fail } from "k6";
3+
import { authenticate } from "./helpers/auth.js";
4+
5+
const IDENTITY_URL = __ENV.IDENTITY_URL;
6+
const API_URL = __ENV.API_URL;
7+
const CLIENT_ID = __ENV.CLIENT_ID;
8+
const AUTH_USERNAME = __ENV.AUTH_USER_EMAIL;
9+
const AUTH_PASSWORD = __ENV.AUTH_USER_PASSWORD_HASH;
10+
11+
export const options = {
12+
ext: {
13+
loadimpact: {
14+
projectID: 3639465,
15+
name: "Sync",
16+
},
17+
},
18+
scenarios: {
19+
constant_load: {
20+
executor: "constant-arrival-rate",
21+
rate: 30,
22+
timeUnit: "1m", // 0.5 requests / second
23+
duration: "10m",
24+
preAllocatedVUs: 5,
25+
},
26+
ramping_load: {
27+
executor: "ramping-arrival-rate",
28+
startRate: 30,
29+
timeUnit: "1m", // 0.5 requests / second to start
30+
stages: [
31+
{ duration: "30s", target: 30 },
32+
{ duration: "2m", target: 75 },
33+
{ duration: "1m", target: 60 },
34+
{ duration: "2m", target: 100 },
35+
{ duration: "2m", target: 90 },
36+
{ duration: "1m", target: 120 },
37+
{ duration: "30s", target: 150 },
38+
{ duration: "30s", target: 60 },
39+
{ duration: "30s", target: 0 },
40+
],
41+
preAllocatedVUs: 20,
42+
},
43+
},
44+
thresholds: {
45+
http_req_failed: ["rate<0.01"],
46+
http_req_duration: ["p(95)<1200"],
47+
},
48+
};
49+
50+
export function setup() {
51+
return authenticate(IDENTITY_URL, CLIENT_ID, AUTH_USERNAME, AUTH_PASSWORD);
52+
}
53+
54+
export default function (data) {
55+
const params = {
56+
headers: {
57+
Accept: "application/json",
58+
"Content-Type": "application/json",
59+
Authorization: `Bearer ${data.access_token}`,
60+
"X-ClientId": CLIENT_ID,
61+
},
62+
tags: { name: "Sync" },
63+
};
64+
65+
const excludeDomains = Math.random() > 0.5;
66+
67+
const syncRes = http.get(`${API_URL}/sync?excludeDomains=${excludeDomains}`, params);
68+
if (
69+
!check(syncRes, {
70+
"sync status is 200": (r) => r.status === 200,
71+
})
72+
) {
73+
console.error(`Sync failed with status ${syncRes.status}: ${syncRes.body}`);
74+
fail("sync status code was *not* 200");
75+
}
76+
77+
if (syncRes.status === 200) {
78+
const syncJson = syncRes.json();
79+
80+
check(syncJson, {
81+
"sync response has profile": (j) => j.profile !== undefined,
82+
"sync response has folders": (j) => Array.isArray(j.folders),
83+
"sync response has collections": (j) => Array.isArray(j.collections),
84+
"sync response has ciphers": (j) => Array.isArray(j.ciphers),
85+
"sync response has policies": (j) => Array.isArray(j.policies),
86+
"sync response has sends": (j) => Array.isArray(j.sends),
87+
"sync response has correct object type": (j) => j.object === "sync"
88+
});
89+
}
90+
}

0 commit comments

Comments
 (0)