package daemon import ( "sync/atomic" "testing" "time" ) func TestIdleTimer_FiresAfterTimeout(t *testing.T) { var fired atomic.Bool timer := NewIdleTimer(50*time.Millisecond, func() { fired.Store(true) }) defer timer.Stop() time.Sleep(120 * time.Millisecond) if !fired.Load() { t.Error("idle timer should have fired") } } func TestIdleTimer_ResetPreventsTimeout(t *testing.T) { var fired atomic.Bool timer := NewIdleTimer(80*time.Millisecond, func() { fired.Store(true) }) defer timer.Stop() // 每 40ms Reset 一次,不应触发(每次都在 80ms 超时前重置) for i := 0; i < 4; i++ { time.Sleep(40 * time.Millisecond) timer.Reset() } if fired.Load() { t.Error("idle timer should not have fired after repeated resets") } } func TestIdleTimer_FiresAfterNoActivity(t *testing.T) { var fired atomic.Bool timer := NewIdleTimer(50*time.Millisecond, func() { fired.Store(true) }) defer timer.Stop() // 先 Reset 几次,然后停止重置 timer.Reset() timer.Reset() // 等待超时 time.Sleep(120 * time.Millisecond) if !fired.Load() { t.Error("idle timer should fire after activity stops") } } func TestIdleTimer_StopPreventsCallback(t *testing.T) { var fired atomic.Bool timer := NewIdleTimer(50*time.Millisecond, func() { fired.Store(true) }) timer.Stop() // 立即停止 time.Sleep(100 * time.Millisecond) if fired.Load() { t.Error("stopped timer should not fire callback") } } func TestIdleTimer_StopIdempotent(t *testing.T) { timer := NewIdleTimer(50*time.Millisecond, func() {}) // 多次 Stop 不应 panic timer.Stop() timer.Stop() timer.Stop() } func TestIdleTimer_ResetNonBlocking(t *testing.T) { // Reset 应该是非阻塞的,即使快速连续调用 timer := NewIdleTimer(1*time.Second, func() {}) defer timer.Stop() done := make(chan struct{}) go func() { for i := 0; i < 1000; i++ { timer.Reset() } close(done) }() select { case <-done: case <-time.After(100 * time.Millisecond): t.Error("1000 Reset calls should complete quickly (non-blocking)") } }