1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <algorithm> 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h" 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/stl_util.h" 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/quic/congestion_control/rtt_stats.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/quic/congestion_control/tcp_loss_algorithm.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/quic/quic_unacked_packet_map.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/quic/test_tools/mock_clock.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace net { 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace test { 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class TcpLossAlgorithmTest : public ::testing::Test { 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) protected: 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) TcpLossAlgorithmTest() 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : unacked_packets_() { 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu QuicTime::Delta::Zero(), 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu clock_.Now()); 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void SendDataPacket(QuicPacketSequenceNumber sequence_number) { 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NULL, 0, new RetransmittableFrames()); 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.AddPacket(packet); 31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch unacked_packets_.SetSent(sequence_number, clock_.Now(), 1000, true); 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void VerifyLosses(QuicPacketSequenceNumber largest_observed, 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber* losses_expected, 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) size_t num_losses) { 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SequenceNumberSet lost_packets = 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) loss_algorithm_.DetectLostPackets( 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_, clock_.Now(), largest_observed, rtt_stats_); 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(num_losses, lost_packets.size()); 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < num_losses; ++i) { 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(ContainsKey(lost_packets, losses_expected[i])); 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicUnackedPacketMap unacked_packets_; 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) TCPLossAlgorithm loss_algorithm_; 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RttStats rtt_stats_; 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MockClock clock_; 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, NackRetransmit1Packet) { 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 5; 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Transmit 5 packets. 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // No loss on one ack. 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(2); 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 1); 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(2, NULL, 0); 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // No loss on two acks. 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(3); 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 2); 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(3, NULL, 0); 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Loss on three acks. 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(4); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 3); 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost[] = { 1 }; 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(4, lost, arraysize(lost)); 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A stretch ack is an ack that covers more than 1 packet of previously 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// unacknowledged data. 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) { 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 10; 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Transmit 10 packets. 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Nack the first packet 3 times in a single StretchAck. 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 3); 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(2); 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(3); 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(4); 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost[] = { 1 }; 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(4, lost, arraysize(lost)); 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Ack a packet 3 packets ahead, causing a retransmit. 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketSingleAck) { 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 10; 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Transmit 10 packets. 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Nack the first packet 3 times in an AckFrame with three missing packets. 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 3); 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(2, 2); 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(3, 1); 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(4); 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost[] = { 1 }; 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(4, lost, arraysize(lost)); 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, EarlyRetransmit1Packet) { 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 2; 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Transmit 2 packets. 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Early retransmit when the final packet gets acked and the first is nacked. 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(2); 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 1); 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(2, NULL, 0); 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(clock_.Now().Add(rtt_stats_.SmoothedRtt().Multiply(1.25)), 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) loss_algorithm_.GetLossTimeout()); 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clock_.AdvanceTime(rtt_stats_.latest_rtt().Multiply(1.25)); 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost[] = { 1 }; 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(2, lost, arraysize(lost)); 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, EarlyRetransmitAllPackets) { 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 5; 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Advance the time 1/4 RTT between 3 and 4. 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (i == 3) { 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clock_.AdvanceTime(rtt_stats_.SmoothedRtt().Multiply(0.25)); 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Early retransmit when the final packet gets acked and 1.25 RTTs have 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // elapsed since the packets were sent. 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(kNumSentPackets); 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This simulates a single ack following multiple missing packets with FACK. 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i < kNumSentPackets; ++i) { 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(i, kNumSentPackets - i); 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost[] = { 1, 2 }; 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(kNumSentPackets, lost, arraysize(lost)); 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The time has already advanced 1/4 an RTT, so ensure the timeout is set 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 1.25 RTTs after the earliest pending packet(3), not the last(4). 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(clock_.Now().Add(rtt_stats_.SmoothedRtt()), 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) loss_algorithm_.GetLossTimeout()); 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clock_.AdvanceTime(rtt_stats_.SmoothedRtt()); 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost2[] = { 1, 2, 3 }; 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(kNumSentPackets, lost2, arraysize(lost2)); 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(clock_.Now().Add(rtt_stats_.SmoothedRtt().Multiply(0.25)), 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) loss_algorithm_.GetLossTimeout()); 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clock_.AdvanceTime(rtt_stats_.SmoothedRtt().Multiply(0.25)); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicPacketSequenceNumber lost3[] = { 1, 2, 3, 4 }; 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(kNumSentPackets, lost3, arraysize(lost3)); 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(TcpLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) { 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const size_t kNumSentPackets = 2; 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Transmit 2 packets. 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 1; i <= kNumSentPackets; ++i) { 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SendDataPacket(i); 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Neuter packet 1. 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveRetransmittability(1); 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Early retransmit when the final packet gets acked and the first is nacked. 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.IncreaseLargestObserved(2); 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unacked_packets_.RemoveFromInFlight(2); 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unacked_packets_.NackPacket(1, 1); 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VerifyLosses(2, NULL, 0); 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace test 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace net 184