Files
adolf/extensions/qa-matrix/src/substrate/recording-proxy.test.ts
alvis bedb527145
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Vendor OpenClaw source as Adolf fork baseline
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:36:54 +00:00

715 lines
26 KiB
TypeScript

// Qa Matrix tests cover redacted protocol recording and manifest derivation.
import { createServer } from "node:http";
import { afterEach, describe, expect, it } from "vitest";
import { startMatrixQaFaultProxy } from "./fault-proxy.js";
import { normalizeMatrixQaRoute, startMatrixQaRecordingProxy } from "./recording-proxy.js";
const closeCallbacks: Array<() => Promise<void>> = [];
afterEach(async () => {
while (closeCallbacks.length > 0) {
await closeCallbacks.pop()?.();
}
});
async function startRecordingTarget(options?: { alwaysFailState?: boolean }) {
let syncCount = 0;
let stateCount = 0;
const server = createServer((req, res) => {
const url = new URL(req.url ?? "/", "http://matrix.test");
if (url.pathname.endsWith("/sync")) {
syncCount += 1;
const since = url.searchParams.get("since");
res.writeHead(200, { "content-type": "application/json" });
res.end(
JSON.stringify({
account_data: {
events: [
{
content: {
encrypted: {
SECRET_NESTED_STORAGE_KEY: { ciphertext: "secret-nested-ciphertext" },
},
unsigned: {
"secret-custom-field-name": "secret-custom-field-value",
},
url: "mxc://matrix.test/secret-media",
info: { mimetype: "image/png" },
},
type: "m.cross_signing.master",
},
],
},
device_keys: {
"@secret-user:matrix.test": {
SECRET_DEVICE: {
keys: {
"ed25519:SECRET_DEVICE": "secret-signing-key",
},
},
},
},
device_one_time_keys_count: { signed_curve25519: 12 },
device_unused_fallback_key_types: ["signed_curve25519"],
next_batch: since === "echoed-unknown" ? since : `secret-sync-${syncCount}`,
device_lists: { changed: ["secret-device"] },
rooms: {
join: {
"!secret-room:matrix.test": {
timeline: {
events: [
{ type: "m.room.message" },
{ sender: "@secret-sender:matrix.test", type: "m.room.encrypted" },
],
},
},
},
},
}),
);
return;
}
if (url.pathname.includes("/room_keys/keys")) {
res.writeHead(200, { "content-type": "application/json" });
res.end(
JSON.stringify({
rooms: {
"!secret-backup-room:matrix.test": {
sessions: {
"secret-backup-session": { first_message_index: 0 },
},
},
},
}),
);
return;
}
if (url.pathname.endsWith("/keys/upload")) {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({ one_time_key_counts: {} }));
return;
}
if (url.pathname.endsWith("/keys/query")) {
res.writeHead(200, { "content-type": "application/json" });
res.end(
JSON.stringify({
failures: {
"secret-server.example": { errcode: "M_UNAVAILABLE" },
},
}),
);
return;
}
if (url.pathname.includes("/account_data/")) {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({}));
return;
}
if (url.pathname.includes("/sendToDevice/")) {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({}));
return;
}
if (url.pathname.includes("/state/")) {
stateCount += 1;
const status = options?.alwaysFailState || stateCount === 1 ? 401 : 200;
res.writeHead(status, { "content-type": "application/json" });
res.end(
status === 401
? JSON.stringify({ errcode: "M_UNKNOWN_TOKEN", error: "secret-response" })
: JSON.stringify({ name: "secret-state-name" }),
);
return;
}
res.writeHead(401, { "content-type": "application/json" });
res.end(JSON.stringify({ errcode: "M_UNKNOWN_TOKEN", error: "secret-response" }));
});
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
server.off("error", reject);
resolve();
});
});
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("recording target did not bind");
}
closeCallbacks.push(
async () =>
await new Promise<void>((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
}),
);
return `http://127.0.0.1:${address.port}`;
}
describe("Matrix QA recording proxy", () => {
it("records only redacted shapes and derives scenario expectations", async () => {
const targetBaseUrl = await startRecordingTarget();
const proxy = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => proxy.stop());
proxy.setScenarioId("matrix-recording-test");
const firstSync = await fetch(
`${proxy.baseUrl}/_matrix/client/v3/sync?timeout=0&access_token=secret-query`,
{ headers: { authorization: "Bearer secret-header" } },
);
const firstBody = (await firstSync.json()) as { next_batch: string };
await fetch(
`${proxy.baseUrl}/_matrix/client/v3/sync?timeout=0&since=${encodeURIComponent(firstBody.next_batch)}`,
{ headers: { authorization: "Bearer secret-header" } },
);
const postState = async () => {
await fetch(
`${proxy.baseUrl}/_matrix/client/v3/rooms/!secret:matrix.test/state/m.room.name`,
{
body: JSON.stringify({ password: "secret-password", body: "secret-message" }),
headers: {
authorization: "Bearer secret-header",
"content-type": "application/json",
},
method: "POST",
},
);
};
await postState();
await fetch(`${proxy.baseUrl}/_matrix/client/v3/room_keys/keys`, {
headers: {
authorization: "Bearer secret-header",
},
});
await fetch(`${proxy.baseUrl}/_matrix/client/v3/keys/upload`, {
body: JSON.stringify({
device_keys: {
algorithms: ["m.olm.v1.curve25519-aes-sha2"],
device_id: "SECRET_UPLOAD_DEVICE",
keys: { "ed25519:SECRET_UPLOAD_DEVICE": "secret-upload-key" },
user_id: "@secret-upload:matrix.test",
},
one_time_keys: {
"signed_curve25519:SECRET_ONE_TIME": { key: "secret-one-time-key" },
},
}),
headers: {
authorization: "Bearer secret-header",
"content-type": "application/json",
},
method: "POST",
});
await fetch(`${proxy.baseUrl}/_matrix/client/v3/keys/query`, {
body: JSON.stringify({ device_keys: {} }),
headers: { "content-type": "application/json" },
method: "POST",
});
await fetch(
`${proxy.baseUrl}/_matrix/client/v3/user/@secret-upload%3Amatrix.test/account_data/m.cross_signing.master`,
{
body: JSON.stringify({
encrypted: {
SECRET_STORAGE_KEY: { ciphertext: "secret-ciphertext" },
},
}),
headers: { "content-type": "application/json" },
method: "PUT",
},
);
await fetch(
`${proxy.baseUrl}/_matrix/client/v3/user/@secret-upload%3Amatrix.test/account_data/m.megolm_backup.v1`,
{
body: JSON.stringify({ version: "1" }),
headers: { "content-type": "application/json" },
method: "PUT",
},
);
await fetch(`${proxy.baseUrl}/_matrix/client/v3/sendToDevice/m.room.encrypted/transaction-42`, {
body: JSON.stringify({
messages: {
"@secret-recipient:matrix.test": {
SECRET_RECIPIENT_DEVICE: { content: "secret-device-message" },
},
},
}),
headers: { "content-type": "application/json" },
method: "PUT",
});
await postState();
const records = proxy.records();
const serialized = JSON.stringify(records);
expect(serialized).not.toContain("secret-query");
expect(serialized).not.toContain("secret-header");
expect(serialized).not.toContain("secret-password");
expect(serialized).not.toContain("secret-message");
expect(serialized).not.toContain("secret-sync");
expect(serialized).not.toContain("secret-response");
expect(serialized).not.toContain("secret-room");
expect(serialized).not.toContain("secret-backup-room");
expect(serialized).not.toContain("secret-backup-session");
expect(serialized).not.toContain("secret-state-name");
expect(serialized).not.toContain("secret-user");
expect(serialized).not.toContain("SECRET_DEVICE");
expect(serialized).not.toContain("SECRET_UPLOAD_DEVICE");
expect(serialized).not.toContain("SECRET_ONE_TIME");
expect(serialized).not.toContain("SECRET_RECIPIENT_DEVICE");
expect(serialized).not.toContain("secret-server.example");
expect(serialized).not.toContain("SECRET_STORAGE_KEY");
expect(serialized).not.toContain("SECRET_NESTED_STORAGE_KEY");
expect(serialized).not.toContain("secret-custom-field-name");
const keyUpload = records.find((record) => record.request.route.endsWith("/keys/upload"));
expect(keyUpload?.request.body).toEqual({
kind: "json",
fields: [
"device_keys.algorithms",
"device_keys.device_id",
"device_keys.keys.{keyId}",
"device_keys.user_id",
"one_time_keys.{keyId}.key",
],
});
const sendToDevice = records.find((record) => record.request.route.includes("sendToDevice"));
expect(sendToDevice?.request.body).toEqual({
kind: "json",
fields: ["messages.{userId}.{deviceId}.content"],
});
const keyQuery = records.find((record) => record.request.route.endsWith("/keys/query"));
expect(keyQuery?.response.body).toEqual({
kind: "json",
fields: ["failures.{serverName}.errcode"],
});
const secretStorage = records.find((record) =>
record.request.route.endsWith("/account_data/m.cross_signing.master"),
);
expect(secretStorage?.request.body).toEqual({
kind: "json",
fields: ["encrypted.{keyId}.ciphertext"],
});
expect(records[1]?.sync).toMatchObject({ continuity: true, since: "sync-1" });
const manifest = proxy.buildManifest({
generatedAt: "2026-07-03T00:00:00.000Z",
requestedProfile: "all",
scenarioIds: ["matrix-recording-test"],
substrate: { id: "tuwunel", version: "v1.5.1" },
});
const expectation = manifest.scenarios["matrix-recording-test"];
expect(manifest.profile).toEqual({
derivedFrom: "observed-request-response-traffic",
id: "matrix-qa-v1",
});
expect(expectation?.syncTokens).toEqual({
continuityObserved: true,
incrementalRequests: 1,
initialRequests: 1,
responseTokens: 2,
});
expect(expectation?.state.device).toEqual([
"/_matrix/client/v3/keys/upload",
"/_matrix/client/v3/sync",
]);
expect(expectation?.state.key).toContain(
"/_matrix/client/v3/user/{userId}/account_data/m.cross_signing.master",
);
expect(expectation?.state.key).toContain("/_matrix/client/v3/sync");
expect(expectation?.state.backup).toContain(
"/_matrix/client/v3/user/{userId}/account_data/m.megolm_backup.v1",
);
expect(expectation?.state.media).toContain("/_matrix/client/v3/sync");
expect(expectation?.ordering[0]).toMatchObject({
requestBody: { kind: "empty" },
responseBody: {
kind: "json",
fields: expect.arrayContaining([
"rooms.join.{roomId}.timeline.events[].sender",
"rooms.join.{roomId}.timeline.events[].type",
]),
},
});
expect(expectation?.retries).toEqual([]);
expect(expectation?.errors).toEqual([
{
errcode: "M_UNKNOWN_TOKEN",
method: "POST",
route: "/_matrix/client/v3/rooms/{roomId}/state/m.room.name",
status: 401,
},
]);
});
it("normalizes substrate-specific Matrix identifiers from routes", () => {
expect(
normalizeMatrixQaRoute(
"/_matrix/client/v3/rooms/!room%3Amatrix.test/send/m.room.message/txn-123",
),
).toBe("/_matrix/client/v3/rooms/{roomId}/send/m.room.message/{transactionId}");
expect(
normalizeMatrixQaRoute(
"/_matrix/client/v3/rooms/!room%3Amatrix.test/redact/$event%3Amatrix.test/txn-123",
),
).toBe("/_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{transactionId}");
expect(normalizeMatrixQaRoute("/_matrix/media/v3/download/matrix.test/secret-media-id")).toBe(
"/_matrix/media/v3/download/{serverName}/{mediaId}",
);
expect(
normalizeMatrixQaRoute(
"/_matrix/media/v3/download/matrix.test/secret-media-id/private-report.pdf",
),
).toBe("/_matrix/media/v3/download/{serverName}/{mediaId}/{filename}");
expect(
normalizeMatrixQaRoute("/_matrix/client/v1/media/thumbnail/matrix.test/secret-media-id"),
).toBe("/_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}");
expect(
normalizeMatrixQaRoute("/_matrix/client/v3/user/@alice%3Amatrix.test/filter/filter-42"),
).toBe("/_matrix/client/v3/user/{userId}/filter/{filterId}");
expect(
normalizeMatrixQaRoute(
"/_matrix/client/v3/user/@alice%3Amatrix.test/account_data/m.secret_storage.key.secret-key-id",
),
).toBe("/_matrix/client/v3/user/{userId}/account_data/m.secret_storage.key.{keyId}");
expect(
normalizeMatrixQaRoute("/_matrix/client/v3/room_keys/keys/!room%3Amatrix.test/session-42"),
).toBe("/_matrix/client/v3/room_keys/keys/{roomId}/{sessionId}");
});
it("records the response observed after scenario-local fault injection", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-fault-recording-test");
const faultProxy = await startMatrixQaFaultProxy({
targetBaseUrl,
...recording,
rules: [
{
id: "backup-unavailable",
match: (request) => request.path.endsWith("/room_keys/version"),
response: () => ({
body: { errcode: "M_NOT_FOUND", error: "secret-fault-message" },
status: 404,
}),
},
],
});
closeCallbacks.push(() => faultProxy.stop());
await fetch(`${faultProxy.baseUrl}/_matrix/client/v3/room_keys/version`);
const record = recording
.records()
.find((entry) => entry.scenarioId === "matrix-fault-recording-test");
expect(record?.response).toMatchObject({ errcode: "M_NOT_FOUND", status: 404 });
expect(JSON.stringify(record)).not.toContain("secret-fault-message");
});
it("records proxy-generated upstream failures", async () => {
const recording = await startMatrixQaRecordingProxy({
targetBaseUrl: "http://127.0.0.1:1",
});
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-upstream-failure-test");
const response = await fetch(`${recording.baseUrl}/_matrix/client/v3/sync?timeout=0`);
expect(response.status).toBe(502);
expect(recording.records().at(-1)?.response).toMatchObject({
errcode: "MATRIX_QA_FAULT_PROXY_ERROR",
status: 502,
});
});
it("redacts signature upload device and cross-signing key identifiers", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-signatures-recording-test");
await fetch(`${recording.baseUrl}/_matrix/client/v3/keys/signatures/upload`, {
body: JSON.stringify({
"@secret-signing-user:matrix.test": {
SECRET_CROSS_SIGNING_KEY: { signatures: {} },
},
}),
headers: { "content-type": "application/json" },
method: "POST",
});
const record = recording.records().at(-1);
expect(record?.request.body).toEqual({
kind: "json",
fields: ["{userId}.{deviceOrKeyId}.signatures"],
});
expect(JSON.stringify(record)).not.toContain("secret-signing-user");
expect(JSON.stringify(record)).not.toContain("SECRET_CROSS_SIGNING_KEY");
});
it("reports sync continuity only when every incremental token is recognized", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-sync-discontinuity-test");
await fetch(`${recording.baseUrl}/_matrix/client/v3/sync?timeout=0&since=unknown-token`);
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-sync-discontinuity-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-sync-discontinuity-test"]?.syncTokens).toMatchObject({
continuityObserved: false,
incrementalRequests: 1,
});
});
it("does not learn an unknown request token from the same sync response", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-echoed-sync-token-test");
await fetch(`${recording.baseUrl}/_matrix/client/v3/sync?timeout=0&since=echoed-unknown`);
expect(recording.records().at(-1)?.sync).toMatchObject({
continuity: false,
since: "sync-unknown",
});
});
it("does not conflate distinct same-shape operations as retries", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-distinct-operation-test");
await fetch(
`${recording.baseUrl}/_matrix/client/v3/rooms/!first:matrix.test/state/m.room.name`,
{
body: JSON.stringify({ name: "first" }),
headers: { "content-type": "application/json" },
method: "POST",
},
);
await fetch(
`${recording.baseUrl}/_matrix/client/v3/rooms/!second:matrix.test/state/m.room.name`,
{
body: JSON.stringify({ name: "second" }),
headers: { "content-type": "application/json" },
method: "POST",
},
);
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-distinct-operation-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-distinct-operation-test"]?.retries).toEqual([]);
});
it("does not conflate identical operations from different principals", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-principal-retry-test");
const endpoint = `${recording.baseUrl}/_matrix/client/v3/rooms/!same:matrix.test/state/m.room.name`;
await fetch(endpoint, {
body: JSON.stringify({ name: "same" }),
headers: { authorization: "Bearer first", "content-type": "application/json" },
method: "POST",
});
await fetch(endpoint, {
body: JSON.stringify({ name: "same" }),
headers: { authorization: "Bearer second", "content-type": "application/json" },
method: "POST",
});
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-principal-retry-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-principal-retry-test"]?.retries).toEqual([]);
});
it("attributes sync completion to the active scenario", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("previous-scenario");
const context = recording.createExchangeContext?.({
body: Buffer.alloc(0),
headers: {},
method: "GET",
path: "/_matrix/client/v3/sync",
search: "?timeout=0",
});
recording.setScenarioId("active-scenario");
await recording.onExchange?.({
context,
request: {
body: Buffer.alloc(0),
headers: {},
method: "GET",
path: "/_matrix/client/v3/sync",
search: "?timeout=0",
},
response: {
body: Buffer.from(JSON.stringify({ next_batch: "sync-complete" })),
headers: new Headers({ "content-type": "application/json" }),
status: 200,
},
});
expect(recording.records().at(-1)?.scenarioId).toBe("active-scenario");
});
it("does not share sync-token continuity across principals", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-principal-sync-test");
const exchange = async (bearerToken: string, search: string, nextBatch: string) => {
const request = {
bearerToken,
body: Buffer.alloc(0),
headers: {},
method: "GET",
path: "/_matrix/client/v3/sync",
search,
};
await recording.onExchange?.({
context: recording.createExchangeContext?.(request),
request,
response: {
body: Buffer.from(JSON.stringify({ next_batch: nextBatch })),
headers: new Headers({ "content-type": "application/json" }),
status: 200,
},
});
};
await exchange("first", "?timeout=0", "shared-token");
await exchange("second", "?timeout=0&since=shared-token", "second-token");
expect(recording.records().at(-1)?.sync).toMatchObject({
continuity: false,
since: "sync-unknown",
});
});
it("ends a retry chain at the first successful recovery", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-retry-boundary-test");
const endpoint = `${recording.baseUrl}/_matrix/client/v3/rooms/!same:matrix.test/state/m.room.name`;
const request = () =>
fetch(endpoint, {
body: JSON.stringify({ name: "same" }),
headers: { "content-type": "application/json" },
method: "POST",
});
await request();
await request();
await request();
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-retry-boundary-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-retry-boundary-test"]?.retries).toEqual([
expect.objectContaining({ attempts: 2, statuses: [401, 200] }),
]);
});
it("records exhausted retry chains without recovery", async () => {
const targetBaseUrl = await startRecordingTarget({ alwaysFailState: true });
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-exhausted-retry-test");
const endpoint = `${recording.baseUrl}/_matrix/client/v3/rooms/!exhausted:matrix.test/state/m.room.name`;
await fetch(endpoint, { method: "POST" });
await fetch(endpoint, { method: "POST" });
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-exhausted-retry-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-exhausted-retry-test"]?.retries).toEqual([
expect.objectContaining({ attempts: 2, statuses: [401, 401] }),
]);
});
it("does not infer retries across intervening operations", async () => {
const targetBaseUrl = await startRecordingTarget();
const recording = await startMatrixQaRecordingProxy({ targetBaseUrl });
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-independent-operation-test");
const stateEndpoint = `${recording.baseUrl}/_matrix/client/v3/rooms/!same:matrix.test/state/m.room.name`;
await fetch(stateEndpoint, { method: "POST" });
await fetch(`${recording.baseUrl}/_matrix/client/versions`);
await fetch(stateEndpoint, { method: "POST" });
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-independent-operation-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-independent-operation-test"]?.retries).toEqual([]);
});
it("records repeated retry chains for the same operation", async () => {
let requestCount = 0;
const server = createServer((_req, res) => {
requestCount += 1;
const status = requestCount % 2 === 1 ? 503 : 200;
res.writeHead(status, { "content-type": "application/json" });
res.end(JSON.stringify(status === 200 ? {} : { errcode: "M_UNAVAILABLE" }));
});
await new Promise<void>((resolve) => {
server.listen(0, "127.0.0.1", () => resolve());
});
closeCallbacks.push(
() =>
new Promise<void>((resolve, reject) => {
server.close((error) => {
if (error) {
reject(error);
return;
}
resolve();
});
}),
);
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("retry target did not bind");
}
const recording = await startMatrixQaRecordingProxy({
targetBaseUrl: `http://127.0.0.1:${address.port}`,
});
closeCallbacks.push(() => recording.stop());
recording.setScenarioId("matrix-repeated-retry-test");
const endpoint = `${recording.baseUrl}/_matrix/client/v3/rooms/!same:matrix.test/state/m.room.name`;
for (let attempt = 0; attempt < 4; attempt += 1) {
await fetch(endpoint, { method: "POST" });
}
const manifest = recording.buildManifest({
requestedProfile: "test",
scenarioIds: ["matrix-repeated-retry-test"],
substrate: { id: "tuwunel", version: "test" },
});
expect(manifest.scenarios["matrix-repeated-retry-test"]?.retries).toEqual([
expect.objectContaining({ attempts: 2, statuses: [503, 200] }),
expect.objectContaining({ attempts: 2, statuses: [503, 200] }),
]);
});
});