test(session): load tests for session api (#9212)

# Which Problems Are Solved

We currently are not able to benchmark the performance of the session
api

# How the Problems Are Solved

Load tests were added to
- use sessions in oidc tokens analog
https://zitadel.com/docs/guides/integrate/login-ui/oidc-standard

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/7847
This commit is contained in:
Silvan
2025-01-29 12:08:20 +00:00
committed by GitHub
parent 679ab58fa1
commit b10428fb56
18 changed files with 409 additions and 112 deletions
@@ -1,7 +1,7 @@
import { loginByUsernamePassword } from '../login_ui';
import { createOrg, removeOrg } from '../org';
import {createMachine, User, addMachineSecret} from '../user';
import {clientCredentials, userinfo} from '../oidc';
import { createMachine, User, addMachineSecret } from '../user';
import { clientCredentials, userinfo } from '../oidc';
import { Config, MaxVUs } from '../config';
export async function setup() {
@@ -37,10 +37,9 @@ export async function setup() {
}
export default function (data: any) {
clientCredentials(data.machines[__VU - 1].loginName, data.machines[__VU - 1].password)
.then((token) => {
userinfo(token.accessToken!)
})
clientCredentials(data.machines[__VU - 1].loginName, data.machines[__VU - 1].password).then((token) => {
userinfo(token.accessToken!);
});
}
export function teardown(data: any) {
@@ -1,7 +1,7 @@
import { loginByUsernamePassword } from '../login_ui';
import { createOrg, removeOrg } from '../org';
import {createMachine, User, addMachineKey} from '../user';
import {JWTProfileRequest, token, userinfo} from '../oidc';
import { createMachine, User, addMachineKey } from '../user';
import { JWTProfileRequest, token, userinfo } from '../oidc';
import { Config, MaxVUs } from '../config';
import encoding from 'k6/encoding';
@@ -10,10 +10,10 @@ const publicKey = encoding.b64encode(open('../.keys/key.pem.pub'));
export async function setup() {
const tokens = loginByUsernamePassword(Config.admin as User);
console.info('setup: admin signed in');
const org = await createOrg(tokens.accessToken!);
console.info(`setup: org (${org.organizationId}) created`);
let machines = (
await Promise.all(
Array.from({ length: MaxVUs() }, (_, i) => {
@@ -24,16 +24,11 @@ export async function setup() {
return { userId: machine.userId, loginName: machine.loginNames[0] };
});
console.info(`setup: ${machines.length} machines created`);
let keys = (
await Promise.all(
machines.map((machine) => {
return addMachineKey(
machine.userId,
org,
tokens.accessToken!,
publicKey,
);
return addMachineKey(machine.userId, org, tokens.accessToken!, publicKey);
}),
)
).map((key, i) => {
@@ -45,7 +40,7 @@ export async function setup() {
}
export default function (data: any) {
token(new JWTProfileRequest(data.machines[__VU - 1].userId, data.machines[__VU - 1].keyId))
token(new JWTProfileRequest(data.machines[__VU - 1].userId, data.machines[__VU - 1].keyId));
}
export function teardown(data: any) {
@@ -1,7 +1,7 @@
import { loginByUsernamePassword } from '../login_ui';
import { createOrg, removeOrg } from '../org';
import {createMachine, User, addMachineKey} from '../user';
import {JWTProfileRequest, token, userinfo} from '../oidc';
import { createMachine, User, addMachineKey } from '../user';
import { JWTProfileRequest, token, userinfo } from '../oidc';
import { Config } from '../config';
import encoding from 'k6/encoding';
@@ -10,20 +10,20 @@ const publicKey = encoding.b64encode(open('../.keys/key.pem.pub'));
export async function setup() {
const tokens = loginByUsernamePassword(Config.admin as User);
console.info('setup: admin signed in');
const org = await createOrg(tokens.accessToken!);
console.info(`setup: org (${org.organizationId}) created`);
const machine = await createMachine(`zitachine`, org, tokens.accessToken!);
console.info(`setup: machine ${machine.userId} created`);
const key = await addMachineKey(machine.userId, org, tokens.accessToken!, publicKey);
console.info(`setup: key ${key.keyId} added`);
return { tokens, machine: {userId: machine.userId, keyId: key.keyId}, org };
return { tokens, machine: { userId: machine.userId, keyId: key.keyId }, org };
}
export default function (data: any) {
token(new JWTProfileRequest(data.machine.userId, data.machine.keyId))
token(new JWTProfileRequest(data.machine.userId, data.machine.keyId));
}
export function teardown(data: any) {
@@ -1,9 +1,9 @@
import { loginByUsernamePassword } from '../login_ui';
import { createOrg, removeOrg } from '../org';
import { User, createHuman } from '../user';
import { loginByUsernamePassword } from '../../login_ui';
import { createOrg, removeOrg } from '../../org';
import { User, createHuman } from '../../user';
import { Trend } from 'k6/metrics';
import { Config, MaxVUs } from '../config';
import { createSession } from '../session';
import { Config, MaxVUs } from '../../config';
import { createSession } from '../../session';
import { check } from 'k6';
export async function setup() {
@@ -27,12 +27,16 @@ export async function setup() {
const addSessionTrend = new Trend('add_session_duration', true);
export default async function (data: any) {
const start = new Date();
const session = await createSession(data.users[__VU - 1], data.org, data.tokens.accessToken);
const session = await createSession(data.org, data.tokens.accessToken, {
user: {
userId: data.users[__VU - 1].userId,
},
});
check(session, {
'add session is status ok': (s) => s.id !== "",
'add session is status ok': (s) => s.id !== '',
});
addSessionTrend.add(new Date().getTime() - start.getTime());
}
@@ -0,0 +1,53 @@
import { loginByUsernamePassword, initLogin } from '../../login_ui';
import { createOrg, removeOrg } from '../../org';
import { User, addMachineKey, createMachine } from '../../user';
import { Trend } from 'k6/metrics';
import { Config } from '../../config';
import { check } from 'k6';
import { finalizeAuthRequest, JWTProfileRequest, token } from '../../oidc';
import { createSession } from '../../session';
import encoding from 'k6/encoding';
import { addIAMMember } from '../../membership';
const publicKey = encoding.b64encode(open('../.keys/key.pem.pub'));
export async function setup() {
const adminTokens = loginByUsernamePassword(Config.admin as User);
console.log('setup: admin signed in');
const org = await createOrg(adminTokens.accessToken!);
console.log(`setup: org (${org.organizationId}) created`);
const loginUser = await createMachine('load-test', org, adminTokens.accessToken!);
const loginUserKey = await addMachineKey(loginUser.userId, org, adminTokens.accessToken!, publicKey);
await addIAMMember(loginUser.userId, ['IAM_LOGIN_CLIENT'], adminTokens.accessToken!);
const tokens = await token(new JWTProfileRequest(loginUser.userId, loginUserKey.keyId));
return { tokens, user: loginUser, key: loginUserKey, org, adminTokens };
}
// implements the flow described in
// https://zitadel.com/docs/guides/integrate/login-ui/oidc-standard
const addSessionTrend = new Trend('oidc_session_duration', true);
export default async function (data: any) {
const start = new Date();
const authorizeResponse = initLogin(data.tokens.info.client_id);
const authRequestId = new URLSearchParams(authorizeResponse.headers['Location']).values().next().value;
check(authRequestId, {
'auth request id returned': (s) => s !== '',
});
const session = await createSession(data.org, data.tokens.accessToken, {
user: {
userId: data.user.userId,
},
});
await finalizeAuthRequest(authRequestId!, session, data.tokens!);
addSessionTrend.add(new Date().getTime() - start.getTime());
}
export function teardown(data: any) {
removeOrg(data.org, data.adminTokens.accessToken);
}
@@ -0,0 +1,57 @@
import { loginByUsernamePassword } from '../../login_ui';
import { createOrg, removeOrg } from '../../org';
import { createHuman, setEmailOTPOnHuman, User } from '../../user';
import { Trend } from 'k6/metrics';
import { Config, MaxVUs } from '../../config';
import { createSession, setSession } from '../../session';
export async function setup() {
const tokens = loginByUsernamePassword(Config.admin as User);
console.log('setup: admin signed in');
const org = await createOrg(tokens.accessToken!);
console.log(`setup: org (${org.organizationId}) created`);
const humanPromises = Array.from({ length: MaxVUs() }, (_, i) => {
return createHuman(`zitizen-${i}`, org, tokens.accessToken!);
});
const humans = (await Promise.all(humanPromises)).map((user) => {
setEmailOTPOnHuman(user, org, tokens.accessToken!);
return { userId: user.userId, loginName: user.loginNames[0], password: 'Password1!' };
});
console.log(`setup: ${humans.length} users created`);
return { tokens, org, users: humans };
}
// implements the flow described in
// https://zitadel.com/docs/guides/integrate/login-ui/oidc-standard
const otpSessionTrend = new Trend('otp_session_duration', true);
export default async function (data: any) {
const start = new Date();
let session = await createSession(data.org, data.tokens.accessToken, {
user: {
loginName: data.users[__VU - 1].loginName,
},
});
const sessionId = (session as any).sessionId;
session = await setSession(sessionId, session, data.tokens.accessToken, {
otpEmail: {
return_code: {},
},
});
session = await setSession(sessionId, session, data.tokens.accessToken, null, {
otpEmail: {
code: session.challenges.otpEmail,
},
});
otpSessionTrend.add(new Date().getTime() - start.getTime());
}
export function teardown(data: any) {
removeOrg(data.org, data.tokens.accessToken);
}
@@ -0,0 +1,49 @@
import { loginByUsernamePassword } from '../../login_ui';
import { createOrg, removeOrg } from '../../org';
import { createHuman, setEmailOTPOnHuman, User } from '../../user';
import { Trend } from 'k6/metrics';
import { Config, MaxVUs } from '../../config';
import { createSession, setSession } from '../../session';
export async function setup() {
const tokens = loginByUsernamePassword(Config.admin as User);
console.log('setup: admin signed in');
const org = await createOrg(tokens.accessToken!);
console.log(`setup: org (${org.organizationId}) created`);
const humanPromises = Array.from({ length: MaxVUs() }, (_, i) => {
return createHuman(`zitizen-${i}`, org, tokens.accessToken!);
});
const humans = (await Promise.all(humanPromises)).map((user) => {
setEmailOTPOnHuman(user, org, tokens.accessToken!);
return { userId: user.userId, loginName: user.loginNames[0], password: 'Password1!' };
});
console.log(`setup: ${humans.length} users created`);
return { tokens, org, users: humans };
}
const passwordSessionTrend = new Trend('password_session_duration', true);
export default async function (data: any) {
const start = new Date();
let session = await createSession(data.org, data.tokens.accessToken, {
user: {
loginName: data.users[__VU - 1].loginName,
},
});
const sessionId = (session as any).sessionId;
session = await setSession(sessionId, session, data.tokens.accessToken, null, {
password: {
password: data.users[__VU - 1].password,
},
});
passwordSessionTrend.add(new Date().getTime() - start.getTime());
}
export function teardown(data: any) {
removeOrg(data.org, data.tokens.accessToken);
}