90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package proc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestWaitForTrackedCommandReturnsWhenWaitStallsAfterCancel(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
tracked := &TrackedCommand{}
|
|
releaseWait := make(chan struct{})
|
|
defer close(releaseWait)
|
|
|
|
start := time.Now()
|
|
err := waitForTrackedCommand(ctx, tracked, func() error {
|
|
<-releaseWait
|
|
return nil
|
|
}, 20*time.Millisecond, time.Millisecond, time.Millisecond)
|
|
elapsed := time.Since(start)
|
|
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("error = %v, want context.Canceled", err)
|
|
}
|
|
if elapsed > time.Second {
|
|
t.Fatalf("cancelled stalled wait returned too slowly: %v", elapsed)
|
|
}
|
|
if tracked.Diagnostics().KillCalls == 0 {
|
|
t.Fatal("tracked command was not killed")
|
|
}
|
|
if !tracked.Diagnostics().CancelWaitGraceExpired {
|
|
t.Fatal("cancelled stalled wait did not record grace expiry")
|
|
}
|
|
}
|
|
|
|
func TestWaitForTrackedCommandKeepsWaitErrorAfterCancel(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
tracked := &TrackedCommand{}
|
|
waitStarted := make(chan struct{})
|
|
releaseWait := make(chan struct{})
|
|
errWait := errors.New("wait failed after cancel")
|
|
done := make(chan error, 1)
|
|
|
|
go func() {
|
|
done <- waitForTrackedCommand(ctx, tracked, func() error {
|
|
close(waitStarted)
|
|
<-releaseWait
|
|
return errWait
|
|
}, time.Second, time.Millisecond, time.Millisecond)
|
|
}()
|
|
|
|
<-waitStarted
|
|
cancel()
|
|
waitUntilTrackedCommandKilled(t, tracked)
|
|
close(releaseWait)
|
|
|
|
select {
|
|
case err := <-done:
|
|
if err.Error() != context.Canceled.Error() {
|
|
t.Fatalf("error text = %q, want %q", err.Error(), context.Canceled.Error())
|
|
}
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("error = %v, want context.Canceled", err)
|
|
}
|
|
if !errors.Is(err, errWait) {
|
|
t.Fatalf("error = %v, want wrapped wait error %v", err, errWait)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("timed out waiting for cancelled command wait")
|
|
}
|
|
}
|
|
|
|
func waitUntilTrackedCommandKilled(t *testing.T, tracked *TrackedCommand) {
|
|
t.Helper()
|
|
deadline := time.After(time.Second)
|
|
for {
|
|
if tracked.Diagnostics().KillCalls > 0 {
|
|
return
|
|
}
|
|
select {
|
|
case <-deadline:
|
|
t.Fatal("timed out waiting for tracked command kill")
|
|
default:
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
}
|
|
}
|