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.
This commit is contained in:
Pascal André 2026-09-04 14:24:32 +02:00
parent 52f0e62935
commit c0106bd7fd
No known key found for this signature in database

View file

@ -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<void> {
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<void>) | undefined
let removeNew: (() => Promise<void>) | 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<void>) | 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<void>> = []
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<void>) | 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 })
}
})