mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 21:34:46 +00:00
test: clear plugin registry broad matchers
This commit is contained in:
@@ -149,6 +149,49 @@ function createIndex(
|
||||
};
|
||||
}
|
||||
|
||||
function requireRecord(value: unknown, label: string): Record<string, unknown> {
|
||||
expect(typeof value, label).toBe("object");
|
||||
expect(value, label).not.toBeNull();
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function requireArray(value: unknown, label: string): unknown[] {
|
||||
expect(Array.isArray(value), label).toBe(true);
|
||||
return value as unknown[];
|
||||
}
|
||||
|
||||
function expectFields(record: Record<string, unknown>, expected: Record<string, unknown>) {
|
||||
for (const [key, value] of Object.entries(expected)) {
|
||||
expect(record[key], key).toEqual(value);
|
||||
}
|
||||
}
|
||||
|
||||
function expectPluginRecordFields(record: unknown, expected: Record<string, unknown>) {
|
||||
expectFields(requireRecord(record, "plugin record"), expected);
|
||||
}
|
||||
|
||||
function expectDiagnosticCodes(diagnostics: unknown, expectedCodes: string[]) {
|
||||
const codes = requireArray(diagnostics, "diagnostics").map(
|
||||
(diagnostic) => requireRecord(diagnostic, "diagnostic").code,
|
||||
);
|
||||
expect(codes).toEqual(expectedCodes);
|
||||
}
|
||||
|
||||
function expectInstallRecord(
|
||||
installRecords: unknown,
|
||||
pluginId: string,
|
||||
expected: Record<string, unknown>,
|
||||
) {
|
||||
const records = requireRecord(installRecords, "install records");
|
||||
expectFields(requireRecord(records[pluginId], `${pluginId} install record`), expected);
|
||||
}
|
||||
|
||||
function expectSnapshotPluginIds(snapshot: InstalledPluginIndex, expectedPluginIds: string[]) {
|
||||
expect(listPluginRecords({ index: snapshot }).map((plugin) => plugin.pluginId)).toEqual(
|
||||
expectedPluginIds,
|
||||
);
|
||||
}
|
||||
|
||||
describe("plugin registry facade", () => {
|
||||
it("resolves relative plugin API paths against the plugin root", () => {
|
||||
const pluginRoot = path.join(makeTempDir(), "plugins", "demo");
|
||||
@@ -181,7 +224,7 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(listPluginRecords({ index }).map((plugin) => plugin.pluginId)).toEqual(["demo"]);
|
||||
expect(getPluginRecord({ index, pluginId: "demo" })).toMatchObject({
|
||||
expectPluginRecordFields(getPluginRecord({ index, pluginId: "demo" }), {
|
||||
pluginId: "demo",
|
||||
enabled: true,
|
||||
});
|
||||
@@ -246,7 +289,7 @@ describe("plugin registry facade", () => {
|
||||
preferPersisted: false,
|
||||
});
|
||||
|
||||
expect(getPluginRecord({ index, pluginId: "demo" })).toMatchObject({
|
||||
expectPluginRecordFields(getPluginRecord({ index, pluginId: "demo" }), {
|
||||
pluginId: "demo",
|
||||
enabled: false,
|
||||
});
|
||||
@@ -344,26 +387,19 @@ describe("plugin registry facade", () => {
|
||||
expect(normalizePluginId("openai-chat")).toBe("openai");
|
||||
expect(normalizePluginId("unknown-plugin")).toBe("unknown-plugin");
|
||||
|
||||
expect(
|
||||
normalizePluginsConfigWithRegistry(
|
||||
{
|
||||
allow: ["openai-chat"],
|
||||
entries: {
|
||||
"OpenAI-Codex": {
|
||||
enabled: false,
|
||||
},
|
||||
const normalizedConfig = normalizePluginsConfigWithRegistry(
|
||||
{
|
||||
allow: ["openai-chat"],
|
||||
entries: {
|
||||
"OpenAI-Codex": {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
index,
|
||||
),
|
||||
).toMatchObject({
|
||||
allow: ["openai"],
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
index,
|
||||
);
|
||||
expect(normalizedConfig.allow).toEqual(["openai"]);
|
||||
expect(normalizedConfig.entries?.openai?.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it("normalizes plugin config ids from a provided manifest registry without rereading manifests", () => {
|
||||
@@ -387,17 +423,14 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(normalizePluginId("demo-chat")).toBe("demo");
|
||||
expect(
|
||||
normalizePluginsConfigWithRegistry(
|
||||
{
|
||||
allow: ["demo-chat"],
|
||||
},
|
||||
index,
|
||||
{ manifestRegistry: lookUpTable.manifestRegistry },
|
||||
),
|
||||
).toMatchObject({
|
||||
allow: ["demo"],
|
||||
});
|
||||
const normalizedConfig = normalizePluginsConfigWithRegistry(
|
||||
{
|
||||
allow: ["demo-chat"],
|
||||
},
|
||||
index,
|
||||
{ manifestRegistry: lookUpTable.manifestRegistry },
|
||||
);
|
||||
expect(normalizedConfig.allow).toEqual(["demo"]);
|
||||
});
|
||||
|
||||
it("reads the persisted registry before deriving from discovered candidates", async () => {
|
||||
@@ -462,12 +495,8 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-source" }),
|
||||
]);
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
});
|
||||
|
||||
it("falls back to the derived registry when persisted manifest metadata is stale", async () => {
|
||||
@@ -501,9 +530,7 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-source" }),
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
|
||||
expect(result.snapshot.plugins[0]?.manifestHash).not.toBe(persisted.plugins[0]?.manifestHash);
|
||||
});
|
||||
|
||||
@@ -543,9 +570,7 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-source" }),
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
|
||||
expect(result.snapshot.plugins[0]?.packageJson?.hash).not.toBe(
|
||||
persisted.plugins[0]?.packageJson?.hash,
|
||||
);
|
||||
@@ -583,9 +608,7 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-source" }),
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
|
||||
expect(result.snapshot.plugins[0]?.packageJson).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -617,12 +640,8 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-source" }),
|
||||
]);
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
});
|
||||
|
||||
it("falls back to the derived registry when persisted policy is stale", async () => {
|
||||
@@ -655,17 +674,11 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-stale-policy" }),
|
||||
]);
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expect(result.snapshot.installRecords).toMatchObject({
|
||||
persisted: {
|
||||
source: "npm",
|
||||
spec: "persisted-plugin@1.0.0",
|
||||
},
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-policy"]);
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
expectInstallRecord(result.snapshot.installRecords, "persisted", {
|
||||
source: "npm",
|
||||
spec: "persisted-plugin@1.0.0",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -681,12 +694,8 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({ code: "persisted-registry-missing" }),
|
||||
]);
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-missing"]);
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
});
|
||||
|
||||
it("derives fresh config-scoped registries when the persisted registry is missing", () => {
|
||||
@@ -740,15 +749,11 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(result.diagnostics).toEqual([
|
||||
expect.objectContaining({
|
||||
code: "persisted-registry-disabled",
|
||||
message: expect.stringContaining("deprecated break-glass compatibility switch"),
|
||||
}),
|
||||
]);
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expectDiagnosticCodes(result.diagnostics, ["persisted-registry-disabled"]);
|
||||
expect(String(requireRecord(result.diagnostics[0], "diagnostic").message)).toContain(
|
||||
"deprecated break-glass compatibility switch",
|
||||
);
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
});
|
||||
|
||||
it("derives a fresh registry without dropping persisted install records", async () => {
|
||||
@@ -776,14 +781,10 @@ describe("plugin registry facade", () => {
|
||||
});
|
||||
|
||||
expect(result.source).toBe("derived");
|
||||
expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
|
||||
"demo",
|
||||
]);
|
||||
expect(result.snapshot.installRecords).toMatchObject({
|
||||
persisted: {
|
||||
source: "npm",
|
||||
spec: "persisted-plugin@1.0.0",
|
||||
},
|
||||
expectSnapshotPluginIds(result.snapshot, ["demo"]);
|
||||
expectInstallRecord(result.snapshot.installRecords, "persisted", {
|
||||
source: "npm",
|
||||
spec: "persisted-plugin@1.0.0",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -794,16 +795,11 @@ describe("plugin registry facade", () => {
|
||||
const candidate = createCandidate(pluginDir);
|
||||
const env = hermeticEnv();
|
||||
|
||||
await expect(
|
||||
inspectPluginRegistry({ stateDir, candidates: [candidate], env }),
|
||||
).resolves.toMatchObject({
|
||||
state: "missing",
|
||||
refreshReasons: ["missing"],
|
||||
persisted: null,
|
||||
current: {
|
||||
plugins: [expect.objectContaining({ pluginId: "demo" })],
|
||||
},
|
||||
});
|
||||
const missingInspect = await inspectPluginRegistry({ stateDir, candidates: [candidate], env });
|
||||
expect(missingInspect.state).toBe("missing");
|
||||
expect(missingInspect.refreshReasons).toEqual(["missing"]);
|
||||
expect(missingInspect.persisted).toBeNull();
|
||||
expect(missingInspect.current.plugins.map((plugin) => plugin.pluginId)).toEqual(["demo"]);
|
||||
|
||||
await refreshPluginRegistry({
|
||||
reason: "manual",
|
||||
@@ -812,15 +808,10 @@ describe("plugin registry facade", () => {
|
||||
env,
|
||||
});
|
||||
|
||||
await expect(
|
||||
inspectPluginRegistry({ stateDir, candidates: [candidate], env }),
|
||||
).resolves.toMatchObject({
|
||||
state: "fresh",
|
||||
refreshReasons: [],
|
||||
persisted: {
|
||||
plugins: [expect.objectContaining({ pluginId: "demo" })],
|
||||
},
|
||||
});
|
||||
const freshInspect = await inspectPluginRegistry({ stateDir, candidates: [candidate], env });
|
||||
expect(freshInspect.state).toBe("fresh");
|
||||
expect(freshInspect.refreshReasons).toEqual([]);
|
||||
expect(freshInspect.persisted?.plugins.map((plugin) => plugin.pluginId)).toEqual(["demo"]);
|
||||
});
|
||||
|
||||
it("preserves install records when refreshing the persisted registry", async () => {
|
||||
@@ -846,15 +837,16 @@ describe("plugin registry facade", () => {
|
||||
env: hermeticEnv(),
|
||||
});
|
||||
|
||||
await expect(readPersistedInstalledPluginIndex({ stateDir })).resolves.toMatchObject({
|
||||
installRecords: {
|
||||
missing: {
|
||||
source: "npm",
|
||||
spec: "missing-plugin@1.0.0",
|
||||
installPath: path.join(stateDir, "plugins", "missing"),
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
const persisted = await readPersistedInstalledPluginIndex({ stateDir });
|
||||
expect(persisted).not.toBeNull();
|
||||
if (!persisted) {
|
||||
throw new Error("Expected persisted plugin index");
|
||||
}
|
||||
expectInstallRecord(persisted.installRecords, "missing", {
|
||||
source: "npm",
|
||||
spec: "missing-plugin@1.0.0",
|
||||
installPath: path.join(stateDir, "plugins", "missing"),
|
||||
});
|
||||
expect(persisted.plugins).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user