From c0106bd7fda4a3aa959beaf63e1ac99ae891971a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Andr=C3=A9?= Date: Fri, 4 Sep 2026 14:24:32 +0200 Subject: [PATCH] test(opencode): isolate automation registry cross-platform Configure both LOCALAPPDATA and XDG_RUNTIME_DIR for automation bridge tests so each platform resolves its registry inside the test-owned temporary directory. Temporarily clear WSL discovery as well to prevent a Linux test run from reading the host Windows registry. Use the production directory resolver for assertions instead of hard-coding the Windows registry layout. This fixes the deterministic Linux CI failure introduced with the V2 migration while keeping production behavior unchanged. Validate the complete 378-test server suite and the server TypeScript typecheck. --- .../src/opencode/automation-plugin.test.ts | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/server/src/opencode/automation-plugin.test.ts b/packages/server/src/opencode/automation-plugin.test.ts index 8dbc2b76c..969367a37 100644 --- a/packages/server/src/opencode/automation-plugin.test.ts +++ b/packages/server/src/opencode/automation-plugin.test.ts @@ -6,6 +6,7 @@ import path from "node:path" import test from "node:test" import { AUTOMATION_BRIDGE_PATH, + automationBridgeDirectory, automationBridgeDirectories, createAutomationBridgeRegistration, parseDeveloperAction, @@ -50,6 +51,27 @@ function closeServer(server: http.Server | undefined): Promise { return new Promise((resolve) => server?.close(() => resolve()) ?? resolve()) } +function isolateAutomationRegistry(root: string): { directory: string; restore: () => void } { + const previousLocalAppData = process.env.LOCALAPPDATA + const previousXdgRuntimeDir = process.env.XDG_RUNTIME_DIR + const previousWslDistroName = process.env.WSL_DISTRO_NAME + process.env.LOCALAPPDATA = root + process.env.XDG_RUNTIME_DIR = root + delete process.env.WSL_DISTRO_NAME + + return { + directory: automationBridgeDirectory(), + restore: () => { + if (previousLocalAppData === undefined) delete process.env.LOCALAPPDATA + else process.env.LOCALAPPDATA = previousLocalAppData + if (previousXdgRuntimeDir === undefined) delete process.env.XDG_RUNTIME_DIR + else process.env.XDG_RUNTIME_DIR = previousXdgRuntimeDir + if (previousWslDistroName === undefined) delete process.env.WSL_DISTRO_NAME + else process.env.WSL_DISTRO_NAME = previousWslDistroName + }, + } +} + test("validates Developer Mode actions", () => { assert.deepEqual(parseDeveloperAction({ action: "type", ref: "e4", text: "CodeNomad" }), { action: "type", @@ -100,8 +122,7 @@ test("removes only the generated legacy global plugin shim", async () => { test("restart waits for a new native generation and returns a fresh inspection", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "codenomad-automation-restart-")) - const previousLocalAppData = process.env.LOCALAPPDATA - process.env.LOCALAPPDATA = root + const registry = isolateAutomationRegistry(root) const definitions: ToolDefinition[] = [] let removeOld: (() => Promise) | undefined let removeNew: (() => Promise) | undefined @@ -162,16 +183,14 @@ test("restart waits for a new native generation and returns a fresh inspection", await closeServer(newServer) await closeServer(preexistingServer) await Promise.all(distractorServers.map(closeServer)) - if (previousLocalAppData === undefined) delete process.env.LOCALAPPDATA - else process.env.LOCALAPPDATA = previousLocalAppData + registry.restore() await rm(root, { recursive: true, force: true }) } }) test("keeps inspected targets isolated per plugin setup", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "codenomad-automation-isolation-")) - const previousLocalAppData = process.env.LOCALAPPDATA - process.env.LOCALAPPDATA = root + const registry = isolateAutomationRegistry(root) let removeBridge: (() => Promise) | undefined let server: http.Server | undefined try { @@ -190,16 +209,14 @@ test("keeps inspected targets isolated per plugin setup", async () => { } finally { await removeBridge?.() await closeServer(server) - if (previousLocalAppData === undefined) delete process.env.LOCALAPPDATA - else process.env.LOCALAPPDATA = previousLocalAppData + registry.restore() await rm(root, { recursive: true, force: true }) } }) test("pins parallel sessions to their independently inspected bridges", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "codenomad-automation-sessions-")) - const previousLocalAppData = process.env.LOCALAPPDATA - process.env.LOCALAPPDATA = root + const registry = isolateAutomationRegistry(root) const removals: Array<() => Promise> = [] const servers: http.Server[] = [] try { @@ -220,16 +237,14 @@ test("pins parallel sessions to their independently inspected bridges", async () } finally { await Promise.all(removals.map((remove) => remove())) await Promise.all(servers.map(closeServer)) - if (previousLocalAppData === undefined) delete process.env.LOCALAPPDATA - else process.env.LOCALAPPDATA = previousLocalAppData + registry.restore() await rm(root, { recursive: true, force: true }) } }) test("prunes stale registry pressure before limiting discovery", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "codenomad-automation-stale-")) - const previousLocalAppData = process.env.LOCALAPPDATA - process.env.LOCALAPPDATA = root + const registry = isolateAutomationRegistry(root) let removeBridge: (() => Promise) | undefined let server: http.Server | undefined try { @@ -238,7 +253,7 @@ test("prunes stale registry pressure before limiting discovery", async () => { : { result: { target: { id: "live", title: "Live", url: "http://app.test" }, nodes: [], diagnostics: [] } }) server = bridge.server removeBridge = await publishAutomationBridge(createAutomationBridgeRegistration(bridge.url)) - const directory = path.join(root, "CodeNomad", "automation-bridges") + const directory = registry.directory const base = Date.now() + 10_000 for (let index = 0; index < 70; index += 1) { const startedAt = base + index @@ -257,8 +272,7 @@ test("prunes stale registry pressure before limiting discovery", async () => { } finally { await removeBridge?.() await closeServer(server) - if (previousLocalAppData === undefined) delete process.env.LOCALAPPDATA - else process.env.LOCALAPPDATA = previousLocalAppData + registry.restore() await rm(root, { recursive: true, force: true }) } })