mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 13:17:36 +03:00
186 lines
6.6 KiB
Go
186 lines
6.6 KiB
Go
package ackhandler
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/quic-go/quic-go/internal/protocol"
|
|
"github.com/quic-go/quic-go/internal/utils"
|
|
"github.com/quic-go/quic-go/internal/wire"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestReceivedPacketTrackerGenerateACKs(t *testing.T) {
|
|
tracker := newReceivedPacketTracker()
|
|
baseTime := time.Now().Add(-10 * time.Second)
|
|
|
|
require.NoError(t, tracker.ReceivedPacket(protocol.PacketNumber(3), protocol.ECNNon, baseTime, true))
|
|
ack := tracker.GetAckFrame()
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{{Smallest: 3, Largest: 3}}, ack.AckRanges)
|
|
require.Zero(t, ack.DelayTime)
|
|
|
|
require.NoError(t, tracker.ReceivedPacket(protocol.PacketNumber(4), protocol.ECNNon, baseTime.Add(time.Second), true))
|
|
ack = tracker.GetAckFrame()
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{{Smallest: 3, Largest: 4}}, ack.AckRanges)
|
|
require.Zero(t, ack.DelayTime)
|
|
|
|
require.NoError(t, tracker.ReceivedPacket(protocol.PacketNumber(1), protocol.ECNNon, baseTime.Add(time.Second), true))
|
|
ack = tracker.GetAckFrame()
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{
|
|
{Smallest: 3, Largest: 4},
|
|
{Smallest: 1, Largest: 1},
|
|
}, ack.AckRanges)
|
|
require.Zero(t, ack.DelayTime)
|
|
|
|
// non-ack-eliciting packets don't trigger ACKs
|
|
require.NoError(t, tracker.ReceivedPacket(protocol.PacketNumber(10), protocol.ECNNon, baseTime.Add(5*time.Second), false))
|
|
require.Nil(t, tracker.GetAckFrame())
|
|
|
|
require.NoError(t, tracker.ReceivedPacket(protocol.PacketNumber(11), protocol.ECNNon, baseTime.Add(10*time.Second), true))
|
|
ack = tracker.GetAckFrame()
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{
|
|
{Smallest: 10, Largest: 11},
|
|
{Smallest: 3, Largest: 4},
|
|
{Smallest: 1, Largest: 1},
|
|
}, ack.AckRanges)
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerECN(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
require.NoError(t, tr.ReceivedPacket(0, protocol.ECT0, time.Now(), true))
|
|
pn := protocol.PacketNumber(1)
|
|
for i := 0; i < 2; i++ {
|
|
require.NoError(t, tr.ReceivedPacket(pn, protocol.ECT1, time.Now(), true))
|
|
pn++
|
|
}
|
|
for i := 0; i < 3; i++ {
|
|
require.NoError(t, tr.ReceivedPacket(pn, protocol.ECNCE, time.Now(), true))
|
|
pn++
|
|
}
|
|
ack := tr.GetAckFrame(false)
|
|
require.Equal(t, uint64(1), ack.ECT0)
|
|
require.Equal(t, uint64(2), ack.ECT1)
|
|
require.Equal(t, uint64(3), ack.ECNCE)
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerAckEverySecondPacket(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
// the first packet is always acknowledged
|
|
require.NoError(t, tr.ReceivedPacket(0, protocol.ECNNon, time.Now(), true))
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
for p := protocol.PacketNumber(1); p <= 20; p++ {
|
|
require.NoError(t, tr.ReceivedPacket(p, protocol.ECNNon, time.Now(), true))
|
|
switch p % 2 {
|
|
case 0:
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
case 1:
|
|
require.Nil(t, tr.GetAckFrame(true))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerAlarmTimeout(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
// the first packet is always acknowledged
|
|
require.NoError(t, tr.ReceivedPacket(0, protocol.ECNNon, time.Now(), true))
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
|
|
now := time.Now()
|
|
require.NoError(t, tr.ReceivedPacket(1, protocol.ECNNon, now, false))
|
|
require.Nil(t, tr.GetAckFrame(true))
|
|
require.Zero(t, tr.GetAlarmTimeout())
|
|
|
|
rcvTime := now.Add(10 * time.Millisecond)
|
|
require.NoError(t, tr.ReceivedPacket(2, protocol.ECNNon, rcvTime, true))
|
|
require.Equal(t, rcvTime.Add(protocol.MaxAckDelay), tr.GetAlarmTimeout())
|
|
require.Nil(t, tr.GetAckFrame(true))
|
|
|
|
// no timeout after the ACK has been dequeued
|
|
require.NotNil(t, tr.GetAckFrame(false))
|
|
require.Zero(t, tr.GetAlarmTimeout())
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerQueuesECNCE(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
// the first packet is always acknowledged
|
|
require.NoError(t, tr.ReceivedPacket(0, protocol.ECNNon, time.Now(), true))
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
|
|
require.NoError(t, tr.ReceivedPacket(1, protocol.ECNCE, time.Now(), true))
|
|
ack := tr.GetAckFrame(true)
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, protocol.PacketNumber(1), ack.LargestAcked())
|
|
require.EqualValues(t, 1, ack.ECNCE)
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerMissingPackets(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
// the first packet is always acknowledged
|
|
require.NoError(t, tr.ReceivedPacket(0, protocol.ECNNon, time.Now(), true))
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
|
|
require.NoError(t, tr.ReceivedPacket(5, protocol.ECNNon, time.Now(), true))
|
|
ack := tr.GetAckFrame(true) // ACK: 0 and 5, missing: 1, 2, 3, 4
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{{Smallest: 5, Largest: 5}, {Smallest: 0, Largest: 0}}, ack.AckRanges)
|
|
|
|
// now receive one of the missing packets
|
|
require.NoError(t, tr.ReceivedPacket(3, protocol.ECNNon, time.Now(), true))
|
|
require.NotNil(t, tr.GetAckFrame(true))
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerDelayTime(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
now := time.Now()
|
|
require.NoError(t, tr.ReceivedPacket(1, protocol.ECNNon, now, true))
|
|
require.NoError(t, tr.ReceivedPacket(2, protocol.ECNNon, now.Add(-1337*time.Millisecond), true))
|
|
ack := tr.GetAckFrame(true)
|
|
require.NotNil(t, ack)
|
|
require.InDelta(t, 1337*time.Millisecond, ack.DelayTime, float64(50*time.Millisecond))
|
|
|
|
// don't use a negative delay time
|
|
require.NoError(t, tr.ReceivedPacket(3, protocol.ECNNon, now.Add(time.Hour), true))
|
|
ack = tr.GetAckFrame(false)
|
|
require.NotNil(t, ack)
|
|
require.Zero(t, ack.DelayTime)
|
|
}
|
|
|
|
func TestAppDataReceivedPacketTrackerIgnoreBelow(t *testing.T) {
|
|
tr := newAppDataReceivedPacketTracker(utils.DefaultLogger)
|
|
|
|
tr.IgnoreBelow(4)
|
|
// check that packets below 7 are considered duplicates
|
|
require.True(t, tr.IsPotentiallyDuplicate(3))
|
|
require.False(t, tr.IsPotentiallyDuplicate(4))
|
|
|
|
for i := 5; i <= 10; i++ {
|
|
require.NoError(t, tr.ReceivedPacket(protocol.PacketNumber(i), protocol.ECNNon, time.Now(), true))
|
|
}
|
|
ack := tr.GetAckFrame(true)
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{{Smallest: 5, Largest: 10}}, ack.AckRanges)
|
|
|
|
tr.IgnoreBelow(7)
|
|
|
|
require.NoError(t, tr.ReceivedPacket(11, protocol.ECNNon, time.Now(), true))
|
|
require.NoError(t, tr.ReceivedPacket(12, protocol.ECNNon, time.Now(), true))
|
|
ack = tr.GetAckFrame(true)
|
|
require.NotNil(t, ack)
|
|
require.Equal(t, []wire.AckRange{{Smallest: 7, Largest: 12}}, ack.AckRanges)
|
|
|
|
// make sure that old packets are not accepted
|
|
require.ErrorContains(t,
|
|
tr.ReceivedPacket(4, protocol.ECNNon, time.Now(), true),
|
|
"recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet 4",
|
|
)
|
|
}
|