Files
openclaw/src/commands/config-validation.test.ts
2026-03-24 21:00:36 +00:00

97 lines
3.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import type { PluginCompatibilityNotice } from "../plugins/status.js";
import { createCompatibilityNotice } from "../plugins/status.test-helpers.js";
const readConfigFileSnapshot = vi.fn();
const buildPluginCompatibilityNotices = vi.fn<(_params?: unknown) => PluginCompatibilityNotice[]>(
() => [],
);
vi.mock("../config/config.js", () => ({
readConfigFileSnapshot,
}));
vi.mock("../plugins/status.js", () => ({
buildPluginCompatibilityNotices,
formatPluginCompatibilityNotice: (notice: { pluginId: string; message: string }) =>
`${notice.pluginId} ${notice.message}`,
}));
describe("requireValidConfigSnapshot", () => {
beforeEach(() => {
vi.clearAllMocks();
});
function createValidSnapshot() {
readConfigFileSnapshot.mockResolvedValue({
exists: true,
valid: true,
config: { plugins: {} },
issues: [],
});
buildPluginCompatibilityNotices.mockReturnValue([
createCompatibilityNotice({ pluginId: "legacy-plugin", code: "legacy-before-agent-start" }),
]);
}
function createRuntime() {
return {
log: vi.fn(),
error: vi.fn(),
exit: vi.fn(),
};
}
it("returns config without emitting compatibility advice by default", async () => {
createValidSnapshot();
const runtime = createRuntime();
const { requireValidConfigSnapshot } = await import("./config-validation.js");
const config = await requireValidConfigSnapshot(runtime);
expect(config).toEqual({ plugins: {} });
expect(runtime.error).not.toHaveBeenCalled();
expect(runtime.exit).not.toHaveBeenCalled();
expect(buildPluginCompatibilityNotices).not.toHaveBeenCalled();
expect(runtime.log).not.toHaveBeenCalled();
});
it("emits a non-blocking compatibility advisory when explicitly requested", async () => {
createValidSnapshot();
const runtime = createRuntime();
const { requireValidConfigSnapshot } = await import("./config-validation.js");
const config = await requireValidConfigSnapshot(runtime, {
includeCompatibilityAdvisory: true,
});
expect(config).toEqual({ plugins: {} });
expect(runtime.error).not.toHaveBeenCalled();
expect(runtime.exit).not.toHaveBeenCalled();
expect(String(runtime.log.mock.calls[0]?.[0])).toContain("Plugin compatibility: 1 notice.");
expect(String(runtime.log.mock.calls[0]?.[0])).toContain(
"legacy-plugin still uses legacy before_agent_start",
);
});
it("blocks invalid config before emitting compatibility advice", async () => {
readConfigFileSnapshot.mockResolvedValue({
exists: true,
valid: false,
config: {},
issues: [{ path: "routing.allowFrom", message: "Legacy key" }],
});
const runtime = createRuntime();
const { requireValidConfigSnapshot } = await import("./config-validation.js");
const config = await requireValidConfigSnapshot(runtime, {
includeCompatibilityAdvisory: true,
});
expect(config).toBeNull();
expect(runtime.error).toHaveBeenCalled();
expect(runtime.exit).toHaveBeenCalledWith(1);
expect(runtime.log).not.toHaveBeenCalled();
});
});