mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 01:10:22 +00:00
refactor(test): dedupe startup channel test helpers
This commit is contained in:
@@ -46,6 +46,31 @@ function createCfg(): OpenClawConfig {
|
||||
} as OpenClawConfig;
|
||||
}
|
||||
|
||||
function resolveAccount(cfg: OpenClawConfig): ResolvedDiscordAccount {
|
||||
return discordPlugin.config.resolveAccount(cfg, "default") as ResolvedDiscordAccount;
|
||||
}
|
||||
|
||||
function startDiscordAccount(cfg: OpenClawConfig) {
|
||||
return discordPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: resolveAccount(cfg),
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function installDiscordRuntime(discord: Record<string, unknown>) {
|
||||
setDiscordRuntime({
|
||||
channel: {
|
||||
discord,
|
||||
},
|
||||
logging: {
|
||||
shouldLogVerbose: () => false,
|
||||
},
|
||||
} as unknown as PluginRuntime);
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
probeDiscordMock.mockReset();
|
||||
monitorDiscordProviderMock.mockReset();
|
||||
@@ -87,16 +112,9 @@ describe("discordPlugin outbound", () => {
|
||||
const runtimeProbeDiscord = vi.fn(async () => {
|
||||
throw new Error("runtime Discord probe should not be used");
|
||||
});
|
||||
setDiscordRuntime({
|
||||
channel: {
|
||||
discord: {
|
||||
probeDiscord: runtimeProbeDiscord,
|
||||
},
|
||||
},
|
||||
logging: {
|
||||
shouldLogVerbose: () => false,
|
||||
},
|
||||
} as unknown as PluginRuntime);
|
||||
installDiscordRuntime({
|
||||
probeDiscord: runtimeProbeDiscord,
|
||||
});
|
||||
probeDiscordMock.mockResolvedValue({
|
||||
ok: true,
|
||||
bot: { username: "Bob" },
|
||||
@@ -111,7 +129,7 @@ describe("discordPlugin outbound", () => {
|
||||
});
|
||||
|
||||
const cfg = createCfg();
|
||||
const account = discordPlugin.config.resolveAccount(cfg, "default");
|
||||
const account = resolveAccount(cfg);
|
||||
|
||||
await discordPlugin.status!.probeAccount!({
|
||||
account,
|
||||
@@ -132,17 +150,10 @@ describe("discordPlugin outbound", () => {
|
||||
const runtimeMonitorDiscordProvider = vi.fn(async () => {
|
||||
throw new Error("runtime Discord monitor should not be used");
|
||||
});
|
||||
setDiscordRuntime({
|
||||
channel: {
|
||||
discord: {
|
||||
probeDiscord: runtimeProbeDiscord,
|
||||
monitorDiscordProvider: runtimeMonitorDiscordProvider,
|
||||
},
|
||||
},
|
||||
logging: {
|
||||
shouldLogVerbose: () => false,
|
||||
},
|
||||
} as unknown as PluginRuntime);
|
||||
installDiscordRuntime({
|
||||
probeDiscord: runtimeProbeDiscord,
|
||||
monitorDiscordProvider: runtimeMonitorDiscordProvider,
|
||||
});
|
||||
probeDiscordMock.mockResolvedValue({
|
||||
ok: true,
|
||||
bot: { username: "Bob" },
|
||||
@@ -158,13 +169,7 @@ describe("discordPlugin outbound", () => {
|
||||
monitorDiscordProviderMock.mockResolvedValue(undefined);
|
||||
|
||||
const cfg = createCfg();
|
||||
await discordPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: discordPlugin.config.resolveAccount(cfg, "default") as ResolvedDiscordAccount,
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
);
|
||||
await startDiscordAccount(cfg);
|
||||
|
||||
expect(probeDiscordMock).toHaveBeenCalledWith("discord-token", 2500, {
|
||||
includeApplication: true,
|
||||
|
||||
@@ -39,53 +39,50 @@ function createAccount(params: { token: string; secret: string }): ResolvedLineA
|
||||
};
|
||||
}
|
||||
|
||||
function startLineAccount(params: { account: ResolvedLineAccount; abortSignal?: AbortSignal }) {
|
||||
const { runtime, monitorLineProvider } = createRuntime();
|
||||
setLineRuntime(runtime);
|
||||
return {
|
||||
monitorLineProvider,
|
||||
task: linePlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: params.account,
|
||||
abortSignal: params.abortSignal,
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
describe("linePlugin gateway.startAccount", () => {
|
||||
it("fails startup when channel secret is missing", async () => {
|
||||
const { runtime, monitorLineProvider } = createRuntime();
|
||||
setLineRuntime(runtime);
|
||||
const { monitorLineProvider, task } = startLineAccount({
|
||||
account: createAccount({ token: "token", secret: " " }),
|
||||
});
|
||||
|
||||
await expect(
|
||||
linePlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: createAccount({ token: "token", secret: " " }),
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
),
|
||||
).rejects.toThrow(
|
||||
await expect(task).rejects.toThrow(
|
||||
'LINE webhook mode requires a non-empty channel secret for account "default".',
|
||||
);
|
||||
expect(monitorLineProvider).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fails startup when channel access token is missing", async () => {
|
||||
const { runtime, monitorLineProvider } = createRuntime();
|
||||
setLineRuntime(runtime);
|
||||
const { monitorLineProvider, task } = startLineAccount({
|
||||
account: createAccount({ token: " ", secret: "secret" }),
|
||||
});
|
||||
|
||||
await expect(
|
||||
linePlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: createAccount({ token: " ", secret: "secret" }),
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
),
|
||||
).rejects.toThrow(
|
||||
await expect(task).rejects.toThrow(
|
||||
'LINE webhook mode requires a non-empty channel access token for account "default".',
|
||||
);
|
||||
expect(monitorLineProvider).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("starts provider when token and secret are present", async () => {
|
||||
const { runtime, monitorLineProvider } = createRuntime();
|
||||
setLineRuntime(runtime);
|
||||
|
||||
const abort = new AbortController();
|
||||
const task = linePlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: createAccount({ token: "token", secret: "secret" }),
|
||||
runtime: createRuntimeEnv(),
|
||||
abortSignal: abort.signal,
|
||||
}),
|
||||
);
|
||||
const { monitorLineProvider, task } = startLineAccount({
|
||||
account: createAccount({ token: "token", secret: "secret" }),
|
||||
abortSignal: abort.signal,
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(monitorLineProvider).toHaveBeenCalledWith(
|
||||
|
||||
@@ -37,14 +37,28 @@ function buildAccount(): ResolvedNextcloudTalkAccount {
|
||||
};
|
||||
}
|
||||
|
||||
function mockStartedMonitor() {
|
||||
const stop = vi.fn();
|
||||
hoisted.monitorNextcloudTalkProvider.mockResolvedValue({ stop });
|
||||
return stop;
|
||||
}
|
||||
|
||||
function startNextcloudAccount(abortSignal?: AbortSignal) {
|
||||
return nextcloudTalkPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: buildAccount(),
|
||||
abortSignal,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
describe("nextcloudTalkPlugin gateway.startAccount", () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("keeps startAccount pending until abort, then stops the monitor", async () => {
|
||||
const stop = vi.fn();
|
||||
hoisted.monitorNextcloudTalkProvider.mockResolvedValue({ stop });
|
||||
const stop = mockStartedMonitor();
|
||||
const { abort, task, isSettled } = startAccountAndTrackLifecycle({
|
||||
startAccount: nextcloudTalkPlugin.gateway!.startAccount!,
|
||||
account: buildAccount(),
|
||||
@@ -59,17 +73,11 @@ describe("nextcloudTalkPlugin gateway.startAccount", () => {
|
||||
});
|
||||
|
||||
it("stops immediately when startAccount receives an already-aborted signal", async () => {
|
||||
const stop = vi.fn();
|
||||
hoisted.monitorNextcloudTalkProvider.mockResolvedValue({ stop });
|
||||
const stop = mockStartedMonitor();
|
||||
const abort = new AbortController();
|
||||
abort.abort();
|
||||
|
||||
await nextcloudTalkPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: buildAccount(),
|
||||
abortSignal: abort.signal,
|
||||
}),
|
||||
);
|
||||
await startNextcloudAccount(abort.signal);
|
||||
|
||||
expect(hoisted.monitorNextcloudTalkProvider).toHaveBeenCalledOnce();
|
||||
expect(stop).toHaveBeenCalledOnce();
|
||||
|
||||
@@ -59,6 +59,18 @@ function resolveAccount(cfg: OpenClawConfig, accountId: string): ResolvedTelegra
|
||||
return telegramPlugin.config.resolveAccount(cfg, accountId) as ResolvedTelegramAccount;
|
||||
}
|
||||
|
||||
function createStartTelegramContext(cfg: OpenClawConfig, accountId: string) {
|
||||
return createStartAccountContext({
|
||||
account: resolveAccount(cfg, accountId),
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
});
|
||||
}
|
||||
|
||||
function startTelegramAccount(cfg: OpenClawConfig, accountId: string) {
|
||||
return telegramPlugin.gateway!.startAccount!(createStartTelegramContext(cfg, accountId));
|
||||
}
|
||||
|
||||
function installGatewayRuntime(params?: { probeOk?: boolean; botUsername?: string }) {
|
||||
const monitorTelegramProvider = vi
|
||||
.spyOn(monitorModule, "monitorTelegramProvider")
|
||||
@@ -167,9 +179,9 @@ describe("telegramPlugin groups", () => {
|
||||
describe("telegramPlugin duplicate token guard", () => {
|
||||
it("marks secondary account as not configured when token is shared", async () => {
|
||||
const cfg = createCfg();
|
||||
const alertsAccount = telegramPlugin.config.resolveAccount(cfg, "alerts");
|
||||
const workAccount = telegramPlugin.config.resolveAccount(cfg, "work");
|
||||
const opsAccount = telegramPlugin.config.resolveAccount(cfg, "ops");
|
||||
const alertsAccount = resolveAccount(cfg, "alerts");
|
||||
const workAccount = resolveAccount(cfg, "work");
|
||||
const opsAccount = resolveAccount(cfg, "ops");
|
||||
|
||||
expect(await telegramPlugin.config.isConfigured!(alertsAccount, cfg)).toBe(true);
|
||||
expect(await telegramPlugin.config.isConfigured!(workAccount, cfg)).toBe(false);
|
||||
@@ -182,7 +194,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
|
||||
it("surfaces duplicate-token reason in status snapshot", async () => {
|
||||
const cfg = createCfg();
|
||||
const workAccount = telegramPlugin.config.resolveAccount(cfg, "work");
|
||||
const workAccount = resolveAccount(cfg, "work");
|
||||
const snapshot = await telegramPlugin.status!.buildAccountSnapshot!({
|
||||
account: workAccount,
|
||||
cfg,
|
||||
@@ -201,15 +213,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
});
|
||||
const cfg = createCfg();
|
||||
|
||||
await expect(
|
||||
telegramPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: resolveAccount(cfg, "work"),
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
),
|
||||
).rejects.toThrow("Duplicate Telegram bot token");
|
||||
await expect(startTelegramAccount(cfg, "work")).rejects.toThrow("Duplicate Telegram bot token");
|
||||
|
||||
expect(probeTelegramMock).not.toHaveBeenCalled();
|
||||
expect(monitorTelegramProviderMock).not.toHaveBeenCalled();
|
||||
@@ -237,13 +241,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
webhookPort: 9876,
|
||||
};
|
||||
|
||||
await telegramPlugin.gateway!.startAccount!(
|
||||
createStartAccountContext({
|
||||
account: resolveAccount(cfg, "ops"),
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
}),
|
||||
);
|
||||
await startTelegramAccount(cfg, "ops");
|
||||
|
||||
expect(probeTelegramMock).toHaveBeenCalledWith("token-ops", 2500, {
|
||||
accountId: "ops",
|
||||
@@ -282,7 +280,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
|
||||
const cfg = createCfg();
|
||||
configureOpsProxyNetwork(cfg);
|
||||
const account = telegramPlugin.config.resolveAccount(cfg, "ops");
|
||||
const account = resolveAccount(cfg, "ops");
|
||||
|
||||
await telegramPlugin.status!.probeAccount!({
|
||||
account,
|
||||
@@ -341,7 +339,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
"-100123": { requireMention: false },
|
||||
},
|
||||
};
|
||||
const account = telegramPlugin.config.resolveAccount(cfg, "ops");
|
||||
const account = resolveAccount(cfg, "ops");
|
||||
|
||||
await telegramPlugin.status!.auditAccount!({
|
||||
account,
|
||||
@@ -484,7 +482,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
const cfg = createCfg();
|
||||
cfg.channels!.telegram!.accounts!.ops = {} as never;
|
||||
|
||||
const alertsAccount = telegramPlugin.config.resolveAccount(cfg, "alerts");
|
||||
const alertsAccount = resolveAccount(cfg, "alerts");
|
||||
expect(await telegramPlugin.config.isConfigured!(alertsAccount, cfg)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -496,11 +494,7 @@ describe("telegramPlugin duplicate token guard", () => {
|
||||
monitorTelegramProviderMock.mockResolvedValue(undefined);
|
||||
|
||||
const cfg = createCfg();
|
||||
const ctx = createStartAccountContext({
|
||||
account: resolveAccount(cfg, "ops"),
|
||||
cfg,
|
||||
runtime: createRuntimeEnv(),
|
||||
});
|
||||
const ctx = createStartTelegramContext(cfg, "ops");
|
||||
ctx.account = {
|
||||
...ctx.account,
|
||||
token: undefined as unknown as string,
|
||||
|
||||
Reference in New Issue
Block a user