From 2ac288f4d053eb8bc5ca37113c353c8ceed75593 Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2026 12:26:32 +0000 Subject: [PATCH] test(plugins): make global switch recovery deterministic (#8342) * test(plugins): trace recurring global recovery failure * test(plugins): control cleanup in global switch recovery --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> --- .../src/server/plugins/index.posix.test.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/server/src/server/plugins/index.posix.test.ts b/packages/server/src/server/plugins/index.posix.test.ts index c529bd37d3..1f8b3f124b 100644 --- a/packages/server/src/server/plugins/index.posix.test.ts +++ b/packages/server/src/server/plugins/index.posix.test.ts @@ -1071,9 +1071,38 @@ export default function contribute(plugin: unknown) { "second", `export default function contribute(plugin: unknown) { void plugin; return () => undefined; }`, ); + // Hold cleanup open so synchronous detach and queued recovery are tested + // independently of compiler/process startup speed on the runner. + let finishCleanup = () => undefined; + const cleanup = new Promise((resolve) => { + finishCleanup = resolve; + }); + const running = new Set(); + const runtime: TestPluginRuntime = { + ...emptyUsageRuntime, + catalog: () => [...running].map((id) => ({ id, clientBundle: "bundle" })), + invoke: async (pluginId) => { + if (!running.has(pluginId)) throw new Error(`Plugin is not available: ${pluginId}`); + return pluginId; + }, + getLogs: () => [], + clearLogs: () => undefined, + startPlugin: async (pluginId, _path, canPublish) => { + if (!canPublish()) throw new Error(`Plugin start cancelled: ${pluginId}`); + running.add(pluginId); + }, + stopPluginById: async (pluginId) => { + const existed = running.delete(pluginId); + await cleanup; + return existed; + }, + stopAll: async () => running.clear(), + subscribe: () => () => undefined, + bindPaseoSessionHost: () => undefined, + }; const store = createStore(home); const service = bindTestSessionHost( - new PluginService(pino({ level: "silent" }), store, "0.4.0"), + new PluginService(pino({ level: "silent" }), store, "0.4.0", { runtime }), ); try { await service.start(); @@ -1087,6 +1116,8 @@ export default function contribute(plugin: unknown) { "Plugin is not available", ); await store.patch({ pluginsEnabled: true }); + expect(service.catalog()).toEqual([]); + finishCleanup(); // Observe recovery itself. Reloading here restarts a healthy plugin and // would also conceal a failure to restart it after the global enable. await expect @@ -1096,6 +1127,7 @@ export default function contribute(plugin: unknown) { { id: "second", status: "running" }, ]); } finally { + finishCleanup(); await service.stopAllPlugins(); } }, 20_000);