fix(watcher): stabilize daemon readiness and tests
This commit is contained in:
@@ -104,7 +104,7 @@ async function getOrCreateEntry(
|
|||||||
entries.delete(key);
|
entries.delete(key);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
attachWatcher(entry);
|
await attachWatcher(entry);
|
||||||
bumpIdle(entry);
|
bumpIdle(entry);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ async function getOrCreateEntry(
|
|||||||
// The first non-empty registration lazily creates the WorkspaceWatcher;
|
// The first non-empty registration lazily creates the WorkspaceWatcher;
|
||||||
// subsequent register/unregister calls update its pattern set in place.
|
// subsequent register/unregister calls update its pattern set in place.
|
||||||
// Honors PI_LSP_DISABLE_WATCHERS for emergency rollback.
|
// Honors PI_LSP_DISABLE_WATCHERS for emergency rollback.
|
||||||
function attachWatcher(entry: ClientEntry): void {
|
async function attachWatcher(entry: ClientEntry): Promise<void> {
|
||||||
if (process.env.PI_LSP_DISABLE_WATCHERS) return;
|
if (process.env.PI_LSP_DISABLE_WATCHERS) return;
|
||||||
const sync = () => {
|
const sync = async () => {
|
||||||
const patterns = entry.client.getFileWatchers();
|
const patterns = entry.client.getFileWatchers();
|
||||||
if (patterns.length === 0 && !entry.watcher) return;
|
if (patterns.length === 0 && !entry.watcher) return;
|
||||||
if (!entry.watcher) {
|
if (!entry.watcher) {
|
||||||
@@ -128,11 +128,13 @@ function attachWatcher(entry: ClientEntry): void {
|
|||||||
log(`watcher patterns`, entry.server.id, JSON.stringify(patterns));
|
log(`watcher patterns`, entry.server.id, JSON.stringify(patterns));
|
||||||
}
|
}
|
||||||
entry.watcher.setPatterns(patterns);
|
entry.watcher.setPatterns(patterns);
|
||||||
|
if (patterns.length > 0) await entry.watcher.ready();
|
||||||
};
|
};
|
||||||
entry.unsubscribeWatchers = entry.client.onWatchersChanged(sync);
|
entry.unsubscribeWatchers = entry.client.onWatchersChanged(() => void sync());
|
||||||
// Initial Sync - Server may have already sent registerCapability during
|
// Initial Sync - Server may have already sent registerCapability during
|
||||||
// initialize before we subscribed.
|
// initialize before we subscribed. Wait for chokidar's initial scan so
|
||||||
sync();
|
// externally-created files are not swallowed as ignoreInitial events.
|
||||||
|
await sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward Events - Sends a batched workspace/didChangeWatchedFiles to the
|
// Forward Events - Sends a batched workspace/didChangeWatchedFiles to the
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ export const tsx = path.resolve(
|
|||||||
"cli.mjs",
|
"cli.mjs",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Unique Test Socket — each test run gets its own Unix socket so we don't
|
// Unique Test Socket — each suite gets its own Unix socket so parallel
|
||||||
// touch any real session daemon.
|
// integration tests don't race through the same daemon.
|
||||||
export function testSocket(): string {
|
export function testSocket(): string {
|
||||||
return path.join(os.tmpdir(), `pi-lsp-test-${process.pid}.sock`);
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lsp-test-"));
|
||||||
|
return path.join(dir, "daemon.sock");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Test Socket — sets PI_LSP_SOCKET_PATH for the current process and
|
// Set Test Socket — sets PI_LSP_SOCKET_PATH for the current process and
|
||||||
@@ -39,7 +40,7 @@ export function setTestSocket(env: Record<string, string | undefined>): () => vo
|
|||||||
return () => {
|
return () => {
|
||||||
delete env.PI_LSP_SOCKET_PATH;
|
delete env.PI_LSP_SOCKET_PATH;
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(sock);
|
fs.rmSync(path.dirname(sock), { recursive: true, force: true });
|
||||||
} catch {
|
} catch {
|
||||||
// Socket may not exist — that's fine.
|
// Socket may not exist — that's fine.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ describe("cli daemon lifecycle", () => {
|
|||||||
const env = { ...process.env };
|
const env = { ...process.env };
|
||||||
let cleanup: () => void;
|
let cleanup: () => void;
|
||||||
|
|
||||||
before(() => {
|
before(async () => {
|
||||||
cleanup = setTestSocket(env);
|
cleanup = setTestSocket(env);
|
||||||
// Stop any stale daemon on this socket before tests run.
|
// Stop any stale daemon on this socket before tests run.
|
||||||
stopTestDaemon(env);
|
await stopTestDaemon(env);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => {
|
after(async () => {
|
||||||
// Tear down daemon and clean up socket after all tests.
|
// Tear down daemon and clean up socket after all tests.
|
||||||
stopTestDaemon(env);
|
await stopTestDaemon(env);
|
||||||
cleanup();
|
cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user