package subprocess import ( "errors" "os/exec" "testing" ) func TestTerminateAndReapPreservesWaitAndCleanupErrors(t *testing.T) { waitErr := errors.New("wait failed") gracefulErr := errors.New("graceful termination failed") forcefulErr := errors.New("forceful termination failed") tree := &recordingProcessTree{ gracefulErr: gracefulErr, forcefulErr: forcefulErr, } waitCh := make(chan error, 1) waitCh <- waitErr gotWaitErr, gotCleanupErr := terminateAndReap(tree, waitCh) if !errors.Is(gotWaitErr, waitErr) { t.Fatalf("wait error = %v, want %v", gotWaitErr, waitErr) } for _, want := range []error{gracefulErr, forcefulErr} { if !errors.Is(gotCleanupErr, want) { t.Fatalf("cleanup error = %v, want wrapped %v", gotCleanupErr, want) } } if tree.gracefulCalls != 1 || tree.forcefulCalls != 1 { t.Fatalf("termination calls = graceful %d, forceful %d; want 1 each", tree.gracefulCalls, tree.forcefulCalls) } } type recordingProcessTree struct { gracefulErr error forcefulErr error gracefulCalls int forcefulCalls int } func (*recordingProcessTree) Start(*exec.Cmd) error { return nil } func (tree *recordingProcessTree) TerminateGracefully() error { tree.gracefulCalls++ return tree.gracefulErr } func (tree *recordingProcessTree) TerminateForcefully() error { tree.forcefulCalls++ return tree.forcefulErr } func (*recordingProcessTree) Dispose() error { return nil }