Merge pull request 'Walk the live password-change gate in k6 load setup' (#442) from feature/u7-k6-password-gate into main
Reviewed-on: https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/442
This commit was merged in pull request #442.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -81,30 +81,63 @@ function otherBase(mine) {
|
||||
return BASE_URLS[0] === mine ? BASE_URLS[1] : BASE_URLS[0];
|
||||
}
|
||||
|
||||
const jsonHeaders = { headers: { 'Content-Type': 'application/json' } };
|
||||
|
||||
function parseJSON(res) {
|
||||
try {
|
||||
return res.json();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 与现网一致:管理员建号 → 首登 must_change → POST /api/auth/password → 再登录。
|
||||
// 压测口令保持不变(next=同一密码),只走完设密门,不另造后门清标志。
|
||||
function loginReady(base, owner, password) {
|
||||
const login = http.post(`${base}/api/auth/login`, JSON.stringify({ owner, password }), jsonHeaders);
|
||||
if (login.status !== 200) return login;
|
||||
const body = parseJSON(login);
|
||||
if (body && body.mustChangePassword) {
|
||||
const ch = http.post(`${base}/api/auth/password`, JSON.stringify({ next: password }), jsonHeaders);
|
||||
if (ch.status !== 200) return ch;
|
||||
return http.post(`${base}/api/auth/login`, JSON.stringify({ owner, password }), jsonHeaders);
|
||||
}
|
||||
return login;
|
||||
}
|
||||
|
||||
// ---- setup:管理员建压测用户;双实例时建共享热点会话 ----
|
||||
|
||||
export function setup() {
|
||||
const adminBase = BASE_URLS[0];
|
||||
const login = http.post(`${adminBase}/api/auth/login`, JSON.stringify({ owner: ADMIN_OWNER, password: ADMIN_PASS }), { headers: { 'Content-Type': 'application/json' } });
|
||||
if (login.status !== 200) throw new Error(`admin login: ${login.status} ${login.body}`);
|
||||
const adminLogin = loginReady(adminBase, ADMIN_OWNER, ADMIN_PASS);
|
||||
if (adminLogin.status !== 200) throw new Error(`admin login: ${adminLogin.status} ${adminLogin.body}`);
|
||||
|
||||
const users = [];
|
||||
for (let i = 0; i < USERS; i++) {
|
||||
const owner = `load_u${i}`;
|
||||
const password = `load-user-pass-${i}-Aa9`;
|
||||
const created = http.post(`${adminBase}/api/admin/users`, JSON.stringify({ owner, name: `压测用户${i}`, password, isAdmin: false }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const created = http.post(`${adminBase}/api/admin/users`, JSON.stringify({ owner, name: `压测用户${i}`, password, isAdmin: false }), jsonHeaders);
|
||||
if (created.status !== 200 && created.status !== 409) throw new Error(`create user ${owner}: ${created.status} ${created.body}`);
|
||||
users.push({ owner, password });
|
||||
}
|
||||
// 建号必须保持管理员会话;设密会换 cookie,只能在全员建完后逐个走门。
|
||||
for (const u of users) {
|
||||
const gated = loginReady(adminBase, u.owner, u.password);
|
||||
if (gated.status !== 200) throw new Error(`activate ${u.owner}: ${gated.status} ${gated.body}`);
|
||||
}
|
||||
|
||||
// 热点会话:多 VU 跨实例争抢同一会话(C2「互相不拖累」的争用源)。
|
||||
// 建用户时 cookie 落在最后一位 load_u* 上,热点资源须用管理员会话。
|
||||
const adminAgain = loginReady(adminBase, ADMIN_OWNER, ADMIN_PASS);
|
||||
if (adminAgain.status !== 200) throw new Error(`admin re-login: ${adminAgain.status} ${adminAgain.body}`);
|
||||
let hotspot = null;
|
||||
if (BASE_URLS.length >= 2) {
|
||||
const proj = http.post(`${adminBase}/api/projects`, JSON.stringify({ name: 'hotspot-shared' }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const proj = http.post(`${adminBase}/api/projects`, JSON.stringify({ name: 'hotspot-shared' }), jsonHeaders);
|
||||
if (proj.status !== 200) throw new Error(`hotspot project: ${proj.status} ${proj.body}`);
|
||||
const conv = http.post(`${adminBase}/api/projects/${proj.json().id}/conversations`, JSON.stringify({ title: '热点会话' }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const projBody = parseJSON(proj);
|
||||
const conv = http.post(`${adminBase}/api/projects/${projBody.id}/conversations`, JSON.stringify({ title: '热点会话' }), jsonHeaders);
|
||||
if (conv.status !== 200) throw new Error(`hotspot conv: ${conv.status} ${conv.body}`);
|
||||
hotspot = { projectID: proj.json().id, convID: conv.json().id, owner: ADMIN_OWNER, password: ADMIN_PASS };
|
||||
hotspot = { projectID: projBody.id, convID: parseJSON(conv).id, owner: ADMIN_OWNER, password: ADMIN_PASS };
|
||||
}
|
||||
|
||||
return { users, hotspot, bases: BASE_URLS };
|
||||
@@ -115,16 +148,26 @@ export function setup() {
|
||||
export default function (data) {
|
||||
const base = baseForVU();
|
||||
const u = data.users[exec.scenario.iterationInTest % data.users.length];
|
||||
const login = http.post(`${base}/api/auth/login`, JSON.stringify({ owner: u.owner, password: u.password }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const login = loginReady(base, u.owner, u.password);
|
||||
if (login.status !== 200) {
|
||||
check(null, { 'user login': () => false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!u.__ctx) {
|
||||
const proj = http.post(`${base}/api/projects`, JSON.stringify({ name: `压测-${u.owner}` }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const conv = http.post(`${base}/api/projects/${proj.json().id}/conversations`, JSON.stringify({ title: '压测会话' }), { headers: { 'Content-Type': 'application/json' } });
|
||||
u.__ctx = { projectID: proj.json().id, convID: conv.json().id };
|
||||
const proj = http.post(`${base}/api/projects`, JSON.stringify({ name: `压测-${u.owner}` }), jsonHeaders);
|
||||
const projBody = parseJSON(proj);
|
||||
if (proj.status !== 200 || !projBody || !projBody.id) {
|
||||
check(proj, { 'create project 2xx': () => false });
|
||||
return;
|
||||
}
|
||||
const conv = http.post(`${base}/api/projects/${projBody.id}/conversations`, JSON.stringify({ title: '压测会话' }), jsonHeaders);
|
||||
const convBody = parseJSON(conv);
|
||||
if (conv.status !== 200 || !convBody || !convBody.id) {
|
||||
check(conv, { 'create conversation 2xx': () => false });
|
||||
return;
|
||||
}
|
||||
u.__ctx = { projectID: projBody.id, convID: convBody.id };
|
||||
}
|
||||
const { projectID, convID } = u.__ctx;
|
||||
|
||||
@@ -143,7 +186,7 @@ export default function (data) {
|
||||
if (BASE_URLS.length >= 2 && exec.scenario.iterationInTest % 5 === 0) {
|
||||
const other = otherBase(base);
|
||||
// 另一实例需同用户登录(cookie jar 按 VU;换 host 需重新登录)。
|
||||
const loginB = http.post(`${other}/api/auth/login`, JSON.stringify({ owner: u.owner, password: u.password }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const loginB = loginReady(other, u.owner, u.password);
|
||||
if (loginB.status === 200) {
|
||||
const cross = http.get(`${other}/api/conversations/${convID}`);
|
||||
if (cross.status === 200) crossReadOk.add(1);
|
||||
@@ -158,7 +201,7 @@ export default function (data) {
|
||||
if (data.hotspot && exec.scenario.iterationInTest % 5 === 0) {
|
||||
targetConv = data.hotspot.convID;
|
||||
// 热点会话属 admin:先以 admin 登录再写。
|
||||
const hl = http.post(`${writeBase}/api/auth/login`, JSON.stringify({ owner: data.hotspot.owner, password: data.hotspot.password }), { headers: { 'Content-Type': 'application/json' } });
|
||||
const hl = loginReady(writeBase, data.hotspot.owner, data.hotspot.password);
|
||||
if (hl.status !== 200) {
|
||||
check(null, { 'hotspot admin login': () => false });
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user