142 lines
4.9 KiB
JavaScript
142 lines
4.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { createRequire } from "node:module";
|
|
|
|
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const runtimeDir = await fs.mkdtemp(path.join(os.tmpdir(), "boss-attachment-analysis-"));
|
|
const stateFile = path.join(runtimeDir, "data", "boss-state.json");
|
|
const require = createRequire(import.meta.url);
|
|
|
|
process.env.BOSS_RUNTIME_ROOT = runtimeDir;
|
|
process.env.BOSS_STATE_FILE = stateFile;
|
|
process.env.BOSS_AUTH_AUTO_LOGIN = "0";
|
|
|
|
const { NextRequest } = require("next/server");
|
|
const authLoginRoute = require(path.join(rootDir, ".next/standalone/.next/server/app/api/auth/login/route.js"));
|
|
const attachmentsRoute = require(
|
|
path.join(rootDir, ".next/standalone/.next/server/app/api/v1/projects/[projectId]/attachments/route.js"),
|
|
);
|
|
const analyzeRoute = require(
|
|
path.join(
|
|
rootDir,
|
|
".next/standalone/.next/server/app/api/v1/projects/[projectId]/attachments/[attachmentId]/analyze/route.js",
|
|
),
|
|
);
|
|
|
|
const loginHandler = authLoginRoute.routeModule.userland.POST;
|
|
const uploadHandler = attachmentsRoute.routeModule.userland.POST;
|
|
const analyzeHandler = analyzeRoute.routeModule.userland.POST;
|
|
|
|
async function invokeRoute(handler, url, init = {}, context) {
|
|
const request = new NextRequest(url, {
|
|
method: init.method ?? "GET",
|
|
headers: init.headers,
|
|
body: init.body,
|
|
});
|
|
return handler(request, context);
|
|
}
|
|
|
|
function parseCookieValue(setCookieHeader, cookieName) {
|
|
assert.ok(setCookieHeader, "set-cookie header is missing");
|
|
const match = setCookieHeader.match(new RegExp(`${cookieName}=([^;]+)`));
|
|
assert.ok(match, `${cookieName} cookie is missing`);
|
|
return match[1];
|
|
}
|
|
|
|
async function loginAsAdmin() {
|
|
const response = await invokeRoute(
|
|
loginHandler,
|
|
"http://localhost/api/auth/login",
|
|
{
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({
|
|
account: "17600003315",
|
|
password: "boss123456",
|
|
method: "password",
|
|
}),
|
|
},
|
|
);
|
|
assert.equal(response.status, 200, "login should succeed");
|
|
const payload = await response.json();
|
|
assert.equal(payload.ok, true, "login payload should be ok");
|
|
const cookie = parseCookieValue(response.headers.get("set-cookie"), "boss_session");
|
|
return { cookie, payload };
|
|
}
|
|
|
|
async function uploadAttachment(cookie, projectId, fileName, type, bytes) {
|
|
const form = new FormData();
|
|
form.set("file", new File([bytes], fileName, { type }));
|
|
|
|
const response = await invokeRoute(
|
|
uploadHandler,
|
|
`http://localhost/api/v1/projects/${projectId}/attachments`,
|
|
{
|
|
method: "POST",
|
|
headers: { cookie: `boss_session=${cookie}` },
|
|
body: form,
|
|
},
|
|
{ params: Promise.resolve({ projectId }) },
|
|
);
|
|
assert.equal(response.status, 200, `upload ${fileName} should succeed`);
|
|
return response.json();
|
|
}
|
|
|
|
const { cookie } = await loginAsAdmin();
|
|
|
|
const textUpload = await uploadAttachment(
|
|
cookie,
|
|
"master-agent",
|
|
"analysis-note.txt",
|
|
"text/plain",
|
|
Buffer.from("text attachment for automatic analysis"),
|
|
);
|
|
assert.equal(textUpload.attachment.analysisState, "queued_auto", "text attachment should queue automatically");
|
|
assert.ok(textUpload.analysisTask, "queued auto attachment should create a master agent task");
|
|
assert.equal(textUpload.analysisTask.taskType, "attachment_analysis", "queued task type should be attachment_analysis");
|
|
assert.equal(
|
|
textUpload.analysisTask.attachmentFileName,
|
|
"analysis-note.txt",
|
|
"queued task should carry attachment file name",
|
|
);
|
|
|
|
const manualUpload = await uploadAttachment(
|
|
cookie,
|
|
"master-agent",
|
|
"manual-binary.bin",
|
|
"application/octet-stream",
|
|
Buffer.from([0, 1, 2, 3]),
|
|
);
|
|
assert.equal(manualUpload.attachment.analysisState, "ready_manual", "binary attachment should be manually analyzable");
|
|
|
|
const analyzeResponse = await invokeRoute(
|
|
analyzeHandler,
|
|
`http://localhost/api/v1/projects/master-agent/attachments/${manualUpload.attachment.attachmentId}/analyze`,
|
|
{
|
|
method: "POST",
|
|
headers: { cookie: `boss_session=${cookie}` },
|
|
},
|
|
{
|
|
params: Promise.resolve({
|
|
projectId: "master-agent",
|
|
attachmentId: manualUpload.attachment.attachmentId,
|
|
}),
|
|
},
|
|
);
|
|
assert.equal(analyzeResponse.status, 200, "manual analyze should succeed");
|
|
const analyzePayload = await analyzeResponse.json();
|
|
assert.ok(analyzePayload.taskId, "manual analyze should return a taskId");
|
|
assert.ok(analyzePayload.task, "manual analyze should return a task payload");
|
|
assert.equal(analyzePayload.task.taskType, "attachment_analysis", "manual analyze task should be attachment_analysis");
|
|
assert.equal(
|
|
analyzePayload.task.attachmentId,
|
|
manualUpload.attachment.attachmentId,
|
|
"manual task should link the attachment",
|
|
);
|
|
|
|
console.log("attachment analysis validation passed");
|