package backend import ( "context" "sync/atomic" "testing" "time" ) func TestSetHeartbeatInterval_ValidValue(t *testing.T) { atomic.StoreInt32(&heartbeatIntervalSecs, 30) SetHeartbeatInterval(60) if got := atomic.LoadInt32(&heartbeatIntervalSecs); got != 60 { t.Errorf("heartbeatIntervalSecs = %d, want 60", got) } } func TestSetHeartbeatInterval_ZeroIgnored(t *testing.T) { atomic.StoreInt32(&heartbeatIntervalSecs, 30) SetHeartbeatInterval(0) if got := atomic.LoadInt32(&heartbeatIntervalSecs); got != 30 { t.Errorf("heartbeatIntervalSecs = %d, want 30 (zero should be ignored)", got) } } func TestSetHeartbeatInterval_NegativeIgnored(t *testing.T) { atomic.StoreInt32(&heartbeatIntervalSecs, 30) SetHeartbeatInterval(-1) if got := atomic.LoadInt32(&heartbeatIntervalSecs); got != 30 { t.Errorf("heartbeatIntervalSecs = %d, want 30 (negative should be ignored)", got) } } func TestRunHeartbeat_CallsFunction(t *testing.T) { atomic.StoreInt32(&heartbeatIntervalSecs, 1) var callCount int64 fn := func(_ int) { atomic.AddInt64(&callCount, 1) } ctx, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) go func() { runHeartbeat(ctx, fn) close(done) }() time.Sleep(1500 * time.Millisecond) cancel() <-done // wait for goroutine to exit before the test returns if got := atomic.LoadInt64(&callCount); got < 1 { t.Errorf("fn was called %d times, want at least 1", got) } } func TestRunHeartbeat_CancelsOnContext(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() // already cancelled var callCount int64 fn := func(_ int) { atomic.AddInt64(&callCount, 1) } done := make(chan struct{}) go func() { runHeartbeat(ctx, fn) close(done) }() select { case <-done: // returned quickly as expected case <-time.After(100 * time.Millisecond): t.Error("runHeartbeat did not return promptly after context cancellation") } if got := atomic.LoadInt64(&callCount); got != 0 { t.Errorf("fn was called %d times, want 0 for already-cancelled context", got) } }