


























@@ -0,0 +1,114 @@
1+import fs from "node:fs";
2+import os from "node:os";
3+import path from "node:path";
4+import { describe, expect, it } from "vitest";
5+import {
6+clearCurrentPluginMetadataSnapshot,
7+getCurrentPluginMetadataSnapshot,
8+setCurrentPluginMetadataSnapshot,
9+} from "./current-plugin-metadata-snapshot.js";
10+import { resolveInstalledPluginIndexPolicyHash } from "./installed-plugin-index-policy.js";
11+import { writePersistedInstalledPluginIndexSync } from "./installed-plugin-index-store.js";
12+import type { PluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";
13+14+function createSnapshot(
15+params: {
16+config?: Parameters<typeof resolveInstalledPluginIndexPolicyHash>[0];
17+workspaceDir?: string;
18+} = {},
19+): PluginMetadataSnapshot {
20+return {
21+policyHash: resolveInstalledPluginIndexPolicyHash(params.config),
22+ ...(params.workspaceDir ? { workspaceDir: params.workspaceDir } : {}),
23+index: {
24+version: 1,
25+hostContractVersion: "test",
26+compatRegistryVersion: "test",
27+migrationVersion: 1,
28+policyHash: resolveInstalledPluginIndexPolicyHash(params.config),
29+generatedAtMs: 1,
30+installRecords: {},
31+plugins: [],
32+diagnostics: [],
33+},
34+registryDiagnostics: [],
35+manifestRegistry: { plugins: [], diagnostics: [] },
36+plugins: [],
37+diagnostics: [],
38+byPluginId: new Map(),
39+normalizePluginId: (pluginId) => pluginId,
40+owners: {
41+channels: new Map(),
42+channelConfigs: new Map(),
43+providers: new Map(),
44+modelCatalogProviders: new Map(),
45+cliBackends: new Map(),
46+setupProviders: new Map(),
47+commandAliases: new Map(),
48+contracts: new Map(),
49+},
50+metrics: {
51+registrySnapshotMs: 0,
52+manifestRegistryMs: 0,
53+ownerMapsMs: 0,
54+totalMs: 0,
55+indexPluginCount: 0,
56+manifestPluginCount: 0,
57+},
58+};
59+}
60+61+describe("current plugin metadata snapshot", () => {
62+it("returns the current snapshot only for matching config policy and workspace", () => {
63+const config = { plugins: { allow: ["demo"] } };
64+const snapshot = createSnapshot({ config, workspaceDir: "/workspace/a" });
65+setCurrentPluginMetadataSnapshot(snapshot, { config });
66+67+expect(getCurrentPluginMetadataSnapshot({ config, workspaceDir: "/workspace/a" })).toBe(
68+snapshot,
69+);
70+expect(getCurrentPluginMetadataSnapshot({ config })).toBe(snapshot);
71+expect(
72+getCurrentPluginMetadataSnapshot({
73+config: { plugins: { allow: ["other"] } },
74+workspaceDir: "/workspace/a",
75+}),
76+).toBeUndefined();
77+expect(
78+getCurrentPluginMetadataSnapshot({ config, workspaceDir: "/workspace/b" }),
79+).toBeUndefined();
80+});
81+82+it("rejects a current snapshot when plugin load paths change", () => {
83+const config = { plugins: { load: { paths: ["/plugins/one"] } } };
84+const snapshot = createSnapshot({ config });
85+setCurrentPluginMetadataSnapshot(snapshot, { config });
86+87+expect(getCurrentPluginMetadataSnapshot({ config })).toBe(snapshot);
88+expect(
89+getCurrentPluginMetadataSnapshot({
90+config: { plugins: { load: { paths: ["/plugins/two"] } } },
91+}),
92+).toBeUndefined();
93+});
94+95+it("clears the current snapshot", () => {
96+setCurrentPluginMetadataSnapshot(createSnapshot());
97+clearCurrentPluginMetadataSnapshot();
98+99+expect(getCurrentPluginMetadataSnapshot()).toBeUndefined();
100+});
101+102+it("clears the current snapshot when the persisted installed index changes", () => {
103+const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-metadata-"));
104+try {
105+setCurrentPluginMetadataSnapshot(createSnapshot());
106+107+writePersistedInstalledPluginIndexSync(createSnapshot().index, { stateDir: tempDir });
108+109+expect(getCurrentPluginMetadataSnapshot()).toBeUndefined();
110+} finally {
111+fs.rmSync(tempDir, { recursive: true, force: true });
112+}
113+});
114+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。