openclaw / src /context-engine /registry.selection.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
76289e7 verified
Raw History Blame Contribute Delete
8.69 kB
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
import { createContextEngineLogicalTurnLease } from "../agents/harness/context-engine-logical-turn.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import { withPluginRuntimeRegistryScope } from "../plugins/runtime/gateway-request-scope.js";
import { setPluginEnabledInConfig } from "../plugins/toggle-config.js";
import { LegacyContextEngine } from "./legacy.js";
import {
listContextEngineQuarantines,
registerContextEngineInRegistry,
resolveContextEngine,
resolveContextEngineOwnerPluginId,
resolveLogicalTurnContextEngines,
} from "./registry.js";
import { resetContextEngineRuntimeQuarantineForTests } from "./registry.test-support.js";
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
const engineId = "synthetic-engine";
const ownerId = "synthetic-owner";
beforeEach(() => {
vi.stubEnv("OPENCLAW_STATE_DIR", tempDirs.make("context-engine-selection-"));
resetContextEngineRuntimeQuarantineForTests();
});
afterEach(() => {
resetContextEngineRuntimeQuarantineForTests();
vi.restoreAllMocks();
vi.unstubAllEnvs();
});
// Each case owns a registry; factories expose invocation independently from selection metadata.
function fixture(owner = engineId, registered = true) {
const registry = createEmptyPluginRegistry();
const factory = vi.fn(() => ({
info: { id: engineId, name: "Synthetic" },
ingest: async () => ({ ingested: false }),
assemble: async () => ({ messages: [], estimatedTokens: 0 }),
compact: async () => ({ ok: true, compacted: false, reason: "fixture" }),
}));
registerContextEngineInRegistry(registry, "legacy", () => new LegacyContextEngine(), "core");
if (registered) {
registerContextEngineInRegistry(registry, engineId, factory, `plugin:${owner}`);
}
return { registry, factory };
}
for (const path of ["standalone", "logical-turn"] as const) {
describe(path, () => {
// Exercise both public resolvers and release every returned instance before assertions.
async function resolve(config: OpenClawConfig) {
if (path === "standalone") {
const engine = await resolveContextEngine(config);
const result = {
id: engine.info.id,
owner: resolveContextEngineOwnerPluginId(engine),
failure: undefined,
};
await engine.dispose?.();
return result;
}
const result = await resolveLogicalTurnContextEngines(config);
await result.configured.engine.dispose?.();
if (result.configured !== result.fallback) {
await result.fallback.engine.dispose?.();
}
return {
id: result.configuredId,
owner: result.configured.ownerPluginId,
failure: result.configuredFailure,
};
}
it.each([
["disabled absent", engineId, false, { entries: { [engineId]: { enabled: false } } }],
["disabled registered", engineId, true, { entries: { [engineId]: { enabled: false } } }],
["global disable absent", engineId, false, { enabled: false }],
["global disable registered", engineId, true, { enabled: false }],
["denied absent", engineId, false, { deny: [engineId] }],
["denied registered", engineId, true, { deny: [engineId] }],
["distinct owner disabled", ownerId, true, { entries: { [ownerId]: { enabled: false } } }],
["distinct owner denied", ownerId, true, { deny: [ownerId] }],
] satisfies Array<[string, string, boolean, OpenClawConfig["plugins"]]>)(
"uses normal default for %s",
async (_name, owner, registered, policy) => {
const { registry, factory } = fixture(owner, registered);
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const error = vi.spyOn(console, "error").mockImplementation(() => {});
const config = { plugins: { ...policy, slots: { contextEngine: engineId } } };
await withPluginRuntimeRegistryScope(registry, async () => {
expect(await resolve(config)).toEqual({
id: "legacy",
owner: undefined,
failure: undefined,
});
expect(listContextEngineQuarantines()).toEqual([]);
});
expect(factory).not.toHaveBeenCalled();
expect(warn).not.toHaveBeenCalled();
expect(error).not.toHaveBeenCalled();
expect(config.plugins.slots.contextEngine).toBe(engineId);
},
);
it.each([undefined, "", "legacy", "none"])("uses default for slot %s", async (slot) => {
const { registry, factory } = fixture();
await withPluginRuntimeRegistryScope(registry, async () => {
expect(
await resolve({ plugins: { enabled: false, slots: { contextEngine: slot } } }),
).toEqual({ id: "legacy", owner: undefined, failure: undefined });
expect(listContextEngineQuarantines()).toEqual([]);
});
expect(factory).not.toHaveBeenCalled();
});
it.each([engineId, ownerId])(
"keeps enabled engine ID separate from owner %s",
async (owner) => {
const { registry, factory } = fixture(owner);
await withPluginRuntimeRegistryScope(registry, async () => {
expect(
await resolve({
plugins: {
slots: { contextEngine: engineId },
entries: { [owner]: { enabled: true } },
},
}),
).toEqual({ id: engineId, owner, failure: undefined });
});
expect(factory).toHaveBeenCalledOnce();
},
);
it.each(["missing", "factory"])("preserves enabled %s failure", async (failure) => {
const { registry, factory } = fixture(engineId, failure !== "missing");
factory.mockImplementation(() => {
throw new Error("synthetic factory failure");
});
vi.spyOn(console, "error").mockImplementation(() => {});
await withPluginRuntimeRegistryScope(registry, async () => {
const result = await resolve({ plugins: { slots: { contextEngine: engineId } } });
if (path === "logical-turn") {
expect(result.failure).toContain(
failure === "missing" ? "not registered" : "synthetic factory failure",
);
} else {
expect(result.id).toBe("legacy");
expect(listContextEngineQuarantines()).toEqual([
expect.objectContaining({
engineId,
operation: failure === "missing" ? "resolve" : "factory",
}),
]);
}
});
});
it("disables then re-enables without clearing the retained slot or registering again", async () => {
const { registry, factory } = fixture();
const initial = { plugins: { slots: { contextEngine: engineId } } };
const disabled = setPluginEnabledInConfig(initial, engineId, false);
await withPluginRuntimeRegistryScope(registry, async () => {
expect((await resolve(disabled)).id).toBe("legacy");
expect(factory).not.toHaveBeenCalled();
expect((await resolve(setPluginEnabledInConfig(disabled, engineId, true))).id).toBe(
engineId,
);
expect(listContextEngineQuarantines()).toEqual([]);
});
expect(disabled.plugins?.slots?.contextEngine).toBe(engineId);
expect(factory).toHaveBeenCalledOnce();
});
});
}
it.each([true, false])(
"plugin disable produces subsequent ordinary logical turns without degradation warnings (registered=%s)",
async (registered) => {
const { registry, factory } = fixture(engineId, registered);
const config = setPluginEnabledInConfig(
{ plugins: { slots: { contextEngine: engineId } } },
engineId,
false,
);
const warn = vi.fn();
await withPluginRuntimeRegistryScope(registry, async () => {
for (const runId of ["first", "second"]) {
const lease = await createContextEngineLogicalTurnLease({
config,
identity: { runId, sessionId: "synthetic-session" },
warn,
});
try {
lease.begin();
expect(lease.effectiveEngineId).toBe("legacy");
expect(lease.degraded).toBe(false);
await lease.engine.assemble({
sessionId: "synthetic-session",
messages: [],
tokenBudget: 100,
});
} finally {
await lease.dispose();
}
}
expect(listContextEngineQuarantines()).toEqual([]);
});
expect(factory).not.toHaveBeenCalled();
expect(warn).not.toHaveBeenCalled();
},
);