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}
diff --git a/net/dcsctp/public/dcsctp_handover_state.h b/net/dcsctp/public/dcsctp_handover_state.h
index d1267ca..0f870b8 100644
--- a/net/dcsctp/public/dcsctp_handover_state.h
+++ b/net/dcsctp/public/dcsctp_handover_state.h
@@ -32,6 +32,8 @@
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 @@
enum class HandoverUnreadinessReason : uint32_t {
kWrongConnectionState = 1,
kSendQueueNotEmpty = 2,
- kDataTrackerNotIdle = 4,
+ kPendingStreamResetRequest = 4,
kDataTrackerTsnBlocksPending = 8,
kReassemblyQueueNotEmpty = 16,
kReassemblyQueueDeliveredTSNsGap = 32,
@@ -53,8 +55,7 @@
kRetransmissionQueueFastRecovery = 1024,
kRetransmissionQueueNotEmpty = 2048,
kPendingStreamReset = 4096,
- kPendingStreamResetRequest = 8192,
- kMax = kPendingStreamResetRequest,
+ kMax = kPendingStreamReset,
};
// Return value of `DcSctpSocketInterface::GetHandoverReadiness`. Set of
diff --git a/net/dcsctp/rx/BUILD.gn b/net/dcsctp/rx/BUILD.gn
index 6c49648..2179e69 100644
--- a/net/dcsctp/rx/BUILD.gn
+++ b/net/dcsctp/rx/BUILD.gn
@@ -17,6 +17,7 @@
"../common:sequence_numbers",
"../packet:chunk",
"../packet:data",
+ "../public:socket",
"../timer",
]
sources = [
diff --git a/net/dcsctp/rx/data_tracker.cc b/net/dcsctp/rx/data_tracker.cc
index 5b563a8..f31847b 100644
--- a/net/dcsctp/rx/data_tracker.cc
+++ b/net/dcsctp/rx/data_tracker.cc
@@ -356,4 +356,17 @@
}
}
+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
diff --git a/net/dcsctp/rx/data_tracker.h b/net/dcsctp/rx/data_tracker.h
index 167f5a0..fb8add8 100644
--- a/net/dcsctp/rx/data_tracker.h
+++ b/net/dcsctp/rx/data_tracker.h
@@ -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 @@
// 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 @@
void HandleDelayedAckTimerExpiry();
+ HandoverReadinessStatus GetHandoverReadiness() const;
+
+ void AddHandoverState(DcSctpSocketHandoverState& state);
+
private:
enum class AckState {
// No need to send an ACK.
@@ -166,7 +175,7 @@
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_;
diff --git a/net/dcsctp/rx/data_tracker_test.cc b/net/dcsctp/rx/data_tracker_test.cc
index 5c2e56f..e59f8a9 100644
--- a/net/dcsctp/rx/data_tracker_test.cc
+++ b/net/dcsctp/rx/data_tracker_test.cc
@@ -40,23 +40,33 @@
"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, 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, 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, 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, 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, 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, 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 @@
// 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 @@
// 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, 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 @@
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 @@
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, 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, 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, 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, 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, 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, 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, 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, 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, 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 @@
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, 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 @@
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 @@
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, 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, 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, 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, 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, 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