Просмотр исходного кода

test(subagent): reap SDK startup before readiness fixture cleanup

_Kerman 1 месяц назад
Родитель
Сommit
404097f813
1 измененных файлов с 23 добавлено и 9 удалено
  1. 23 9
      packages/subagent/subagent-dsh-sdk/tests/subagent-dsh-sdk.spec.ts

+ 23 - 9
packages/subagent/subagent-dsh-sdk/tests/subagent-dsh-sdk.spec.ts

@@ -8,7 +8,7 @@
 
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { Context } from '@deepseek-ai/cordis'
-import { existsSync, mkdtempSync, rmSync } from 'node:fs'
+import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
 import { tmpdir } from 'node:os'
 import { join, relative } from 'node:path'
 import { fileURLToPath } from 'node:url'
@@ -113,9 +113,9 @@ function expectedFailure(fields: string): string {
 /**
  * Poll until `file` exists (the fake touches it once the probed state is
  * reached), so cancel tests wait on a CONDITION rather than an arbitrary
- * timeout. Fails loud if the child never signals readiness.
+ * timeout. The caller supplies the lane's effective test budget.
  */
-async function waitForFile(file: string, timeoutMs = 5000): Promise<void> {
+async function waitForFile(file: string, timeoutMs: number): Promise<void> {
   const deadline = Date.now() + timeoutMs
   while (!existsSync(file)) {
     if (Date.now() > deadline) throw new Error(`fake runtime never became ready (${file})`)
@@ -524,7 +524,7 @@ describe('dsh-subagent-dsh-sdk provider', () => {
     await ctx.fiber.dispose()
   })
 
-  it('cancelling between handshake and publish rejects start after reap', async () => {
+  it('cancelling between handshake and publish rejects start after reap', async ({ task }) => {
     // The abort lands while the child is INSIDE initialize (ready-file
     // handshake window): the fake touches READY, we abort, then GO lets the
     // handshake complete — so the post-race `flags.cancelled` recheck must
@@ -532,6 +532,8 @@ describe('dsh-subagent-dsh-sdk provider', () => {
     const tmp = mkdtempSync(join(tmpdir(), 'subagent-dsh-sdk-midcancel-'))
     const ready = join(tmp, 'ready')
     const go = join(tmp, 'go')
+    const createHarness = runInternals.createHarness.bind(runInternals)
+    runInternals.createHarness = options => createHarness({ ...options, initializeTimeoutMs: task.timeout })
     try {
       const controller = new AbortController()
       const spec: SdkRunSpec = {
@@ -547,12 +549,24 @@ describe('dsh-subagent-dsh-sdk provider', () => {
         disposeGraceMs: 200,
       }
       const pending = startSdkRun(request('p', controller.signal), spec)
-      await waitForFile(ready)
-      controller.abort('mid-handshake')
-      const { writeFileSync } = await import('node:fs')
-      writeFileSync(go, 'go\n')
-      await expect(pending).rejects.toThrow('aborted before the SDK child started')
+      // Observe failed startup while readiness is pending; rollback owns the child.
+      const settled = pending.then(
+        run => ({ kind: 'started' as const, run }),
+        (error: unknown) => ({ kind: 'failed' as const, error }),
+      )
+      try {
+        await waitForFile(ready, task.timeout)
+        controller.abort('mid-handshake')
+        writeFileSync(go, 'go\n')
+        await expect(pending).rejects.toThrow('aborted before the SDK child started')
+      } finally {
+        controller.abort('test cleanup')
+        writeFileSync(go, 'go\n')
+        const outcome = await settled
+        if (outcome.kind === 'started') await outcome.run.dispose()
+      }
     } finally {
+      runInternals.createHarness = createHarness
       rmSync(tmp, { recursive: true, force: true })
     }
   })