using Vanguard.Server.Realtime; namespace Vanguard.Server.Tests; public class HeartbeatStateTests { private static readonly DateTimeOffset Start = new(2026, 10, 21, 12, 0, 0, TimeSpan.Zero); private static readonly TimeSpan Idle = TimeSpan.FromSeconds(20); private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(20); [Fact] public void Server_Pings_After_Idle_And_Closes_After_Timeout() { var state = new HeartbeatState(Start); Assert.Equal(HeartbeatActionKind.None, state.Evaluate(Start, Idle, Timeout).Kind); Assert.Equal(HeartbeatActionKind.None, state.Evaluate(Start.AddSeconds(19), Idle, Timeout).Kind); var ping = state.Evaluate(Start.AddSeconds(20), Idle, Timeout); Assert.Equal(HeartbeatActionKind.Ping, ping.Kind); Assert.Equal(1, ping.Nonce); Assert.Equal(HeartbeatActionKind.None, state.Evaluate(Start.AddSeconds(30), Idle, Timeout).Kind); Assert.Equal(HeartbeatActionKind.Timeout, state.Evaluate(Start.AddSeconds(40), Idle, Timeout).Kind); } [Fact] public void Any_Frame_Resets_The_Idle_Timer() { var state = new HeartbeatState(Start); state.Evaluate(Start.AddSeconds(20), Idle, Timeout); // ping отправлен state.Touch(Start.AddSeconds(25)); // клиент ответил Assert.Equal(HeartbeatActionKind.None, state.Evaluate(Start.AddSeconds(44), Idle, Timeout).Kind); var next = state.Evaluate(Start.AddSeconds(45), Idle, Timeout); Assert.Equal(HeartbeatActionKind.Ping, next.Kind); Assert.Equal(2, next.Nonce); } }