fix(dap): reject and bound the unix socket connect on Linux
connectSocket captured only resolve from Promise.withResolvers and its error handler merely errored the stream, so a Bun.connect failure (ECONNREFUSED/ENOENT/EACCES on a stat-ready-but-dead socket) never settled the promise. The unbounded await in #spawnSocketUnix then hung the launch forever, and the surrounding kill/reap guard could not fire. Capture reject, track an opened flag, reject on error/close-before-open and on the Bun.connect promise rejection, and bound the connect with a timeout matching the launch deadline (cleared on settle). Thread timeoutMs from #spawnSocketUnix. Export connectSocket for a deterministic reject-path test. Fixes #4087
This commit is contained in:
@@ -4,7 +4,7 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import * as dapModule from "@oh-my-pi/pi-coding-agent/dap";
|
||||
import { DapClient, waitForTcpServerListening } from "@oh-my-pi/pi-coding-agent/dap/client";
|
||||
import { connectSocket, DapClient, waitForTcpServerListening } from "@oh-my-pi/pi-coding-agent/dap/client";
|
||||
import { DapSessionManager } from "@oh-my-pi/pi-coding-agent/dap/session";
|
||||
import type {
|
||||
DapCapabilities,
|
||||
@@ -487,6 +487,20 @@ describe("DAP launch failure handling", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("connectSocket unix transport", () => {
|
||||
it("rejects instead of hanging when the unix socket cannot be connected", async () => {
|
||||
// A path that stat would report as a socket but that no one listens on
|
||||
// yields ECONNREFUSED/ENOENT from Bun.connect. Before the fix the error
|
||||
// handler only errored the stream and the returned promise never settled,
|
||||
// so `await connectSocket(...)` hung the launch forever.
|
||||
const deadSocket = path.join(os.tmpdir(), `omp-dap-dead-${Date.now()}-${Math.random().toString(36).slice(2)}.sock`);
|
||||
const start = Date.now();
|
||||
await expect(connectSocket({ unix: deadSocket }, 5_000)).rejects.toThrow();
|
||||
// Must settle on the connect error, not linger until the timeout bound.
|
||||
expect(Date.now() - start).toBeLessThan(2_000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DAP TCP transport resilience", () => {
|
||||
const TCP_ADAPTER_BASE: DapResolvedAdapter = {
|
||||
...TEST_ADAPTER,
|
||||
|
||||
Reference in New Issue
Block a user