package zitcli
import (
"errors"
"os/exec"
"testing"
"craftdesign.group/quarry/internal/ops"
)
// A child killed by a signal is not a child that failed. The forge
// restarting mid-operation SIGTERMs the whole cgroup, and the reader
// deserves "ask again" rather than "something went wrong".
func TestASignalledChildIsNotAFailure(t *testing.T) {
cmd := exec.Command("sh", "-c", "kill -TERM $$; sleep 5")
err := cmd.Run()
if err == nil {
t.Fatal("the child was supposed to be signalled")
}
if !signalled(err) {
t.Errorf("FAIL: a SIGTERMed child did not read as signalled: %v", err)
}
// The trap this fixes: ExitCode() is -1 for a signalled process, so
// every switch on the exit status falls through to the default and
// reports a generic fault.
if got := exitCode(err); got != -1 {
t.Errorf("FAIL: exit code = %d, want -1 for a signalled child", got)
}
}
// An ordinary non-zero exit is still a failure, not a restart.
func TestAnOrdinaryFailureIsNotReadAsARestart(t *testing.T) {
err := exec.Command("sh", "-c", "exit 3").Run()
if err == nil {
t.Fatal("the child was supposed to fail")
}
if signalled(err) {
t.Errorf("FAIL: exit 3 read as a signal")
}
if got := exitCode(err); got != 3 {
t.Errorf("FAIL: exit code = %d, want 3", got)
}
}
// ErrStopped carries "ask again in a moment" through the same class
// every other temporary refusal in the forge uses, so no caller needs
// to learn a new one.
func TestStoppedReadsAsTemporarilyUnavailable(t *testing.T) {
if !errors.Is(ErrStopped, ops.ErrUnavailable) {
t.Errorf("FAIL: ErrStopped is not an unavailability")
}
}