fix(auth): close cancellation and workspace races

This commit is contained in:
2026-08-17 19:32:03 +02:00
parent d12b629420
commit 0a2c667231
10 changed files with 822 additions and 221 deletions
@@ -2,88 +2,80 @@ package compose
import (
"errors"
"os"
"testing"
"time"
)
func TestWindowsCancellationTreatsProcessReapedBeforeTreeTerminationAsSuccess(t *testing.T) {
func TestTerminationKillsTheTreeEvenWhenTheDirectChildIsAlreadyReaped(t *testing.T) {
done := make(chan error, 1)
done <- nil
treeFailure := errors.New("tree termination failed")
treeCalls := 0
directCalls := 0
err := terminateWindowsProcess(done, func() error {
err := terminateProcessTree(done, func() error {
treeCalls++
return errors.New("tree termination should not run")
return treeFailure
}, func() error {
directCalls++
return errors.New("direct termination should not run")
}, 0)
return os.ErrProcessDone
}, time.Second)
if err != nil {
t.Fatalf("terminateWindowsProcess() error = %v, want nil", err)
if treeCalls != 1 {
t.Fatalf("tree termination calls = %d, want 1", treeCalls)
}
if treeCalls != 0 || directCalls != 0 {
t.Fatalf("termination calls = tree:%d direct:%d, want none", treeCalls, directCalls)
if directCalls != 1 {
t.Fatalf("direct termination calls = %d, want 1 fallback after tree failure", directCalls)
}
if !errors.Is(err, treeFailure) || !errors.Is(err, ErrProcessReap) {
t.Fatalf("terminateProcessTree() error = %v, want tree failure and ErrProcessReap", err)
}
if errors.Is(err, os.ErrProcessDone) {
t.Fatalf("terminateProcessTree() error = %v, must treat an already-reaped direct child as benign", err)
}
}
func TestWindowsCancellationTreatsProcessReapedAfterTreeTerminationAsSuccess(t *testing.T) {
func TestTerminationWaitsForTheOriginalProcessAfterTreeTermination(t *testing.T) {
done := make(chan error, 1)
done <- nil
directCalls := 0
err := terminateWindowsProcess(done, func() error {
done <- nil
return ErrProcessReap
}, func() error {
err := terminateProcessTree(done, func() error { return nil }, func() error {
directCalls++
return errors.New("direct termination should not run")
}, 0)
return errors.New("direct fallback should not run after a successful tree termination")
}, time.Second)
if err != nil {
t.Fatalf("terminateWindowsProcess() error = %v, want nil", err)
t.Fatalf("terminateProcessTree() error = %v, want nil", err)
}
if directCalls != 0 {
t.Fatalf("direct termination calls = %d, want 0", directCalls)
}
}
func TestWindowsCancellationTreatsProcessReapedAfterDirectTerminationAsSuccess(t *testing.T) {
done := make(chan error, 1)
directCalls := 0
func TestTerminationJoinsTreeDirectAndReapFailures(t *testing.T) {
done := make(chan error)
treeFailure := errors.New("tree termination failed")
directFailure := errors.New("direct termination failed")
err := terminateWindowsProcess(done, func() error {
return ErrProcessReap
}, func() error {
directCalls++
done <- nil
return ErrProcessReap
}, 0)
err := terminateProcessTree(done, func() error { return treeFailure }, func() error { return directFailure }, 0)
if err != nil {
t.Fatalf("terminateWindowsProcess() error = %v, want nil", err)
}
if directCalls != 1 {
t.Fatalf("direct termination calls = %d, want 1", directCalls)
for _, want := range []error{treeFailure, directFailure, ErrProcessReap} {
if !errors.Is(err, want) {
t.Fatalf("terminateProcessTree() error = %v, want %v", err, want)
}
}
}
func TestWindowsCancellationReportsReapFailureWhenProcessSurvives(t *testing.T) {
func TestTerminationReportsReapFailureWhenTheTreeTerminatesButTheProcessNeverReaps(t *testing.T) {
done := make(chan error)
treeCalls := 0
directCalls := 0
err := terminateWindowsProcess(done, func() error {
treeCalls++
return ErrProcessReap
}, func() error {
directCalls++
return ErrProcessReap
err := terminateProcessTree(done, func() error { return nil }, func() error {
return errors.New("direct fallback should not run")
}, 0)
if !errors.Is(err, ErrProcessReap) {
t.Fatalf("terminateWindowsProcess() error = %v, want ErrProcessReap", err)
}
if treeCalls != 1 || directCalls != 1 {
t.Fatalf("termination calls = tree:%d direct:%d, want one each", treeCalls, directCalls)
t.Fatalf("terminateProcessTree() error = %v, want ErrProcessReap", err)
}
}