feat: bootstrap commercial AI drama platform
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { dbRun, withTransaction } from "../server/db.mjs";
|
||||
|
||||
const api = process.env.AI_DRAMA_API_BASE || "http://127.0.0.1:8787";
|
||||
const scope = {
|
||||
"x-organization-id": "org-studio-lab",
|
||||
"x-workspace-id": "ws-local-aidrama",
|
||||
"x-project-id": "thunder-mouth"
|
||||
};
|
||||
|
||||
async function request(path, headers = {}, options = {}) {
|
||||
const response = await fetch(`${api}${path}`, {
|
||||
...options,
|
||||
headers: { "content-type": "application/json", ...headers, ...(options.headers || {}) }
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
return { response, payload };
|
||||
}
|
||||
|
||||
async function login() {
|
||||
const result = await request("/api/auth/login", {}, { method: "POST", body: JSON.stringify({ email: "producer@local.test", password: "Demo@123456" }) });
|
||||
assert.equal(result.response.ok, true, "限流回归登录失败");
|
||||
return { authorization: `Bearer ${result.payload.session.token}` };
|
||||
}
|
||||
|
||||
const owner = { ...(await login()), ...scope };
|
||||
const restoreOwner = { ...(await login()), ...scope };
|
||||
let clientId = "";
|
||||
let originalLimit = 120;
|
||||
let changedLimit = false;
|
||||
|
||||
try {
|
||||
const config = await request("/api/system/config", owner);
|
||||
assert.equal(config.response.ok, true, "读取系统配置失败");
|
||||
const setting = config.payload.settings.find((item) => item.key === "api.rate_limit_per_minute");
|
||||
originalLimit = Number(setting?.value ?? 120);
|
||||
|
||||
const created = await request("/api/system/api-clients", owner, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name: `Smoke Rate Limit Client ${Date.now()}`, scopes: ["jobs:read"] })
|
||||
});
|
||||
assert.equal(created.response.status, 201, "限流回归 API 客户端创建失败");
|
||||
clientId = created.payload.client.id;
|
||||
const clientHeaders = { authorization: `Bearer ${created.payload.clientKey}`, ...scope };
|
||||
|
||||
const updated = await request("/api/system/config", owner, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ settings: [{ key: "api.rate_limit_per_minute", value: 2 }] })
|
||||
});
|
||||
assert.equal(updated.response.ok, true, "降低 API 限流配置失败");
|
||||
changedLimit = true;
|
||||
|
||||
const first = await request("/api/jobs", clientHeaders);
|
||||
const second = await request("/api/jobs", clientHeaders);
|
||||
const third = await request("/api/jobs", clientHeaders);
|
||||
assert.equal(first.response.status, 200, "限流窗口内第一次请求不应被阻断");
|
||||
assert.equal(second.response.status, 200, "限流窗口内第二次请求不应被阻断");
|
||||
assert.equal(first.response.headers.get("x-ratelimit-limit"), "2", "响应必须返回限流上限");
|
||||
assert.equal(second.response.headers.get("x-ratelimit-remaining"), "0", "第二次请求后剩余额度应为 0");
|
||||
assert.equal(third.response.status, 429, "超过限流上限必须返回 429");
|
||||
assert.equal(third.payload.error, "rate_limit_exceeded", "限流错误码必须稳定");
|
||||
assert.ok(Number(third.response.headers.get("retry-after")) > 0, "429 必须返回 Retry-After");
|
||||
assert.equal(third.response.headers.get("x-ratelimit-remaining"), "0", "429 响应剩余额度应为 0");
|
||||
|
||||
console.log("api rate-limit smoke passed: configured limit, headers, 429, retry-after");
|
||||
} finally {
|
||||
if (changedLimit) {
|
||||
const restored = await request("/api/system/config", restoreOwner, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ settings: [{ key: "api.rate_limit_per_minute", value: originalLimit }] })
|
||||
});
|
||||
assert.equal(restored.response.ok, true, "限流回归未能恢复原配置");
|
||||
}
|
||||
if (clientId) {
|
||||
withTransaction(() => {
|
||||
dbRun("DELETE FROM api_clients WHERE id = ?", [clientId]);
|
||||
dbRun("DELETE FROM audit_logs WHERE target_id = ?", [clientId]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user