82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package compose
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTerminationKillsTheTreeEvenWhenTheDirectChildIsAlreadyReaped(t *testing.T) {
|
|
done := make(chan error, 1)
|
|
done <- nil
|
|
treeFailure := errors.New("tree termination failed")
|
|
treeCalls := 0
|
|
directCalls := 0
|
|
|
|
err := terminateProcessTree(done, func() error {
|
|
treeCalls++
|
|
return treeFailure
|
|
}, func() error {
|
|
directCalls++
|
|
return os.ErrProcessDone
|
|
}, time.Second)
|
|
|
|
if treeCalls != 1 {
|
|
t.Fatalf("tree termination calls = %d, want 1", treeCalls)
|
|
}
|
|
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 TestTerminationWaitsForTheOriginalProcessAfterTreeTermination(t *testing.T) {
|
|
done := make(chan error, 1)
|
|
done <- nil
|
|
directCalls := 0
|
|
|
|
err := terminateProcessTree(done, func() error { return nil }, func() error {
|
|
directCalls++
|
|
return errors.New("direct fallback should not run after a successful tree termination")
|
|
}, time.Second)
|
|
|
|
if err != nil {
|
|
t.Fatalf("terminateProcessTree() error = %v, want nil", err)
|
|
}
|
|
if directCalls != 0 {
|
|
t.Fatalf("direct termination calls = %d, want 0", directCalls)
|
|
}
|
|
}
|
|
|
|
func TestTerminationJoinsTreeDirectAndReapFailures(t *testing.T) {
|
|
done := make(chan error)
|
|
treeFailure := errors.New("tree termination failed")
|
|
directFailure := errors.New("direct termination failed")
|
|
|
|
err := terminateProcessTree(done, func() error { return treeFailure }, func() error { return directFailure }, 0)
|
|
|
|
for _, want := range []error{treeFailure, directFailure, ErrProcessReap} {
|
|
if !errors.Is(err, want) {
|
|
t.Fatalf("terminateProcessTree() error = %v, want %v", err, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTerminationReportsReapFailureWhenTheTreeTerminatesButTheProcessNeverReaps(t *testing.T) {
|
|
done := make(chan error)
|
|
|
|
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("terminateProcessTree() error = %v, want ErrProcessReap", err)
|
|
}
|
|
}
|