-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauth-lifecycle.k6.mjs
More file actions
172 lines (143 loc) · 4.04 KB
/
auth-lifecycle.k6.mjs
File metadata and controls
172 lines (143 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import http from "k6/http";
import { check, group, sleep } from "k6";
const baseUrl = __ENV.BASE_URL || "http://app:3000";
const password = "strong-pass-123";
http.setResponseCallback(http.expectedStatuses(200, 201, 401));
export const options = {
summaryTrendStats: ["avg", "min", "med", "max", "p(90)", "p(95)", "p(99)"],
scenarios: {
session_lifecycle: {
executor: "constant-vus",
exec: "sessionLifecycle",
vus: 5,
duration: "20s",
},
refresh_replay: {
executor: "per-vu-iterations",
exec: "refreshReplayLifecycle",
vus: 5,
iterations: 25,
maxDuration: "30s",
startTime: "2s",
},
},
thresholds: {
http_req_failed: ["rate<0.01"],
"http_req_duration{expected_response:true}": [
"p(95)<750",
"p(99)<1200",
],
},
};
const jsonHeaders = {
headers: {
"Content-Type": "application/json",
},
};
function uniqueIdentity(prefix) {
const id = `${prefix}-${__VU}-${__ITER}-${Date.now()}`;
return {
email: `${id}@benchmark.test`,
name: `Bench ${id}`,
};
}
function registerUser(identity) {
return http.post(
`${baseUrl}/v1/auth/register`,
JSON.stringify({
name: identity.name,
email: identity.email,
password,
}),
jsonHeaders,
);
}
function loginUser(identity) {
return http.post(
`${baseUrl}/v1/auth/sessions`,
JSON.stringify({
email: identity.email,
password,
}),
jsonHeaders,
);
}
export function sessionLifecycle() {
const identity = uniqueIdentity("session");
group("register", () => {
const response = registerUser(identity);
check(response, {
"register returns 201": (result) => result.status === 201,
});
});
const loginResponse = group("login", () => {
const response = loginUser(identity);
check(response, {
"login returns 200": (result) => result.status === 200,
"login returns access token": (result) => Boolean(result.json("accessToken")),
"login returns refresh token": (result) => Boolean(result.json("refreshToken")),
});
return response;
});
if (loginResponse.status !== 200) {
return;
}
const accessToken = loginResponse.json("accessToken");
group("profile", () => {
const response = http.get(`${baseUrl}/v1/auth/me`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
check(response, {
"profile returns 200": (result) => result.status === 200,
"profile response contains the registered email": (result) =>
result.json("user.email") === identity.email,
});
});
sleep(1);
}
export function refreshReplayLifecycle() {
const identity = uniqueIdentity("refresh");
const registerResponse = registerUser(identity);
check(registerResponse, {
"refresh scenario register returns 201": (result) => result.status === 201,
});
const loginResponse = loginUser(identity);
check(loginResponse, {
"refresh scenario login returns 200": (result) => result.status === 200,
});
if (loginResponse.status !== 200) {
return;
}
const refreshToken = loginResponse.json("refreshToken");
group("refresh", () => {
const response = http.post(
`${baseUrl}/v1/auth/tokens/refresh`,
JSON.stringify({ refreshToken }),
jsonHeaders,
);
check(response, {
"refresh returns 200": (result) => result.status === 200,
"refresh rotates the token": (result) =>
result.status === 200 && result.json("refreshToken") !== refreshToken,
});
});
group("replay rejection", () => {
const replayResponse = http.post(
`${baseUrl}/v1/auth/tokens/refresh`,
JSON.stringify({ refreshToken }),
jsonHeaders,
);
check(replayResponse, {
"refresh replay returns 401": (result) => result.status === 401,
"refresh replay returns REFRESH_TOKEN_REUSED": (result) =>
result.json("error.code") === "REFRESH_TOKEN_REUSED",
});
});
}
export function handleSummary(data) {
return {
"/scripts/results/auth-benchmark-summary.json": JSON.stringify(data, null, 2),
};
}