diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-01-11 13:54:37 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-01-14 17:25:03 +0300 |
commit | 532aec4b5020ef887bf899e984071a4c2443d283 (patch) | |
tree | 6db468874b2e1588ffc0869de7585d15a7e94fb1 /cmd/gitaly-wrapper | |
parent | 8cab4f8b7423dccc64211265d7d55a1028f86af1 (diff) |
cmd/gitaly-wrapper: Add tests to check for process liveliness
When trying to adopt a process as pointed to by the PID file we have to
test whether the PID exists at all anymore. Add tests to verify it works
as expected.
While at it, rename the function to `isProcessAlive()` to clarify what
the function does.
Diffstat (limited to 'cmd/gitaly-wrapper')
-rw-r--r-- | cmd/gitaly-wrapper/main.go | 6 | ||||
-rw-r--r-- | cmd/gitaly-wrapper/main_test.go | 49 |
2 files changed, 52 insertions, 3 deletions
diff --git a/cmd/gitaly-wrapper/main.go b/cmd/gitaly-wrapper/main.go index 89b5be44d..8634c9d83 100644 --- a/cmd/gitaly-wrapper/main.go +++ b/cmd/gitaly-wrapper/main.go @@ -72,7 +72,7 @@ func main() { forwardSignals(process, logger) // wait - for isAlive(process) { + for isProcessAlive(process) { time.Sleep(1 * time.Second) } @@ -96,7 +96,7 @@ func findProcess(pidFilePath string) (*os.Process, error) { return nil, err } - if isAlive(process) { + if isProcessAlive(process) { return process, nil } @@ -156,7 +156,7 @@ func readPIDFile(pidFilePath string) (int, error) { return strconv.Atoi(string(data)) } -func isAlive(p *os.Process) bool { +func isProcessAlive(p *os.Process) bool { // After p exits, and after it gets reaped, this p.Signal will fail. It is crucial that p gets reaped. // If p was spawned by the current process, it will get reaped from a goroutine that does cmd.Wait(). // If p was spawned by someone else we rely on them to reap it, or on p to become an orphan. diff --git a/cmd/gitaly-wrapper/main_test.go b/cmd/gitaly-wrapper/main_test.go index 0f053cb8f..19a20f4a1 100644 --- a/cmd/gitaly-wrapper/main_test.go +++ b/cmd/gitaly-wrapper/main_test.go @@ -204,3 +204,52 @@ func TestIsExpectedProcess(t *testing.T) { require.False(t, isExpectedProcess(cmd.Process, "does not match")) require.True(t, isExpectedProcess(cmd.Process, "bash")) } + +func TestIsProcessAlive(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + t.Run("nonexistent process", func(t *testing.T) { + // And now let's check with a nonexistent process. FindProcess never returns an + // error on Unix systems even if the process doesn't exist, so this is fine. + process, err := os.FindProcess(77777777) + require.NoError(t, err) + require.False(t, isProcessAlive(process)) + }) + + t.Run("existing process", func(t *testing.T) { + executable := testhelper.WriteExecutable(t, filepath.Join(testhelper.TempDir(t), "noop"), []byte( + `#!/usr/bin/env bash + echo ready + read wait_until_killed + `)) + + cmd := exec.CommandContext(ctx, executable) + stdout, err := cmd.StdoutPipe() + require.NoError(t, err) + _, err = cmd.StdinPipe() + require.NoError(t, err) + + require.NoError(t, cmd.Start()) + + // Wait for the process to be ready such that we know it's started up successfully + // and is executing the bash shell. + _, err = stdout.Read(make([]byte, 10)) + require.NoError(t, err) + + t.Run("running", func(t *testing.T) { + require.True(t, isProcessAlive(cmd.Process)) + }) + + t.Run("zombie", func(t *testing.T) { + // The process will be considered alive as long as it hasn't been reaped yet. + require.NoError(t, cmd.Process.Kill()) + require.True(t, isProcessAlive(cmd.Process)) + }) + + t.Run("reaped", func(t *testing.T) { + require.Error(t, cmd.Wait()) + require.False(t, isProcessAlive(cmd.Process)) + }) + }) +} |