Files
openclaw/extensions/qa-matrix/src/cli.ts
Dallin Romney 253b784468 test(qa): use qa flow for channel routing scenarios (#101076)
* test(qa): canonicalize channel routing scenarios

* test(qa): enforce Crabline actor allowlists

* test(qa): preserve canonical flow integration

* test(matrix): use retained topology fixture id

* test(qa): preserve WhatsApp live defaults

* QA: declare channel transport policy in scenarios

* refactor(qa): keep transport policy type local

* refactor(qa): keep transport policy on leaf contract

* test(matrix): use retained routing fixture
2026-07-06 18:35:41 -07:00

102 lines
3.5 KiB
TypeScript

// Qa Matrix plugin module implements cli behavior.
import type { Command } from "commander";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import {
createLazyCliRuntimeLoader,
createLiveTransportQaCliRegistration,
type LiveTransportQaCliRegistration,
type LiveTransportQaCommandOptions,
} from "./shared/live-transport-cli.js";
type MatrixQaCliRuntime = typeof import("./cli.runtime.js");
type MatrixQaAdapterRuntime = typeof import("./adapter.runtime.js");
const DISABLE_MATRIX_QA_FORCE_EXIT_ENV = "OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT";
const loadMatrixQaCliRuntime = createLazyCliRuntimeLoader<MatrixQaCliRuntime>(
() => import("./cli.runtime.js"),
);
const loadMatrixQaAdapterRuntime = createLazyCliRuntimeLoader<MatrixQaAdapterRuntime>(
() => import("./adapter.runtime.js"),
);
async function flushProcessStream(stream: NodeJS.WriteStream) {
if (stream.destroyed || !stream.writable) {
return;
}
await new Promise<void>((resolve) => {
try {
stream.write("", () => resolve());
} catch {
resolve();
}
});
}
async function exitMatrixQaCommand(code: number): Promise<never> {
// Matrix crypto native handles can outlive the QA run even after every
// client/gateway/harness has been stopped. This command is single-shot, so
// artifact completion should terminate deterministically on both pass and fail.
await Promise.all([flushProcessStream(process.stdout), flushProcessStream(process.stderr)]);
process.exit(code);
}
async function runQaMatrix(opts: LiveTransportQaCommandOptions) {
const runtime = await loadMatrixQaCliRuntime();
if (process.env[DISABLE_MATRIX_QA_FORCE_EXIT_ENV] === "1") {
await runtime.runQaMatrixCommand(opts);
return;
}
try {
await runtime.runQaMatrixCommand(opts);
await exitMatrixQaCommand(0);
} catch (error) {
process.stderr.write(`${formatErrorMessage(error)}\n`);
await exitMatrixQaCommand(1);
}
}
export const matrixQaAdapterFactory: NonNullable<LiveTransportQaCliRegistration["adapterFactory"]> =
{
id: "matrix",
scenarioIds: [
"channel-chat-baseline",
"channel-canary",
"channel-dm-group-routing",
"channel-mention-gating",
"channel-sender-allowlist",
"channel-top-level-reply-shape",
"channel-secondary-conversation-isolation",
"channel-multi-actor-ordering",
"thread-follow-up",
"thread-isolation",
"thread-reply-override",
"dm-shared-session",
"dm-per-room-session",
],
matches: ({ channelId, driver }) => driver === "live" && channelId === "matrix",
async create(context) {
return await (await loadMatrixQaAdapterRuntime()).createMatrixQaTransportAdapter(context);
},
};
export const matrixQaCliRegistration: LiveTransportQaCliRegistration =
createLiveTransportQaCliRegistration({
commandName: "matrix",
adapterFactory: matrixQaAdapterFactory,
description: "Run the Docker-backed Matrix live QA lane against a disposable homeserver",
outputDirHelp: "Matrix QA artifact directory",
profileHelp:
"Matrix QA profile: all, fast, transport, media, e2ee-smoke, e2ee-deep, or e2ee-cli (default: all)",
failFastHelp: "Stop after the first failed Matrix check or scenario",
scenarioHelp: "Run only the named Matrix QA scenario (repeatable)",
sutAccountHelp: "Temporary Matrix account id inside the QA gateway config",
run: runQaMatrix,
});
export const qaRunnerCliRegistrations = [matrixQaCliRegistration] as const;
export function registerMatrixQaCli(qa: Command) {
matrixQaCliRegistration.register(qa);
}