diff --git a/smoke/run.test.ts b/smoke/run.test.ts index d9b6c7274..7a46ec00e 100644 --- a/smoke/run.test.ts +++ b/smoke/run.test.ts @@ -128,12 +128,14 @@ let server: Server | null = null; let disconnect: (() => void) | null = null; let base = ""; -afterEach(() => { +afterEach(async () => { // As switching projects does: run ids restart with each server. resetRuns(); disconnect?.(); - server?.close(); - if (base) rmSync(base, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 }); + await server?.close(); + // A language server's own process (jdtls's JVM) can outlive the server's for a moment: + // deleting its data directory has to wait for it. + if (base) rmSync(base, { recursive: true, force: true, maxRetries: 10, retryDelay: 1000 }); }); async function open(c: Case): Promise { diff --git a/smoke/server.ts b/smoke/server.ts index 241e8130a..af387c384 100644 --- a/smoke/server.ts +++ b/smoke/server.ts @@ -78,9 +78,14 @@ export class Server { } } - close() { - this.child.stdin.end(); - this.child.kill(); + /** Kills the server; resolves once the process is gone (its children may still be exiting). */ + async close(): Promise { + if (this.child.exitCode === null && !this.child.killed) { + const exited = new Promise((resolve) => this.child.once("exit", () => resolve())); + this.child.stdin.end(); + this.child.kill(); + await exited; + } } private request(method: string, params: unknown): Promise {