TEST - CODEX AGENTS: real Tasker e2e smoke harness

This commit is contained in:
DCCONSTRUCTIONS 2026-05-14 19:44:05 +03:00
parent 9f402074f2
commit 418914fefd
2 changed files with 183 additions and 0 deletions

View File

@ -12,6 +12,7 @@
"check": "tsc --noEmit -p tsconfig.json",
"migrate": "tsx src/scripts/migrate.ts",
"migrate:dist": "node dist/scripts/migrate.js",
"smoke:e2e": "tsx src/scripts/smoke-e2e.ts",
"smoke:gateway": "tsx src/scripts/smoke-gateway.ts",
"start": "node dist/server.js"
},

182
src/scripts/smoke-e2e.ts Normal file
View File

@ -0,0 +1,182 @@
import { Pool } from "pg";
import { buildApp } from "../app.js";
import { loadConfig } from "../config.js";
import { runMigrations } from "../db/migrations.js";
const config = loadConfig();
const workspaceSlug = readRequiredEnv("SMOKE_WORKSPACE_SLUG");
const projectId = readRequiredEnv("SMOKE_PROJECT_ID");
if (!config.DATABASE_URL) {
throw new Error("DATABASE_URL is required for e2e smoke test.");
}
if (!config.NODEDC_INTERNAL_ACCESS_TOKEN) {
throw new Error("NODEDC_INTERNAL_ACCESS_TOKEN is required for e2e smoke test.");
}
const migrationPool = new Pool({ connectionString: config.DATABASE_URL });
await runMigrations(migrationPool);
await migrationPool.end();
const app = await buildApp({
...config,
LOG_LEVEL: process.env.LOG_LEVEL === "debug" ? "debug" : "silent",
});
try {
const suffix = Date.now().toString(36);
const agentId = await createAgent(suffix);
await upsertGrant(agentId);
const token = await createToken(agentId);
const authHeaders = { Authorization: `Bearer ${token}` };
const projects = await requestJson("GET", "/api/v1/tools/projects", authHeaders);
const context = await requestJson(
"GET",
`/api/v1/tools/projects/${projectId}/context?workspace_slug=${encodeURIComponent(workspaceSlug)}`,
authHeaders
);
const issue = await requestJson("POST", "/api/v1/tools/issues", authHeaders, {
project_id: projectId,
workspace_slug: workspaceSlug,
title: `NODE.DC Codex API smoke ${suffix}`,
description: "Created by Agent Gateway e2e smoke test.",
priority: "medium",
structured_blocks: [
{
id: "current-architecture",
type: "text",
title: "Текущая архитектура",
body: "Gateway создал карточку через реальный Tasker internal adapter.",
},
{
id: "checker-1",
type: "checker",
title: "Чекер smoke",
items: [
{
id: "auth",
text: "Agent token accepted",
checked: true,
},
{
id: "tasker",
text: "Tasker adapter created issue",
checked: true,
},
],
},
],
});
const issueId = issue.issue.id as string;
await requestJson("POST", `/api/v1/tools/issues/${issueId}/comments`, authHeaders, {
project_id: projectId,
workspace_slug: workspaceSlug,
body: "Smoke comment from Agent Gateway.",
});
const states = Array.isArray(context.states) ? context.states : [];
const targetState = states.find((state) => typeof state?.id === "string");
if (targetState) {
await requestJson("POST", `/api/v1/tools/issues/${issueId}/move`, authHeaders, {
project_id: projectId,
workspace_slug: workspaceSlug,
state_id: targetState.id,
});
}
console.log(
JSON.stringify(
{
ok: true,
tasker_url: config.NODEDC_TASKER_INTERNAL_URL,
workspace_slug: workspaceSlug,
project_id: projectId,
visible_projects: Array.isArray(projects.projects) ? projects.projects.length : null,
issue_id: issueId,
moved: Boolean(targetState),
},
null,
2
)
);
} finally {
await app.close();
}
async function createAgent(suffix: string): Promise<string> {
const payload = await requestJson("POST", "/api/v1/agents", undefined, {
owner_user_id: `e2e-owner-${suffix}`,
owner_email: `e2e-${suffix}@example.test`,
display_name: `E2E Codex ${suffix}`,
});
return payload.agent.id as string;
}
async function upsertGrant(agentId: string): Promise<void> {
await requestJson("POST", `/api/v1/agents/${agentId}/grants`, undefined, {
workspace_slug: workspaceSlug,
project_id: projectId,
scopes: [
"workspace:read",
"project:read",
"issue:read",
"issue:create",
"issue:update",
"issue:move",
"issue:comment",
"issue:label",
"issue:assign",
"issue:structured_blocks:write",
],
mode: "voluntary",
created_by_user_id: "e2e-smoke-admin",
});
}
async function createToken(agentId: string): Promise<string> {
const payload = await requestJson("POST", `/api/v1/agents/${agentId}/tokens`, undefined, {
name: "E2E smoke token",
});
return payload.token as string;
}
async function requestJson(
method: "GET" | "POST",
url: string,
headers?: Record<string, string>,
payload?: unknown
): Promise<Record<string, any>> {
const injectOptions: any = {
method,
url,
headers,
};
if (payload !== undefined) {
injectOptions.payload = payload;
}
const response = await app.inject(injectOptions);
const body = response.body ? JSON.parse(response.body) : {};
if (response.statusCode < 200 || response.statusCode >= 300) {
throw new Error(`HTTP ${response.statusCode} for ${method} ${url}: ${JSON.stringify(body)}`);
}
return body;
}
function readRequiredEnv(key: string): string {
const value = process.env[key]?.trim();
if (!value) {
throw new Error(`${key} is required for e2e smoke test.`);
}
return value;
}