




























@@ -2,6 +2,7 @@ import { describe, expect, it, vi } from "vitest";
22import type { OpenClawConfig } from "../config/types.openclaw.js";
33import {
44PluginLruCache,
5+createConfigScopedPromiseLoader,
56resolveConfigScopedRuntimeCacheValue,
67type ConfigScopedRuntimeCache,
78} from "./plugin-cache-primitives.js";
@@ -84,3 +85,64 @@ describe("resolveConfigScopedRuntimeCacheValue", () => {
8485expect(load).toHaveBeenCalledOnce();
8586});
8687});
88+89+describe("createConfigScopedPromiseLoader", () => {
90+it("dedupes concurrent default loads", async () => {
91+let calls = 0;
92+const loader = createConfigScopedPromiseLoader(async () => `loaded-${++calls}`);
93+94+await expect(Promise.all([loader.load(), loader.load()])).resolves.toEqual([
95+"loaded-1",
96+"loaded-1",
97+]);
98+await expect(loader.load()).resolves.toBe("loaded-1");
99+expect(calls).toBe(1);
100+});
101+102+it("caches loads by config object", async () => {
103+const firstConfig = { plugins: { load: { disabled: true } } } as OpenClawConfig;
104+const secondConfig = { plugins: { load: { disabled: false } } } as OpenClawConfig;
105+const load = vi.fn(async (config?: OpenClawConfig) =>
106+config === firstConfig ? "first" : "second",
107+);
108+const loader = createConfigScopedPromiseLoader(load);
109+110+await expect(loader.load(firstConfig)).resolves.toBe("first");
111+await expect(loader.load(firstConfig)).resolves.toBe("first");
112+await expect(loader.load(secondConfig)).resolves.toBe("second");
113+114+expect(load).toHaveBeenCalledTimes(2);
115+});
116+117+it("evicts rejected loads so retries can recover", async () => {
118+const config = {} as OpenClawConfig;
119+let calls = 0;
120+const loader = createConfigScopedPromiseLoader(async () => {
121+calls += 1;
122+if (calls === 1) {
123+throw new Error("transient");
124+}
125+return "recovered";
126+});
127+128+await expect(loader.load(config)).rejects.toThrow("transient");
129+await expect(loader.load(config)).resolves.toBe("recovered");
130+expect(calls).toBe(2);
131+});
132+133+it("clears default and config-scoped entries", async () => {
134+const config = {} as OpenClawConfig;
135+let calls = 0;
136+const loader = createConfigScopedPromiseLoader(
137+async (owner?: OpenClawConfig) => `${owner ? "config" : "default"}-${++calls}`,
138+);
139+140+await expect(loader.load()).resolves.toBe("default-1");
141+await expect(loader.load(config)).resolves.toBe("config-2");
142+143+loader.clear();
144+145+await expect(loader.load()).resolves.toBe("default-3");
146+await expect(loader.load(config)).resolves.toBe("config-4");
147+});
148+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。