mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-23 14:45:46 +00:00
test: speed up nextcloud talk and zalo status tests
This commit is contained in:
@@ -7,16 +7,6 @@ import {
|
||||
} from "../../../test/helpers/plugins/start-account-lifecycle.js";
|
||||
import type { ResolvedNextcloudTalkAccount } from "./accounts.js";
|
||||
|
||||
vi.mock("../../../test/helpers/config/bundled-channel-config-runtime.js", () => ({
|
||||
getBundledChannelRuntimeMap: () => new Map(),
|
||||
getBundledChannelConfigSchemaMap: () => new Map(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
const hoisted = vi.hoisted(() => ({
|
||||
monitorNextcloudTalkProvider: vi.fn(),
|
||||
}));
|
||||
@@ -29,7 +19,7 @@ vi.mock("./monitor.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
const { nextcloudTalkPlugin } = await import("./channel.js");
|
||||
const { nextcloudTalkGatewayAdapter } = await import("./gateway.js");
|
||||
|
||||
function buildAccount(): ResolvedNextcloudTalkAccount {
|
||||
return {
|
||||
@@ -54,7 +44,7 @@ function mockStartedMonitor() {
|
||||
}
|
||||
|
||||
function startNextcloudAccount(abortSignal?: AbortSignal) {
|
||||
return nextcloudTalkPlugin.gateway!.startAccount!(
|
||||
return nextcloudTalkGatewayAdapter.startAccount(
|
||||
createStartAccountContext({
|
||||
account: buildAccount(),
|
||||
abortSignal,
|
||||
@@ -70,7 +60,7 @@ describe("nextcloud-talk startAccount lifecycle", () => {
|
||||
it("keeps startAccount pending until abort, then stops the monitor", async () => {
|
||||
const stop = mockStartedMonitor();
|
||||
const { abort, task, isSettled } = startAccountAndTrackLifecycle({
|
||||
startAccount: nextcloudTalkPlugin.gateway!.startAccount!,
|
||||
startAccount: nextcloudTalkGatewayAdapter.startAccount,
|
||||
account: buildAccount(),
|
||||
});
|
||||
await expectStopPendingUntilAbort({
|
||||
|
||||
@@ -6,13 +6,11 @@ import {
|
||||
createScopedDmSecurityResolver,
|
||||
} from "openclaw/plugin-sdk/channel-config-helpers";
|
||||
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
||||
import { createAccountStatusSink } from "openclaw/plugin-sdk/channel-lifecycle";
|
||||
import {
|
||||
createLoggedPairingApprovalNotifier,
|
||||
createPairingPrefixStripper,
|
||||
} from "openclaw/plugin-sdk/channel-pairing";
|
||||
import { createAllowlistProviderRouteAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
||||
import { runStoppablePassiveMonitor } from "openclaw/plugin-sdk/extension-shared";
|
||||
import {
|
||||
buildWebhookChannelStatusSummary,
|
||||
createComputedAccountStatusAdapter,
|
||||
@@ -25,16 +23,10 @@ import {
|
||||
type ResolvedNextcloudTalkAccount,
|
||||
} from "./accounts.js";
|
||||
import { nextcloudTalkApprovalAuth } from "./approval-auth.js";
|
||||
import {
|
||||
buildChannelConfigSchema,
|
||||
clearAccountEntryFields,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
type ChannelPlugin,
|
||||
type OpenClawConfig,
|
||||
} from "./channel-api.js";
|
||||
import { buildChannelConfigSchema, DEFAULT_ACCOUNT_ID, type ChannelPlugin } from "./channel-api.js";
|
||||
import { NextcloudTalkConfigSchema } from "./config-schema.js";
|
||||
import { nextcloudTalkDoctor } from "./doctor.js";
|
||||
import { monitorNextcloudTalkProvider } from "./monitor.js";
|
||||
import { nextcloudTalkGatewayAdapter } from "./gateway.js";
|
||||
import {
|
||||
looksLikeNextcloudTalkTargetId,
|
||||
normalizeNextcloudTalkMessagingTarget,
|
||||
@@ -197,97 +189,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
|
||||
},
|
||||
}),
|
||||
}),
|
||||
gateway: {
|
||||
startAccount: async (ctx) => {
|
||||
const account = ctx.account;
|
||||
if (!account.secret || !account.baseUrl) {
|
||||
throw new Error(
|
||||
`Nextcloud Talk not configured for account "${account.accountId}" (missing secret or baseUrl)`,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.log?.info(`[${account.accountId}] starting Nextcloud Talk webhook server`);
|
||||
|
||||
const statusSink = createAccountStatusSink({
|
||||
accountId: ctx.accountId,
|
||||
setStatus: ctx.setStatus,
|
||||
});
|
||||
|
||||
await runStoppablePassiveMonitor({
|
||||
abortSignal: ctx.abortSignal,
|
||||
start: async () =>
|
||||
await monitorNextcloudTalkProvider({
|
||||
accountId: account.accountId,
|
||||
config: ctx.cfg as CoreConfig,
|
||||
runtime: ctx.runtime,
|
||||
abortSignal: ctx.abortSignal,
|
||||
statusSink,
|
||||
}),
|
||||
});
|
||||
},
|
||||
logoutAccount: async ({ accountId, cfg }) => {
|
||||
const nextCfg = { ...cfg } as OpenClawConfig;
|
||||
const nextSection = cfg.channels?.["nextcloud-talk"]
|
||||
? { ...cfg.channels["nextcloud-talk"] }
|
||||
: undefined;
|
||||
let cleared = false;
|
||||
let changed = false;
|
||||
|
||||
if (nextSection) {
|
||||
if (accountId === DEFAULT_ACCOUNT_ID && nextSection.botSecret) {
|
||||
delete nextSection.botSecret;
|
||||
cleared = true;
|
||||
changed = true;
|
||||
}
|
||||
const accountCleanup = clearAccountEntryFields({
|
||||
accounts: nextSection.accounts as Record<string, object> | undefined,
|
||||
accountId,
|
||||
fields: ["botSecret"],
|
||||
});
|
||||
if (accountCleanup.changed) {
|
||||
changed = true;
|
||||
if (accountCleanup.cleared) {
|
||||
cleared = true;
|
||||
}
|
||||
if (accountCleanup.nextAccounts) {
|
||||
nextSection.accounts = accountCleanup.nextAccounts as Record<string, unknown>;
|
||||
} else {
|
||||
delete nextSection.accounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (nextSection && Object.keys(nextSection).length > 0) {
|
||||
nextCfg.channels = { ...nextCfg.channels, "nextcloud-talk": nextSection };
|
||||
} else {
|
||||
const nextChannels = { ...nextCfg.channels } as Record<string, unknown>;
|
||||
delete nextChannels["nextcloud-talk"];
|
||||
if (Object.keys(nextChannels).length > 0) {
|
||||
nextCfg.channels = nextChannels as OpenClawConfig["channels"];
|
||||
} else {
|
||||
delete nextCfg.channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = resolveNextcloudTalkAccount({
|
||||
cfg: changed ? (nextCfg as CoreConfig) : (cfg as CoreConfig),
|
||||
accountId,
|
||||
});
|
||||
const loggedOut = resolved.secretSource === "none";
|
||||
|
||||
if (changed) {
|
||||
await getNextcloudTalkRuntime().config.writeConfigFile(nextCfg);
|
||||
}
|
||||
|
||||
return {
|
||||
cleared,
|
||||
envSecret: Boolean(process.env.NEXTCLOUD_TALK_BOT_SECRET?.trim()),
|
||||
loggedOut,
|
||||
};
|
||||
},
|
||||
},
|
||||
gateway: nextcloudTalkGatewayAdapter,
|
||||
},
|
||||
pairing: {
|
||||
text: {
|
||||
|
||||
106
extensions/nextcloud-talk/src/gateway.ts
Normal file
106
extensions/nextcloud-talk/src/gateway.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { createAccountStatusSink } from "openclaw/plugin-sdk/channel-lifecycle";
|
||||
import { runStoppablePassiveMonitor } from "openclaw/plugin-sdk/extension-shared";
|
||||
import { resolveNextcloudTalkAccount } from "./accounts.js";
|
||||
import {
|
||||
clearAccountEntryFields,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
type ChannelPlugin,
|
||||
type OpenClawConfig,
|
||||
} from "./channel-api.js";
|
||||
import { monitorNextcloudTalkProvider } from "./monitor.js";
|
||||
import { getNextcloudTalkRuntime } from "./runtime.js";
|
||||
import type { CoreConfig, ResolvedNextcloudTalkAccount } from "./types.js";
|
||||
|
||||
export const nextcloudTalkGatewayAdapter: NonNullable<
|
||||
ChannelPlugin<ResolvedNextcloudTalkAccount>["gateway"]
|
||||
> = {
|
||||
startAccount: async (ctx) => {
|
||||
const account = ctx.account;
|
||||
if (!account.secret || !account.baseUrl) {
|
||||
throw new Error(
|
||||
`Nextcloud Talk not configured for account "${account.accountId}" (missing secret or baseUrl)`,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.log?.info(`[${account.accountId}] starting Nextcloud Talk webhook server`);
|
||||
|
||||
const statusSink = createAccountStatusSink({
|
||||
accountId: ctx.accountId,
|
||||
setStatus: ctx.setStatus,
|
||||
});
|
||||
|
||||
await runStoppablePassiveMonitor({
|
||||
abortSignal: ctx.abortSignal,
|
||||
start: async () =>
|
||||
await monitorNextcloudTalkProvider({
|
||||
accountId: account.accountId,
|
||||
config: ctx.cfg as CoreConfig,
|
||||
runtime: ctx.runtime,
|
||||
abortSignal: ctx.abortSignal,
|
||||
statusSink,
|
||||
}),
|
||||
});
|
||||
},
|
||||
logoutAccount: async ({ accountId, cfg }) => {
|
||||
const nextCfg = { ...cfg } as OpenClawConfig;
|
||||
const nextSection = cfg.channels?.["nextcloud-talk"]
|
||||
? { ...cfg.channels["nextcloud-talk"] }
|
||||
: undefined;
|
||||
let cleared = false;
|
||||
let changed = false;
|
||||
|
||||
if (nextSection) {
|
||||
if (accountId === DEFAULT_ACCOUNT_ID && nextSection.botSecret) {
|
||||
delete nextSection.botSecret;
|
||||
cleared = true;
|
||||
changed = true;
|
||||
}
|
||||
const accountCleanup = clearAccountEntryFields({
|
||||
accounts: nextSection.accounts as Record<string, object> | undefined,
|
||||
accountId,
|
||||
fields: ["botSecret"],
|
||||
});
|
||||
if (accountCleanup.changed) {
|
||||
changed = true;
|
||||
if (accountCleanup.cleared) {
|
||||
cleared = true;
|
||||
}
|
||||
if (accountCleanup.nextAccounts) {
|
||||
nextSection.accounts = accountCleanup.nextAccounts as Record<string, unknown>;
|
||||
} else {
|
||||
delete nextSection.accounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (nextSection && Object.keys(nextSection).length > 0) {
|
||||
nextCfg.channels = { ...nextCfg.channels, "nextcloud-talk": nextSection };
|
||||
} else {
|
||||
const nextChannels = { ...nextCfg.channels } as Record<string, unknown>;
|
||||
delete nextChannels["nextcloud-talk"];
|
||||
if (Object.keys(nextChannels).length > 0) {
|
||||
nextCfg.channels = nextChannels as OpenClawConfig["channels"];
|
||||
} else {
|
||||
delete nextCfg.channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = resolveNextcloudTalkAccount({
|
||||
cfg: changed ? (nextCfg as CoreConfig) : (cfg as CoreConfig),
|
||||
accountId,
|
||||
});
|
||||
const loggedOut = resolved.secretSource === "none";
|
||||
|
||||
if (changed) {
|
||||
await getNextcloudTalkRuntime().config.writeConfigFile(nextCfg);
|
||||
}
|
||||
|
||||
return {
|
||||
cleared,
|
||||
envSecret: Boolean(process.env.NEXTCLOUD_TALK_BOT_SECRET?.trim()),
|
||||
loggedOut,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -1,9 +1,15 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createPluginSetupWizardStatus } from "../../../test/helpers/plugins/setup-wizard.js";
|
||||
import type { OpenClawConfig } from "../runtime-api.js";
|
||||
import { zaloPlugin } from "./channel.js";
|
||||
import { zaloSetupWizard } from "./setup-surface.js";
|
||||
|
||||
const zaloGetStatus = createPluginSetupWizardStatus(zaloPlugin);
|
||||
const zaloGetStatus = createPluginSetupWizardStatus({
|
||||
id: "zalo",
|
||||
meta: {
|
||||
label: "Zalo",
|
||||
},
|
||||
setupWizard: zaloSetupWizard,
|
||||
} as never);
|
||||
|
||||
describe("zalo setup wizard status", () => {
|
||||
it("treats SecretRef botToken as configured", async () => {
|
||||
|
||||
Reference in New Issue
Block a user