test(windows): cover teardown decisions deterministically

This commit is contained in:
Tianyi Cui
2026-07-22 14:34:26 +08:00
parent 5da343126c
commit 7b6b544243
5 changed files with 54 additions and 11 deletions
@@ -5,6 +5,7 @@ import {
signalProcessGroup,
signalProcessTree,
taskkillProcessTree,
waitForTreeExit,
} from '@deepseek-ai/dsh-lsp-local/src/connection.ts'
import type {
ConnectionWriter,
@@ -248,6 +249,19 @@ describe('process-tree signaling', () => {
expect(run).toHaveBeenCalledWith(-42, 'SIGKILL')
})
it('waits for tree exit and stops when its bound aborts', async () => {
const isAlive = vi.fn()
.mockReturnValueOnce(true)
.mockReturnValue(false)
const yieldNow = vi.fn(() => Promise.resolve())
await expect(waitForTreeExit(isAlive, undefined, yieldNow)).resolves.toBe(true)
expect(yieldNow).toHaveBeenCalledOnce()
const controller = new AbortController()
controller.abort()
await expect(waitForTreeExit(() => true, controller.signal, yieldNow)).resolves.toBe(false)
})
it('uses taskkill for a Windows tree and a negative pid for a POSIX group', () => {
const operations = fakeProcessTreeOperations()
signalProcessTree('win32', 42, 'SIGTERM', operations)
+10 -1
View File
@@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { mkdtemp, mkdir, readFile, rm, writeFile, realpath } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
@@ -6,6 +6,7 @@ import { pathToFileURL, fileURLToPath } from 'node:url'
import { LspInstance, readHostSource } from '@deepseek-ai/dsh-lsp-local'
import { encodeMessage } from '@deepseek-ai/dsh-lsp-local'
import type { ConnectionWriter } from '@deepseek-ai/dsh-lsp-local/src/connection.ts'
import { escalateProcessTree } from '@deepseek-ai/dsh-lsp-local/src/instance.ts'
import type { InstanceSpec } from '@deepseek-ai/dsh-lsp-local/src/instance.ts'
import type { LspProviderQuery, LspQueryResult } from '@deepseek-ai/dsh-lsp'
@@ -242,6 +243,14 @@ describe('LspInstance query and abort', () => {
})
describe('LspInstance disposal', () => {
it('escalates only when the process tree survives its grace period', () => {
const forceKill = vi.fn()
escalateProcessTree(false, forceKill)
expect(forceKill).toHaveBeenCalledOnce()
escalateProcessTree(true, forceKill)
expect(forceKill).toHaveBeenCalledOnce()
})
it('lets a server finish protocol exit before signal escalation', async () => {
const marker = join(root, 'graceful-exit.log')
const instance = makeInstance({