Files
pikasTech-HWLAB/internal/cloud/server-test-helpers.ts
T

834 lines
24 KiB
TypeScript

import assert from "node:assert/strict";
import { chmod, mkdtemp, mkdir, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
const TEST_AGENT_USERNAME = "server-test-agent";
const TEST_AGENT_PASSWORD = "server-test-agent-password";
const testAuthByPort = new Map();
export function durableBlockedRuntime({ blocker, blockedLayer, queryResult, gates }) {
return {
adapter: "postgres",
durable: false,
durableRequested: true,
durableCapable: false,
ready: false,
status: "blocked",
blocker,
reason: `test durable runtime blocker ${blocker}`,
liveRuntimeEvidence: false,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult,
endpointRedacted: true,
valueRedacted: true,
errorCode: "TEST_BLOCKER"
},
schema: {
checked: gates.schema !== "not_checked",
ready: gates.schema === "ready",
missingTables: gates.schema === "blocked" ? ["gateway_sessions"] : [],
missingColumns: gates.schema === "blocked" ? ["gateway_sessions.gateway_session_json"] : []
},
migration: {
checked: gates.migration !== "not_checked",
ready: gates.migration === "ready",
missing: gates.migration !== "ready"
},
gates: Object.fromEntries(Object.entries(gates).map(([name, status]) => [
name,
{
checked: status !== "not_checked",
ready: status === "ready",
status,
blocker: status === "blocked" ? blocker : null
}
])),
durabilityContract: {
ready: false,
status: "blocked",
requiredEvidence: "runtime_adapter_schema_migration_read_query",
dbLiveEvidenceIsDurabilityEvidence: false,
liveRuntimeEvidence: false,
adapterQueryRequired: true,
blockedLayer,
blocker,
secretMaterialRead: false
},
safety: {
secretMaterialRead: false,
valuesRedacted: true,
endpointRedacted: true
},
counts: {}
};
}
export function durableReadyRuntime() {
return {
adapter: "postgres",
durable: true,
durableRequested: true,
durableCapable: true,
ready: true,
status: "ready",
blocker: null,
reason: "test durable runtime ready",
liveRuntimeEvidence: true,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult: "durable_readiness_ready",
endpointRedacted: true,
valueRedacted: true
},
schema: {
checked: true,
ready: true,
missingTables: [],
missingColumns: []
},
migration: {
checked: true,
ready: true,
missing: false
},
gates: Object.fromEntries(["ssl", "auth", "schema", "migration", "durability"].map((name) => [
name,
{
checked: true,
ready: true,
status: "ready",
blocker: null
}
])),
durabilityContract: {
ready: true,
status: "ready",
requiredEvidence: "runtime_adapter_schema_migration_read_query",
dbLiveEvidenceIsDurabilityEvidence: false,
liveRuntimeEvidence: true,
adapterQueryRequired: true,
blockedLayer: null,
blocker: null,
secretMaterialRead: false
},
safety: {
secretMaterialRead: false,
valuesRedacted: true,
endpointRedacted: true
},
counts: {}
};
}
export function layerStatus(gateStatus) {
if (gateStatus === "ready") return "pass";
if (gateStatus === "blocked") return "blocked";
return "not_proven";
}
export function layerForBlockedCase(blockedLayer) {
if (blockedLayer === "durability_query") return "durability";
return blockedLayer;
}
export async function m3ReadinessRequestJson(url, request = {}) {
const parsed = new URL(url);
const body = request.body ?? {};
if (url.startsWith("http://gateway-1") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: m3GatewayStatus({
gatewayId: "gwsimu_1",
gatewaySessionId: "gws_gwsimu_1",
boxId: "boxsimu_1",
resourceId: "res_boxsimu_1"
})
};
}
if (url.startsWith("http://gateway-1") && parsed.pathname === "/invoke") {
return {
ok: true,
status: 200,
body: {
accepted: true,
operationId: "op_m3_status_do1",
traceId: "trc_m3_status_do1",
boxId: "boxsimu_1",
resourceId: "res_boxsimu_1",
port: "DO1",
value: false,
state: {
port: "DO1",
direction: "output",
value: false,
source: "gateway-simu",
updatedAt: "2026-05-23T00:00:00.000Z"
},
auditId: "aud_m3_status_do1",
evidenceId: "evd_m3_status_do1"
}
};
}
if (url.startsWith("http://gateway-2") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: m3GatewayStatus({
gatewayId: "gwsimu_2",
gatewaySessionId: "gws_gwsimu_2",
boxId: "boxsimu_2",
resourceId: "res_boxsimu_2"
})
};
}
if (url.startsWith("http://gateway-2") && parsed.pathname === "/invoke") {
const value = request.body?.operationId?.includes("do_write") || request.body?.operationId?.includes("do-write")
? true
: false;
return {
ok: true,
status: 200,
body: {
accepted: true,
operationId: "op_m3_status_di1",
traceId: "trc_m3_status_di1",
boxId: "boxsimu_2",
resourceId: "res_boxsimu_2",
port: "DI1",
value,
state: {
port: "DI1",
direction: "input",
value,
source: "patch-panel",
sourceResourceId: "res_boxsimu_1",
sourcePort: "DO1",
propagatedBy: "hwlab-patch-panel",
updatedAt: "2026-05-23T00:00:00.000Z"
},
auditId: "aud_m3_status_di1",
evidenceId: "evd_m3_status_di1"
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: {
serviceId: "hwlab-patch-panel",
state: "active",
activeConnections: [
{
fromResourceId: "res_boxsimu_1",
fromPort: "DO1",
toResourceId: "res_boxsimu_2",
toPort: "DI1"
}
]
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/wiring") {
return {
ok: true,
status: 200,
body: {
wiringConfigId: "wir_m3_do1_di1",
status: "active",
connections: [
{
from: {
resourceId: "res_boxsimu_1",
port: "DO1"
},
to: {
resourceId: "res_boxsimu_2",
port: "DI1"
},
mode: "exclusive"
}
]
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/sync/tick") {
return {
ok: true,
status: 200,
body: {
accepted: true,
propagatedBy: "hwlab-patch-panel",
routeCount: 1,
deliveryCount: 1,
routes: [
{
accepted: true,
deliveryCount: 1,
deliveries: [
{
resourceId: "res_boxsimu_2",
port: "DI1",
value: body.signals?.[0]?.value ?? false,
sourceResourceId: "res_boxsimu_1",
sourcePort: "DO1",
deliveryStatus: "applied"
}
]
}
]
}
};
}
throw new Error(`unexpected M3 readiness request ${url}`);
}
export function m3GatewayStatus({ gatewayId, gatewaySessionId, boxId, resourceId }) {
return {
serviceId: "hwlab-gateway-simu",
gatewayId,
gatewaySessionId,
session: {
gatewayId,
gatewaySessionId
},
registry: {
gatewayId,
gatewaySessionId,
boxes: [
{
boxId,
resourceId,
state: "registered"
}
]
}
};
}
export function codexStdioReadyFixture({ workspace, codexHome }) {
return {
kind: "codex-app-server-stdio-runner",
provider: "codex-stdio",
backend: "hwlab-cloud-api/codex-app-server-stdio",
status: "feasible",
ready: true,
startupReady: true,
canStartLongLivedCodexStdio: true,
command: path.join(process.cwd(), "node_modules", ".bin", "codex"),
binaryOnPath: true,
binary: {
present: true,
executable: true,
nativeDependencyPresent: true,
versionDetected: true
},
workspace,
workspaceState: { exists: true, readable: true, writable: true, writeRequired: true },
codexHome,
codexHomeState: { exists: true, readable: true, writable: true, writeRequired: true },
sandbox: "workspace-write",
enabled: true,
supervisor: { configured: true, mode: "repo-owned-node-supervisor" },
tokenBoundary: { present: true, secretMaterialRead: false, valuesRedacted: true },
egress: { configured: true, directPublicOpenAi: false, valueRedacted: true },
protocol: {
status: "wired",
wired: true,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
missingTools: [],
command: "codex app-server --listen stdio://"
},
commandProbe: {
status: "ready",
ready: true,
probe: "workspace.pwd",
traceId: "trc_codex_stdio_command_probe",
toolCalls: [{
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdoutSummary: "workspace path matched",
outputTruncated: false
}],
secretMaterialRead: false,
valuesRedacted: true
},
stdioProtocol: {
status: "wired",
wired: true,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
missingTools: [],
command: "codex app-server --listen stdio://"
},
sessionLifecycle: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
lifecycleSupervisor: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
runtimeContract: {
status: "ready",
ready: true,
binary: {
status: "present",
present: true,
executable: true,
nativeDependencyPresent: true,
versionDetected: true
},
stdioProtocol: {
status: "wired",
wired: true,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
missingTools: []
},
commandProbe: {
status: "ready",
ready: true,
probe: "workspace.pwd",
traceId: "trc_codex_stdio_command_probe",
toolCalls: [{
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdoutSummary: "workspace path matched",
outputTruncated: false
}],
secretMaterialRead: false,
valuesRedacted: true
},
lifecycleSupervisor: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
workspaceMount: {
path: workspace,
status: "ready",
mounted: true,
readable: true,
writable: true,
sandbox: "workspace-write"
},
codexHome: {
path: codexHome,
status: "ready",
exists: true,
readable: true,
writable: true
},
cancelReapTraceReadiness: {
status: "ready",
cancel: true,
reap: true,
traceCapture: true,
idleTimeout: true
}
},
blockers: [],
blockerCodes: [],
safety: { secretMaterialRead: false, valuesRedacted: true }
};
}
export function codexStdioChatFixture({ workspace, codexHome, params }) {
const traceId = params.traceId;
const session = {
sessionId: "ses_server_stdio_pwd",
conversationId: params.conversationId,
status: "idle",
workspace,
sandbox: "workspace-write",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
capabilityLevel: "long-lived-codex-stdio-session",
implementationType: "repo-owned-codex-app-server-stdio-session",
createdAt: "2026-05-23T00:00:00.000Z",
updatedAt: "2026-05-23T00:00:00.000Z",
idleTimeoutMs: 1800000,
expiresAt: "2026-05-23T00:30:00.000Z",
lastTraceId: traceId,
turn: 1,
threadId: "thread_server_stdio_pwd",
reused: false,
durable: true,
longLivedSession: true,
codexStdio: true,
writeCapable: true,
secretMaterialStored: false,
valuesRedacted: true
};
const feasibility = codexStdioReadyFixture({ workspace, codexHome });
return {
provider: "codex-stdio",
model: "gpt-test",
backend: "hwlab-cloud-api/codex-app-server-stdio",
content: `stdio pwd\n${workspace}`,
workspace,
sandbox: "workspace-write",
session,
sessionMode: "codex-app-server-stdio-long-lived",
sessionReuse: {
conversationId: params.conversationId,
sessionId: session.sessionId,
threadId: session.threadId,
mapped: true,
reused: false,
turn: 1,
previousTurns: 0,
workspace,
status: "idle",
idleTimeoutMs: 1800000
},
implementationType: "repo-owned-codex-app-server-stdio-session",
runnerLimitations: ["secret-values-redacted"],
codexStdioFeasibility: feasibility,
longLivedSessionGate: {
status: "pass",
pass: true,
provider: "codex-stdio",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
blockers: []
},
toolCalls: [{
id: "tool_server_stdio_pwd",
type: "workspace-read",
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdout: workspace,
stderrSummary: "",
outputTruncated: false,
traceId
}],
skills: {
status: "not_requested",
items: [],
count: 0,
blockers: []
},
runner: {
kind: "codex-app-server-stdio-runner",
provider: "codex-stdio",
backend: "hwlab-cloud-api/codex-app-server-stdio",
workspace,
sandbox: "workspace-write",
session: "codex-app-server-stdio-long-lived",
sessionMode: "codex-app-server-stdio-long-lived",
sessionId: session.sessionId,
implementationType: "repo-owned-codex-app-server-stdio-session",
codexStdio: true,
longLivedSession: true,
durableSession: true,
writeCapable: true,
readOnly: false,
capabilityLevel: "long-lived-codex-stdio-session"
},
runnerTrace: {
traceId,
runnerKind: "codex-app-server-stdio-runner",
workspace,
sandbox: "workspace-write",
sessionMode: "codex-app-server-stdio-long-lived",
sessionId: session.sessionId,
sessionStatus: "idle",
turn: 1,
implementationType: "repo-owned-codex-app-server-stdio-session",
events: ["stdio:acquire", "session:created", "stdio:ready", "tool:pwd:completed"],
outputTruncated: false,
valuesPrinted: false
},
capabilityLevel: "long-lived-codex-stdio-session",
providerTrace: {
transport: "stdio",
protocol: "codex-app-server-jsonrpc-stdio",
command: "codex app-server --listen stdio://",
toolName: "codex",
threadId: "thread_server_stdio_pwd",
valuesPrinted: false
}
};
}
export function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export async function postAgent(port, body) {
const nextBody = { ...body };
let auth = testAuthByPort.get(port) ?? null;
const manual = nextBody.sessionId ? null : await createManualAgentSession(port, {
conversationId: nextBody.conversationId,
projectId: nextBody.projectId,
providerProfile: nextBody.providerProfile
});
auth = auth ?? manual;
if (manual) {
nextBody.conversationId = manual.conversationId;
nextBody.sessionId = manual.sessionId;
}
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
...(auth?.cookie ? { cookie: auth.cookie } : {}),
...(nextBody.traceId ? { "x-trace-id": nextBody.traceId } : {})
},
body: JSON.stringify(nextBody)
});
assert.equal(response.status, 200);
return response.json();
}
export async function createManualAgentSession(port, input = {}) {
const auth = await ensureTestAgentAuth(port);
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/sessions`, {
method: "POST",
headers: {
"content-type": "application/json",
cookie: auth.cookie
},
body: JSON.stringify({
conversationId: input.conversationId,
sessionId: input.sessionId,
projectId: input.projectId,
providerProfile: input.providerProfile,
updatedByClient: "server-agent-chat-test"
})
});
const body = await response.json();
assert.equal(response.status, 201);
assert.equal(body.ok, true);
assert.equal(body.session.usable, true);
return {
cookie: auth.cookie,
headers: {
"content-type": "application/json",
cookie: auth.cookie
},
session: body.session,
sessionId: body.session.sessionId,
conversationId: body.session.conversationId
};
}
export async function ensureTestAgentAuth(port) {
const cached = testAuthByPort.get(port);
if (cached?.cookie) return cached;
const setup = await fetch(`http://127.0.0.1:${port}/v1/setup/first-admin`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
username: TEST_AGENT_USERNAME,
displayName: "Server Test Agent",
password: TEST_AGENT_PASSWORD
})
});
let cookie = sessionCookieFromResponse(setup);
if (!cookie) {
const login = await fetch(`http://127.0.0.1:${port}/auth/login`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ username: TEST_AGENT_USERNAME, password: TEST_AGENT_PASSWORD })
});
cookie = sessionCookieFromResponse(login);
assert.equal(login.status, 200);
} else {
assert.equal(setup.status, 201);
}
assert.ok(cookie);
const auth = { cookie };
testAuthByPort.set(port, auth);
return auth;
}
function sessionCookieFromResponse(response) {
const value = response.headers.get("set-cookie") ?? "";
return value.split(";")[0] || "";
}
export async function pollAgentResult(port, traceId, init = {}) {
let last = null;
for (let attempt = 0; attempt < 20; attempt += 1) {
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/result/${encodeURIComponent(traceId)}`, init);
last = {
status: response.status,
body: await response.json()
};
if (response.status === 200) return last.body;
if (response.status !== 202) throw new Error(`Code Agent result polling failed: ${JSON.stringify(last)}`);
await delay(10);
}
throw new Error(`Code Agent result did not complete: ${JSON.stringify(last)}`);
}
export async function createFakeCodexCommand() {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-fake-codex-"));
const packageRoot = path.join(root, "node_modules", "@openai", "codex");
const command = path.join(packageRoot, "bin", "codex.js");
const native = path.join(root, "node_modules", "@openai", "codex-linux-x64", "vendor", "x86_64-unknown-linux-musl", "codex", "codex");
await mkdir(path.dirname(command), { recursive: true });
await mkdir(path.dirname(native), { recursive: true });
await writeFile(path.join(packageRoot, "package.json"), JSON.stringify({ name: "@openai/codex", version: "0.128.0" }), "utf8");
await writeFile(command, "#!/usr/bin/env node\nconsole.log('codex 0.128.0');\n", "utf8");
await writeFile(native, "#!/bin/sh\nexit 0\n", "utf8");
await chmod(command, 0o755);
await chmod(native, 0o755);
return { root, command };
}
export async function prepareFakeCodexHome(codexHome) {
await mkdir(codexHome, { recursive: true });
await writeFile(path.join(codexHome, "config.toml"), "model = \"gpt-test\"\n", "utf8");
await writeFile(path.join(codexHome, "auth.json"), "{\"auth\":\"redacted-test-placeholder\"}\n", "utf8");
return codexHome;
}
export function createFakeAppServerClient({ text = "真实 Codex stdio 回复", delayMs = 0 } = {}) {
let notificationHandler = null;
return {
async initialize() {
return { initialized: true };
},
setNotificationHandler(handler) {
notificationHandler = typeof handler === "function" ? handler : null;
},
async startThread() {
notificationHandler?.({ method: "thread/started", params: { thread: { id: "thread_server_test_stdio" } } });
return { threadId: "thread_server_test_stdio" };
},
async resumeThread(args) {
notificationHandler?.({ method: "thread/started", params: { thread: { id: args.threadId } } });
return { threadId: args.threadId };
},
async startTurn() {
const turnId = "turn_server_test_stdio";
notificationHandler?.({ method: "turn/started", params: { turn: { id: turnId } } });
if (delayMs > 0) await delay(delayMs);
notificationHandler?.({ method: "item/agentMessage/delta", params: { itemId: "item_server_test_stdio", delta: text } });
notificationHandler?.({ method: "item/completed", params: { item: { id: "item_server_test_stdio", type: "agentMessage", text } } });
notificationHandler?.({ method: "turn/completed", params: { turn: { id: turnId, status: "completed" } } });
return { turnId };
},
close() {}
};
}
export async function postAgentRaw(port, body, headers = {}) {
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
...headers
},
body
});
return {
status: response.status,
body: await response.json()
};
}
export function createGreenM3StatusRuntimeStore({ blocker = null } = {}) {
return {
async readiness() {
return {
adapter: "postgres",
durable: true,
durableRequested: true,
durableCapable: true,
ready: true,
status: "ready",
blocker,
reason: "Postgres durable runtime adapter completed live schema, migration, and read readiness queries",
liveRuntimeEvidence: true,
fixtureEvidence: false
};
},
async queryAuditEvents() {
return {
events: [
{
auditId: "aud_m3_di_read_d5afd84b-3a9d-475f-894f-dff8ea5f49ff_succeeded",
traceId: "trc_hotfix_307_verify_1779527747043_read_false",
actorType: "user",
actorId: "usr_m3_operator",
action: "m3.io.di.read",
targetType: "hardware_operation",
targetId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
projectId: "prj_mvp_topology",
gatewaySessionId: "gws_gwsimu_2",
operationId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
serviceId: "hwlab-cloud-api",
outcome: "succeeded",
metadata: {
route: "res_boxsimu_1:DO1->hwlab-patch-panel->res_boxsimu_2:DI1"
},
environment: "dev",
occurredAt: "2026-05-23T00:00:00.000Z"
}
],
count: 1
};
},
async queryEvidenceRecords() {
return {
records: [
{
evidenceId: "evd_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f_succeeded",
projectId: "prj_mvp_topology",
operationId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
kind: "trace",
uri: "memory://hwlab-cloud-api/op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f/m3-io-control.json",
sha256: "0".repeat(64),
serviceId: "hwlab-cloud-api",
environment: "dev",
metadata: {
traceId: "trc_hotfix_307_verify_1779527747043_read_false",
route: "res_boxsimu_1:DO1->hwlab-patch-panel->res_boxsimu_2:DI1"
},
createdAt: "2026-05-23T00:00:00.000Z"
}
],
count: 1
};
}
};
}