@@ -167,17 +167,29 @@ test.runIf(process.platform !== 'win32')(
167167//
168168// The kill paths below address a process group whose leader this worker already reaped, and
169169// the hermetic signal setup ends a worker's authority over a pid at that moment. So every
170- // group write is answered by `guardGroupWrites` below, which is the seam that setup points a
171- // real kill path at: it records what the kill aimed at and refuses to deliver it.
170+ // group write is answered by `guardGroupWrites` below, which is the seam that setup points a real
171+ // kill path at: it records what the kill aimed at and answers the way a real group would, either
172+ // a delivery nothing was reached for or the `ESRCH` a vanished group throws.
172173
173174type GroupWrite = { readonly pid : number ; readonly signal : string | number } ;
174175
175- function guardGroupWrites ( ) : { restore : ( ) => void ; writes : GroupWrite [ ] } {
176+ /** How a guarded group write answers, matching what a real group would do. */
177+ type GroupWriteAnswer = 'no-group-reached' | 'no-such-process' ;
178+
179+ function guardGroupWrites ( answer : GroupWriteAnswer = 'no-group-reached' ) : {
180+ restore : ( ) => void ;
181+ writes : GroupWrite [ ] ;
182+ } {
176183 const original = process . kill . bind ( process ) ;
177184 const writes : GroupWrite [ ] = [ ] ;
178185 process . kill = ( ( pid : number , signal : string | number = 'SIGTERM' ) => {
179186 if ( pid < 0 ) {
180187 writes . push ( { pid, signal } ) ;
188+ if ( answer === 'no-such-process' ) {
189+ const error = new Error ( 'no such process' ) as NodeJS . ErrnoException ;
190+ error . code = 'ESRCH' ;
191+ throw error ;
192+ }
181193 return false ;
182194 }
183195 return original ( pid , signal as NodeJS . Signals ) ;
@@ -200,17 +212,6 @@ test('group signaling addresses the negative pid and reports delivery', () => {
200212 }
201213} ) ;
202214
203- test ( 'a group write in this module can only come from the seam' , ( ) => {
204- // A second group-signal path in here would be the second seam the callers were written
205- // against once more, and nothing at runtime distinguishes the two.
206- const source = fs . readFileSync ( new URL ( './exec.ts' , import . meta. url ) , 'utf8' ) ;
207- const seam = source . indexOf ( 'export function signalProcessGroupBestEffort' ) ;
208- const writes = [ ...source . matchAll ( / p r o c e s s \. k i l l \( - / g) ] . map ( ( match ) => match . index ?? - 1 ) ;
209-
210- assert . ok ( seam >= 0 ) ;
211- assert . deepEqual ( writes , [ seam + source . slice ( seam ) . indexOf ( 'process.kill(-' ) ] ) ;
212- } ) ;
213-
214215test ( 'group signaling reports a vanished group and never signals an invalid pid' , ( ) => {
215216 const killSpy = vi . spyOn ( process , 'kill' ) . mockImplementation ( ( ) => {
216217 const error = new Error ( 'not found' ) as NodeJS . ErrnoException ;
@@ -263,10 +264,10 @@ test.runIf(process.platform !== 'win32')(
263264test . runIf ( process . platform !== 'win32' ) (
264265 'a detached deadline whose group cannot be signalled still settles' ,
265266 async ( ) => {
266- // A vanished group, an empty group, and a group owned by someone else all answer this
267- // write with nothing, and the seam swallows that . The command still cannot wait on a pipe
267+ // A vanished group answers the group write by throwing `ESRCH` , and a group owned by someone
268+ // else by throwing `EPERM`; the seam swallows both . The command still cannot wait on a pipe
268269 // holder it just asked to be killed.
269- const groupWrites = guardGroupWrites ( ) ;
270+ const groupWrites = guardGroupWrites ( 'no-such-process' ) ;
270271 try {
271272 const startedAt = Date . now ( ) ;
272273 await assert . rejects (
0 commit comments