diff --git a/tests/testTransport.cpp b/tests/testTransport.cpp index a890307..1806829 100644 --- a/tests/testTransport.cpp +++ b/tests/testTransport.cpp @@ -163,3 +163,161 @@ VF_TEST(reliableMessagesLargerThanTheMtuAreFragmentedAndReassembledByteForByte) CHECK(got == huge); CHECK_EQ(sender.unackedFragmentCount(), static_cast(0)); + ByteBuffer extra; + CHECK(!receiver.popReliable(extra)); +} + +VF_TEST(unreliableChannelDropsAMessageOlderThanTheNewestOneAlreadyDelivered) { + LinkQuality slow; + slow.latencyTicks = 12; + slow.seed = 0x2222333344445555ull; + LoopbackLink link(slow); + + TransportConfig config; + config.mtu = 256; + Transport sender(link, 0, config); + Transport receiver(link, 1, config); + + sender.sendUnreliable(messageOf(0, 32)); + sender.flush(0); + + LinkQuality fast = slow; + fast.latencyTicks = 1; + link.setQuality(fast); + + sender.sendUnreliable(messageOf(1, 32)); + sender.flush(1); + + std::vector received; + for (uint64_t tick = 2; tick < 40; ++tick) { + receiver.pump(tick); + receiver.flush(tick); + ByteBuffer got; + while (receiver.popUnreliable(got)) received.push_back(indexOf(got)); + } + + CHECK_EQ(received.size(), static_cast(1)); + CHECK_EQ(received[0], 1u); + CHECK_EQ(receiver.stats().staleDropped, static_cast(1)); + CHECK_EQ(receiver.unreliableChannel().highestDeliveredMessageId(), 1u); +} + +VF_TEST(unreliableMessagesAreNeverRetransmittedWhileReliableOnesAre) { + LinkQuality quality; + quality.lossPercent = 50; + quality.latencyTicks = 1; + quality.seed = 0x5a5a5a5a5a5a5a5aull; + + LoopbackLink lossyUnreliable(quality); + TransportConfig config; + config.mtu = 256; + config.retransmitTimeoutTicks = 4; + Transport unreliableSender(lossyUnreliable, 0, config); + Transport unreliableReceiver(lossyUnreliable, 1, config); + for (uint32_t i = 0; i < 40; ++i) unreliableSender.sendUnreliable(messageOf(i, 24)); + + std::size_t unreliableArrived = 0; + for (uint64_t tick = 0; tick < 200; ++tick) { + stepPair(unreliableSender, unreliableReceiver, tick); + ByteBuffer got; + while (unreliableReceiver.popUnreliable(got)) ++unreliableArrived; + } + CHECK(unreliableArrived < 40u); + CHECK_EQ(unreliableSender.stats().retransmitted, static_cast(0)); + + LoopbackLink lossyReliable(quality); + Transport reliableSender(lossyReliable, 0, config); + Transport reliableReceiver(lossyReliable, 1, config); + for (uint32_t i = 0; i < 40; ++i) reliableSender.sendReliable(messageOf(i, 24)); + + std::size_t reliableArrived = 0; + for (uint64_t tick = 0; tick < 600; ++tick) { + stepPair(reliableSender, reliableReceiver, tick); + ByteBuffer got; + while (reliableReceiver.popReliable(got)) ++reliableArrived; + } + CHECK_EQ(reliableArrived, static_cast(40)); + CHECK(reliableSender.stats().retransmitted > 0u); + CHECK(reliableSender.stats().datagramsLost > 0u); +} + +VF_TEST(duplicatedDatagramsAreCountedAndNeverDeliveredTwice) { + LinkQuality quality; + quality.duplicatePercent = 100; + quality.latencyTicks = 1; + quality.seed = 0x0badc0de0badc0deull; + + LoopbackLink link(quality); + TransportConfig config; + config.mtu = 256; + Transport sender(link, 0, config); + Transport receiver(link, 1, config); + + for (uint32_t i = 0; i < 30; ++i) sender.sendReliable(messageOf(i, 60)); + + std::vector order; + for (uint64_t tick = 0; tick < 200; ++tick) { + stepPair(sender, receiver, tick); + ByteBuffer got; + while (receiver.popReliable(got)) order.push_back(indexOf(got)); + } + + CHECK_EQ(order.size(), static_cast(30)); + for (std::size_t i = 0; i < order.size(); ++i) CHECK_EQ(order[i], static_cast(i)); + CHECK(receiver.stats().duplicatesDropped > 0u); + CHECK_EQ(link.duplicatedCount(), link.sentCount() - link.droppedCount()); + CHECK(receiver.stats().datagramsReceived > receiver.stats().duplicatesDropped); +} + +VF_TEST(theSendWindowCapsHowManyDatagramsCanBeUnacknowledgedAtOnce) { + LinkQuality quality; + quality.latencyTicks = 6; + quality.seed = 0x1010101020202020ull; + + LoopbackLink link(quality); + TransportConfig config; + config.mtu = 96; + config.sendWindow = 4; + config.retransmitTimeoutTicks = 40; + Transport sender(link, 0, config); + Transport receiver(link, 1, config); + + for (uint32_t i = 0; i < 60; ++i) sender.sendReliable(messageOf(i, 50)); + + std::size_t peakInFlight = 0; + std::size_t arrived = 0; + for (uint64_t tick = 0; tick < 900; ++tick) { + stepPair(sender, receiver, tick); + if (sender.inFlightDatagramCount() > peakInFlight) + peakInFlight = sender.inFlightDatagramCount(); + ByteBuffer got; + while (receiver.popReliable(got)) ++arrived; + } + CHECK_EQ(peakInFlight, static_cast(4)); + CHECK_EQ(arrived, static_cast(60)); +} + +VF_TEST(smoothedRoundTripTimeConvergesOnTheLinkLatency) { + LinkQuality quality; + quality.latencyTicks = 3; + quality.seed = 0x9999888877776666ull; + + LoopbackLink link(quality); + TransportConfig config; + config.mtu = 256; + config.retransmitTimeoutTicks = 30; + Transport sender(link, 0, config); + Transport receiver(link, 1, config); + + CHECK_EQ(sender.stats().smoothedRttTicks, 0.0); + for (uint32_t i = 0; i < 40; ++i) sender.sendReliable(messageOf(i, 20)); + for (uint64_t tick = 0; tick < 120; ++tick) { + stepPair(sender, receiver, tick); + ByteBuffer got; + while (receiver.popReliable(got)) { + } + } + CHECK_NEAR(sender.stats().smoothedRttTicks, 6.0, 0.001); + CHECK_EQ(sender.stats().datagramsLost, static_cast(0)); +} +