mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
perf(test): streamline qa gateway child tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { lstat, mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -456,45 +456,41 @@ describe("buildQaRuntimeEnv", () => {
|
||||
});
|
||||
|
||||
it("force-stops gateway children that ignore the graceful signal", async () => {
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
[
|
||||
"-e",
|
||||
[
|
||||
"process.on('SIGTERM', () => {});",
|
||||
"process.stdout.write('ready\\n');",
|
||||
"setInterval(() => {}, 1000);",
|
||||
].join(""),
|
||||
],
|
||||
const child = Object.assign(new EventEmitter(), {
|
||||
pid: 12345,
|
||||
exitCode: null as number | null,
|
||||
signalCode: null as string | null,
|
||||
kill: vi.fn((signal?: "SIGTERM" | "SIGKILL" | number) => {
|
||||
if (signal === "SIGKILL") {
|
||||
child.signalCode = "SIGKILL";
|
||||
queueMicrotask(() => child.emit("exit"));
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
const processKill = vi.spyOn(process, "kill").mockImplementation((_pid, signal) => {
|
||||
if (signal === "SIGKILL") {
|
||||
child.signalCode = "SIGKILL";
|
||||
queueMicrotask(() => child.emit("exit"));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
await __testing.stopQaGatewayChildProcessTree(
|
||||
child as unknown as Parameters<typeof __testing.stopQaGatewayChildProcessTree>[0],
|
||||
{
|
||||
detached: process.platform !== "win32",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
gracefulTimeoutMs: 1,
|
||||
forceTimeoutMs: 10,
|
||||
},
|
||||
);
|
||||
cleanups.push(async () => {
|
||||
if (child.exitCode === null && child.signalCode === null) {
|
||||
try {
|
||||
if (process.platform === "win32") {
|
||||
child.kill("SIGKILL");
|
||||
} else if (child.pid) {
|
||||
process.kill(-child.pid, "SIGKILL");
|
||||
}
|
||||
} catch {
|
||||
// The child already exited.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
child.once("error", reject);
|
||||
child.stdout?.once("data", () => resolve());
|
||||
});
|
||||
|
||||
await __testing.stopQaGatewayChildProcessTree(child, {
|
||||
gracefulTimeoutMs: 50,
|
||||
forceTimeoutMs: 1_000,
|
||||
});
|
||||
|
||||
if (process.platform === "win32") {
|
||||
expect(child.kill).toHaveBeenCalledWith("SIGTERM");
|
||||
expect(child.kill).toHaveBeenCalledWith("SIGKILL");
|
||||
} else {
|
||||
expect(processKill).toHaveBeenCalledWith(-12345, "SIGTERM");
|
||||
expect(processKill).toHaveBeenCalledWith(-12345, "SIGKILL");
|
||||
}
|
||||
expect(child.exitCode !== null || child.signalCode !== null).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import {
|
||||
applyAuthProfileConfig,
|
||||
upsertAuthProfile,
|
||||
validateAnthropicSetupToken,
|
||||
} from "openclaw/plugin-sdk/provider-auth";
|
||||
import { resolveQaAgentAuthDir, writeQaAuthProfiles } from "../shared/auth-store.js";
|
||||
|
||||
export const QA_LIVE_ANTHROPIC_SETUP_TOKEN_ENV = "OPENCLAW_QA_LIVE_ANTHROPIC_SETUP_TOKEN";
|
||||
export const QA_LIVE_SETUP_TOKEN_VALUE_ENV = "OPENCLAW_LIVE_SETUP_TOKEN_VALUE";
|
||||
@@ -40,16 +38,15 @@ export async function stageQaLiveAnthropicSetupToken(params: {
|
||||
if (!resolved) {
|
||||
return params.cfg;
|
||||
}
|
||||
const agentDir = path.join(params.stateDir, "agents", "main", "agent");
|
||||
await fs.mkdir(agentDir, { recursive: true });
|
||||
upsertAuthProfile({
|
||||
profileId: resolved.profileId,
|
||||
credential: {
|
||||
type: "token",
|
||||
provider: "anthropic",
|
||||
token: resolved.token,
|
||||
await writeQaAuthProfiles({
|
||||
agentDir: resolveQaAgentAuthDir({ stateDir: params.stateDir, agentId: "main" }),
|
||||
profiles: {
|
||||
[resolved.profileId]: {
|
||||
type: "token",
|
||||
provider: "anthropic",
|
||||
token: resolved.token,
|
||||
},
|
||||
},
|
||||
agentDir,
|
||||
});
|
||||
return applyAuthProfileConfig(params.cfg, {
|
||||
profileId: resolved.profileId,
|
||||
|
||||
31
extensions/qa-lab/src/providers/shared/auth-store.ts
Normal file
31
extensions/qa-lab/src/providers/shared/auth-store.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
type QaAuthProfileCredential =
|
||||
| {
|
||||
type: "api_key";
|
||||
provider: string;
|
||||
key: string;
|
||||
displayName?: string;
|
||||
}
|
||||
| {
|
||||
type: "token";
|
||||
provider: string;
|
||||
token: string;
|
||||
};
|
||||
|
||||
export function resolveQaAgentAuthDir(params: { stateDir: string; agentId: string }): string {
|
||||
return path.join(params.stateDir, "agents", params.agentId, "agent");
|
||||
}
|
||||
|
||||
export async function writeQaAuthProfiles(params: {
|
||||
agentDir: string;
|
||||
profiles: Record<string, QaAuthProfileCredential>;
|
||||
}): Promise<void> {
|
||||
await fs.mkdir(params.agentDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(params.agentDir, "auth-profiles.json"),
|
||||
`${JSON.stringify({ version: 1, profiles: params.profiles }, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { applyAuthProfileConfig, upsertAuthProfile } from "openclaw/plugin-sdk/provider-auth";
|
||||
import { applyAuthProfileConfig } from "openclaw/plugin-sdk/provider-auth-api-key";
|
||||
import { resolveQaAgentAuthDir, writeQaAuthProfiles } from "./auth-store.js";
|
||||
|
||||
/** Providers the mock harness stages placeholder credentials for by default. */
|
||||
export const QA_MOCK_AUTH_PROVIDERS = Object.freeze(["openai", "anthropic"] as const);
|
||||
@@ -42,21 +41,20 @@ export async function stageQaMockAuthProfiles(params: {
|
||||
const providers = [...new Set(params.providers ?? QA_MOCK_AUTH_PROVIDERS)];
|
||||
let next = params.cfg;
|
||||
for (const agentId of agentIds) {
|
||||
const agentDir = path.join(params.stateDir, "agents", agentId, "agent");
|
||||
await fs.mkdir(agentDir, { recursive: true });
|
||||
for (const provider of providers) {
|
||||
const profileId = buildQaMockProfileId(provider);
|
||||
upsertAuthProfile({
|
||||
profileId,
|
||||
credential: {
|
||||
type: "api_key",
|
||||
provider,
|
||||
key: "qa-mock-not-a-real-key",
|
||||
displayName: `QA mock ${provider} credential`,
|
||||
},
|
||||
agentDir,
|
||||
});
|
||||
}
|
||||
await writeQaAuthProfiles({
|
||||
agentDir: resolveQaAgentAuthDir({ stateDir: params.stateDir, agentId }),
|
||||
profiles: Object.fromEntries(
|
||||
providers.map((provider) => [
|
||||
buildQaMockProfileId(provider),
|
||||
{
|
||||
type: "api_key",
|
||||
provider,
|
||||
key: "qa-mock-not-a-real-key",
|
||||
displayName: `QA mock ${provider} credential`,
|
||||
},
|
||||
]),
|
||||
),
|
||||
});
|
||||
}
|
||||
for (const provider of providers) {
|
||||
next = applyAuthProfileConfig(next, {
|
||||
|
||||
Reference in New Issue
Block a user