mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-14 10:41:23 +00:00
test: speed up matrix channel seam tests
This commit is contained in:
91
extensions/matrix/src/channel-account-paths.ts
Normal file
91
extensions/matrix/src/channel-account-paths.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
||||
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
import type { MatrixProbe } from "./matrix/probe.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
type ResolveMatrixAuth = (params: { cfg: CoreConfig; accountId?: string }) => Promise<{
|
||||
homeserver: string;
|
||||
accessToken: string;
|
||||
userId: string;
|
||||
deviceId?: string;
|
||||
allowPrivateNetwork?: boolean;
|
||||
ssrfPolicy?: unknown;
|
||||
dispatcherPolicy?: unknown;
|
||||
}>;
|
||||
|
||||
type ProbeMatrix = (params: {
|
||||
homeserver: string;
|
||||
accessToken: string;
|
||||
userId: string;
|
||||
deviceId?: string;
|
||||
timeoutMs?: number;
|
||||
accountId?: string;
|
||||
allowPrivateNetwork?: boolean;
|
||||
ssrfPolicy?: unknown;
|
||||
dispatcherPolicy?: unknown;
|
||||
}) => Promise<MatrixProbe>;
|
||||
|
||||
type SendMessageMatrix = (
|
||||
to: string,
|
||||
message: string,
|
||||
options?: { accountId?: string },
|
||||
) => Promise<unknown>;
|
||||
|
||||
export function createMatrixProbeAccount(params: {
|
||||
resolveMatrixAuth: ResolveMatrixAuth;
|
||||
probeMatrix: ProbeMatrix;
|
||||
}) {
|
||||
return async ({
|
||||
account,
|
||||
timeoutMs,
|
||||
cfg,
|
||||
}: {
|
||||
account: { accountId?: string };
|
||||
timeoutMs?: number;
|
||||
cfg: unknown;
|
||||
}): Promise<MatrixProbe> => {
|
||||
try {
|
||||
const auth = await params.resolveMatrixAuth({
|
||||
cfg: cfg as CoreConfig,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
return await params.probeMatrix({
|
||||
homeserver: auth.homeserver,
|
||||
accessToken: auth.accessToken,
|
||||
userId: auth.userId,
|
||||
deviceId: auth.deviceId,
|
||||
timeoutMs,
|
||||
accountId: account.accountId,
|
||||
allowPrivateNetwork: auth.allowPrivateNetwork,
|
||||
ssrfPolicy: auth.ssrfPolicy,
|
||||
dispatcherPolicy: auth.dispatcherPolicy,
|
||||
});
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
error: formatMatrixErrorMessage(err),
|
||||
elapsedMs: 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createMatrixPairingText(sendMessageMatrix: SendMessageMatrix) {
|
||||
return {
|
||||
idLabel: "matrixUserId",
|
||||
message: PAIRING_APPROVED_MESSAGE,
|
||||
normalizeAllowEntry: createPairingPrefixStripper(/^matrix:/i),
|
||||
notify: async ({
|
||||
id,
|
||||
message,
|
||||
accountId,
|
||||
}: {
|
||||
id: string;
|
||||
message: string;
|
||||
accountId?: string;
|
||||
}) => {
|
||||
await sendMessageMatrix(`user:${id}`, message, accountId ? { accountId } : {});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js";
|
||||
|
||||
const sendMessageMatrixMock = vi.hoisted(() => vi.fn());
|
||||
const probeMatrixMock = vi.hoisted(() => vi.fn());
|
||||
@@ -28,8 +29,6 @@ vi.mock("./matrix/client.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
const { matrixPlugin } = await import("./channel.js");
|
||||
|
||||
describe("matrix account path propagation", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -54,9 +53,15 @@ describe("matrix account path propagation", () => {
|
||||
});
|
||||
|
||||
it("forwards accountId when notifying pairing approval", async () => {
|
||||
await matrixPlugin.pairing!.notifyApproval?.({
|
||||
cfg: {},
|
||||
const pairingText = createMatrixPairingText(sendMessageMatrixMock);
|
||||
|
||||
expect(pairingText.normalizeAllowEntry(" matrix:@user:example.org ")).toBe(
|
||||
"@user:example.org",
|
||||
);
|
||||
|
||||
await pairingText.notify({
|
||||
id: "@user:example.org",
|
||||
message: pairingText.message,
|
||||
accountId: "poe",
|
||||
});
|
||||
|
||||
@@ -68,7 +73,12 @@ describe("matrix account path propagation", () => {
|
||||
});
|
||||
|
||||
it("forwards accountId and deviceId to matrix probes", async () => {
|
||||
await matrixPlugin.status!.probeAccount?.({
|
||||
const probeAccount = createMatrixProbeAccount({
|
||||
resolveMatrixAuth: resolveMatrixAuthMock,
|
||||
probeMatrix: probeMatrixMock,
|
||||
});
|
||||
|
||||
await probeAccount({
|
||||
cfg: {} as never,
|
||||
timeoutMs: 500,
|
||||
account: {
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock("./matrix/actions/verification.js", () => ({
|
||||
bootstrapMatrixVerification: verificationMocks.bootstrapMatrixVerification,
|
||||
}));
|
||||
|
||||
import { matrixPlugin } from "./channel.js";
|
||||
import { matrixConfigAdapter } from "./config-adapter.js";
|
||||
import { runMatrixSetupBootstrapAfterConfigWrite } from "./setup-bootstrap.js";
|
||||
import { matrixSetupAdapter } from "./setup-core.js";
|
||||
import { installMatrixTestRuntime } from "./test-runtime.js";
|
||||
@@ -238,7 +238,7 @@ describe("matrix setup post-write bootstrap", () => {
|
||||
});
|
||||
|
||||
it("clears allowPrivateNetwork and proxy when deleting the default Matrix account config", () => {
|
||||
const updated = matrixPlugin.config.deleteAccount?.({
|
||||
const updated = matrixConfigAdapter.deleteAccount?.({
|
||||
cfg: {
|
||||
channels: {
|
||||
matrix: {
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
||||
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
||||
import {
|
||||
adaptScopedAccountAccessor,
|
||||
createScopedChannelConfigAdapter,
|
||||
createScopedDmSecurityResolver,
|
||||
} from "openclaw/plugin-sdk/channel-config-helpers";
|
||||
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
|
||||
import { createChatChannelPlugin, type ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
||||
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
||||
import {
|
||||
createAllowlistProviderOpenWarningCollector,
|
||||
projectAccountConfigWarningCollector,
|
||||
} from "openclaw/plugin-sdk/channel-policy";
|
||||
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
||||
import { createScopedAccountReplyToModeResolver } from "openclaw/plugin-sdk/conversation-runtime";
|
||||
import {
|
||||
createChannelDirectoryAdapter,
|
||||
@@ -32,6 +28,8 @@ import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { matrixMessageActions } from "./actions.js";
|
||||
import { matrixApprovalCapability } from "./approval-native.js";
|
||||
import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js";
|
||||
import { DEFAULT_ACCOUNT_ID, matrixConfigAdapter } from "./config-adapter.js";
|
||||
import { MatrixConfigSchema } from "./config-schema.js";
|
||||
import { matrixDoctor } from "./doctor.js";
|
||||
import { shouldSuppressLocalMatrixExecApprovalPrompt } from "./exec-approvals.js";
|
||||
@@ -40,14 +38,11 @@ import {
|
||||
resolveMatrixGroupToolPolicy,
|
||||
} from "./group-mentions.js";
|
||||
import {
|
||||
listMatrixAccountIds,
|
||||
resolveDefaultMatrixAccountId,
|
||||
resolveMatrixAccount,
|
||||
resolveMatrixAccountConfig,
|
||||
type ResolvedMatrixAccount,
|
||||
} from "./matrix/accounts.js";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
import { normalizeMatrixAllowList, normalizeMatrixUserId } from "./matrix/monitor/allowlist.js";
|
||||
import { normalizeMatrixUserId } from "./matrix/monitor/allowlist.js";
|
||||
import type { MatrixProbe } from "./matrix/probe.js";
|
||||
import {
|
||||
normalizeMatrixMessagingTarget,
|
||||
@@ -152,34 +147,6 @@ function projectMatrixConversationBinding(binding: {
|
||||
};
|
||||
}
|
||||
|
||||
const matrixConfigAdapter = createScopedChannelConfigAdapter<
|
||||
ResolvedMatrixAccount,
|
||||
ReturnType<typeof resolveMatrixAccountConfig>,
|
||||
CoreConfig
|
||||
>({
|
||||
sectionKey: "matrix",
|
||||
listAccountIds: listMatrixAccountIds,
|
||||
resolveAccount: adaptScopedAccountAccessor(resolveMatrixAccount),
|
||||
resolveAccessorAccount: ({ cfg, accountId }) =>
|
||||
resolveMatrixAccountConfig({ cfg: cfg, accountId }),
|
||||
defaultAccountId: resolveDefaultMatrixAccountId,
|
||||
clearBaseFields: [
|
||||
"name",
|
||||
"homeserver",
|
||||
"network",
|
||||
"proxy",
|
||||
"userId",
|
||||
"accessToken",
|
||||
"password",
|
||||
"deviceId",
|
||||
"deviceName",
|
||||
"avatarUrl",
|
||||
"initialSyncLimit",
|
||||
],
|
||||
resolveAllowFrom: (account) => account.dm?.allowFrom,
|
||||
formatAllowFrom: (allowFrom) => normalizeMatrixAllowList(allowFrom),
|
||||
});
|
||||
|
||||
const resolveMatrixDmPolicy = createScopedDmSecurityResolver<ResolvedMatrixAccount>({
|
||||
channelKey: "matrix",
|
||||
resolvePolicy: (account) => account.config.dm?.policy,
|
||||
@@ -465,32 +432,20 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
|
||||
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("matrix", accounts),
|
||||
buildChannelSummary: ({ snapshot }) =>
|
||||
buildProbeChannelStatusSummary(snapshot, { baseUrl: snapshot.baseUrl ?? null }),
|
||||
probeAccount: async ({ account, timeoutMs, cfg }) => {
|
||||
try {
|
||||
const { probeMatrix, resolveMatrixAuth } = await loadMatrixChannelRuntime();
|
||||
const auth = await resolveMatrixAuth({
|
||||
cfg: cfg as CoreConfig,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
return await probeMatrix({
|
||||
homeserver: auth.homeserver,
|
||||
accessToken: auth.accessToken,
|
||||
userId: auth.userId,
|
||||
deviceId: auth.deviceId,
|
||||
timeoutMs,
|
||||
accountId: account.accountId,
|
||||
allowPrivateNetwork: auth.allowPrivateNetwork,
|
||||
ssrfPolicy: auth.ssrfPolicy,
|
||||
dispatcherPolicy: auth.dispatcherPolicy,
|
||||
});
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
error: formatMatrixErrorMessage(err),
|
||||
elapsedMs: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
probeAccount: async ({ account, timeoutMs, cfg }) =>
|
||||
await createMatrixProbeAccount({
|
||||
resolveMatrixAuth: async ({ cfg, accountId }) =>
|
||||
(await loadMatrixChannelRuntime()).resolveMatrixAuth({
|
||||
cfg,
|
||||
accountId,
|
||||
}),
|
||||
probeMatrix: async (params) =>
|
||||
await (await loadMatrixChannelRuntime()).probeMatrix(params),
|
||||
})({
|
||||
account,
|
||||
timeoutMs,
|
||||
cfg,
|
||||
}),
|
||||
resolveAccountSnapshot: ({ account, runtime }) => ({
|
||||
accountId: account.accountId,
|
||||
name: account.name,
|
||||
@@ -562,15 +517,10 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
|
||||
),
|
||||
},
|
||||
pairing: {
|
||||
text: {
|
||||
idLabel: "matrixUserId",
|
||||
message: PAIRING_APPROVED_MESSAGE,
|
||||
normalizeAllowEntry: createPairingPrefixStripper(/^matrix:/i),
|
||||
notify: async ({ id, message, accountId }) => {
|
||||
const { sendMessageMatrix } = await loadMatrixChannelRuntime();
|
||||
await sendMessageMatrix(`user:${id}`, message, accountId ? { accountId } : {});
|
||||
},
|
||||
},
|
||||
text: createMatrixPairingText(
|
||||
async (to, message, options) =>
|
||||
await (await loadMatrixChannelRuntime()).sendMessageMatrix(to, message, options),
|
||||
),
|
||||
},
|
||||
threading: {
|
||||
resolveReplyToMode: createScopedAccountReplyToModeResolver<
|
||||
|
||||
43
extensions/matrix/src/config-adapter.ts
Normal file
43
extensions/matrix/src/config-adapter.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
||||
import {
|
||||
adaptScopedAccountAccessor,
|
||||
createScopedChannelConfigAdapter,
|
||||
} from "openclaw/plugin-sdk/channel-config-helpers";
|
||||
import {
|
||||
listMatrixAccountIds,
|
||||
resolveDefaultMatrixAccountId,
|
||||
resolveMatrixAccount,
|
||||
resolveMatrixAccountConfig,
|
||||
type ResolvedMatrixAccount,
|
||||
} from "./matrix/accounts.js";
|
||||
import { normalizeMatrixAllowList } from "./matrix/monitor/allowlist.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID };
|
||||
|
||||
export const matrixConfigAdapter = createScopedChannelConfigAdapter<
|
||||
ResolvedMatrixAccount,
|
||||
ReturnType<typeof resolveMatrixAccountConfig>,
|
||||
CoreConfig
|
||||
>({
|
||||
sectionKey: "matrix",
|
||||
listAccountIds: listMatrixAccountIds,
|
||||
resolveAccount: adaptScopedAccountAccessor(resolveMatrixAccount),
|
||||
resolveAccessorAccount: ({ cfg, accountId }) => resolveMatrixAccountConfig({ cfg, accountId }),
|
||||
defaultAccountId: resolveDefaultMatrixAccountId,
|
||||
clearBaseFields: [
|
||||
"name",
|
||||
"homeserver",
|
||||
"network",
|
||||
"proxy",
|
||||
"userId",
|
||||
"accessToken",
|
||||
"password",
|
||||
"deviceId",
|
||||
"deviceName",
|
||||
"avatarUrl",
|
||||
"initialSyncLimit",
|
||||
],
|
||||
resolveAllowFrom: (account) => account.dm?.allowFrom,
|
||||
formatAllowFrom: (allowFrom) => normalizeMatrixAllowList(allowFrom),
|
||||
});
|
||||
Reference in New Issue
Block a user