mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
test: share matrix harness fixtures
This commit is contained in:
@@ -4,6 +4,47 @@ import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { __testing, startMatrixQaHarness, writeMatrixQaHarnessFiles } from "./harness.runtime.js";
|
||||
|
||||
type MatrixQaHarnessDeps = Parameters<typeof startMatrixQaHarness>[1];
|
||||
type MatrixQaHarnessResult = Awaited<ReturnType<typeof startMatrixQaHarness>>;
|
||||
|
||||
async function withStartedMatrixHarness(
|
||||
deps: MatrixQaHarnessDeps,
|
||||
verify: (params: { outputDir: string; result: MatrixQaHarnessResult }) => Promise<void> | void,
|
||||
) {
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
},
|
||||
deps,
|
||||
);
|
||||
await verify({ outputDir, result });
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function createContainerNetworkRunCommand(calls?: string[]) {
|
||||
return async function runCommand(command: string, args: string[], cwd?: string) {
|
||||
calls?.push([command, ...args, `@${cwd}`].join(" "));
|
||||
const rendered = args.join(" ");
|
||||
if (rendered.includes("ps --format json")) {
|
||||
return { stdout: '{"State":"running"}\n', stderr: "" };
|
||||
}
|
||||
if (rendered.includes("ps -q")) {
|
||||
return { stdout: "container-123\n", stderr: "" };
|
||||
}
|
||||
if (rendered.includes("inspect --format")) {
|
||||
return { stdout: "172.18.0.10\n", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
};
|
||||
}
|
||||
|
||||
describe("matrix harness runtime", () => {
|
||||
it("writes a pinned Tuwunel compose file and redacted manifest", async () => {
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
@@ -46,227 +87,144 @@ describe("matrix harness runtime", () => {
|
||||
it("starts the harness, waits for versions, and exposes a stop command", async () => {
|
||||
const calls: string[] = [];
|
||||
const fetchCalls: string[] = [];
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
await withStartedMatrixHarness(
|
||||
{
|
||||
async runCommand(command, args, cwd) {
|
||||
calls.push([command, ...args, `@${cwd}`].join(" "));
|
||||
if (args.join(" ").includes("ps --format json")) {
|
||||
return { stdout: '[{"State":"running"}]\n', stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
{
|
||||
async runCommand(command, args, cwd) {
|
||||
calls.push([command, ...args, `@${cwd}`].join(" "));
|
||||
if (args.join(" ").includes("ps --format json")) {
|
||||
return { stdout: '[{"State":"running"}]\n', stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return { ok: true };
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
);
|
||||
|
||||
expect(calls).toEqual([
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml down --remove-orphans @/repo/openclaw`,
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml up -d @/repo/openclaw`,
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml ps --format json matrix-qa-homeserver @/repo/openclaw`,
|
||||
]);
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
]);
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
expect(result.stopCommand).toBe(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml down --remove-orphans`,
|
||||
);
|
||||
await result.restartService();
|
||||
expect(calls).toContain(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml restart matrix-qa-homeserver @/repo/openclaw`,
|
||||
);
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return { ok: true };
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
async ({ outputDir, result }) => {
|
||||
expect(calls).toEqual([
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml down --remove-orphans @/repo/openclaw`,
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml up -d @/repo/openclaw`,
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml ps --format json matrix-qa-homeserver @/repo/openclaw`,
|
||||
]);
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
]);
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
expect(result.stopCommand).toBe(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml down --remove-orphans`,
|
||||
);
|
||||
await result.restartService();
|
||||
expect(calls).toContain(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml restart matrix-qa-homeserver @/repo/openclaw`,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("treats empty Docker health fields as a fallback to running state", async () => {
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
await withStartedMatrixHarness(
|
||||
{
|
||||
async runCommand(_command, args) {
|
||||
if (args.join(" ").includes("ps --format json")) {
|
||||
return { stdout: '{"Health":"","State":"running"}\n', stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
{
|
||||
async runCommand(_command, args) {
|
||||
if (args.join(" ").includes("ps --format json")) {
|
||||
return { stdout: '{"Health":"","State":"running"}\n', stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
fetchImpl: vi.fn(async () => ({ ok: true })),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
fetchImpl: vi.fn(async () => ({ ok: true })),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
({ result }) => {
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to the container IP when the host port is unreachable", async () => {
|
||||
const calls: string[] = [];
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
},
|
||||
{
|
||||
async runCommand(command, args, cwd) {
|
||||
calls.push([command, ...args, `@${cwd}`].join(" "));
|
||||
const rendered = args.join(" ");
|
||||
if (rendered.includes("ps --format json")) {
|
||||
return { stdout: '{"State":"running"}\n', stderr: "" };
|
||||
}
|
||||
if (rendered.includes("ps -q")) {
|
||||
return { stdout: "container-123\n", stderr: "" };
|
||||
}
|
||||
if (rendered.includes("inspect --format")) {
|
||||
return { stdout: "172.18.0.10\n", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
fetchImpl: vi.fn(async (input: string) => ({
|
||||
ok: input.startsWith("http://172.18.0.10:8008/"),
|
||||
})),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.baseUrl).toBe("http://172.18.0.10:8008/");
|
||||
expect(calls).toContain(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml ps -q matrix-qa-homeserver @/repo/openclaw`,
|
||||
);
|
||||
expect(calls).toContain(
|
||||
"docker inspect --format {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} container-123 @/repo/openclaw",
|
||||
);
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
await withStartedMatrixHarness(
|
||||
{
|
||||
runCommand: createContainerNetworkRunCommand(calls),
|
||||
fetchImpl: vi.fn(async (input: string) => ({
|
||||
ok: input.startsWith("http://172.18.0.10:8008/"),
|
||||
})),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
({ outputDir, result }) => {
|
||||
expect(result.baseUrl).toBe("http://172.18.0.10:8008/");
|
||||
expect(calls).toContain(
|
||||
`docker compose -f ${outputDir}/docker-compose.matrix-qa.yml ps -q matrix-qa-homeserver @/repo/openclaw`,
|
||||
);
|
||||
expect(calls).toContain(
|
||||
"docker inspect --format {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} container-123 @/repo/openclaw",
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps the host URL when the container IP is also unreachable", async () => {
|
||||
const fetchCalls: string[] = [];
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
},
|
||||
{
|
||||
async runCommand(_command, args) {
|
||||
const rendered = args.join(" ");
|
||||
if (rendered.includes("ps --format json")) {
|
||||
return { stdout: '{"State":"running"}\n', stderr: "" };
|
||||
}
|
||||
if (rendered.includes("ps -q")) {
|
||||
return { stdout: "container-123\n", stderr: "" };
|
||||
}
|
||||
if (rendered.includes("inspect --format")) {
|
||||
return { stdout: "172.18.0.10\n", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return {
|
||||
ok:
|
||||
input === "http://127.0.0.1:28008/_matrix/client/versions" &&
|
||||
fetchCalls.filter((url) => url === input).length > 1,
|
||||
};
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
]);
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
await withStartedMatrixHarness(
|
||||
{
|
||||
runCommand: createContainerNetworkRunCommand(),
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return {
|
||||
ok:
|
||||
input === "http://127.0.0.1:28008/_matrix/client/versions" &&
|
||||
fetchCalls.filter((url) => url === input).length > 1,
|
||||
};
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
({ result }) => {
|
||||
expect(result.baseUrl).toBe("http://127.0.0.1:28008/");
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps probing the container URL until it becomes reachable", async () => {
|
||||
const fetchCalls: string[] = [];
|
||||
const outputDir = await mkdtemp(path.join(os.tmpdir(), "matrix-qa-harness-"));
|
||||
|
||||
try {
|
||||
const result = await startMatrixQaHarness(
|
||||
{
|
||||
outputDir,
|
||||
repoRoot: "/repo/openclaw",
|
||||
homeserverPort: 28008,
|
||||
},
|
||||
{
|
||||
async runCommand(_command, args) {
|
||||
const rendered = args.join(" ");
|
||||
if (rendered.includes("ps --format json")) {
|
||||
return { stdout: '{"State":"running"}\n', stderr: "" };
|
||||
}
|
||||
if (rendered.includes("ps -q")) {
|
||||
return { stdout: "container-123\n", stderr: "" };
|
||||
}
|
||||
if (rendered.includes("inspect --format")) {
|
||||
return { stdout: "172.18.0.10\n", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
},
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return {
|
||||
ok:
|
||||
input === "http://172.18.0.10:8008/_matrix/client/versions" &&
|
||||
fetchCalls.filter((url) => url === input).length > 1,
|
||||
};
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.baseUrl).toBe("http://172.18.0.10:8008/");
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
]);
|
||||
} finally {
|
||||
await rm(outputDir, { recursive: true, force: true });
|
||||
}
|
||||
await withStartedMatrixHarness(
|
||||
{
|
||||
runCommand: createContainerNetworkRunCommand(),
|
||||
fetchImpl: vi.fn(async (input: string) => {
|
||||
fetchCalls.push(input);
|
||||
return {
|
||||
ok:
|
||||
input === "http://172.18.0.10:8008/_matrix/client/versions" &&
|
||||
fetchCalls.filter((url) => url === input).length > 1,
|
||||
};
|
||||
}),
|
||||
sleepImpl: vi.fn(async () => {}),
|
||||
resolveHostPortImpl: vi.fn(async (port: number) => port),
|
||||
},
|
||||
({ result }) => {
|
||||
expect(result.baseUrl).toBe("http://172.18.0.10:8008/");
|
||||
expect(fetchCalls).toEqual([
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
"http://127.0.0.1:28008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
"http://172.18.0.10:8008/_matrix/client/versions",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user