test: trim import-heavy startup paths

This commit is contained in:
Peter Steinberger
2026-03-22 05:02:09 +00:00
parent 8727338372
commit e1854dfbf6
9 changed files with 697 additions and 448 deletions

View File

@@ -1,11 +1,11 @@
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { parseFeishuConversationId } from "../../extensions/feishu/src/conversation-id.js";
import { parseTelegramTopicConversation } from "../../extensions/telegram/runtime-api.js";
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import type { ChannelConfiguredBindingProvider, ChannelPlugin } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
import { parseTelegramTopicConversation } from "./conversation-id.js";
import * as persistentBindingsResolveModule from "./persistent-bindings.resolve.js";
import { buildConfiguredAcpSessionKey } from "./persistent-bindings.types.js";
const managerMocks = vi.hoisted(() => ({

View File

@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it } from "vitest";
import { normalizeTelegramMessagingTarget } from "../../extensions/telegram/api.js";
import { normalizeTelegramMessagingTarget } from "../../extensions/telegram/src/normalize.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
import { extractMessagingToolSend } from "./pi-embedded-subscribe.tools.js";

View File

@@ -3,24 +3,33 @@ import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
buildConfigDocBaseline,
type ConfigDocBaseline,
renderConfigDocBaselineStatefile,
writeConfigDocBaselineStatefile,
} from "./doc-baseline.js";
describe("config doc baseline integration", () => {
const tempRoots: string[] = [];
let sharedBaselinePromise: Promise<Awaited<ReturnType<typeof buildConfigDocBaseline>>> | null =
null;
const generatedBaselineJsonPath = path.resolve(
process.cwd(),
"docs/.generated/config-baseline.json",
);
const generatedBaselineJsonlPath = path.resolve(
process.cwd(),
"docs/.generated/config-baseline.jsonl",
);
let sharedBaselinePromise: Promise<ConfigDocBaseline> | null = null;
let sharedRenderedPromise: Promise<
Awaited<ReturnType<typeof renderConfigDocBaselineStatefile>>
> | null = null;
let sharedByPathPromise: Promise<
Map<string, Awaited<ReturnType<typeof buildConfigDocBaseline>>["entries"][number]>
> | null = null;
let sharedGeneratedJsonPromise: Promise<string> | null = null;
let sharedGeneratedJsonlPromise: Promise<string> | null = null;
let sharedByPathPromise: Promise<Map<string, ConfigDocBaseline["entries"][number]>> | null = null;
function getSharedBaseline() {
sharedBaselinePromise ??= buildConfigDocBaseline();
sharedBaselinePromise ??= fs
.readFile(generatedBaselineJsonPath, "utf8")
.then((raw) => JSON.parse(raw) as ConfigDocBaseline);
return sharedBaselinePromise;
}
@@ -29,6 +38,16 @@ describe("config doc baseline integration", () => {
return sharedRenderedPromise;
}
function getGeneratedJson() {
sharedGeneratedJsonPromise ??= fs.readFile(generatedBaselineJsonPath, "utf8");
return sharedGeneratedJsonPromise;
}
function getGeneratedJsonl() {
sharedGeneratedJsonlPromise ??= fs.readFile(generatedBaselineJsonlPath, "utf8");
return sharedGeneratedJsonlPromise;
}
function getSharedByPath() {
sharedByPathPromise ??= getSharedBaseline().then(
(baseline) => new Map(baseline.entries.map((entry) => [entry.path, entry])),
@@ -45,13 +64,25 @@ describe("config doc baseline integration", () => {
});
it("is deterministic across repeated runs", async () => {
const first = await getSharedRendered();
const second = await renderConfigDocBaselineStatefile();
const baseline = await getSharedBaseline();
const first = await renderConfigDocBaselineStatefile(baseline);
const second = await renderConfigDocBaselineStatefile(baseline);
expect(second.json).toBe(first.json);
expect(second.jsonl).toBe(first.jsonl);
});
it("matches the checked-in generated baseline artifacts", async () => {
const [rendered, generatedJson, generatedJsonl] = await Promise.all([
getSharedRendered(),
getGeneratedJson(),
getGeneratedJsonl(),
]);
expect(rendered.json).toBe(generatedJson);
expect(rendered.jsonl).toBe(generatedJsonl);
});
it("includes core, channel, and plugin config metadata", async () => {
const byPath = await getSharedByPath();

View File

@@ -1,23 +1,70 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { parseTelegramTarget } from "../../../extensions/telegram/api.js";
import { telegramOutbound, whatsappOutbound } from "../../../test/channel-outbounds.js";
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../whatsapp/normalize.js";
import { resolveOutboundTarget } from "./targets.js";
const telegramMessaging = {
parseExplicitTarget: ({ raw }: { raw: string }) => {
const target = parseTelegramTarget(raw);
return {
to: target.chatId,
threadId: target.messageThreadId,
chatType: target.chatType === "unknown" ? undefined : target.chatType,
};
},
type TelegramTargetParts = {
chatId: string;
messageThreadId?: number;
chatType: "direct" | "group" | "unknown";
};
function parseTelegramTestTarget(raw: string): TelegramTargetParts {
const trimmed = raw
.trim()
.replace(/^(telegram|tg):/i, "")
.trim();
const topicMatch = /^(.+?):topic:(\d+)$/u.exec(trimmed);
if (topicMatch) {
const chatId = topicMatch[1];
return {
chatId,
messageThreadId: Number.parseInt(topicMatch[2], 10),
chatType: chatId.startsWith("-") ? "group" : "direct",
};
}
const threadMatch = /^(.+):(\d+)$/u.exec(trimmed);
if (threadMatch) {
const chatId = threadMatch[1];
return {
chatId,
messageThreadId: Number.parseInt(threadMatch[2], 10),
chatType: chatId.startsWith("-") ? "group" : "direct",
};
}
return {
chatId: trimmed,
chatType: trimmed.startsWith("-") ? "group" : "direct",
};
}
const telegramMessaging = {
parseExplicitTarget: ({ raw }: { raw: string }) => parseTelegramTestMessagingTarget(raw),
};
export function inferTelegramTestChatType(to: string): "direct" | "group" | undefined {
const chatType = parseTelegramTestTarget(to).chatType;
return chatType === "unknown" ? undefined : chatType;
}
export function parseTelegramTestMessagingTarget(raw: string): {
to: string;
threadId?: number;
chatType?: "direct" | "group";
} {
const target = parseTelegramTestTarget(raw);
return {
to: target.chatId,
threadId: target.messageThreadId,
chatType: target.chatType === "unknown" ? undefined : target.chatType,
};
}
const whatsappMessaging = {
inferTargetChatType: ({ to }: { to: string }) => {
const normalized = normalizeWhatsAppTarget(to);
@@ -31,6 +78,24 @@ const whatsappMessaging = {
},
};
export const telegramOutboundStub: ChannelOutboundAdapter = {
deliveryMode: "direct",
};
export const whatsappOutboundStub: ChannelOutboundAdapter = {
deliveryMode: "gateway",
resolveTarget: ({ to }) => {
const normalized = typeof to === "string" ? normalizeWhatsAppTarget(to) : undefined;
if (normalized) {
return { ok: true as const, to: normalized };
}
return {
ok: false as const,
error: new Error("WhatsApp target required"),
};
},
};
export function installResolveOutboundTargetPluginRegistryHooks(): void {
beforeEach(() => {
setActivePluginRegistry(
@@ -41,7 +106,7 @@ export function installResolveOutboundTargetPluginRegistryHooks(): void {
...createOutboundTestPlugin({
id: "whatsapp",
label: "WhatsApp",
outbound: whatsappOutbound,
outbound: whatsappOutboundStub,
messaging: whatsappMessaging,
}),
config: {
@@ -60,7 +125,7 @@ export function installResolveOutboundTargetPluginRegistryHooks(): void {
...createOutboundTestPlugin({
id: "telegram",
label: "Telegram",
outbound: telegramOutbound,
outbound: telegramOutboundStub,
messaging: telegramMessaging,
}),
config: {

View File

@@ -1,6 +1,4 @@
import { beforeEach, describe, expect, it } from "vitest";
import { parseTelegramTarget } from "../../../extensions/telegram/src/targets.js";
import { telegramOutbound, whatsappOutbound } from "../../../test/channel-outbounds.js";
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { SessionEntry } from "../../config/sessions/types.js";
@@ -14,25 +12,19 @@ import {
} from "./targets.js";
import type { SessionDeliveryTarget } from "./targets.js";
import {
inferTelegramTestChatType,
installResolveOutboundTargetPluginRegistryHooks,
parseTelegramTestMessagingTarget,
runResolveOutboundTargetCoreTests,
telegramOutboundStub,
whatsappOutboundStub,
} from "./targets.shared-test.js";
runResolveOutboundTargetCoreTests();
const telegramMessaging = {
parseExplicitTarget: ({ raw }: { raw: string }) => {
const target = parseTelegramTarget(raw);
return {
to: target.chatId,
threadId: target.messageThreadId,
chatType: target.chatType === "unknown" ? undefined : target.chatType,
};
},
inferTargetChatType: ({ to }: { to: string }) => {
const target = parseTelegramTarget(to);
return target.chatType === "unknown" ? undefined : target.chatType;
},
parseExplicitTarget: ({ raw }: { raw: string }) => parseTelegramTestMessagingTarget(raw),
inferTargetChatType: ({ to }: { to: string }) => inferTelegramTestChatType(to),
};
const whatsappMessaging = {
@@ -72,7 +64,7 @@ beforeEach(() => {
pluginId: "telegram",
plugin: createOutboundTestPlugin({
id: "telegram",
outbound: telegramOutbound,
outbound: telegramOutboundStub,
messaging: telegramMessaging,
}),
source: "test",
@@ -81,7 +73,7 @@ beforeEach(() => {
pluginId: "whatsapp",
plugin: createOutboundTestPlugin({
id: "whatsapp",
outbound: whatsappOutbound,
outbound: whatsappOutboundStub,
messaging: whatsappMessaging,
}),
source: "test",
@@ -155,7 +147,7 @@ describe("resolveOutboundTarget defaultTo config fallback", () => {
pluginId: "telegram",
plugin: createOutboundTestPlugin({
id: "telegram",
outbound: telegramOutbound,
outbound: telegramOutboundStub,
messaging: telegramMessaging,
}),
source: "test",

View File

@@ -9,10 +9,7 @@ import { buildPluginSdkEntrySources, pluginSdkEntrypoints } from "./entrypoints.
const require = createRequire(import.meta.url);
const tsdownModuleUrl = pathToFileURL(require.resolve("tsdown")).href;
const bundledRepresentativeEntrypoints = [
"index",
"runtime",
"channel-runtime",
"provider-setup",
"matrix-runtime-heavy",
"windows-spawn",
] as const;

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,7 @@ import {
resolveProviderPluginChoice,
resolveProviderWizardOptions,
} from "../provider-wizard.js";
import type { ProviderPlugin } from "../types.js";
import { providerContractPluginIds, uniqueProviderContractProviders } from "./registry.js";
import type { ProviderAuthMethod, ProviderPlugin } from "../types.js";
const resolvePluginProvidersMock = vi.fn();
@@ -14,6 +13,94 @@ vi.mock("../providers.js", () => ({
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
}));
function createAuthMethod(
params: Pick<ProviderAuthMethod, "id" | "label"> &
Partial<Pick<ProviderAuthMethod, "hint" | "wizard">>,
): ProviderAuthMethod {
return {
id: params.id,
label: params.label,
...(params.hint ? { hint: params.hint } : {}),
...(params.wizard ? { wizard: params.wizard } : {}),
kind: "api_key",
run: async () => ({ profiles: [] }),
};
}
const TEST_PROVIDERS: ProviderPlugin[] = [
{
id: "alpha",
label: "Alpha",
auth: [
createAuthMethod({
id: "api-key",
label: "API key",
wizard: {
choiceLabel: "Alpha key",
choiceHint: "Use an API key",
groupId: "alpha",
groupLabel: "Alpha",
onboardingScopes: ["text-inference"],
},
}),
createAuthMethod({
id: "oauth",
label: "OAuth",
wizard: {
choiceId: "alpha-oauth",
choiceLabel: "Alpha OAuth",
groupId: "alpha",
groupLabel: "Alpha",
groupHint: "Recommended",
},
}),
],
wizard: {
modelPicker: {
label: "Alpha custom",
hint: "Pick Alpha models",
methodId: "oauth",
},
},
},
{
id: "beta",
label: "Beta",
auth: [createAuthMethod({ id: "token", label: "Token" })],
wizard: {
setup: {
choiceLabel: "Beta setup",
groupId: "beta",
groupLabel: "Beta",
},
modelPicker: {
label: "Beta custom",
},
},
},
{
id: "gamma",
label: "Gamma",
auth: [
createAuthMethod({ id: "default", label: "Default auth" }),
createAuthMethod({ id: "alt", label: "Alt auth" }),
],
wizard: {
setup: {
methodId: "alt",
choiceId: "gamma-alt",
choiceLabel: "Gamma alt",
groupId: "gamma",
groupLabel: "Gamma",
},
},
},
];
const TEST_PROVIDER_IDS = TEST_PROVIDERS.map((provider) => provider.id).toSorted((left, right) =>
left.localeCompare(right),
);
function resolveExpectedWizardChoiceValues(providers: ProviderPlugin[]) {
const values: string[] = [];
@@ -43,6 +130,11 @@ function resolveExpectedWizardChoiceValues(providers: ProviderPlugin[]) {
continue;
}
if (provider.auth.length === 1) {
values.push(setup.choiceId?.trim() || provider.id);
continue;
}
values.push(
...provider.auth.map((method) => buildProviderPluginMethodChoice(provider.id, method.id)),
);
@@ -73,15 +165,15 @@ function resolveExpectedModelPickerValues(providers: ProviderPlugin[]) {
describe("provider wizard contract", () => {
beforeEach(() => {
resolvePluginProvidersMock.mockReset();
resolvePluginProvidersMock.mockReturnValue(uniqueProviderContractProviders);
resolvePluginProvidersMock.mockReturnValue(TEST_PROVIDERS);
});
it("exposes every registered provider setup choice through the shared wizard layer", () => {
it("exposes every wizard setup choice through the shared wizard layer", () => {
const options = resolveProviderWizardOptions({
config: {
plugins: {
enabled: true,
allow: providerContractPluginIds,
allow: TEST_PROVIDER_IDS,
slots: {
memory: "none",
},
@@ -92,7 +184,7 @@ describe("provider wizard contract", () => {
expect(
options.map((option) => option.value).toSorted((left, right) => left.localeCompare(right)),
).toEqual(resolveExpectedWizardChoiceValues(uniqueProviderContractProviders));
).toEqual(resolveExpectedWizardChoiceValues(TEST_PROVIDERS));
expect(options.map((option) => option.value)).toEqual([
...new Set(options.map((option) => option.value)),
]);
@@ -101,7 +193,7 @@ describe("provider wizard contract", () => {
it("round-trips every shared wizard choice back to its provider and auth method", () => {
for (const option of resolveProviderWizardOptions({ config: {}, env: process.env })) {
const resolved = resolveProviderPluginChoice({
providers: uniqueProviderContractProviders,
providers: TEST_PROVIDERS,
choice: option.value,
});
expect(resolved).not.toBeNull();
@@ -110,15 +202,15 @@ describe("provider wizard contract", () => {
}
});
it("exposes every registered model-picker entry through the shared wizard layer", () => {
it("exposes every model-picker entry through the shared wizard layer", () => {
const entries = resolveProviderModelPickerEntries({ config: {}, env: process.env });
expect(
entries.map((entry) => entry.value).toSorted((left, right) => left.localeCompare(right)),
).toEqual(resolveExpectedModelPickerValues(uniqueProviderContractProviders));
).toEqual(resolveExpectedModelPickerValues(TEST_PROVIDERS));
for (const entry of entries) {
const resolved = resolveProviderPluginChoice({
providers: uniqueProviderContractProviders,
providers: TEST_PROVIDERS,
choice: entry.value,
});
expect(resolved).not.toBeNull();

View File

@@ -7,7 +7,7 @@ import type {
SessionBindingAdapter,
SessionBindingRecord,
} from "../infra/outbound/session-binding-service.js";
import { createEmptyPluginRegistry } from "./registry.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import { setActivePluginRegistry } from "./runtime.js";
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-binding-"));