From 3d76c80da5b092459a17916eb7a5fdfb952e14dc Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Thu, 26 Mar 2026 16:28:01 -0400 Subject: [PATCH] test(core): validate external AbortSignal propagation through LocalSubagentSession The existing abort test mocked the executor to always reject, meaning it would pass even if the abort wiring was broken. Add a test that actually fires the caller's AbortSignal and asserts it propagates through the abortListener -> session.abort() -> internal AbortController -> executor chain. --- .../core/src/agents/local-invocation.test.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/core/src/agents/local-invocation.test.ts b/packages/core/src/agents/local-invocation.test.ts index e3a182284e..e0511b76e7 100644 --- a/packages/core/src/agents/local-invocation.test.ts +++ b/packages/core/src/agents/local-invocation.test.ts @@ -502,6 +502,46 @@ describe('LocalSubagentInvocation', () => { ); }); + it('external AbortSignal propagates through session to abort executor', async () => { + // This test validates the wiring: caller signal → abortListener → session.abort() + // → internal AbortController → executor's signal aborts. + // The previous test mocks the executor to always reject, so it would pass even + // if the abort wiring was broken. This test requires the signal to actually fire. + const controller = new AbortController(); + let executorSignal: AbortSignal | undefined; + + mockExecutorInstance.run.mockImplementation( + (_p: unknown, sig: AbortSignal) => { + executorSignal = sig; + return new Promise((_resolve, reject) => { + sig.addEventListener('abort', () => { + const err = new Error('AbortError'); + err.name = 'AbortError'; + reject(err); + }); + }); + }, + ); + + const executePromise = invocation.execute( + controller.signal, + updateOutput, + ); + + // Wait for the executor to start so executorSignal is populated + await vi.waitFor(() => { + expect(executorSignal).toBeDefined(); + }); + + expect(executorSignal!.aborted).toBe(false); + + // Fire the external signal — this must propagate through to abort the executor + controller.abort(); + + await expect(executePromise).rejects.toThrow(); + expect(executorSignal!.aborted).toBe(true); + }); + it('should throw an error and bubble cancellation when execution returns ABORTED', async () => { const mockOutput = { result: 'Cancelled by user',