webrtc_m130/net/dcsctp/rx/data_tracker_test.cc
Victor Boivie a55746808e dcsctp: Only process meaningful FORWARD-TSN
Similar to change I602a8552a9a4c853684fcf105309ec3d8073f2c2, which
ensured that only new DATA chunks would be processed by the reassembly
queue by utilizing the data tracker, the same is done for FORWARD-TSN
chunks.

By having the data tracker gate keeping what is provided to the
reassembly queue, the reassembly queue can be simplified as well, which
is an added bonus, by removing last_assembled_tsn_watermark_ and
reassembled_messages_ as those were protecting the queue from
re-delivering messages it had already delivered, but as now the data
tracker would ensure that it wouldn't re-process DATA/FORWARD-TSNs, that
would have the same effect. In this CL, we will still update those
variables and save to the handover state, but not actually read from
them, and then when this change has been rolled out on the servers, I
can remove the variables as well.

The core change is to move validation from ReassemblyQueue::Handle
to DataTracker::HandleForwardTsn.

Some tests have been moved/replicated into data_tracker_test.cc to
ensure that it catches the issues that the reassembly queue did earlier.

Bug: webrtc:14600
Change-Id: I75c1d5911185d594f73c8b1e6bcf776e88f5b7c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/321603
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40856}
2023-10-02 16:05:11 +00:00

789 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;
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 absl::nullopt; },
TimerOptions(DurationMs(0)))),
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);
}
TimeMs now_ = TimeMs(0);
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