TestReap checks that the reaper successfully reaps exited processes and passes their PIDs through the shared channel.
(t *testing.T)
| 77 | // TestReap checks that the reaper successfully reaps exited |
| 78 | // processes and passes their PIDs through the shared channel. |
| 79 | func TestReap(t *testing.T) { |
| 80 | t.Parallel() |
| 81 | if testutil.InCI() { |
| 82 | t.Skip("Detected CI, skipping reaper tests") |
| 83 | } |
| 84 | if !runSubprocess(t) { |
| 85 | return |
| 86 | } |
| 87 | |
| 88 | pids := make(reap.PidCh, 1) |
| 89 | var reapLock sync.RWMutex |
| 90 | opts := append([]reaper.Option{ |
| 91 | reaper.WithPIDCallback(pids), |
| 92 | reaper.WithExecArgs("/bin/sh", "-c", "exit 0"), |
| 93 | reaper.WithReapLock(&reapLock), |
| 94 | }, withDone(t)...) |
| 95 | reapLock.RLock() |
| 96 | exitCode, err := reaper.ForkReap(opts...) |
| 97 | reapLock.RUnlock() |
| 98 | require.NoError(t, err) |
| 99 | require.Equal(t, 0, exitCode) |
| 100 | |
| 101 | cmd := exec.Command("tail", "-f", "/dev/null") |
| 102 | err = cmd.Start() |
| 103 | require.NoError(t, err) |
| 104 | |
| 105 | cmd2 := exec.Command("tail", "-f", "/dev/null") |
| 106 | err = cmd2.Start() |
| 107 | require.NoError(t, err) |
| 108 | |
| 109 | err = cmd.Process.Kill() |
| 110 | require.NoError(t, err) |
| 111 | |
| 112 | err = cmd2.Process.Kill() |
| 113 | require.NoError(t, err) |
| 114 | |
| 115 | expectedPIDs := []int{cmd.Process.Pid, cmd2.Process.Pid} |
| 116 | |
| 117 | for range len(expectedPIDs) { |
| 118 | select { |
| 119 | case <-time.After(testutil.WaitShort): |
| 120 | t.Fatalf("Timed out waiting for process") |
| 121 | case pid := <-pids: |
| 122 | require.Contains(t, expectedPIDs, pid) |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | //nolint:tparallel // Subtests must be sequential, each starts its own reaper. |
| 128 | func TestForkReapExitCodes(t *testing.T) { |
nothing calls this directly
no test coverage detected