| /* |
| * 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/rx/data_tracker.h" |
| |
| #include <cstdint> |
| #include <initializer_list> |
| #include <memory> |
| #include <optional> |
| |
| #include "api/array_view.h" |
| #include "api/task_queue/task_queue_base.h" |
| #include "net/dcsctp/common/handover_testing.h" |
| #include "net/dcsctp/packet/chunk/sack_chunk.h" |
| #include "net/dcsctp/timer/fake_timeout.h" |
| #include "net/dcsctp/timer/timer.h" |
| #include "rtc_base/gunit.h" |
| #include "test/gmock.h" |
| |
| namespace dcsctp { |
| namespace { |
| using ::testing::ElementsAre; |
| using ::testing::IsEmpty; |
| using ::testing::SizeIs; |
| using ::testing::UnorderedElementsAre; |
| using ::webrtc::TimeDelta; |
| using ::webrtc::Timestamp; |
| |
| constexpr size_t kArwnd = 10000; |
| constexpr TSN kInitialTSN(11); |
| |
| class DataTrackerTest : public testing::Test { |
| protected: |
| DataTrackerTest() |
| : timeout_manager_([this]() { return now_; }), |
| timer_manager_([this](webrtc::TaskQueueBase::DelayPrecision precision) { |
| return timeout_manager_.CreateTimeout(precision); |
| }), |
| timer_(timer_manager_.CreateTimer( |
| "test/delayed_ack", |
| []() { return TimeDelta::Zero(); }, |
| TimerOptions(TimeDelta::Zero()))), |
| tracker_( |
| std::make_unique<DataTracker>("log: ", timer_.get(), kInitialTSN)) { |
| } |
| |
| void Observer(std::initializer_list<uint32_t> tsns, |
| bool expect_as_duplicate = false) { |
| for (const uint32_t tsn : tsns) { |
| if (expect_as_duplicate) { |
| EXPECT_FALSE( |
| tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false))); |
| } else { |
| EXPECT_TRUE( |
| tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false))); |
| } |
| } |
| } |
| |
| void HandoverTracker() { |
| EXPECT_TRUE(tracker_->GetHandoverReadiness().IsReady()); |
| DcSctpSocketHandoverState state; |
| tracker_->AddHandoverState(state); |
| g_handover_state_transformer_for_test(&state); |
| tracker_ = |
| std::make_unique<DataTracker>("log: ", timer_.get(), kInitialTSN); |
| tracker_->RestoreFromState(state); |
| } |
| |
| Timestamp now_ = Timestamp::Zero(); |
| FakeTimeoutManager timeout_manager_; |
| TimerManager timer_manager_; |
| std::unique_ptr<Timer> timer_; |
| std::unique_ptr<DataTracker> tracker_; |
| }; |
| |
| TEST_F(DataTrackerTest, Empty) { |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ObserverSingleInOrderPacket) { |
| Observer({11}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ObserverManyInOrderMovesCumulativeTsnAck) { |
| Observer({11, 12, 13}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(13)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ObserveOutOfOrderMovesCumulativeTsnAck) { |
| Observer({12, 13, 14, 11}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, SingleGap) { |
| Observer({12}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ExampleFromRFC4960Section334) { |
| Observer({11, 12, 14, 15, 17}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(12)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3), |
| SackChunk::GapAckBlock(5, 5))); |
| EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, AckAlreadyReceivedChunk) { |
| Observer({11}); |
| SackChunk sack1 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack1.gap_ack_blocks(), IsEmpty()); |
| |
| // Receive old chunk |
| Observer({8}, /*expect_as_duplicate=*/true); |
| SackChunk sack2 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, DoubleSendRetransmittedChunk) { |
| Observer({11, 13, 14, 15}); |
| SackChunk sack1 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack1.gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 4))); |
| |
| // Fill in the hole. |
| Observer({12, 16, 17, 18}); |
| SackChunk sack2 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(18)); |
| EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); |
| |
| // Receive chunk 12 again. |
| Observer({12}, /*expect_as_duplicate=*/true); |
| Observer({19, 20, 21}); |
| SackChunk sack3 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack3.cumulative_tsn_ack(), TSN(21)); |
| EXPECT_THAT(sack3.gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ForwardTsnSimple) { |
| // Messages (11, 12, 13), (14, 15) - first message expires. |
| Observer({11, 12, 15}); |
| |
| tracker_->HandleForwardTsn(TSN(13)); |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(13)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); |
| } |
| |
| TEST_F(DataTrackerTest, ForwardTsnSkipsFromGapBlock) { |
| // Messages (11, 12, 13), (14, 15) - first message expires. |
| Observer({11, 12, 14}); |
| |
| tracker_->HandleForwardTsn(TSN(13)); |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, ExampleFromRFC3758) { |
| tracker_->HandleForwardTsn(TSN(102)); |
| |
| Observer({102}, /*expect_as_duplicate=*/true); |
| Observer({104, 105, 107}); |
| |
| tracker_->HandleForwardTsn(TSN(103)); |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(105)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); |
| } |
| |
| TEST_F(DataTrackerTest, EmptyAllAcks) { |
| Observer({11, 13, 14, 15}); |
| |
| tracker_->HandleForwardTsn(TSN(100)); |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(100)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, SetsArwndCorrectly) { |
| SackChunk sack1 = tracker_->CreateSelectiveAck(/*a_rwnd=*/100); |
| EXPECT_EQ(sack1.a_rwnd(), 100u); |
| |
| SackChunk sack2 = tracker_->CreateSelectiveAck(/*a_rwnd=*/101); |
| EXPECT_EQ(sack2.a_rwnd(), 101u); |
| } |
| |
| TEST_F(DataTrackerTest, WillIncreaseCumAckTsn) { |
| EXPECT_EQ(tracker_->last_cumulative_acked_tsn(), TSN(10)); |
| EXPECT_FALSE(tracker_->will_increase_cum_ack_tsn(TSN(10))); |
| EXPECT_TRUE(tracker_->will_increase_cum_ack_tsn(TSN(11))); |
| EXPECT_FALSE(tracker_->will_increase_cum_ack_tsn(TSN(12))); |
| |
| Observer({11, 12, 13, 14, 15}); |
| EXPECT_EQ(tracker_->last_cumulative_acked_tsn(), TSN(15)); |
| EXPECT_FALSE(tracker_->will_increase_cum_ack_tsn(TSN(15))); |
| EXPECT_TRUE(tracker_->will_increase_cum_ack_tsn(TSN(16))); |
| EXPECT_FALSE(tracker_->will_increase_cum_ack_tsn(TSN(17))); |
| } |
| |
| TEST_F(DataTrackerTest, ForceShouldSendSackImmediately) { |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| |
| tracker_->ForceImmediateSack(); |
| |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| } |
| |
| TEST_F(DataTrackerTest, WillAcceptValidTSNs) { |
| // The initial TSN is always one more than the last, which is our base. |
| TSN last_tsn = TSN(*kInitialTSN - 1); |
| int limit = static_cast<int>(DataTracker::kMaxAcceptedOutstandingFragments); |
| |
| for (int i = -limit; i <= limit; ++i) { |
| EXPECT_TRUE(tracker_->IsTSNValid(TSN(*last_tsn + i))); |
| } |
| } |
| |
| TEST_F(DataTrackerTest, WillNotAcceptInvalidTSNs) { |
| // The initial TSN is always one more than the last, which is our base. |
| TSN last_tsn = TSN(*kInitialTSN - 1); |
| |
| size_t limit = DataTracker::kMaxAcceptedOutstandingFragments; |
| EXPECT_FALSE(tracker_->IsTSNValid(TSN(*last_tsn + limit + 1))); |
| EXPECT_FALSE(tracker_->IsTSNValid(TSN(*last_tsn - (limit + 1)))); |
| EXPECT_FALSE(tracker_->IsTSNValid(TSN(*last_tsn + 0x8000000))); |
| EXPECT_FALSE(tracker_->IsTSNValid(TSN(*last_tsn - 0x8000000))); |
| } |
| |
| TEST_F(DataTrackerTest, ReportSingleDuplicateTsns) { |
| Observer({11, 12}); |
| Observer({11}, /*expect_as_duplicate=*/true); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(12)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), UnorderedElementsAre(TSN(11))); |
| } |
| |
| TEST_F(DataTrackerTest, ReportMultipleDuplicateTsns) { |
| Observer({11, 12, 13, 14}); |
| Observer({12, 13, 12, 13}, /*expect_as_duplicate=*/true); |
| Observer({15, 16}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(16)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), UnorderedElementsAre(TSN(12), TSN(13))); |
| } |
| |
| TEST_F(DataTrackerTest, ReportDuplicateTsnsInGapAckBlocks) { |
| Observer({11, /*12,*/ 13, 14}); |
| Observer({13, 14}, /*expect_as_duplicate=*/true); |
| Observer({15, 16}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 5))); |
| EXPECT_THAT(sack.duplicate_tsns(), UnorderedElementsAre(TSN(13), TSN(14))); |
| } |
| |
| TEST_F(DataTrackerTest, ClearsDuplicateTsnsAfterCreatingSack) { |
| Observer({11, 12, 13, 14}); |
| Observer({12, 13, 12, 13}, /*expect_as_duplicate=*/true); |
| Observer({15, 16}); |
| SackChunk sack1 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(16)); |
| EXPECT_THAT(sack1.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack1.duplicate_tsns(), UnorderedElementsAre(TSN(12), TSN(13))); |
| |
| Observer({17}); |
| SackChunk sack2 = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(17)); |
| EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack2.duplicate_tsns(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, LimitsNumberOfDuplicatesReported) { |
| for (size_t i = 0; i < DataTracker::kMaxDuplicateTsnReported + 10; ++i) { |
| TSN tsn(11 + i); |
| tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false)); |
| tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false)); |
| } |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| EXPECT_THAT(sack.duplicate_tsns(), |
| SizeIs(DataTracker::kMaxDuplicateTsnReported)); |
| } |
| |
| TEST_F(DataTrackerTest, LimitsNumberOfGapAckBlocksReported) { |
| for (size_t i = 0; i < DataTracker::kMaxGapAckBlocksReported + 10; ++i) { |
| TSN tsn(11 + i * 2); |
| tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false)); |
| } |
| |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack.gap_ack_blocks(), |
| SizeIs(DataTracker::kMaxGapAckBlocksReported)); |
| } |
| |
| TEST_F(DataTrackerTest, SendsSackForFirstPacketObserved) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, SendsSackEverySecondPacketWhenThereIsNoPacketLoss) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({12}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| Observer({13}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({14}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| Observer({15}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, SendsSackEveryPacketOnPacketLoss) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({13}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({14}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({15}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({16}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| // Fill the hole. |
| Observer({12}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| // Goes back to every second packet |
| Observer({17}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({18}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, SendsSackOnDuplicateDataChunks) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({11}, /*expect_as_duplicate=*/true); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({12}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| // Goes back to every second packet |
| Observer({13}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| // Duplicate again |
| Observer({12}, /*expect_as_duplicate=*/true); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockAddSingleBlock) { |
| Observer({12}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockAddsAnother) { |
| Observer({12}); |
| Observer({14}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2), |
| SackChunk::GapAckBlock(4, 4))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockAddsDuplicate) { |
| Observer({12}); |
| Observer({12}, /*expect_as_duplicate=*/true); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); |
| EXPECT_THAT(sack.duplicate_tsns(), ElementsAre(TSN(12))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockExpandsToRight) { |
| Observer({12}); |
| Observer({13}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockExpandsToRightWithOther) { |
| Observer({12}); |
| Observer({20}); |
| Observer({30}); |
| Observer({21}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 2), // |
| SackChunk::GapAckBlock(10, 11), // |
| SackChunk::GapAckBlock(20, 20))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockExpandsToLeft) { |
| Observer({13}); |
| Observer({12}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockExpandsToLeftWithOther) { |
| Observer({12}); |
| Observer({21}); |
| Observer({30}); |
| Observer({20}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 2), // |
| SackChunk::GapAckBlock(10, 11), // |
| SackChunk::GapAckBlock(20, 20))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockExpandsToLRightAndMerges) { |
| Observer({12}); |
| Observer({20}); |
| Observer({22}); |
| Observer({30}); |
| Observer({21}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(sack.gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 2), // |
| SackChunk::GapAckBlock(10, 12), // |
| SackChunk::GapAckBlock(20, 20))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockMergesManyBlocksIntoOne) { |
| Observer({22}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12))); |
| Observer({30}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12), // |
| SackChunk::GapAckBlock(20, 20))); |
| Observer({24}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12), // |
| SackChunk::GapAckBlock(14, 14), // |
| SackChunk::GapAckBlock(20, 20))); |
| Observer({28}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12), // |
| SackChunk::GapAckBlock(14, 14), // |
| SackChunk::GapAckBlock(18, 18), // |
| SackChunk::GapAckBlock(20, 20))); |
| Observer({26}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12), // |
| SackChunk::GapAckBlock(14, 14), // |
| SackChunk::GapAckBlock(16, 16), // |
| SackChunk::GapAckBlock(18, 18), // |
| SackChunk::GapAckBlock(20, 20))); |
| Observer({29}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 12), // |
| SackChunk::GapAckBlock(14, 14), // |
| SackChunk::GapAckBlock(16, 16), // |
| SackChunk::GapAckBlock(18, 20))); |
| Observer({23}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 14), // |
| SackChunk::GapAckBlock(16, 16), // |
| SackChunk::GapAckBlock(18, 20))); |
| Observer({27}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 14), // |
| SackChunk::GapAckBlock(16, 20))); |
| |
| Observer({25}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(12, 20))); |
| Observer({20}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(10, 10), // |
| SackChunk::GapAckBlock(12, 20))); |
| Observer({32}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(10, 10), // |
| SackChunk::GapAckBlock(12, 20), // |
| SackChunk::GapAckBlock(22, 22))); |
| Observer({21}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(10, 20), // |
| SackChunk::GapAckBlock(22, 22))); |
| Observer({31}); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(10, 22))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveBeforeCumAckTsn) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(8)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(10)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 4), // |
| SackChunk::GapAckBlock(10, 12), |
| SackChunk::GapAckBlock(20, 21))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveBeforeFirstBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(11)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(6, 8), // |
| SackChunk::GapAckBlock(16, 17))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveAtBeginningOfFirstBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(12)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(6, 8), // |
| SackChunk::GapAckBlock(16, 17))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveAtMiddleOfFirstBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| tracker_->HandleForwardTsn(TSN(13)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(6, 8), // |
| SackChunk::GapAckBlock(16, 17))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveAtEndOfFirstBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| tracker_->HandleForwardTsn(TSN(14)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(6, 8), // |
| SackChunk::GapAckBlock(16, 17))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveRightAfterFirstBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(18)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(18)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(2, 4), // |
| SackChunk::GapAckBlock(12, 13))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveRightBeforeSecondBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(19)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(8, 9))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveRightAtStartOfSecondBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(20)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(8, 9))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveRightAtMiddleOfSecondBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(21)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(8, 9))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveRightAtEndOfSecondBlock) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(22)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), |
| ElementsAre(SackChunk::GapAckBlock(8, 9))); |
| } |
| |
| TEST_F(DataTrackerTest, GapAckBlockRemoveeFarAfterAllBlocks) { |
| Observer({12, 13, 14, 20, 21, 22, 30, 31}); |
| |
| tracker_->HandleForwardTsn(TSN(40)); |
| EXPECT_EQ(tracker_->CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(40)); |
| EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, HandoverEmpty) { |
| HandoverTracker(); |
| Observer({11}); |
| SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); |
| EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); |
| EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); |
| } |
| |
| TEST_F(DataTrackerTest, |
| HandoverWhileSendingSackEverySecondPacketWhenThereIsNoPacketLoss) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| |
| HandoverTracker(); |
| |
| Observer({12}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| Observer({13}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| Observer({14}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| Observer({15}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_FALSE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, HandoverWhileSendingSackEveryPacketOnPacketLoss) { |
| Observer({11}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| Observer({13}); |
| EXPECT_EQ(tracker_->GetHandoverReadiness(), |
| HandoverReadinessStatus().Add( |
| HandoverUnreadinessReason::kDataTrackerTsnBlocksPending)); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| Observer({14}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| EXPECT_EQ(tracker_->GetHandoverReadiness(), |
| HandoverReadinessStatus( |
| HandoverUnreadinessReason::kDataTrackerTsnBlocksPending)); |
| Observer({15}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| Observer({16}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| // Fill the hole. |
| Observer({12}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| // Goes back to every second packet |
| Observer({17}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_TRUE(tracker_->ShouldSendAck()); |
| |
| HandoverTracker(); |
| |
| Observer({18}); |
| tracker_->ObservePacketEnd(); |
| EXPECT_FALSE(tracker_->ShouldSendAck()); |
| EXPECT_TRUE(timer_->is_running()); |
| } |
| |
| TEST_F(DataTrackerTest, DoesNotAcceptDataBeforeForwardTsn) { |
| Observer({12, 13, 14, 15, 17}); |
| tracker_->ObservePacketEnd(); |
| |
| tracker_->HandleForwardTsn(TSN(13)); |
| |
| EXPECT_FALSE(tracker_->Observe(TSN(11))); |
| } |
| |
| TEST_F(DataTrackerTest, DoesNotAcceptDataAtForwardTsn) { |
| Observer({12, 13, 14, 15, 17}); |
| tracker_->ObservePacketEnd(); |
| |
| tracker_->HandleForwardTsn(TSN(16)); |
| |
| EXPECT_FALSE(tracker_->Observe(TSN(16))); |
| } |
| |
| TEST_F(DataTrackerTest, DoesNotAcceptDataBeforeCumAckTsn) { |
| EXPECT_EQ(kInitialTSN, TSN(11)); |
| EXPECT_FALSE(tracker_->Observe(TSN(10))); |
| } |
| |
| TEST_F(DataTrackerTest, DoesNotAcceptContiguousDuplicateData) { |
| EXPECT_EQ(kInitialTSN, TSN(11)); |
| EXPECT_TRUE(tracker_->Observe(TSN(11))); |
| EXPECT_FALSE(tracker_->Observe(TSN(11))); |
| EXPECT_TRUE(tracker_->Observe(TSN(12))); |
| EXPECT_FALSE(tracker_->Observe(TSN(12))); |
| EXPECT_FALSE(tracker_->Observe(TSN(11))); |
| EXPECT_FALSE(tracker_->Observe(TSN(10))); |
| } |
| |
| TEST_F(DataTrackerTest, DoesNotAcceptGapsWithDuplicateData) { |
| EXPECT_EQ(kInitialTSN, TSN(11)); |
| EXPECT_TRUE(tracker_->Observe(TSN(11))); |
| EXPECT_FALSE(tracker_->Observe(TSN(11))); |
| |
| EXPECT_TRUE(tracker_->Observe(TSN(14))); |
| EXPECT_FALSE(tracker_->Observe(TSN(14))); |
| |
| EXPECT_TRUE(tracker_->Observe(TSN(13))); |
| EXPECT_FALSE(tracker_->Observe(TSN(13))); |
| |
| EXPECT_TRUE(tracker_->Observe(TSN(12))); |
| EXPECT_FALSE(tracker_->Observe(TSN(12))); |
| } |
| |
| TEST_F(DataTrackerTest, NotReadyForHandoverWhenHavingTsnGaps) { |
| tracker_->Observe(TSN(10)); |
| tracker_->Observe(TSN(12)); |
| EXPECT_EQ(tracker_->GetHandoverReadiness(), |
| HandoverReadinessStatus().Add( |
| HandoverUnreadinessReason::kDataTrackerTsnBlocksPending)); |
| |
| tracker_->Observe(TSN(11)); |
| EXPECT_EQ(tracker_->GetHandoverReadiness(), HandoverReadinessStatus()); |
| } |
| |
| } // namespace |
| } // namespace dcsctp |