diff --git a/runner.go b/runner.go index e7b045a..72e23f0 100644 --- a/runner.go +++ b/runner.go @@ -2,7 +2,6 @@ package process import ( "context" - "fmt" "sync" "time" @@ -61,8 +60,10 @@ type RunResult struct { ExitCode int Duration time.Duration Output string - Error error - Skipped bool + // Error only reports start-time or orchestration failures. A started process + // that exits non-zero uses ExitCode to report failure and leaves Error nil. + Error error + Skipped bool } // Passed returns true if the process succeeded. @@ -268,9 +269,8 @@ func (r *Runner) runSpec(ctx context.Context, spec RunSpec) RunResult { case StatusKilled: runErr = coreerr.E("Runner.runSpec", "process was killed", nil) case StatusExited: - if proc.ExitCode != 0 { - runErr = coreerr.E("Runner.runSpec", fmt.Sprintf("process exited with code %d", proc.ExitCode), nil) - } + // Non-zero exits are surfaced through ExitCode; Error remains nil so + // callers can distinguish execution failure from orchestration failure. case StatusFailed: runErr = coreerr.E("Runner.runSpec", "process failed to start", nil) } diff --git a/runner_test.go b/runner_test.go index 94dbf50..84b85b5 100644 --- a/runner_test.go +++ b/runner_test.go @@ -51,6 +51,12 @@ func TestRunner_RunSequential(t *testing.T) { assert.Equal(t, 1, result.Passed) assert.Equal(t, 1, result.Failed) assert.Equal(t, 1, result.Skipped) + require.Len(t, result.Results, 3) + assert.Equal(t, 0, result.Results[0].ExitCode) + assert.NoError(t, result.Results[0].Error) + assert.Equal(t, 1, result.Results[1].ExitCode) + assert.NoError(t, result.Results[1].Error) + assert.True(t, result.Results[2].Skipped) }) t.Run("allow failure continues", func(t *testing.T) {