From 559efcee28cd4ba4d631a7f4d7052de84c47b587 Mon Sep 17 00:00:00 2001 From: LiangshouX Date: Wed, 28 Oct 2026 19:25:49 +0800 Subject: [PATCH] test(dsh): pin the plugin lifetime that stops install jobs dispose() on the manager stops running installs, but nothing tied that to the plugin's own lifetime: a change to the registration could have left pip running after the plugin unloads. Mount the plugin, replace the provided manager's dispose with a counter, run the envLifetime cleanup and assert it is called once. --- integrations/dsh/tests/dsh-index.test.mjs | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/integrations/dsh/tests/dsh-index.test.mjs b/integrations/dsh/tests/dsh-index.test.mjs index 1e74147f..8877065f 100644 --- a/integrations/dsh/tests/dsh-index.test.mjs +++ b/integrations/dsh/tests/dsh-index.test.mjs @@ -261,3 +261,56 @@ function applyPlugin(t, ctx, input) { }); return apply(ctx, { ...input, autoMemoryQueueDir: directory }); } + +test("disposes the environment manager when the plugin unloads", async (t) => { + const effects = []; + const provided = {}; + const directory = mkdtempSync(join(tmpdir(), "reme-dsh-dispose-")); + t.after(async () => { + // Stop the runtime before removing the queue directory it reads on shutdown. + await provided.remeMemory?.disposeAll(); + rmSync(directory, { recursive: true, force: true }); + }); + const ctx = { + fiber: { state: 0 }, + logger: { debug() {}, warn() {}, log() {} }, + provide(name, value) { + provided[name] = value; + }, + plugin() { + return Promise.resolve(); + }, + inject() {}, + effect(execute, label) { + effects.push({ label, cleanup: execute() }); + return () => {}; + }, + tools: { + register() { + return () => {}; + }, + }, + on() {}, + }; + apply(ctx, { + autoMemoryEnabled: false, + autoDreamEnabled: false, + autoMemoryQueueDir: directory, + }); + + const manager = provided.remeEnv; + assert.ok(manager, "the environment manager is provided to the context"); + let disposed = 0; + manager.dispose = () => { + disposed += 1; + }; + + // The plugin owns the lifetime of the installs it started, so unloading it + // must reach the manager rather than leaving pip running. + const lifetime = effects.find( + (entry) => entry.label === "remeMemory.envLifetime()", + ); + assert.ok(lifetime?.cleanup, "the env lifetime effect registers a cleanup"); + lifetime.cleanup(); + assert.equal(disposed, 1); +});