test: dedupe shared setup in channel and doctor config tests

This commit is contained in:
Peter Steinberger
2026-02-18 03:38:06 +00:00
parent d1ab852972
commit e57628165a
5 changed files with 62 additions and 114 deletions

View File

@@ -6,7 +6,6 @@ import type { DiscordProbe } from "../../discord/probe.js";
import type { DiscordTokenResolution } from "../../discord/token.js";
import type { IMessageProbe } from "../../imessage/probe.js";
import type { LineProbeResult } from "../../line/types.js";
import type { PluginRegistry } from "../../plugins/registry.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import type { SignalProbe } from "../../signal/probe.js";
import type { SlackProbe } from "../../slack/probe.js";
@@ -118,23 +117,7 @@ describe("channel plugin catalog", () => {
});
});
const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({
plugins: [],
tools: [],
hooks: [],
typedHooks: [],
commands: [],
channels,
providers: [],
gatewayHandlers: {},
httpHandlers: [],
httpRoutes: [],
cliRegistrars: [],
services: [],
diagnostics: [],
});
const emptyRegistry = createRegistry([]);
const emptyRegistry = createTestRegistry([]);
const msteamsOutbound: ChannelOutboundAdapter = {
deliveryMode: "direct",
@@ -160,7 +143,7 @@ const msteamsPlugin: ChannelPlugin = {
outbound: msteamsOutbound,
};
const registryWithMSTeams = createRegistry([
const registryWithMSTeams = createTestRegistry([
{ pluginId: "msteams", plugin: msteamsPlugin, source: "test" },
]);

View File

@@ -23,6 +23,19 @@ async function runDoctorConfigWithInput(params: {
});
}
function expectGoogleChatDmAllowFromRepaired(cfg: unknown) {
const typed = cfg as {
channels: {
googlechat: {
dm: { allowFrom: string[] };
allowFrom?: string[];
};
};
};
expect(typed.channels.googlechat.dm.allowFrom).toEqual(["*"]);
expect(typed.channels.googlechat.allowFrom).toBeUndefined();
}
describe("doctor config flow", () => {
it("preserves invalid config for doctor repairs", async () => {
const result = await runDoctorConfigWithInput({
@@ -361,20 +374,7 @@ describe("doctor config flow", () => {
},
});
const cfg = result.cfg as unknown as {
channels: {
googlechat: {
dm: {
policy: string;
allowFrom: string[];
};
allowFrom?: string[];
};
};
};
expect(cfg.channels.googlechat.dm.allowFrom).toEqual(["*"]);
expect(cfg.channels.googlechat.allowFrom).toBeUndefined();
expectGoogleChatDmAllowFromRepaired(result.cfg);
});
it("repairs googlechat account dm.policy open by setting dm.allowFrom on repair", async () => {
@@ -430,19 +430,6 @@ describe("doctor config flow", () => {
},
});
const cfg = result.cfg as unknown as {
channels: {
googlechat: {
dm: {
policy: string;
allowFrom: string[];
};
allowFrom?: string[];
};
};
};
expect(cfg.channels.googlechat.dm.allowFrom).toEqual(["*"]);
expect(cfg.channels.googlechat.allowFrom).toBeUndefined();
expectGoogleChatDmAllowFromRepaired(result.cfg);
});
});

View File

@@ -51,6 +51,26 @@ vi.mock("./daemon-install-helpers.js", () => ({
import { maybeRepairGatewayServiceConfig } from "./doctor-gateway-services.js";
function makeDoctorIo() {
return { log: vi.fn(), error: vi.fn(), exit: vi.fn() };
}
function makeDoctorPrompts() {
return {
confirm: vi.fn().mockResolvedValue(true),
confirmRepair: vi.fn().mockResolvedValue(true),
confirmAggressive: vi.fn().mockResolvedValue(true),
confirmSkipInNonInteractive: vi.fn().mockResolvedValue(true),
select: vi.fn().mockResolvedValue("node"),
shouldRepair: false,
shouldForce: false,
};
}
async function runRepair(cfg: OpenClawConfig) {
await maybeRepairGatewayServiceConfig(cfg, "local", makeDoctorIo(), makeDoctorPrompts());
}
describe("maybeRepairGatewayServiceConfig", () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -91,20 +111,7 @@ describe("maybeRepairGatewayServiceConfig", () => {
},
};
await maybeRepairGatewayServiceConfig(
cfg,
"local",
{ log: vi.fn(), error: vi.fn(), exit: vi.fn() },
{
confirm: vi.fn().mockResolvedValue(true),
confirmRepair: vi.fn().mockResolvedValue(true),
confirmAggressive: vi.fn().mockResolvedValue(true),
confirmSkipInNonInteractive: vi.fn().mockResolvedValue(true),
select: vi.fn().mockResolvedValue("node"),
shouldRepair: false,
shouldForce: false,
},
);
await runRepair(cfg);
expect(mocks.auditGatewayServiceConfig).toHaveBeenCalledWith(
expect.objectContaining({
@@ -164,20 +171,7 @@ describe("maybeRepairGatewayServiceConfig", () => {
gateway: {},
};
await maybeRepairGatewayServiceConfig(
cfg,
"local",
{ log: vi.fn(), error: vi.fn(), exit: vi.fn() },
{
confirm: vi.fn().mockResolvedValue(true),
confirmRepair: vi.fn().mockResolvedValue(true),
confirmAggressive: vi.fn().mockResolvedValue(true),
confirmSkipInNonInteractive: vi.fn().mockResolvedValue(true),
select: vi.fn().mockResolvedValue("node"),
shouldRepair: false,
shouldForce: false,
},
);
await runRepair(cfg);
expect(mocks.auditGatewayServiceConfig).toHaveBeenCalledWith(
expect.objectContaining({

View File

@@ -1,7 +1,7 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { ChannelPlugin } from "../channels/plugins/types.js";
import type { PluginRegistry } from "../plugins/registry.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createTestRegistry } from "../test-utils/channel-plugins.js";
import { resolveChannelCapabilities } from "./channel-capabilities.js";
import type { OpenClawConfig } from "./config.js";
@@ -86,7 +86,7 @@ describe("resolveChannelCapabilities", () => {
it("supports msteams capabilities", () => {
setActivePluginRegistry(
createRegistry([
createTestRegistry([
{
pluginId: "msteams",
source: "test",
@@ -127,22 +127,6 @@ describe("resolveChannelCapabilities", () => {
});
});
const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({
plugins: [],
tools: [],
hooks: [],
typedHooks: [],
commands: [],
channels,
providers: [],
gatewayHandlers: {},
httpHandlers: [],
httpRoutes: [],
cliRegistrars: [],
services: [],
diagnostics: [],
});
const createStubPlugin = (id: string): ChannelPlugin => ({
id,
meta: {
@@ -159,7 +143,7 @@ const createStubPlugin = (id: string): ChannelPlugin => ({
},
});
const baseRegistry = createRegistry([
const baseRegistry = createTestRegistry([
{ pluginId: "telegram", source: "test", plugin: createStubPlugin("telegram") },
{ pluginId: "slack", source: "test", plugin: createStubPlugin("slack") },
]);

View File

@@ -15,6 +15,24 @@ installCronTestHooks({
baseTimeIso: "2026-02-06T17:00:00.000Z",
});
function createStartedCron(storePath: string) {
const cron = new CronService({
storePath,
cronEnabled: true,
log: noopLogger,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const, summary: "ok" })),
});
return {
cron,
start: async () => {
await cron.start();
return cron;
},
};
}
describe("CronService store migrations", () => {
it("migrates legacy top-level agentTurn fields and initializes missing state", async () => {
const store = await makeStorePath();
@@ -52,16 +70,7 @@ describe("CronService store migrations", () => {
"utf-8",
);
const cron = new CronService({
storePath: store.storePath,
cronEnabled: true,
log: noopLogger,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const, summary: "ok" })),
});
await cron.start();
const cron = await createStartedCron(store.storePath).start();
const status = await cron.status();
expect(status.enabled).toBe(true);
@@ -132,16 +141,7 @@ describe("CronService store migrations", () => {
"utf-8",
);
const cron = new CronService({
storePath: store.storePath,
cronEnabled: true,
log: noopLogger,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const, summary: "ok" })),
});
await cron.start();
const cron = await createStartedCron(store.storePath).start();
const jobs = await cron.list({ includeDisabled: true });
const job = jobs.find((entry) => entry.id === "legacy-agentturn-no-timeout");