package dbx import ( "context" "sync/atomic" "testing" "time" ) func TestHealthChecker_StartStop(t *testing.T) { nodes := makeTestNodes("a", "b") hc := newHealthChecker(nodes, HealthCheckConfig{ Interval: 100 * time.Millisecond, Timeout: 50 * time.Millisecond, }, nopLogger{}, nil) hc.start() // Just verify it can be stopped without deadlock hc.shutdown() } func TestHealthChecker_MetricsCallbacks(t *testing.T) { var downCalled, upCalled atomic.Int32 metrics := &MetricsHook{ OnNodeDown: func(_ context.Context, node string, err error) { downCalled.Add(1) }, OnNodeUp: func(_ context.Context, node string) { upCalled.Add(1) }, } node := &Node{name: "test"} node.healthy.Store(true) hc := newHealthChecker([]*Node{node}, HealthCheckConfig{ Interval: time.Hour, // won't tick in test Timeout: 50 * time.Millisecond, }, nopLogger{}, metrics) // Simulate a down check: node has no pool, so ping will fail // We can't easily test with a real pool here, but checkNode // will panic on nil pool. In integration tests, we use real pools. _ = hc // just verify construction works // Verify state transitions node.healthy.Store(false) if node.IsHealthy() { t.Error("expected unhealthy") } node.healthy.Store(true) if !node.IsHealthy() { t.Error("expected healthy") } }