using VoiceCat.Server.Transport; using Voicecat.V1; namespace VoiceCat.Tests; public class PacketLossTrackerTests { [Fact] public void FastModeReportsWindowedLossAndCapsExtremeValues() { var clock = new ManualClock(); var tracker = new PacketLossTracker(clock); Assert.Null(tracker.Observe(0, 1, PacketLossMode.PacketLossAutoFast)); for (ulong sequence = 1; sequence <= 100; sequence++) if (sequence % 10 != 0) Assert.Null(tracker.Observe(sequence, 1, PacketLossMode.PacketLossAutoFast)); clock.Advance(TimeSpan.FromSeconds(3)); PacketLossSample sample = Assert.IsType(tracker.Observe(101, 1, PacketLossMode.PacketLossAutoFast)); Assert.Equal(10U, sample.MeasuredPercent); Assert.Equal(10U, sample.AppliedPercent); tracker = new(clock); Assert.Null(tracker.Observe(0, 1, PacketLossMode.PacketLossAutoFast)); clock.Advance(TimeSpan.FromSeconds(3)); sample = Assert.IsType(tracker.Observe(100, 1, PacketLossMode.PacketLossAutoFast)); Assert.Equal(99U, sample.MeasuredPercent); Assert.Equal(30U, sample.AppliedPercent); } [Fact] public void ReorderingDoesNotCountAsLossAndStableModeWaitsForItsWindow() { var clock = new ManualClock(); var tracker = new PacketLossTracker(clock); tracker.Observe(0, 1, PacketLossMode.PacketLossAutoStable); tracker.Observe(2, 1, PacketLossMode.PacketLossAutoStable); tracker.Observe(1, 1, PacketLossMode.PacketLossAutoStable); for (ulong sequence = 3; sequence <= 30; sequence++) tracker.Observe(sequence, 1, PacketLossMode.PacketLossAutoStable); clock.Advance(TimeSpan.FromSeconds(29)); Assert.Null(tracker.Observe(31, 1, PacketLossMode.PacketLossAutoStable)); clock.Advance(TimeSpan.FromSeconds(1)); PacketLossSample sample = Assert.IsType(tracker.Observe(32, 1, PacketLossMode.PacketLossAutoStable)); Assert.Equal(0U, sample.MeasuredPercent); } [Fact] public void ManualModeAndChannelChangesResetMeasurement() { var clock = new ManualClock(); var tracker = new PacketLossTracker(clock); tracker.Observe(0, 1, PacketLossMode.PacketLossAutoFast); clock.Advance(TimeSpan.FromSeconds(3)); Assert.Null(tracker.Observe(100, 2, PacketLossMode.PacketLossAutoFast)); Assert.Null(tracker.Observe(101, 2, PacketLossMode.PacketLossManual)); } private sealed class ManualClock : TimeProvider { private long timestamp; public override long TimestampFrequency => 1_000; public override long GetTimestamp() => timestamp; internal void Advance(TimeSpan duration) => timestamp += (long)duration.TotalMilliseconds; } }