import { beforeEach, describe, expect, it, vi } from "vitest" ;
const resolveDefaultAgentIdMock = vi.hoisted(() => vi.fn());
const resolveAgentWorkspaceDirMock = vi.hoisted(() => vi.fn());
const getLoadedChannelPluginMock = vi.hoisted(() => vi.fn());
const getChannelPluginMock = vi.hoisted(() => vi.fn());
const applyPluginAutoEnableMock = vi.hoisted(() => vi.fn());
const resolveRuntimePluginRegistryMock = vi.hoisted(() => vi.fn());
const getActivePluginRegistryMock = vi.hoisted(() => vi.fn());
const getActivePluginChannelRegistryMock = vi.hoisted(() => vi.fn());
const getActivePluginChannelRegistryVersionMock = vi.hoisted(() => vi.fn());
const normalizeMessageChannelMock = vi.hoisted(() => vi.fn());
const isDeliverableMessageChannelMock = vi.hoisted(() => vi.fn());
vi.mock("../../agents/agent-scope.js" , () => ({
resolveDefaultAgentId: (...args: unknown[]) => resolveDefaultAgentIdMock(...args),
resolveAgentWorkspaceDir: (...args: unknown[]) => resolveAgentWorkspaceDirMock(...args),
}));
vi.mock("../../channels/plugins/index.js" , () => ({
getLoadedChannelPlugin: (...args: unknown[]) => getLoadedChannelPluginMock(...args),
getChannelPlugin: (...args: unknown[]) => getChannelPluginMock(...args),
}));
vi.mock("../../config/plugin-auto-enable.js" , () => ({
applyPluginAutoEnable: (...args: unknown[]) => applyPluginAutoEnableMock(...args),
}));
vi.mock("../../plugins/loader.js" , () => ({
resolveRuntimePluginRegistry: (...args: unknown[]) => resolveRuntimePluginRegistryMock(...args),
}));
vi.mock("../../plugins/runtime.js" , () => ({
getActivePluginRegistry: (...args: unknown[]) => getActivePluginRegistryMock(...args),
getActivePluginChannelRegistry: (...args: unknown[]) =>
getActivePluginChannelRegistryMock(...args),
getActivePluginChannelRegistryVersion: (...args: unknown[]) =>
getActivePluginChannelRegistryVersionMock(...args),
}));
vi.mock("../../utils/message-channel.js" , () => ({
normalizeMessageChannel: (...args: unknown[]) => normalizeMessageChannelMock(...args),
isDeliverableMessageChannel: (...args: unknown[]) => isDeliverableMessageChannelMock(...args),
}));
import { importFreshModule } from "../../../test/helpers/import-fresh.js" ;
async function importChannelResolution(scope: string) {
return await importFreshModule<typeof import ("./channel-resolution.js" )>(
import .meta.url,
`./channel-resolution.js?scope=${scope}`,
);
}
function expectBootstrapArgs() {
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith(
expect.objectContaining({
config: { autoEnabled: true },
activationSourceConfig: { channels: {} },
workspaceDir: "/tmp/workspace" ,
runtimeOptions: {
allowGatewaySubagentBinding: true ,
},
}),
);
}
describe("outbound channel resolution" , () => {
beforeEach(async () => {
resolveDefaultAgentIdMock.mockReset();
resolveAgentWorkspaceDirMock.mockReset();
getLoadedChannelPluginMock.mockReset();
getChannelPluginMock.mockReset();
applyPluginAutoEnableMock.mockReset();
resolveRuntimePluginRegistryMock.mockReset();
getActivePluginRegistryMock.mockReset();
getActivePluginChannelRegistryMock.mockReset();
getActivePluginChannelRegistryVersionMock.mockReset();
normalizeMessageChannelMock.mockReset();
isDeliverableMessageChannelMock.mockReset();
normalizeMessageChannelMock.mockImplementation((value?: string | null ) =>
typeof value === "string" ? value.trim().toLowerCase() : undefined,
);
isDeliverableMessageChannelMock.mockImplementation((value?: string) =>
["alpha" , "beta" , "gamma" ].includes(String(value)),
);
getActivePluginRegistryMock.mockReturnValue({ channels: [] });
getActivePluginChannelRegistryMock.mockReturnValue({ channels: [] });
getActivePluginChannelRegistryVersionMock.mockReturnValue(1 );
applyPluginAutoEnableMock.mockReturnValue({
config: { autoEnabled: true },
autoEnabledReasons: {},
});
resolveDefaultAgentIdMock.mockReturnValue("main" );
resolveAgentWorkspaceDirMock.mockReturnValue("/tmp/workspace" );
const channelResolution = await importChannelResolution("reset" );
channelResolution.resetOutboundChannelResolutionStateForTest();
});
it.each([
{ input: " Alpha " , expected: "alpha" },
{ input: "unknown" , expected: undefined },
{ input: null , expected: undefined },
])("normalizes deliverable outbound channel for %j" , async ({ input, expected }) => {
const channelResolution = await importChannelResolution("normalize" );
expect(channelResolution.normalizeDeliverableOutboundChannel(input)).toBe(expected);
});
it("returns the already-registered plugin without bootstrapping" , async () => {
const plugin = { id: "alpha" };
getLoadedChannelPluginMock.mockReturnValueOnce(plugin);
const channelResolution = await importChannelResolution("existing-plugin" );
expect(
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: {} as never,
}),
).toBe(plugin);
expect(resolveRuntimePluginRegistryMock).not.toHaveBeenCalled();
});
it("falls back to the active registry when getChannelPlugin misses" , async () => {
const plugin = { id: "alpha" };
getChannelPluginMock.mockReturnValue(undefined);
getActivePluginRegistryMock.mockReturnValue({
channels: [{ plugin }],
});
getActivePluginChannelRegistryMock.mockReturnValue({
channels: [{ plugin }],
});
const channelResolution = await importChannelResolution("direct-registry" );
expect(
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: {} as never,
}),
).toBe(plugin);
});
it("bootstraps plugins once per registry key and returns the newly loaded plugin" , async () => {
const plugin = { id: "alpha" };
getLoadedChannelPluginMock.mockReturnValueOnce(undefined).mockReturnValueOnce(plugin);
const channelResolution = await importChannelResolution("bootstrap-success" );
expect(
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
}),
).toBe(plugin);
expectBootstrapArgs();
getChannelPluginMock.mockReturnValue(undefined);
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
});
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledTimes(1 );
expectBootstrapArgs();
});
it("bootstraps when the active registry has other channels but not the requested one" , async () => {
const plugin = { id: "alpha" };
getLoadedChannelPluginMock.mockReturnValueOnce(undefined).mockReturnValueOnce(plugin);
getActivePluginRegistryMock.mockReturnValue({
channels: [{ plugin: { id: "beta" } }],
});
getActivePluginChannelRegistryMock.mockReturnValue({
channels: [{ plugin: { id: "beta" } }],
});
const channelResolution = await importChannelResolution("bootstrap-missing-target" );
expect(
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
}),
).toBe(plugin);
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledTimes(1 );
});
it("retries bootstrap after a transient load failure" , async () => {
getChannelPluginMock.mockReturnValue(undefined);
resolveRuntimePluginRegistryMock.mockImplementationOnce(() => {
throw new Error("transient" );
});
const channelResolution = await importChannelResolution("bootstrap-retry" );
expect(
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
}),
).toBeUndefined();
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
});
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledTimes(2 );
});
it("retries bootstrap when the pinned channel registry version changes" , async () => {
getChannelPluginMock.mockReturnValue(undefined);
const channelResolution = await importChannelResolution("channel-version-change" );
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
});
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledTimes(1 );
getActivePluginChannelRegistryVersionMock.mockReturnValue(2 );
channelResolution.resolveOutboundChannelPlugin({
channel: "alpha" ,
cfg: { channels: {} } as never,
});
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledTimes(2 );
});
});
Messung V0.5 in Prozent C=100 H=92 G=95
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland