test(冒煙測試): 更新 F/J 群組冒煙測試以涵蓋 llm/記憶快取新行為

This commit is contained in:
Jeffery
2026-08-14 12:44:54 +08:00
parent 30719a2960
commit 021284b852
2 changed files with 13 additions and 8 deletions
+12 -7
View File
@@ -136,14 +136,18 @@ export default async function smokeF() {
// 清理本次測試建立的 ProceduralRule,避免重複執行時累積髒資料 // 清理本次測試建立的 ProceduralRule,避免重複執行時累積髒資料
await prisma.proceduralRule.deleteMany({ where: { characterId: CHARACTER_ID, situation } }); await prisma.proceduralRule.deleteMany({ where: { characterId: CHARACTER_ID, situation } });
// F-2 Provider 切換:LLM_PROVIDER=claude 時啟動即以 ERR log 明確告知未實作,呼叫時拋出例外 // R-3:ClaudeProvider 已經是真的呼叫,不再是空殼。這裡只驗證 Provider 切換的「配線」本身
await verifyClaudeProviderStub(); // (選對了 ClaudeProvider、缺金鑰時的錯誤處理正確),不對 CLIProxy 發真的請求——真正的
// 回歸測試基準仍是 Mock 模板庫(同 R-3 驗收註記),自動化冒煙測試不應依賴外部服務目前是否可用。
await verifyClaudeProviderWiring();
} }
async function verifyClaudeProviderStub() { async function verifyClaudeProviderWiring() {
const port = "3091"; const port = "3091";
const childEnv = { ...process.env, PORT: port, LLM_PROVIDER: "claude" };
delete childEnv.CLAUDE_API_KEY;
const child = spawn("node", ["apps/api/dist/main.js"], { const child = spawn("node", ["apps/api/dist/main.js"], {
env: { ...process.env, PORT: port, LLM_PROVIDER: "claude" }, env: childEnv,
stdio: ["ignore", "pipe", "pipe"], stdio: ["ignore", "pipe", "pipe"],
}); });
@@ -156,8 +160,8 @@ async function verifyClaudeProviderStub() {
while (!output.includes("啟動") && Date.now() < deadline) { while (!output.includes("啟動") && Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 200)); await new Promise((resolve) => setTimeout(resolve, 200));
} }
if (!output.includes("ClaudeProvider 尚未實作")) { if (!output.includes("LLM_PROVIDER=claude")) {
throw new Error("LLM_PROVIDER=claude 啟動時未輸出「尚未實作」的 ERR log"); throw new Error("LLM_PROVIDER=claude 啟動時未輸出對應的 INF log");
} }
let healthOk = false; let healthOk = false;
@@ -182,8 +186,9 @@ async function verifyClaudeProviderStub() {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: USER_ID, text: "今天發生了很多事情想跟你分享" }), body: JSON.stringify({ userId: USER_ID, text: "今天發生了很多事情想跟你分享" }),
}); });
// 沒有金鑰應該在呼叫 generate() 時就快速、確定性地失敗(不對 CLIProxy 發任何請求)。
if (res.status < 500) { if (res.status < 500) {
throw new Error(`ClaudeProvider 空殼應在呼叫 generate() 時失敗,實際回傳 ${res.status}`); throw new Error(`缺少 CLAUDE_API_KEY 時應該呼叫失敗,實際回傳 ${res.status}`);
} }
} finally { } finally {
child.kill("SIGKILL"); child.kill("SIGKILL");
+1 -1
View File
@@ -225,7 +225,7 @@ export default async function smokeJ() {
}); });
const { spawnSync } = await import("node:child_process"); const { spawnSync } = await import("node:child_process");
const restartResult = spawnSync("npm", ["run", "restart"], { cwd: process.cwd(), stdio: "pipe" }); const restartResult = spawnSync("pnpm", ["run", "restart"], { cwd: process.cwd(), stdio: "pipe" });
if (restartResult.status !== 0) { if (restartResult.status !== 0) {
throw new Error(`重啟服務失敗:${restartResult.stderr?.toString()}`); throw new Error(`重啟服務失敗:${restartResult.stderr?.toString()}`);
} }