mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
fix(qa): restore safe no-fork gateway runtime
This commit is contained in:
@@ -26,7 +26,7 @@ function createParams(baseEnv?: NodeJS.ProcessEnv) {
|
||||
}
|
||||
|
||||
describe("buildQaRuntimeEnv", () => {
|
||||
it("allows normal reply config flows while keeping fast test mode", () => {
|
||||
it("keeps the slow-reply QA opt-out enabled under fast mode", () => {
|
||||
const env = buildQaRuntimeEnv({
|
||||
...createParams(),
|
||||
providerMode: "mock-openai",
|
||||
|
||||
@@ -110,8 +110,7 @@ export function buildQaRuntimeEnv(params: {
|
||||
OPENCLAW_SKIP_CANVAS_HOST: "1",
|
||||
OPENCLAW_NO_RESPAWN: "1",
|
||||
OPENCLAW_TEST_FAST: "1",
|
||||
// QA uses the fast runtime envelope for speed, but it still exercises
|
||||
// normal config-driven heartbeats and runtime config writes.
|
||||
// QA still exercises normal reply-config flows under the fast envelope.
|
||||
OPENCLAW_ALLOW_SLOW_REPLY_TESTS: "1",
|
||||
XDG_CONFIG_HOME: params.xdgConfigHome,
|
||||
XDG_DATA_HOME: params.xdgDataHome,
|
||||
@@ -120,10 +119,6 @@ export function buildQaRuntimeEnv(params: {
|
||||
return normalizeQaProviderModeEnv(env, params.providerMode);
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
buildQaRuntimeEnv,
|
||||
};
|
||||
|
||||
async function waitForGatewayReady(params: {
|
||||
baseUrl: string;
|
||||
logs: () => string;
|
||||
@@ -140,17 +135,17 @@ async function waitForGatewayReady(params: {
|
||||
`gateway exited before becoming healthy (exitCode=${String(params.child.exitCode)}, signal=${String(params.child.signalCode)}):\n${params.logs()}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
for (const readyPath of ["/readyz", "/healthz"]) {
|
||||
const response = await fetch(`${params.baseUrl}${readyPath}`, {
|
||||
for (const healthPath of ["/readyz", "/healthz"]) {
|
||||
try {
|
||||
const response = await fetch(`${params.baseUrl}${healthPath}`, {
|
||||
signal: AbortSignal.timeout(2_000),
|
||||
});
|
||||
if (response.ok) {
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// retry until timeout
|
||||
}
|
||||
} catch {
|
||||
// retry until timeout
|
||||
}
|
||||
await sleep(250);
|
||||
}
|
||||
@@ -270,7 +265,6 @@ export async function startQaGatewayChild(params: {
|
||||
rpcClient = await startQaGatewayRpcClient({
|
||||
wsUrl,
|
||||
token: gatewayToken,
|
||||
env,
|
||||
logs,
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -21,24 +21,18 @@ describe("startQaGatewayRpcClient", () => {
|
||||
gatewayRpcMock.reset();
|
||||
});
|
||||
|
||||
it("calls the in-process gateway cli helper with the qa runtime env", async () => {
|
||||
it("calls the in-process gateway cli helper without mutating process.env", async () => {
|
||||
const originalHome = process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_QA_TEST_ONLY;
|
||||
|
||||
gatewayRpcMock.callGatewayFromCli.mockImplementationOnce(async () => {
|
||||
expect(process.env.OPENCLAW_HOME).toBe("/tmp/openclaw-home");
|
||||
expect(process.env.OPENCLAW_QA_TEST_ONLY).toBe("1");
|
||||
expect(process.env.OPENCLAW_HOME).toBeUndefined();
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
const client = await startQaGatewayRpcClient({
|
||||
wsUrl: "ws://127.0.0.1:18789",
|
||||
token: "qa-token",
|
||||
env: {
|
||||
OPENCLAW_HOME: "/tmp/openclaw-home",
|
||||
OPENCLAW_QA_TEST_ONLY: "1",
|
||||
} as NodeJS.ProcessEnv,
|
||||
logs: () => "qa logs",
|
||||
});
|
||||
|
||||
@@ -63,7 +57,6 @@ describe("startQaGatewayRpcClient", () => {
|
||||
);
|
||||
|
||||
expect(process.env.OPENCLAW_HOME).toBe(originalHome);
|
||||
expect(process.env.OPENCLAW_QA_TEST_ONLY).toBeUndefined();
|
||||
});
|
||||
|
||||
it("wraps request failures with gateway logs", async () => {
|
||||
@@ -71,7 +64,6 @@ describe("startQaGatewayRpcClient", () => {
|
||||
const client = await startQaGatewayRpcClient({
|
||||
wsUrl: "ws://127.0.0.1:18789",
|
||||
token: "qa-token",
|
||||
env: { OPENCLAW_HOME: "/tmp/openclaw-home" } as NodeJS.ProcessEnv,
|
||||
logs: () => "qa logs",
|
||||
});
|
||||
|
||||
@@ -84,7 +76,6 @@ describe("startQaGatewayRpcClient", () => {
|
||||
const client = await startQaGatewayRpcClient({
|
||||
wsUrl: "ws://127.0.0.1:18789",
|
||||
token: "qa-token",
|
||||
env: { OPENCLAW_HOME: "/tmp/openclaw-home" } as NodeJS.ProcessEnv,
|
||||
logs: () => "qa logs",
|
||||
});
|
||||
|
||||
|
||||
@@ -18,34 +18,6 @@ function formatQaGatewayRpcError(error: unknown, logs: () => string) {
|
||||
|
||||
let qaGatewayRpcQueue = Promise.resolve();
|
||||
|
||||
async function withScopedProcessEnv<T>(env: NodeJS.ProcessEnv, task: () => Promise<T>): Promise<T> {
|
||||
const original = new Map<string, string | undefined>();
|
||||
const keys = new Set([...Object.keys(process.env), ...Object.keys(env)]);
|
||||
|
||||
for (const key of keys) {
|
||||
original.set(key, process.env[key]);
|
||||
const nextValue = env[key];
|
||||
if (nextValue === undefined) {
|
||||
delete process.env[key];
|
||||
continue;
|
||||
}
|
||||
process.env[key] = nextValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return await task();
|
||||
} finally {
|
||||
for (const key of keys) {
|
||||
const previousValue = original.get(key);
|
||||
if (previousValue === undefined) {
|
||||
delete process.env[key];
|
||||
continue;
|
||||
}
|
||||
process.env[key] = previousValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function runQueuedQaGatewayRpc<T>(task: () => Promise<T>): Promise<T> {
|
||||
const run = qaGatewayRpcQueue.then(task, task);
|
||||
qaGatewayRpcQueue = run.then(
|
||||
@@ -58,7 +30,6 @@ async function runQueuedQaGatewayRpc<T>(task: () => Promise<T>): Promise<T> {
|
||||
export async function startQaGatewayRpcClient(params: {
|
||||
wsUrl: string;
|
||||
token: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
logs: () => string;
|
||||
}): Promise<QaGatewayRpcClient> {
|
||||
const wrapError = (error: unknown) => formatQaGatewayRpcError(error, params.logs);
|
||||
@@ -72,24 +43,20 @@ export async function startQaGatewayRpcClient(params: {
|
||||
try {
|
||||
return await runQueuedQaGatewayRpc(
|
||||
async () =>
|
||||
await withScopedProcessEnv(
|
||||
params.env,
|
||||
async () =>
|
||||
await callGatewayFromCli(
|
||||
method,
|
||||
{
|
||||
url: params.wsUrl,
|
||||
token: params.token,
|
||||
timeout: String(opts?.timeoutMs ?? 20_000),
|
||||
expectFinal: opts?.expectFinal,
|
||||
json: true,
|
||||
},
|
||||
rpcParams ?? {},
|
||||
{
|
||||
expectFinal: opts?.expectFinal,
|
||||
progress: false,
|
||||
},
|
||||
),
|
||||
await callGatewayFromCli(
|
||||
method,
|
||||
{
|
||||
url: params.wsUrl,
|
||||
token: params.token,
|
||||
timeout: String(opts?.timeoutMs ?? 20_000),
|
||||
expectFinal: opts?.expectFinal,
|
||||
json: true,
|
||||
},
|
||||
rpcParams ?? {},
|
||||
{
|
||||
expectFinal: opts?.expectFinal,
|
||||
progress: false,
|
||||
},
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user