package main import ( "context" "fmt" "io" "log/slog" "os" "path/filepath" "syscall" "testing" "time" "github.com/monlet/agent/internal/config" ) type reloadCall struct { cfg *config.Config agentID string } type fakeReloadTarget struct { reloads chan reloadCall failures chan struct{} } func (f *fakeReloadTarget) RecordReloadFailure() { f.failures <- struct{}{} } func (f *fakeReloadTarget) Reload(cfg *config.Config, agentID string) error { f.reloads <- reloadCall{cfg: cfg, agentID: agentID} return nil } func TestRunReloadLoopHandlesSIGHUP(t *testing.T) { cfgPath := writeTestConfig(t) target := &fakeReloadTarget{ reloads: make(chan reloadCall, 1), failures: make(chan struct{}, 1), } ctx, cancel := context.WithCancel(context.Background()) defer cancel() hup := make(chan os.Signal, 1) go runReloadLoop(ctx, cfgPath, hup, target, discardLogger()) hup <- syscall.SIGHUP select { case call := <-target.reloads: if call.agentID != "agent-test" || len(call.cfg.Checks) != 1 { t.Fatalf("unexpected reload call: agent_id=%q cfg=%+v", call.agentID, call.cfg) } case <-time.After(time.Second): t.Fatal("reload was not called") } } func TestRunReloadLoopRecordsLoadFailure(t *testing.T) { target := &fakeReloadTarget{ reloads: make(chan reloadCall, 1), failures: make(chan struct{}, 1), } ctx, cancel := context.WithCancel(context.Background()) defer cancel() hup := make(chan os.Signal, 1) go runReloadLoop(ctx, filepath.Join(t.TempDir(), "missing.toml"), hup, target, discardLogger()) hup <- syscall.SIGHUP select { case <-target.failures: case <-time.After(time.Second): t.Fatal("reload failure was not recorded") } } func TestShutdownWatchdogExitsAfterTimeout(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) exits := make(chan int, 1) startShutdownWatchdog(ctx, time.Millisecond, discardLogger(), func(code int) { exits <- code }) cancel() select { case code := <-exits: if code != 1 { t.Fatalf("exit code: %d", code) } case <-time.After(time.Second): t.Fatal("watchdog did not exit") } } func writeTestConfig(t *testing.T) string { t.Helper() path := filepath.Join(t.TempDir(), "agent.toml") body := fmt.Sprintf(` agent_id = "agent-test" state_dir = %q [server] enabled = true url = "http://localhost" [[checks]] id = "c1" command = "true" interval = "10s" timeout = "5s" `, t.TempDir()) if err := os.WriteFile(path, []byte(body), 0o600); err != nil { t.Fatal(err) } return path } func discardLogger() *slog.Logger { return slog.New(slog.NewTextHandler(io.Discard, nil)) }