From 1bd92975c2745039759991693a5bc76e09f7cfd1 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 20:43:26 +0100 Subject: [PATCH] test: share matrix runtime fixtures --- extensions/matrix/src/doctor.test.ts | 59 +++--- .../matrix/src/migration-snapshot.test.ts | 78 +++----- .../matrix/src/plugin-entry.runtime.test.ts | 189 ++++++------------ 3 files changed, 118 insertions(+), 208 deletions(-) diff --git a/extensions/matrix/src/doctor.test.ts b/extensions/matrix/src/doctor.test.ts index 7fa9f71ad9c..b730776cd0e 100644 --- a/extensions/matrix/src/doctor.test.ts +++ b/extensions/matrix/src/doctor.test.ts @@ -35,6 +35,23 @@ describe("matrix doctor", () => { vi.clearAllMocks(); }); + function normalizeMatrixDmConfig(dm: Record) { + const normalize = matrixDoctor.normalizeCompatibilityConfig; + expect(normalize).toBeDefined(); + if (!normalize) { + throw new Error("expected Matrix doctor compatibility normalizer"); + } + return normalize({ + cfg: { + channels: { + matrix: { + dm, + }, + }, + } as never, + }); + } + it("formats state and crypto previews", () => { expect( formatMatrixLegacyStatePreview({ @@ -283,24 +300,10 @@ describe("matrix doctor", () => { // so they must not count toward the allowFrom population check — otherwise // the migration would emit policy="allowlist" with an effectively empty // allowlist, silently blocking all DMs. - const normalize = matrixDoctor.normalizeCompatibilityConfig; - expect(normalize).toBeDefined(); - if (!normalize) { - return; - } - - const result = normalize({ - cfg: { - channels: { - matrix: { - dm: { - enabled: true, - policy: "trusted", - allowFrom: [" ", "\t", ""], - }, - }, - }, - } as never, + const result = normalizeMatrixDmConfig({ + enabled: true, + policy: "trusted", + allowFrom: [" ", "\t", ""], }); const matrixDm = (result.config.channels?.matrix as { dm?: { policy?: string } })?.dm; @@ -313,23 +316,9 @@ describe("matrix doctor", () => { }); it("migrates legacy channels.matrix.dm.policy 'trusted' without allowFrom to 'pairing'", () => { - const normalize = matrixDoctor.normalizeCompatibilityConfig; - expect(normalize).toBeDefined(); - if (!normalize) { - return; - } - - const result = normalize({ - cfg: { - channels: { - matrix: { - dm: { - enabled: true, - policy: "trusted", - }, - }, - }, - } as never, + const result = normalizeMatrixDmConfig({ + enabled: true, + policy: "trusted", }); const matrixDm = (result.config.channels?.matrix as { dm?: { policy?: string } })?.dm; diff --git a/extensions/matrix/src/migration-snapshot.test.ts b/extensions/matrix/src/migration-snapshot.test.ts index 172de40fe64..2ee71746047 100644 --- a/extensions/matrix/src/migration-snapshot.test.ts +++ b/extensions/matrix/src/migration-snapshot.test.ts @@ -22,6 +22,34 @@ import { resolveMatrixAccountStorageRoot } from "./storage-paths.js"; const createBackupArchiveMock = vi.hoisted(() => vi.fn()); +const MATRIX_CREDENTIALS = { + homeserver: "https://matrix.example.org", + userId: "@bot:example.org", + accessToken: "tok-123", +} as const; + +function makeMatrixMigrationConfig() { + return { + channels: { + matrix: MATRIX_CREDENTIALS, + }, + } as never; +} + +function seedLegacyMatrixCrypto(home: string) { + const stateDir = path.join(home, ".openclaw"); + const { rootDir } = resolveMatrixAccountStorageRoot({ + stateDir, + ...MATRIX_CREDENTIALS, + }); + fs.mkdirSync(path.join(rootDir, "crypto"), { recursive: true }); + fs.writeFileSync( + path.join(rootDir, "crypto", "bot-sdk.json"), + JSON.stringify({ deviceId: "DEVICE123" }), + "utf8", + ); +} + describe("matrix migration snapshots", () => { beforeEach(() => { createBackupArchiveMock.mockReset(); @@ -96,29 +124,8 @@ describe("matrix migration snapshots", () => { it("treats legacy Matrix crypto as actionable when the extension inspector is present", async () => { await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - const { rootDir } = resolveMatrixAccountStorageRoot({ - stateDir, - homeserver: "https://matrix.example.org", - userId: "@bot:example.org", - accessToken: "tok-123", - }); - fs.mkdirSync(path.join(rootDir, "crypto"), { recursive: true }); - fs.writeFileSync( - path.join(rootDir, "crypto", "bot-sdk.json"), - JSON.stringify({ deviceId: "DEVICE123" }), - "utf8", - ); - - const cfg = { - channels: { - matrix: { - homeserver: "https://matrix.example.org", - userId: "@bot:example.org", - accessToken: "tok-123", - }, - }, - } as never; + seedLegacyMatrixCrypto(home); + const cfg = makeMatrixMigrationConfig(); const detection = detectLegacyMatrixCrypto({ cfg, @@ -140,29 +147,8 @@ describe("matrix migration snapshots", () => { legacyCryptoInspectorAvailability.available = false; await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - const { rootDir } = resolveMatrixAccountStorageRoot({ - stateDir, - homeserver: "https://matrix.example.org", - userId: "@bot:example.org", - accessToken: "tok-123", - }); - fs.mkdirSync(path.join(rootDir, "crypto"), { recursive: true }); - fs.writeFileSync( - path.join(rootDir, "crypto", "bot-sdk.json"), - JSON.stringify({ deviceId: "DEVICE123" }), - "utf8", - ); - - const cfg = { - channels: { - matrix: { - homeserver: "https://matrix.example.org", - userId: "@bot:example.org", - accessToken: "tok-123", - }, - }, - } as never; + seedLegacyMatrixCrypto(home); + const cfg = makeMatrixMigrationConfig(); const detection = detectLegacyMatrixCrypto({ cfg, diff --git a/extensions/matrix/src/plugin-entry.runtime.test.ts b/extensions/matrix/src/plugin-entry.runtime.test.ts index 02d0b35e3e1..5a1ce753510 100644 --- a/extensions/matrix/src/plugin-entry.runtime.test.ts +++ b/extensions/matrix/src/plugin-entry.runtime.test.ts @@ -143,6 +143,51 @@ function writeTrustedOpenClawBinFixture( writeFixtureFile(fixtureRoot, "dist/plugin-sdk/group-access.js", "export {};\n"); } +function writeSourceRuntimeWrapperFixture(fixtureRoot: string) { + writeFixtureFile( + fixtureRoot, + "extensions/matrix/src/plugin-entry.runtime.js", + MATRIX_RUNTIME_WRAPPER_SOURCE, + ); + writeFixtureFile( + fixtureRoot, + "extensions/matrix/plugin-entry.handlers.runtime.js", + PACKAGED_RUNTIME_STUB, + ); +} + +function importFixtureModule(fixtureRoot: string, relativePath: string) { + const wrapperUrl = pathToFileURL(path.join(fixtureRoot, relativePath)); + return import(`${wrapperUrl.href}?t=${Date.now()}`); +} + +function expectRuntimeWrapperExports(mod: unknown) { + expect(mod).toMatchObject({ + ensureMatrixCryptoRuntime: expect.any(Function), + handleVerifyRecoveryKey: expect.any(Function), + handleVerificationBootstrap: expect.any(Function), + handleVerificationStatus: expect.any(Function), + }); +} + +function writeCapturingSourceRuntimeWrapperFixture(fixtureRoot: string) { + delete matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions; + writeOpenClawAliasFixture(fixtureRoot); + writeCapturingJitiFixture(fixtureRoot); + writeSourceRuntimeWrapperFixture(fixtureRoot); +} + +function expectSourcePluginSdkAliases(fixtureRoot: string) { + expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ + alias: { + [PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), + [SCOPED_PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), + [GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), + [SCOPED_GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), + }, + }); +} + afterEach(() => { for (const dir of tempDirs.splice(0)) { fs.rmSync(dir, { recursive: true, force: true }); @@ -154,28 +199,11 @@ it("loads the source-checkout runtime wrapper through native ESM import", async writeOpenClawPackageFixture(fixtureRoot); writeJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); + writeSourceRuntimeWrapperFixture(fixtureRoot); - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), + expectRuntimeWrapperExports( + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"), ); - const mod = await import(`${wrapperUrl.href}?t=${Date.now()}`); - - expect(mod).toMatchObject({ - ensureMatrixCryptoRuntime: expect.any(Function), - handleVerifyRecoveryKey: expect.any(Function), - handleVerificationBootstrap: expect.any(Function), - handleVerificationStatus: expect.any(Function), - }); }, 240_000); it("loads the packaged runtime wrapper without recursing through the stable root alias", async () => { @@ -199,73 +227,26 @@ it("loads the packaged runtime wrapper without recursing through the stable root PACKAGED_RUNTIME_STUB, ); - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "dist", "plugin-entry.runtime-C88YIa_v.js"), + expectRuntimeWrapperExports( + await importFixtureModule(fixtureRoot, "dist/plugin-entry.runtime-C88YIa_v.js"), ); - const mod = await import(`${wrapperUrl.href}?t=${Date.now()}`); - - expect(mod).toMatchObject({ - ensureMatrixCryptoRuntime: expect.any(Function), - handleVerifyRecoveryKey: expect.any(Function), - handleVerificationBootstrap: expect.any(Function), - handleVerificationStatus: expect.any(Function), - }); }, 240_000); it("builds scoped and unscoped plugin-sdk aliases for the wrapper jiti loader", async () => { const fixtureRoot = makeFixtureRoot(".tmp-matrix-runtime-aliases-"); - delete matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions; - writeOpenClawAliasFixture(fixtureRoot); - writeCapturingJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); + writeCapturingSourceRuntimeWrapperFixture(fixtureRoot); + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"); - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), - ); - await import(`${wrapperUrl.href}?t=${Date.now()}`); - - expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ - alias: { - [PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), - [SCOPED_PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), - [GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), - [SCOPED_GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), - }, - }); + expectSourcePluginSdkAliases(fixtureRoot); }, 240_000); it("resolves extension-api aliases through the same source extension family", async () => { const fixtureRoot = makeFixtureRoot(".tmp-matrix-runtime-extension-api-"); - delete matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions; - writeOpenClawAliasFixture(fixtureRoot); writeFixtureFile(fixtureRoot, "src/extensionAPI.mts", "export {};\n"); - writeCapturingJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); - - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), - ); - await import(`${wrapperUrl.href}?t=${Date.now()}`); + writeCapturingSourceRuntimeWrapperFixture(fixtureRoot); + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"); expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ alias: { @@ -286,21 +267,8 @@ it("keeps wrapper plugin-sdk aliases deterministic and ignores unsafe subpaths", writeFixtureFile(fixtureRoot, "src/plugin-sdk/alpha.ts", "export {};\n"); writeFixtureFile(fixtureRoot, "src/plugin-sdk/zeta.ts", "export {};\n"); writeCapturingJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); - - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), - ); - await import(`${wrapperUrl.href}?t=${Date.now()}`); + writeSourceRuntimeWrapperFixture(fixtureRoot); + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"); const aliasKeys = Object.keys( ( @@ -349,30 +317,10 @@ it("ignores nearby untrusted openclaw package stubs when resolving the wrapper r ); writeFixtureFile(fixtureRoot, "extensions/src/plugin-sdk/group-access.ts", "export {};\n"); writeCapturingJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); + writeSourceRuntimeWrapperFixture(fixtureRoot); + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"); - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), - ); - await import(`${wrapperUrl.href}?t=${Date.now()}`); - - expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ - alias: { - [PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), - [SCOPED_PLUGIN_SDK_ROOT]: path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), - [GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), - [SCOPED_GROUP_ACCESS_SUBPATH]: path.join(fixtureRoot, "src", "plugin-sdk", "group-access.ts"), - }, - }); + expectSourcePluginSdkAliases(fixtureRoot); }, 240_000); it("treats string bin hints case-insensitively when trusting wrapper package roots", async () => { @@ -381,21 +329,8 @@ it("treats string bin hints case-insensitively when trusting wrapper package roo delete matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions; writeTrustedOpenClawBinFixture(fixtureRoot, "OpenClaw.MJS"); writeCapturingJitiFixture(fixtureRoot); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/src/plugin-entry.runtime.js", - MATRIX_RUNTIME_WRAPPER_SOURCE, - ); - writeFixtureFile( - fixtureRoot, - "extensions/matrix/plugin-entry.handlers.runtime.js", - PACKAGED_RUNTIME_STUB, - ); - - const wrapperUrl = pathToFileURL( - path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), - ); - await import(`${wrapperUrl.href}?t=${Date.now()}`); + writeSourceRuntimeWrapperFixture(fixtureRoot); + await importFixtureModule(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js"); expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ alias: {