Przeglądaj źródła

test(subagent): address continuation cleanup review

- Keep cleaning remaining roots even if one cleanup rejects.
- Collapse the duplicated Windows-EPERM rationale to one comment.
- Dispose the cold-resume context's second JsonlSessionPersistence handle on
  the shared root before afterEach removes it.
Chinesezjc 1 miesiąc temu
rodzic
commit
674b3d8afd
1 zmienionych plików z 11 dodań i 10 usunięć
  1. 11 10
      packages/subagent/subagent/tests/continuation.spec.ts

+ 11 - 10
packages/subagent/subagent/tests/continuation.spec.ts

@@ -51,14 +51,14 @@ class GatedAdapter extends LlmAdapter {
   }
 }
 
-// Each persistence-backed temp root has a cleanup that closes its handle before
-// removing the directory. On Windows, rmSync over a directory containing a file
-// whose handle is still open fails with EPERM (the intermittent continuation /
-// skill-filesystem native flakes); jsonl.spec.ts closes the persistence fiber
-// first. Keeping each root's dispose+delete in one closure preserves that order.
+// Each persistence-backed temp root cleans up by closing its handle before
+// removing the directory (Windows rmSync over a dir holding a still-open handle
+// fails with EPERM — the intermittent continuation native flake).
 const cleanups: Array<() => Promise<void>> = []
 afterEach(async () => {
-  for (const cleanup of cleanups.splice(0)) await cleanup()
+  for (const cleanup of cleanups.splice(0)) {
+    try { await cleanup() } catch { /* keep cleaning the rest regardless */ }
+  }
 })
 
 /** Boot the full continuable stack: loop, persistence, providers, and subagents. */
@@ -72,8 +72,6 @@ async function setupWith(adapter: LlmAdapter, options: { persistence?: boolean }
     const persistedRoot = root
     const persistenceFiber = await ctx.plugin(JsonlSessionPersistence, { root })
     disposePersistence = () => persistenceFiber.dispose()
-    // Close the handle first, then delete: on Windows rmSync over a dir holding
-    // a still-open handle EPERMs. Mirrors jsonl.spec.ts.
     cleanups.push(async () => {
       await persistenceFiber.dispose()
       rmSync(persistedRoot, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 })
@@ -415,7 +413,7 @@ describe('SubagentRuntime.startContinuable', () => {
 
     const fresh = new Context()
     await mountAgentLoopTestDependencies(fresh)
-    await fresh.plugin(JsonlSessionPersistence, { root: root! })
+    const freshPersistence = await fresh.plugin(JsonlSessionPersistence, { root: root! })
     await fresh.plugin(AgentLoop, { agents: [] })
     await fresh.plugin(SubagentRuntime)
     await fresh.plugin(SubagentSpawn, { providerName: 'spawn' })
@@ -430,6 +428,10 @@ describe('SubagentRuntime.startContinuable', () => {
     expect(resumed.options.provider).toBeUndefined()
     expect(resumed.options.model).toBeUndefined()
     await drainManager(fresh)
+    // This context opened a second JsonlSessionPersistence handle on the same
+    // root; close it before the shared afterEach removes the root, so Windows
+    // rmSync does not hit a still-open handle.
+    await freshPersistence.dispose()
   })
 
   it('continues turn numbering after an inherited fork prefix and pre-turn descriptor', async () => {
@@ -2444,7 +2446,6 @@ describe('continuable errors', () => {
     await mountAgentLoopTestDependencies(ctx)
     const root = mkdtempSync(join(tmpdir(), 'dsh-subagent-continuation-'))
     const persistenceFiber = await ctx.plugin(JsonlSessionPersistence, { root })
-    // Close the handle before deleting (Windows EPERM on held handles).
     cleanups.push(async () => {
       await persistenceFiber.dispose()
       rmSync(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 })