#include "common.hpp"
#include "RTC/SCTP/public/SctpOptions.hpp"
#include "RTC/SCTP/tx/RetransmissionTimeout.hpp"
#include <catch2/catch_test_macros.hpp>
SCENARIO("SCTP RetransmissionTimeout", "[sctp][retransmissiontimeout]")
{
constexpr uint64_t MaxRttMs{ 8000 };
constexpr uint64_t InitialRtoMs{ 200 };
constexpr uint64_t MaxRtoMs{ 800 };
constexpr uint64_t MinRtoMs{ 120 };
constexpr uint64_t MinRttVarianceMs{ 220 };
auto makeSctpOptions = []()
{
RTC::SCTP::SctpOptions sctpOptions{ .maxRttMs = MaxRttMs,
.initialRtoMs = InitialRtoMs,
.minRtoMs = MinRtoMs,
.maxRtoMs = MaxRtoMs,
.minRttVarianceMs = MinRttVarianceMs };
return sctpOptions;
};
SECTION("has valid initial RTO")
{
const RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
REQUIRE(rto.GetRtoMs() == InitialRtoMs);
}
SECTION("too large values don't affect RTO")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
rto.ObserveRttMs(MaxRttMs + 100);
REQUIRE(rto.GetRtoMs() == InitialRtoMs);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 372);
rto.ObserveRttMs(MaxRttMs + 100);
REQUIRE(rto.GetRtoMs() == 372);
}
SECTION("will never go below minimum RTO")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
for (int i{ 0 }; i < 1000; ++i)
{
rto.ObserveRttMs(1);
}
REQUIRE(rto.GetRtoMs() <= MinRtoMs);
}
SECTION("will never go above maximum RTO")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
for (int i{ 0 }; i < 1000; ++i)
{
rto.ObserveRttMs(MaxRttMs - 1);
rto.ObserveRttMs(MaxRttMs - 100);
}
REQUIRE(rto.GetRtoMs() >= MaxRtoMs);
}
SECTION("calculates RTO for stable RTT")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 372);
rto.ObserveRttMs(128);
REQUIRE(rto.GetRtoMs() == 315);
rto.ObserveRttMs(123);
REQUIRE(rto.GetRtoMs() == 268);
rto.ObserveRttMs(125);
REQUIRE(rto.GetRtoMs() == 233);
rto.ObserveRttMs(127);
REQUIRE(rto.GetRtoMs() == 233);
}
SECTION("calculates RTO for unstable RTT")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 372);
rto.ObserveRttMs(402);
REQUIRE(rto.GetRtoMs() == 623);
rto.ObserveRttMs(728);
REQUIRE(rto.GetRtoMs() == 800);
rto.ObserveRttMs(89);
REQUIRE(rto.GetRtoMs() == 800);
rto.ObserveRttMs(126);
REQUIRE(rto.GetRtoMs() == 800);
}
SECTION("will stabilize RTO after a while")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
rto.ObserveRttMs(124);
rto.ObserveRttMs(402);
rto.ObserveRttMs(728);
rto.ObserveRttMs(89);
rto.ObserveRttMs(126);
REQUIRE(rto.GetRtoMs() == 800);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 800);
rto.ObserveRttMs(122);
REQUIRE(rto.GetRtoMs() == 709);
rto.ObserveRttMs(123);
REQUIRE(rto.GetRtoMs() == 630);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 562);
rto.ObserveRttMs(122);
REQUIRE(rto.GetRtoMs() == 505);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 454);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 410);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 372);
rto.ObserveRttMs(124);
REQUIRE(rto.GetRtoMs() == 340);
}
SECTION("will always stay above RTT")
{
RTC::SCTP::RetransmissionTimeout rto(makeSctpOptions());
for (int i{ 0 }; i < 1000; ++i)
{
rto.ObserveRttMs(124);
}
REQUIRE(rto.GetRtoMs() == 232);
}
SECTION("can specify smaller minimum RTT variance")
{
auto sctpOptions = makeSctpOptions();
sctpOptions.minRttVarianceMs = MinRttVarianceMs - 100;
RTC::SCTP::RetransmissionTimeout rto(sctpOptions);
for (int i{ 0 }; i < 1000; ++i)
{
rto.ObserveRttMs(124);
}
REQUIRE(rto.GetRtoMs() == 184);
}
SECTION("can specify larger minimum RTT variance")
{
auto sctpOptions = makeSctpOptions();
sctpOptions.minRttVarianceMs = MinRttVarianceMs + 100;
RTC::SCTP::RetransmissionTimeout rto(sctpOptions);
for (int i{ 0 }; i < 1000; ++i)
{
rto.ObserveRttMs(124);
}
REQUIRE(rto.GetRtoMs() == 284);
}
}