package main
import (
"io"
"strings"
"sync/atomic"
"testing"
"github.com/spf13/cobra"
"github.com/zzet/gortex/internal/daemon"
)
func restoreServiceSeams() {
serviceActive = defaultServiceActive
serviceStop = defaultServiceStop
serviceRestart = defaultServiceRestart
}
func TestRunDaemonStop_SupervisedRoutesToServiceStop(t *testing.T) {
t.Setenv("XDG_CACHE_HOME", t.TempDir())
defer restoreServiceSeams()
var stopCalls int32
serviceActive = func() bool { return true }
serviceStop = func(io.Writer) error { atomic.AddInt32(&stopCalls, 1); return nil }
serviceRestart = func(io.Writer) error { t.Fatal("restart must not be called by stop"); return nil }
if err := runDaemonStop(&cobra.Command{}, nil); err != nil {
t.Fatalf("runDaemonStop: %v", err)
}
if got := atomic.LoadInt32(&stopCalls); got != 1 {
t.Fatalf("serviceStop calls = %d, want 1 (supervised stop must route through the supervisor)", got)
}
// The stay-down mark is still recorded so a stray `gortex mcp` proxy
// doesn't autostart a second, unsupervised daemon either.
if !daemon.StopIntentActive() {
t.Fatal("supervised stop must still record stop-intent")
}
}
func TestRunDaemonRestart_SupervisedRoutesToServiceRestart(t *testing.T) {
t.Setenv("XDG_CACHE_HOME", t.TempDir())
defer restoreServiceSeams()
var restartCalls int32
serviceActive = func() bool { return true }
serviceRestart = func(io.Writer) error { atomic.AddInt32(&restartCalls, 1); return nil }
serviceStop = func(io.Writer) error { t.Fatal("restart must not stop the supervisor"); return nil }
if err := runDaemonRestart(&cobra.Command{}, nil); err != nil {
t.Fatalf("runDaemonRestart: %v", err)
}
if got := atomic.LoadInt32(&restartCalls); got != 1 {
t.Fatalf("serviceRestart calls = %d, want 1 (supervised restart must bounce via the supervisor)", got)
}
}
func TestDefaultServiceActive_NoUnitFileIsInactive(t *testing.T) {
// Point HOME (and cache) at an empty dir so no unit file exists; detection
// must short-circuit to false without shelling out to the supervisor.
tmp := t.TempDir()
t.Setenv("HOME", tmp)
t.Setenv("XDG_CACHE_HOME", tmp)
if defaultServiceActive() {
t.Fatal("no installed unit file => service must be reported inactive")
}
}
func TestLaunchdTemplate_RestartsOnlyOnFailure(t *testing.T) {
// KeepAlive must be the SuccessfulExit=false policy, not bare , so a
// clean `daemon stop` is not resurrected on macOS.
if !strings.Contains(launchdPlistTemplate, "SuccessfulExit") {
t.Error("launchd plist must use the KeepAlive SuccessfulExit policy")
}
if strings.Contains(launchdPlistTemplate, "KeepAlive\n ") {
t.Error("launchd plist must not use unconditional KeepAlive=true")
}
}
func TestSystemdTemplate_RestartsOnlyOnFailure(t *testing.T) {
if !strings.Contains(systemdUnitTemplate, "Restart=on-failure") {
t.Error("systemd unit must restart only on failure so a clean stop sticks")
}
}