package mesh import ( "testing" "time" ) func TestPeerConnectionTrackerTransitionsReadyAndDegraded(t *testing.T) { now := time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC) tracker := NewPeerConnectionTracker(PeerCacheSnapshot{ Entries: []PeerCacheEntry{ {NodeID: "node-b", Warm: true, WarmReason: "route_adjacent", Endpoint: "quic://node-b:19443"}, }, }, now) begin := tracker.BeginProbe(PeerCacheEntry{NodeID: "node-b", Warm: true}, now.Add(time.Second)) if begin.State != PeerConnectionConnecting { t.Fatalf("begin state = %q, want connecting", begin.State) } ready := tracker.RecordSuccess("node-b", 42, now.Add(2*time.Second)) if ready.State != PeerConnectionReady || ready.ConsecutiveSuccesses != 1 || ready.ConsecutiveFailures != 0 { t.Fatalf("ready state unexpected: %+v", ready) } degraded := tracker.RecordSuccess("node-b", 800, now.Add(3*time.Second)) if degraded.State != PeerConnectionDegraded || degraded.LastLatencyMs != 800 { t.Fatalf("degraded state unexpected: %+v", degraded) } } func TestPeerConnectionTrackerBackoffAfterRepeatedFailures(t *testing.T) { now := time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC) tracker := NewPeerConnectionTracker(PeerCacheSnapshot{ Entries: []PeerCacheEntry{{NodeID: "node-b", Warm: true}}, }, now) first := tracker.RecordFailure("node-b", "timeout", now.Add(time.Second)) if first.State != PeerConnectionDegraded { t.Fatalf("first failure state = %q, want degraded", first.State) } _ = tracker.RecordFailure("node-b", "timeout", now.Add(2*time.Second)) third := tracker.RecordFailure("node-b", "timeout", now.Add(3*time.Second)) if third.State != PeerConnectionBackoff || third.BackoffUntil.IsZero() { t.Fatalf("third failure did not enter backoff: %+v", third) } if tracker.ShouldProbe("node-b", now.Add(4*time.Second)) { t.Fatal("ShouldProbe returned true during backoff") } if !tracker.ShouldProbe("node-b", third.BackoffUntil.Add(time.Millisecond)) { t.Fatal("ShouldProbe returned false after backoff") } recovered := tracker.RecordSuccess("node-b", 12, third.BackoffUntil.Add(time.Second)) if recovered.State != PeerConnectionReady || recovered.ConsecutiveFailures != 0 || !recovered.BackoffUntil.IsZero() { t.Fatalf("success did not recover from backoff: %+v", recovered) } } func TestPeerConnectionTrackerSnapshotCountsStates(t *testing.T) { now := time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC) tracker := NewPeerConnectionTracker(PeerCacheSnapshot{ Entries: []PeerCacheEntry{ {NodeID: "node-a", Warm: true}, {NodeID: "node-b", Warm: true}, {NodeID: "node-c", Warm: true}, }, }, now) tracker.RecordSuccess("node-a", 25, now.Add(time.Second)) tracker.RecordFailure("node-b", "timeout", now.Add(time.Second)) tracker.RecordFailure("node-c", "timeout", now.Add(time.Second)) tracker.RecordFailure("node-c", "timeout", now.Add(2*time.Second)) tracker.RecordFailure("node-c", "timeout", now.Add(3*time.Second)) snapshot := tracker.Snapshot() if snapshot.Total != 3 || snapshot.Ready != 1 || snapshot.Degraded != 1 || snapshot.Backoff != 1 { t.Fatalf("unexpected snapshot: %+v", snapshot) } }