opencode/packages/desktop/src/main/wsl/servers.test.ts
James Long 8c94e9005f
chore: merge dev into v2 (#34788)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com>
Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ben Guthrie <benjee.012@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Max Anderson <max.a.anderson95@gmail.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
2026-07-01 17:12:00 -04:00

231 lines
7.5 KiB
TypeScript

import { expect, test } from "bun:test"
import {
clearWslDistroState,
requireWslIpcString,
requireWslIpcStrings,
wslServerIdToRestart,
wslTerminalArgs,
} from "./policy"
import {
expectOpencodeVersion,
pendingRestartAfterWslInstall,
pollWslHealth,
wslServerIdsToStartOnInitialize,
} from "./startup"
import { createWslServersController, type WslServerConfig } from "./servers"
let persistedServers: WslServerConfig[] = []
let releaseOpencodeResolve: (() => void) | undefined
test("starts every configured WSL server on initialization", () => {
expect(
wslServerIdsToStartOnInitialize([
{ id: "wsl:Debian", distro: "Debian" },
{ id: "wsl:Ubuntu-24.04", distro: "Ubuntu-24.04" },
]),
).toEqual(["wsl:Debian", "wsl:Ubuntu-24.04"])
})
test("rejects an update that did not install the desktop version", () => {
expect(() => expectOpencodeVersion("1.16.2", "1.16.2")).not.toThrow()
expect(() => expectOpencodeVersion("1.14.35", "1.16.2")).toThrow(
"OpenCode update finished but Debian still reports 1.14.35; expected 1.16.2",
)
})
test("restarts an existing distro server after updating OpenCode", () => {
expect(
wslServerIdToRestart(
[
{
config: { id: "wsl:Debian", distro: "Debian" },
runtime: { kind: "ready", url: "", username: null, password: null },
},
],
"Debian",
),
).toBe("wsl:Debian")
expect(wslServerIdToRestart([], "Debian")).toBeUndefined()
})
test("clears cached distro probes when removing a WSL server", () => {
expect(
clearWslDistroState(
{ Debian: { name: "Debian", canExecute: true, hasBash: true, hasCurl: true, error: null } },
{
Debian: {
distro: "Debian",
resolvedPath: "/home/luke/.opencode/bin/opencode",
version: "1.16.2",
expectedVersion: "1.16.2",
matchesDesktop: true,
error: null,
},
},
"Debian",
),
).toEqual({ distroProbes: {}, opencodeChecks: {} })
})
test("opens terminals for distro names containing spaces", () => {
expect(wslTerminalArgs("Ubuntu Preview")).toEqual(["/c", "start", "", "wsl", "-d", "Ubuntu Preview"])
})
test("stops health polling when sidecar startup settles", async () => {
const abort = new AbortController()
let checks = 0
const polling = pollWslHealth(
async () => {
checks++
return false
},
abort.signal,
1,
)
await new Promise((resolve) => setTimeout(resolve, 5))
abort.abort()
await polling
const settled = checks
await new Promise((resolve) => setTimeout(resolve, 5))
expect(checks).toBe(settled)
})
test("validates WSL IPC identifiers at the module boundary", () => {
expect(requireWslIpcString("distro", "Debian")).toBe("Debian")
expect(requireWslIpcStrings("distro", ["Debian", "Ubuntu"])).toEqual(["Debian", "Ubuntu"])
expect(() => requireWslIpcString("distro", "")).toThrow("Invalid distro")
expect(() => requireWslIpcString("server id", undefined)).toThrow("Invalid server id")
expect(() => requireWslIpcStrings("distro", [])).toThrow("Invalid distro")
})
test("derives a required Windows restart from the post-install runtime probe", () => {
expect(pendingRestartAfterWslInstall({ available: false, version: null, error: "WSL unavailable" })).toBe(true)
expect(pendingRestartAfterWslInstall({ available: true, version: "WSL version: 2.6.1", error: null })).toBe(false)
})
test("ignores stale background OpenCode checks after removing a WSL server", async () => {
persistedServers = []
releaseOpencodeResolve = undefined
const controller = createWslServersController(
"1.16.2",
async () => ({
listener: {
stop: () => undefined,
onExit: () => undefined,
},
url: "http://127.0.0.1:4096",
username: "opencode",
password: "secret",
}),
testControllerOptions(),
)
await controller.addServer("Debian")
await waitFor(() => !!releaseOpencodeResolve)
await controller.removeServer("wsl:Debian")
releaseOpencodeResolve?.()
await new Promise((resolve) => setTimeout(resolve, 0))
expect(controller.getState().servers).toEqual([])
expect(controller.getState().opencodeChecks).toEqual({})
})
test("ignores stale startup OpenCode checks after removing a WSL server", async () => {
persistedServers = [{ id: "wsl:Debian", distro: "Debian" }]
releaseOpencodeResolve = undefined
const controller = createWslServersController(
"1.16.2",
async () => new Promise<never>(() => undefined),
testControllerOptions(),
)
await controller.initialize()
await waitFor(() => !!releaseOpencodeResolve)
await controller.removeServer("wsl:Debian")
releaseOpencodeResolve?.()
await new Promise((resolve) => setTimeout(resolve, 0))
expect(controller.getState().servers).toEqual([])
expect(controller.getState().opencodeChecks).toEqual({})
})
test("probes addable distros in parallel before checking OpenCode", async () => {
persistedServers = []
const started: string[] = []
const release = new Map<string, () => void>()
const opencode: string[] = []
const controller = createWslServersController("1.16.2", async () => new Promise<never>(() => undefined), {
...testControllerOptions(),
probeDistro: async (distro) => {
started.push(distro)
await new Promise<void>((resolve) => release.set(distro, resolve))
return { name: distro, canExecute: true, hasBash: true, hasCurl: true, error: null }
},
resolveOpencode: async (distro) => {
opencode.push(distro)
return "/home/me/.opencode/bin/opencode"
},
})
const task = controller.probeAddable(["Debian", "Ubuntu"])
await waitFor(() => started.length === 2)
expect(started).toEqual(["Debian", "Ubuntu"])
expect(opencode).toEqual([])
release.get("Debian")?.()
release.get("Ubuntu")?.()
await task
expect(Object.keys(controller.getState().distroProbes)).toEqual(["Debian", "Ubuntu"])
expect(opencode).toEqual(["Debian", "Ubuntu"])
expect(Object.keys(controller.getState().opencodeChecks)).toEqual(["Debian", "Ubuntu"])
})
test("does not check OpenCode in addable distros that cannot execute commands", async () => {
persistedServers = []
const opencode: string[] = []
const controller = createWslServersController("1.16.2", async () => new Promise<never>(() => undefined), {
...testControllerOptions(),
probeDistro: async (distro) => ({
name: distro,
canExecute: distro === "Debian",
hasBash: distro === "Debian",
hasCurl: distro === "Debian",
error: distro === "Debian" ? null : "Open Ubuntu once to finish setup",
}),
resolveOpencode: async (distro) => {
opencode.push(distro)
return "/home/me/.opencode/bin/opencode"
},
})
await controller.probeAddable(["Debian", "Ubuntu"])
expect(Object.keys(controller.getState().distroProbes)).toEqual(["Debian", "Ubuntu"])
expect(opencode).toEqual(["Debian"])
expect(Object.keys(controller.getState().opencodeChecks)).toEqual(["Debian"])
})
async function waitFor(check: () => boolean) {
for (let attempt = 0; attempt < 20; attempt++) {
if (check()) return
await new Promise((resolve) => setTimeout(resolve, 0))
}
throw new Error("Timed out waiting for condition")
}
function testControllerOptions() {
return {
readServers: () => persistedServers,
writeServers: (servers: WslServerConfig[]) => {
persistedServers = servers
},
readCommandVersion: async () => "1.16.2",
resolveOpencode: async () => {
await new Promise<void>((resolve) => {
releaseOpencodeResolve = resolve
})
return "/home/me/.opencode/bin/opencode"
},
}
}