dcsctp: implement handover in DataTracker

Bug: webrtc:13154
Change-Id: Ia8c41dcffd95dafd904ee630f2131b575fe833dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231955
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Commit-Queue: Sergey Sukhanov <sergeysu@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34996}
This commit is contained in:
Sergey Sukhanov 2021-09-14 22:08:53 +02:00 committed by WebRTC LUCI CQ
parent e229fb83fb
commit 225cd47445
5 changed files with 257 additions and 152 deletions

View File

@ -32,6 +32,8 @@ struct DcSctpSocketHandoverState {
uint32_t id = 0;
};
struct Receive {
bool seen_packet = false;
uint32_t last_cumulative_acked_tsn = 0;
std::vector<OrderedStream> ordered_streams;
std::vector<UnorderedStream> unordered_streams;
};
@ -42,7 +44,7 @@ struct DcSctpSocketHandoverState {
enum class HandoverUnreadinessReason : uint32_t {
kWrongConnectionState = 1,
kSendQueueNotEmpty = 2,
kDataTrackerNotIdle = 4,
kPendingStreamResetRequest = 4,
kDataTrackerTsnBlocksPending = 8,
kReassemblyQueueNotEmpty = 16,
kReassemblyQueueDeliveredTSNsGap = 32,
@ -53,8 +55,7 @@ enum class HandoverUnreadinessReason : uint32_t {
kRetransmissionQueueFastRecovery = 1024,
kRetransmissionQueueNotEmpty = 2048,
kPendingStreamReset = 4096,
kPendingStreamResetRequest = 8192,
kMax = kPendingStreamResetRequest,
kMax = kPendingStreamReset,
};
// Return value of `DcSctpSocketInterface::GetHandoverReadiness`. Set of

View File

@ -17,6 +17,7 @@ rtc_library("data_tracker") {
"../common:sequence_numbers",
"../packet:chunk",
"../packet:data",
"../public:socket",
"../timer",
]
sources = [

View File

@ -356,4 +356,17 @@ absl::string_view DataTracker::ToString(AckState ack_state) {
}
}
HandoverReadinessStatus DataTracker::GetHandoverReadiness() const {
HandoverReadinessStatus status;
if (!additional_tsn_blocks_.empty()) {
status.Add(HandoverUnreadinessReason::kDataTrackerTsnBlocksPending);
}
return status;
}
void DataTracker::AddHandoverState(DcSctpSocketHandoverState& state) {
state.rx.last_cumulative_acked_tsn = last_cumulative_acked_tsn().value();
state.rx.seen_packet = seen_packet_;
}
} // namespace dcsctp

View File

@ -24,6 +24,7 @@
#include "net/dcsctp/packet/chunk/data_common.h"
#include "net/dcsctp/packet/chunk/sack_chunk.h"
#include "net/dcsctp/packet/data.h"
#include "net/dcsctp/public/dcsctp_handover_state.h"
#include "net/dcsctp/timer/timer.h"
namespace dcsctp {
@ -51,13 +52,17 @@ class DataTracker {
// cumulative acked TSN.
static constexpr uint32_t kMaxAcceptedOutstandingFragments = 100000;
explicit DataTracker(absl::string_view log_prefix,
Timer* delayed_ack_timer,
TSN peer_initial_tsn)
DataTracker(absl::string_view log_prefix,
Timer* delayed_ack_timer,
TSN peer_initial_tsn,
const DcSctpSocketHandoverState* handover_state = nullptr)
: log_prefix_(std::string(log_prefix) + "dtrack: "),
seen_packet_(handover_state != nullptr ? handover_state->rx.seen_packet
: false),
delayed_ack_timer_(*delayed_ack_timer),
last_cumulative_acked_tsn_(
tsn_unwrapper_.Unwrap(TSN(*peer_initial_tsn - 1))) {}
last_cumulative_acked_tsn_(tsn_unwrapper_.Unwrap(
handover_state ? TSN(handover_state->rx.last_cumulative_acked_tsn)
: TSN(*peer_initial_tsn - 1))) {}
// Indicates if the provided TSN is valid. If this return false, the data
// should be dropped and not added to any other buffers, which essentially
@ -101,6 +106,10 @@ class DataTracker {
void HandleDelayedAckTimerExpiry();
HandoverReadinessStatus GetHandoverReadiness() const;
void AddHandoverState(DcSctpSocketHandoverState& state);
private:
enum class AckState {
// No need to send an ACK.
@ -166,7 +175,7 @@ class DataTracker {
const std::string log_prefix_;
// If a packet has ever been seen.
bool seen_packet_ = false;
bool seen_packet_;
Timer& delayed_ack_timer_;
AckState ack_state_ = AckState::kIdle;
UnwrappedTSN::Unwrapper tsn_unwrapper_;

View File

@ -40,23 +40,33 @@ class DataTrackerTest : public testing::Test {
"test/delayed_ack",
[]() { return absl::nullopt; },
TimerOptions(DurationMs(0)))),
buf_("log: ", timer_.get(), kInitialTSN) {}
tracker_(
std::make_unique<DataTracker>("log: ", timer_.get(), kInitialTSN)) {
}
void Observer(std::initializer_list<uint32_t> tsns) {
for (const uint32_t tsn : tsns) {
buf_.Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false));
tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false));
}
}
void HandoverTracker() {
EXPECT_TRUE(tracker_->GetHandoverReadiness().IsReady());
DcSctpSocketHandoverState state;
tracker_->AddHandoverState(state);
tracker_ = std::make_unique<DataTracker>("log: ", timer_.get(), kInitialTSN,
&state);
}
TimeMs now_ = TimeMs(0);
FakeTimeoutManager timeout_manager_;
TimerManager timer_manager_;
std::unique_ptr<Timer> timer_;
DataTracker buf_;
std::unique_ptr<DataTracker> tracker_;
};
TEST_F(DataTrackerTest, Empty) {
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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());
@ -64,7 +74,7 @@ TEST_F(DataTrackerTest, Empty) {
TEST_F(DataTrackerTest, ObserverSingleInOrderPacket) {
Observer({11});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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());
@ -72,7 +82,7 @@ TEST_F(DataTrackerTest, ObserverSingleInOrderPacket) {
TEST_F(DataTrackerTest, ObserverManyInOrderMovesCumulativeTsnAck) {
Observer({11, 12, 13});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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());
@ -80,7 +90,7 @@ TEST_F(DataTrackerTest, ObserverManyInOrderMovesCumulativeTsnAck) {
TEST_F(DataTrackerTest, ObserveOutOfOrderMovesCumulativeTsnAck) {
Observer({12, 13, 14, 11});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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());
@ -88,7 +98,7 @@ TEST_F(DataTrackerTest, ObserveOutOfOrderMovesCumulativeTsnAck) {
TEST_F(DataTrackerTest, SingleGap) {
Observer({12});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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());
@ -96,7 +106,7 @@ TEST_F(DataTrackerTest, SingleGap) {
TEST_F(DataTrackerTest, ExampleFromRFC4960Section334) {
Observer({11, 12, 14, 15, 17});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -105,33 +115,33 @@ TEST_F(DataTrackerTest, ExampleFromRFC4960Section334) {
TEST_F(DataTrackerTest, AckAlreadyReceivedChunk) {
Observer({11});
SackChunk sack1 = buf_.CreateSelectiveAck(kArwnd);
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});
SackChunk sack2 = buf_.CreateSelectiveAck(kArwnd);
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 = buf_.CreateSelectiveAck(kArwnd);
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 = buf_.CreateSelectiveAck(kArwnd);
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, 19, 20, 21});
SackChunk sack3 = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack3 = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack3.cumulative_tsn_ack(), TSN(21));
EXPECT_THAT(sack3.gap_ack_blocks(), IsEmpty());
}
@ -140,9 +150,9 @@ TEST_F(DataTrackerTest, ForwardTsnSimple) {
// Messages (11, 12, 13), (14, 15) - first message expires.
Observer({11, 12, 15});
buf_.HandleForwardTsn(TSN(13));
tracker_->HandleForwardTsn(TSN(13));
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(13));
EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2)));
}
@ -151,21 +161,21 @@ TEST_F(DataTrackerTest, ForwardTsnSkipsFromGapBlock) {
// Messages (11, 12, 13), (14, 15) - first message expires.
Observer({11, 12, 14});
buf_.HandleForwardTsn(TSN(13));
tracker_->HandleForwardTsn(TSN(13));
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(14));
EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty());
}
TEST_F(DataTrackerTest, ExampleFromRFC3758) {
buf_.HandleForwardTsn(TSN(102));
tracker_->HandleForwardTsn(TSN(102));
Observer({102, 104, 105, 107});
buf_.HandleForwardTsn(TSN(103));
tracker_->HandleForwardTsn(TSN(103));
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(105));
EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2)));
}
@ -173,40 +183,40 @@ TEST_F(DataTrackerTest, ExampleFromRFC3758) {
TEST_F(DataTrackerTest, EmptyAllAcks) {
Observer({11, 13, 14, 15});
buf_.HandleForwardTsn(TSN(100));
tracker_->HandleForwardTsn(TSN(100));
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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 = buf_.CreateSelectiveAck(/*a_rwnd=*/100);
SackChunk sack1 = tracker_->CreateSelectiveAck(/*a_rwnd=*/100);
EXPECT_EQ(sack1.a_rwnd(), 100u);
SackChunk sack2 = buf_.CreateSelectiveAck(/*a_rwnd=*/101);
SackChunk sack2 = tracker_->CreateSelectiveAck(/*a_rwnd=*/101);
EXPECT_EQ(sack2.a_rwnd(), 101u);
}
TEST_F(DataTrackerTest, WillIncreaseCumAckTsn) {
EXPECT_EQ(buf_.last_cumulative_acked_tsn(), TSN(10));
EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(10)));
EXPECT_TRUE(buf_.will_increase_cum_ack_tsn(TSN(11)));
EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(12)));
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(buf_.last_cumulative_acked_tsn(), TSN(15));
EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(15)));
EXPECT_TRUE(buf_.will_increase_cum_ack_tsn(TSN(16)));
EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(17)));
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(buf_.ShouldSendAck());
EXPECT_FALSE(tracker_->ShouldSendAck());
buf_.ForceImmediateSack();
tracker_->ForceImmediateSack();
EXPECT_TRUE(buf_.ShouldSendAck());
EXPECT_TRUE(tracker_->ShouldSendAck());
}
TEST_F(DataTrackerTest, WillAcceptValidTSNs) {
@ -215,7 +225,7 @@ TEST_F(DataTrackerTest, WillAcceptValidTSNs) {
int limit = static_cast<int>(DataTracker::kMaxAcceptedOutstandingFragments);
for (int i = -limit; i <= limit; ++i) {
EXPECT_TRUE(buf_.IsTSNValid(TSN(*last_tsn + i)));
EXPECT_TRUE(tracker_->IsTSNValid(TSN(*last_tsn + i)));
}
}
@ -224,15 +234,15 @@ TEST_F(DataTrackerTest, WillNotAcceptInvalidTSNs) {
TSN last_tsn = TSN(*kInitialTSN - 1);
size_t limit = DataTracker::kMaxAcceptedOutstandingFragments;
EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn + limit + 1)));
EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn - (limit + 1))));
EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn + 0x8000000)));
EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn - 0x8000000)));
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, 11});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -240,7 +250,7 @@ TEST_F(DataTrackerTest, ReportSingleDuplicateTsns) {
TEST_F(DataTrackerTest, ReportMultipleDuplicateTsns) {
Observer({11, 12, 13, 14, 12, 13, 12, 13, 15, 16});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -248,7 +258,7 @@ TEST_F(DataTrackerTest, ReportMultipleDuplicateTsns) {
TEST_F(DataTrackerTest, ReportDuplicateTsnsInGapAckBlocks) {
Observer({11, /*12,*/ 13, 14, 13, 14, 15, 16});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -256,13 +266,13 @@ TEST_F(DataTrackerTest, ReportDuplicateTsnsInGapAckBlocks) {
TEST_F(DataTrackerTest, ClearsDuplicateTsnsAfterCreatingSack) {
Observer({11, 12, 13, 14, 12, 13, 12, 13, 15, 16});
SackChunk sack1 = buf_.CreateSelectiveAck(kArwnd);
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 = buf_.CreateSelectiveAck(kArwnd);
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());
@ -271,11 +281,11 @@ TEST_F(DataTrackerTest, ClearsDuplicateTsnsAfterCreatingSack) {
TEST_F(DataTrackerTest, LimitsNumberOfDuplicatesReported) {
for (size_t i = 0; i < DataTracker::kMaxDuplicateTsnReported + 10; ++i) {
TSN tsn(11 + i);
buf_.Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
buf_.Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
}
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty());
EXPECT_THAT(sack.duplicate_tsns(),
SizeIs(DataTracker::kMaxDuplicateTsnReported));
@ -284,10 +294,10 @@ TEST_F(DataTrackerTest, LimitsNumberOfDuplicatesReported) {
TEST_F(DataTrackerTest, LimitsNumberOfGapAckBlocksReported) {
for (size_t i = 0; i < DataTracker::kMaxGapAckBlocksReported + 10; ++i) {
TSN tsn(11 + i * 2);
buf_.Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
tracker_->Observe(tsn, AnyDataChunk::ImmediateAckFlag(false));
}
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11));
EXPECT_THAT(sack.gap_ack_blocks(),
SizeIs(DataTracker::kMaxGapAckBlocksReported));
@ -295,99 +305,99 @@ TEST_F(DataTrackerTest, LimitsNumberOfGapAckBlocksReported) {
TEST_F(DataTrackerTest, SendsSackForFirstPacketObserved) {
Observer({11});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
}
TEST_F(DataTrackerTest, SendsSackEverySecondPacketWhenThereIsNoPacketLoss) {
Observer({11});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({12});
buf_.ObservePacketEnd();
EXPECT_FALSE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_FALSE(tracker_->ShouldSendAck());
EXPECT_TRUE(timer_->is_running());
Observer({13});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({14});
buf_.ObservePacketEnd();
EXPECT_FALSE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_FALSE(tracker_->ShouldSendAck());
EXPECT_TRUE(timer_->is_running());
Observer({15});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
}
TEST_F(DataTrackerTest, SendsSackEveryPacketOnPacketLoss) {
Observer({11});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({13});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({14});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({15});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({16});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
// Fill the hole.
Observer({12});
buf_.ObservePacketEnd();
EXPECT_FALSE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_FALSE(tracker_->ShouldSendAck());
EXPECT_TRUE(timer_->is_running());
// Goes back to every second packet
Observer({17});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({18});
buf_.ObservePacketEnd();
EXPECT_FALSE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_FALSE(tracker_->ShouldSendAck());
EXPECT_TRUE(timer_->is_running());
}
TEST_F(DataTrackerTest, SendsSackOnDuplicateDataChunks) {
Observer({11});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({11});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
Observer({12});
buf_.ObservePacketEnd();
EXPECT_FALSE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_FALSE(tracker_->ShouldSendAck());
EXPECT_TRUE(timer_->is_running());
// Goes back to every second packet
Observer({13});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
// Duplicate again
Observer({12});
buf_.ObservePacketEnd();
EXPECT_TRUE(buf_.ShouldSendAck());
tracker_->ObservePacketEnd();
EXPECT_TRUE(tracker_->ShouldSendAck());
EXPECT_FALSE(timer_->is_running());
}
TEST_F(DataTrackerTest, GapAckBlockAddSingleBlock) {
Observer({12});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2)));
}
@ -395,7 +405,7 @@ TEST_F(DataTrackerTest, GapAckBlockAddSingleBlock) {
TEST_F(DataTrackerTest, GapAckBlockAddsAnother) {
Observer({12});
Observer({14});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -404,7 +414,7 @@ TEST_F(DataTrackerTest, GapAckBlockAddsAnother) {
TEST_F(DataTrackerTest, GapAckBlockAddsDuplicate) {
Observer({12});
Observer({12});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
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)));
@ -413,7 +423,7 @@ TEST_F(DataTrackerTest, GapAckBlockAddsDuplicate) {
TEST_F(DataTrackerTest, GapAckBlockExpandsToRight) {
Observer({12});
Observer({13});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3)));
}
@ -423,7 +433,7 @@ TEST_F(DataTrackerTest, GapAckBlockExpandsToRightWithOther) {
Observer({20});
Observer({30});
Observer({21});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 2), //
@ -434,7 +444,7 @@ TEST_F(DataTrackerTest, GapAckBlockExpandsToRightWithOther) {
TEST_F(DataTrackerTest, GapAckBlockExpandsToLeft) {
Observer({13});
Observer({12});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3)));
}
@ -444,7 +454,7 @@ TEST_F(DataTrackerTest, GapAckBlockExpandsToLeftWithOther) {
Observer({21});
Observer({30});
Observer({20});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 2), //
@ -458,7 +468,7 @@ TEST_F(DataTrackerTest, GapAckBlockExpandsToLRightAndMerges) {
Observer({22});
Observer({30});
Observer({21});
SackChunk sack = buf_.CreateSelectiveAck(kArwnd);
SackChunk sack = tracker_->CreateSelectiveAck(kArwnd);
EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(sack.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 2), //
@ -468,73 +478,73 @@ TEST_F(DataTrackerTest, GapAckBlockExpandsToLRightAndMerges) {
TEST_F(DataTrackerTest, GapAckBlockMergesManyBlocksIntoOne) {
Observer({22});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(12, 12)));
Observer({30});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(12, 12), //
SackChunk::GapAckBlock(20, 20)));
Observer({24});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(12, 14), //
SackChunk::GapAckBlock(16, 20)));
Observer({25});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(12, 20)));
Observer({20});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(10, 10), //
SackChunk::GapAckBlock(12, 20)));
Observer({32});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
EXPECT_THAT(tracker_->CreateSelectiveAck(kArwnd).gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(10, 20), //
SackChunk::GapAckBlock(22, 22)));
Observer({31});
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(8));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(10));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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)));
@ -543,9 +553,9 @@ TEST_F(DataTrackerTest, GapAckBlockRemoveBeforeCumAckTsn) {
TEST_F(DataTrackerTest, GapAckBlockRemoveBeforeFirstBlock) {
Observer({12, 13, 14, 20, 21, 22, 30, 31});
buf_.HandleForwardTsn(TSN(11));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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)));
}
@ -553,27 +563,27 @@ TEST_F(DataTrackerTest, GapAckBlockRemoveBeforeFirstBlock) {
TEST_F(DataTrackerTest, GapAckBlockRemoveAtBeginningOfFirstBlock) {
Observer({12, 13, 14, 20, 21, 22, 30, 31});
buf_.HandleForwardTsn(TSN(12));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(13));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(14));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(14));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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)));
}
@ -581,9 +591,9 @@ TEST_F(DataTrackerTest, GapAckBlockRemoveAtEndOfFirstBlock) {
TEST_F(DataTrackerTest, GapAckBlockRemoveRightAfterFirstBlock) {
Observer({12, 13, 14, 20, 21, 22, 30, 31});
buf_.HandleForwardTsn(TSN(18));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(18));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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)));
}
@ -591,46 +601,117 @@ TEST_F(DataTrackerTest, GapAckBlockRemoveRightAfterFirstBlock) {
TEST_F(DataTrackerTest, GapAckBlockRemoveRightBeforeSecondBlock) {
Observer({12, 13, 14, 20, 21, 22, 30, 31});
buf_.HandleForwardTsn(TSN(19));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(20));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(21));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(22));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(22));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(),
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});
buf_.HandleForwardTsn(TSN(40));
EXPECT_EQ(buf_.CreateSelectiveAck(kArwnd).cumulative_tsn_ack(), TSN(40));
EXPECT_THAT(buf_.CreateSelectiveAck(kArwnd).gap_ack_blocks(), IsEmpty());
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());
}
} // namespace
} // namespace dcsctp