(t *testing.T)
| 708 | } |
| 709 | |
| 710 | func TestProcGroupGracefulShutdown(t *testing.T) { |
| 711 | t.Parallel() |
| 712 | |
| 713 | ctx, cancel := context.WithCancel(t.Context()) |
| 714 | logger := slog.Make(sloghuman.Sink(&bytes.Buffer{})) |
| 715 | group := newProcGroup(ctx, logger) |
| 716 | |
| 717 | // Start a process that runs until signaled. |
| 718 | cmd := exec.CommandContext(ctx, "sleep", "60") |
| 719 | cmd.Env = os.Environ() |
| 720 | err := group.Start("sleeper", cmd) |
| 721 | require.NoError(t, err) |
| 722 | |
| 723 | // Cancel the parent context. cmd.Cancel sends SIGINT, and |
| 724 | // cmd.WaitDelay escalates to SIGKILL if needed. |
| 725 | cancel() |
| 726 | |
| 727 | done := make(chan error, 1) |
| 728 | go func() { done <- group.Wait() }() |
| 729 | |
| 730 | select { |
| 731 | case err := <-done: |
| 732 | // The process was killed, so we expect an error. |
| 733 | require.Error(t, err) |
| 734 | case <-time.After(shutdownTimeout + 5*time.Second): |
| 735 | t.Fatal("timed out waiting for graceful shutdown") |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | func TestPoll(t *testing.T) { |
| 740 | t.Parallel() |
nothing calls this directly
no test coverage detected