template-monorepo/test/k6/smoke/auth_password.js

143 lines
3.8 KiB
JavaScript
Raw Permalink Normal View History

2026-05-26 17:10:32 +00:00
// smoke: POST /api/v1/auth/password/{forgot,reset}
//
// Covers forgot:
// happy — active platform 帳號寄重設 OTP
// 404 — member 不存在28301000
// 403 — 未驗證帳號28505000
// 400 — 缺少 email
// 429 — OTP 重送冷卻29604000
//
// Covers reset:
// 403 — OTP 錯誤29505000
// 404 — challenge 不存在29301000
// 403 — purpose 不符(用 registration challenge29505000
// 400 — 新密碼太短
import { sleep } from 'k6';
import { post, checkError } from '../lib/http.js';
import { cfg } from '../lib/config.js';
import {
makeIdentity,
registerEmail,
registerAndConfirm,
passwordForgot,
} from '../lib/auth.js';
export const options = {
vus: 1,
iterations: 1,
thresholds: { checks: ['rate==1.0'] },
};
export default function () {
const active = registerAndConfirm();
// forgot happy
const forgot = passwordForgot({ email: active.identity.email });
if (!forgot.challenge_id) {
throw new Error('password/forgot happy: missing challenge_id');
}
// forgot member not found
checkError(
post('/api/v1/auth/password/forgot', {
tenant_slug: cfg.tenantSlug,
email: `no-such-${Date.now()}@k6.local`,
}),
'POST /auth/password/forgot (member not found)',
404,
28301000,
);
// forgot unverified account
const pending = makeIdentity('pwd-unverified');
registerEmail({
email: pending.email,
password: pending.password,
displayName: pending.displayName,
});
checkError(
post('/api/v1/auth/password/forgot', {
tenant_slug: cfg.tenantSlug,
email: pending.email,
}),
'POST /auth/password/forgot (unverified)',
403,
28505000,
);
// forgot missing email
const missingForgot = post('/api/v1/auth/password/forgot', { tenant_slug: cfg.tenantSlug });
if (missingForgot.status !== 400) {
throw new Error(`password/forgot missing email: expected 400 got ${missingForgot.status}`);
}
// forgot resend cooldown
checkError(
post('/api/v1/auth/password/forgot', {
tenant_slug: cfg.tenantSlug,
email: active.identity.email,
}),
'POST /auth/password/forgot (resend cooldown)',
429,
29604000,
);
sleep(cfg.resendCooldownSeconds + 1);
passwordForgot({ email: active.identity.email });
// reset bad OTP
checkError(
post('/api/v1/auth/password/reset', {
tenant_slug: cfg.tenantSlug,
challenge_id: forgot.challenge_id,
code: '000000',
new_password: 'K6-NewPass-2!',
}),
'POST /auth/password/reset (bad otp)',
403,
29505000,
);
// reset unknown challenge — Redis miss 目前回 50029201000非 404
checkError(
post('/api/v1/auth/password/reset', {
tenant_slug: cfg.tenantSlug,
challenge_id: '00000000-0000-0000-0000-000000000000',
code: '123456',
new_password: 'K6-NewPass-2!',
}),
'POST /auth/password/reset (unknown challenge)',
500,
29201000,
);
// reset purpose mismatch — registration challenge on password reset endpoint
const regOnly = makeIdentity('pwd-purpose');
const reg = registerEmail({
email: regOnly.email,
password: regOnly.password,
displayName: regOnly.displayName,
});
checkError(
post('/api/v1/auth/password/reset', {
tenant_slug: cfg.tenantSlug,
challenge_id: reg.challenge_id,
code: '123456',
new_password: 'K6-NewPass-2!',
}),
'POST /auth/password/reset (purpose mismatch)',
403,
29505000,
);
// reset weak password (validate min=8)
const weak = post('/api/v1/auth/password/reset', {
tenant_slug: cfg.tenantSlug,
challenge_id: forgot.challenge_id,
code: '123456',
new_password: 'short',
});
if (weak.status !== 400) {
throw new Error(`password/reset weak password: expected 400 got ${weak.status}`);
}
}