mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

While this is a fairly big CL, it's fairly straightforward. It replaces uses of TimeMs with webrtc::Timestamp, and additionally does some cleanup of DurationMs to webrtc::TimeDelta that are now easier to do. Bug: webrtc:15593 Change-Id: Id0e3edcba0533e0e8df3358b1778b6995c344243 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/326560 Reviewed-by: Florent Castelli <orphis@webrtc.org> Commit-Queue: Victor Boivie <boivie@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41138}
790 lines
28 KiB
C++
790 lines
28 KiB
C++
/*
|
|
* 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 "absl/types/optional.h"
|
|
#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)));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace dcsctp
|