/* * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "net/dcsctp/tx/retransmission_timeout.h" #include "net/dcsctp/public/dcsctp_options.h" #include "rtc_base/gunit.h" #include "test/gmock.h" namespace dcsctp { namespace { using ::webrtc::TimeDelta; constexpr TimeDelta kMaxRtt = TimeDelta::Millis(8'000); constexpr TimeDelta kInitialRto = TimeDelta::Millis(200); constexpr TimeDelta kMaxRto = TimeDelta::Millis(800); constexpr TimeDelta kMinRto = TimeDelta::Millis(120); constexpr TimeDelta kMinRttVariance = TimeDelta::Millis(220); DcSctpOptions MakeOptions() { DcSctpOptions options; options.rtt_max = DurationMs(kMaxRtt); options.rto_initial = DurationMs(kInitialRto); options.rto_max = DurationMs(kMaxRto); options.rto_min = DurationMs(kMinRto); options.min_rtt_variance = DurationMs(kMinRttVariance); return options; } TEST(RetransmissionTimeoutTest, HasValidInitialRto) { RetransmissionTimeout rto_(MakeOptions()); EXPECT_EQ(rto_.rto(), kInitialRto); } TEST(RetransmissionTimeoutTest, HasValidInitialSrtt) { RetransmissionTimeout rto_(MakeOptions()); EXPECT_EQ(rto_.srtt(), kInitialRto); } TEST(RetransmissionTimeoutTest, NegativeValuesDoNotAffectRTO) { RetransmissionTimeout rto_(MakeOptions()); // Initial negative value rto_.ObserveRTT(TimeDelta::Millis(-10)); EXPECT_EQ(rto_.rto(), kInitialRto); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); // Subsequent negative value rto_.ObserveRTT(TimeDelta::Millis(-10)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); } TEST(RetransmissionTimeoutTest, TooLargeValuesDoNotAffectRTO) { RetransmissionTimeout rto_(MakeOptions()); // Initial too large value rto_.ObserveRTT(kMaxRtt + TimeDelta::Millis(100)); EXPECT_EQ(rto_.rto(), kInitialRto); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); // Subsequent too large value rto_.ObserveRTT(kMaxRtt + TimeDelta::Millis(100)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); } TEST(RetransmissionTimeoutTest, WillNeverGoBelowMinimumRto) { RetransmissionTimeout rto_(MakeOptions()); for (int i = 0; i < 1000; ++i) { rto_.ObserveRTT(TimeDelta::Millis(1)); } EXPECT_GE(rto_.rto(), kMinRto); } TEST(RetransmissionTimeoutTest, WillNeverGoAboveMaximumRto) { RetransmissionTimeout rto_(MakeOptions()); for (int i = 0; i < 1000; ++i) { rto_.ObserveRTT(kMaxRtt - TimeDelta::Millis(1)); // Adding jitter, which would make it RTO be well above RTT. rto_.ObserveRTT(kMaxRtt - TimeDelta::Millis(100)); } EXPECT_LE(rto_.rto(), kMaxRto); } TEST(RetransmissionTimeoutTest, CalculatesRtoForStableRtt) { RetransmissionTimeout rto_(MakeOptions()); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); rto_.ObserveRTT(TimeDelta::Millis(128)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(344)); rto_.ObserveRTT(TimeDelta::Millis(123)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(344)); rto_.ObserveRTT(TimeDelta::Millis(125)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(344)); rto_.ObserveRTT(TimeDelta::Millis(127)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(344)); } TEST(RetransmissionTimeoutTest, CalculatesRtoForUnstableRtt) { RetransmissionTimeout rto_(MakeOptions()); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); rto_.ObserveRTT(TimeDelta::Millis(402)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(622)); rto_.ObserveRTT(TimeDelta::Millis(728)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(800)); rto_.ObserveRTT(TimeDelta::Millis(89)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(800)); rto_.ObserveRTT(TimeDelta::Millis(126)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(800)); } TEST(RetransmissionTimeoutTest, WillStabilizeAfterAWhile) { RetransmissionTimeout rto_(MakeOptions()); rto_.ObserveRTT(TimeDelta::Millis(124)); rto_.ObserveRTT(TimeDelta::Millis(402)); rto_.ObserveRTT(TimeDelta::Millis(728)); rto_.ObserveRTT(TimeDelta::Millis(89)); rto_.ObserveRTT(TimeDelta::Millis(126)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(800)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(800)); rto_.ObserveRTT(TimeDelta::Millis(122)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(710)); rto_.ObserveRTT(TimeDelta::Millis(123)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(631)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(562)); rto_.ObserveRTT(TimeDelta::Millis(122)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(505)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(454)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(410)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(372)); rto_.ObserveRTT(TimeDelta::Millis(124)); EXPECT_EQ(rto_.rto(), TimeDelta::Millis(367)); } TEST(RetransmissionTimeoutTest, WillAlwaysStayAboveRTT) { // In simulations, it's quite common to have a very stable RTT, and having an // RTO at the same value will cause issues as expiry timers will be scheduled // to be expire exactly when a packet is supposed to arrive. The RTO must be // larger than the RTT. In non-simulated environments, this is a non-issue as // any jitter will increase the RTO. RetransmissionTimeout rto_(MakeOptions()); for (int i = 0; i < 1000; ++i) { rto_.ObserveRTT(TimeDelta::Millis(124)); } EXPECT_EQ(rto_.rto(), TimeDelta::Millis(344)); } TEST(RetransmissionTimeoutTest, CanSpecifySmallerMinimumRttVariance) { DcSctpOptions options = MakeOptions(); options.min_rtt_variance = DurationMs(kMinRttVariance - TimeDelta::Millis(100)); RetransmissionTimeout rto_(options); for (int i = 0; i < 1000; ++i) { rto_.ObserveRTT(TimeDelta::Millis(124)); } EXPECT_EQ(rto_.rto(), TimeDelta::Millis(244)); } TEST(RetransmissionTimeoutTest, CanSpecifyLargerMinimumRttVariance) { DcSctpOptions options = MakeOptions(); options.min_rtt_variance = DurationMs(kMinRttVariance + TimeDelta::Millis(100)); RetransmissionTimeout rto_(options); for (int i = 0; i < 1000; ++i) { rto_.ObserveRTT(TimeDelta::Millis(124)); } EXPECT_EQ(rto_.rto(), TimeDelta::Millis(444)); } } // namespace } // namespace dcsctp