1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <algorithm> 6 #include <vector> 7 8 #include "base/logging.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "net/quic/quic_fec_group.h" 11 #include "testing/gmock/include/gmock/gmock.h" 12 13 using ::testing::_; 14 using base::StringPiece; 15 16 namespace net { 17 18 namespace { 19 20 const char* kData[] = { 21 "abc12345678", 22 "987defg", 23 "ghi12345", 24 "987jlkmno", 25 "mno4567890", 26 "789pqrstuvw", 27 }; 28 29 const bool kEntropyFlag[] = { 30 false, 31 true, 32 true, 33 false, 34 true, 35 true, 36 }; 37 38 const bool kTestFecPacketEntropy = false; 39 40 } // namespace 41 42 class QuicFecGroupTest : public ::testing::Test { 43 protected: 44 void RunTest(size_t num_packets, size_t lost_packet, bool out_of_order) { 45 size_t max_len = strlen(kData[0]); 46 scoped_ptr<char[]> redundancy(new char[max_len]); 47 bool entropy_redundancy = false; 48 for (size_t packet = 0; packet < num_packets; ++packet) { 49 for (size_t i = 0; i < max_len; i++) { 50 if (packet == 0) { 51 // Initialize to the first packet. 52 redundancy[i] = kData[0][i]; 53 continue; 54 } 55 // XOR in the remaining packets. 56 uint8 byte = i > strlen(kData[packet]) ? 0x00 : kData[packet][i]; 57 redundancy[i] = redundancy[i] ^ byte; 58 } 59 entropy_redundancy = (entropy_redundancy != kEntropyFlag[packet]); 60 } 61 62 QuicFecGroup group; 63 64 // If we're out of order, send the FEC packet in the position of the 65 // lost packet. Otherwise send all (non-missing) packets, then FEC. 66 if (out_of_order) { 67 // Update the FEC state for each non-lost packet. 68 for (size_t packet = 0; packet < num_packets; packet++) { 69 if (packet == lost_packet) { 70 ASSERT_FALSE(group.IsFinished()); 71 QuicFecData fec; 72 fec.fec_group = 0; 73 fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); 74 ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec)); 75 } else { 76 QuicPacketHeader header; 77 header.packet_sequence_number = packet; 78 header.entropy_flag = kEntropyFlag[packet]; 79 ASSERT_TRUE(group.Update(header, kData[packet])); 80 } 81 ASSERT_TRUE(group.CanRevive() == (packet == num_packets - 1)); 82 } 83 } else { 84 // Update the FEC state for each non-lost packet. 85 for (size_t packet = 0; packet < num_packets; packet++) { 86 if (packet == lost_packet) { 87 continue; 88 } 89 90 QuicPacketHeader header; 91 header.packet_sequence_number = packet; 92 header.entropy_flag = kEntropyFlag[packet]; 93 ASSERT_TRUE(group.Update(header, kData[packet])); 94 ASSERT_FALSE(group.CanRevive()); 95 } 96 97 ASSERT_FALSE(group.IsFinished()); 98 // Attempt to revive the missing packet. 99 QuicFecData fec; 100 fec.fec_group = 0; 101 fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); 102 103 ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec)); 104 } 105 QuicPacketHeader header; 106 char recovered[kMaxPacketSize]; 107 ASSERT_TRUE(group.CanRevive()); 108 size_t len = group.Revive(&header, recovered, arraysize(recovered)); 109 ASSERT_NE(0u, len) 110 << "Failed to revive packet " << lost_packet << " out of " 111 << num_packets; 112 EXPECT_EQ(lost_packet, header.packet_sequence_number) 113 << "Failed to revive packet " << lost_packet << " out of " 114 << num_packets; 115 EXPECT_EQ(kEntropyFlag[lost_packet], header.entropy_flag); 116 ASSERT_GE(len, strlen(kData[lost_packet])) << "Incorrect length"; 117 for (size_t i = 0; i < strlen(kData[lost_packet]); i++) { 118 EXPECT_EQ(kData[lost_packet][i], recovered[i]); 119 } 120 ASSERT_TRUE(group.IsFinished()); 121 } 122 }; 123 124 TEST_F(QuicFecGroupTest, UpdateAndRevive) { 125 RunTest(2, 0, false); 126 RunTest(2, 1, false); 127 128 RunTest(3, 0, false); 129 RunTest(3, 1, false); 130 RunTest(3, 2, false); 131 } 132 133 TEST_F(QuicFecGroupTest, UpdateAndReviveOutOfOrder) { 134 RunTest(2, 0, true); 135 RunTest(2, 1, true); 136 137 RunTest(3, 0, true); 138 RunTest(3, 1, true); 139 RunTest(3, 2, true); 140 } 141 142 TEST_F(QuicFecGroupTest, UpdateFecIfReceivedPacketIsNotCovered) { 143 char data1[] = "abc123"; 144 char redundancy[arraysize(data1)]; 145 for (size_t i = 0; i < arraysize(data1); i++) { 146 redundancy[i] = data1[i]; 147 } 148 149 QuicFecGroup group; 150 151 QuicPacketHeader header; 152 header.packet_sequence_number = 3; 153 group.Update(header, data1); 154 155 QuicFecData fec; 156 fec.fec_group = 1; 157 fec.redundancy = redundancy; 158 159 header.packet_sequence_number = 2; 160 ASSERT_FALSE(group.UpdateFec(2, kTestFecPacketEntropy, fec)); 161 } 162 163 TEST_F(QuicFecGroupTest, ProtectsPacketsBefore) { 164 QuicPacketHeader header; 165 header.packet_sequence_number = 3; 166 167 QuicFecGroup group; 168 ASSERT_TRUE(group.Update(header, kData[0])); 169 170 EXPECT_FALSE(group.ProtectsPacketsBefore(1)); 171 EXPECT_FALSE(group.ProtectsPacketsBefore(2)); 172 EXPECT_FALSE(group.ProtectsPacketsBefore(3)); 173 EXPECT_TRUE(group.ProtectsPacketsBefore(4)); 174 EXPECT_TRUE(group.ProtectsPacketsBefore(5)); 175 EXPECT_TRUE(group.ProtectsPacketsBefore(50)); 176 } 177 178 TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithSeveralPackets) { 179 QuicPacketHeader header; 180 header.packet_sequence_number = 3; 181 182 QuicFecGroup group; 183 ASSERT_TRUE(group.Update(header, kData[0])); 184 185 header.packet_sequence_number = 7; 186 ASSERT_TRUE(group.Update(header, kData[0])); 187 188 header.packet_sequence_number = 5; 189 ASSERT_TRUE(group.Update(header, kData[0])); 190 191 EXPECT_FALSE(group.ProtectsPacketsBefore(1)); 192 EXPECT_FALSE(group.ProtectsPacketsBefore(2)); 193 EXPECT_FALSE(group.ProtectsPacketsBefore(3)); 194 EXPECT_TRUE(group.ProtectsPacketsBefore(4)); 195 EXPECT_TRUE(group.ProtectsPacketsBefore(5)); 196 EXPECT_TRUE(group.ProtectsPacketsBefore(6)); 197 EXPECT_TRUE(group.ProtectsPacketsBefore(7)); 198 EXPECT_TRUE(group.ProtectsPacketsBefore(8)); 199 EXPECT_TRUE(group.ProtectsPacketsBefore(9)); 200 EXPECT_TRUE(group.ProtectsPacketsBefore(50)); 201 } 202 203 TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithFecData) { 204 QuicFecData fec; 205 fec.fec_group = 2; 206 fec.redundancy = kData[0]; 207 208 QuicFecGroup group; 209 ASSERT_TRUE(group.UpdateFec(3, kTestFecPacketEntropy, fec)); 210 211 EXPECT_FALSE(group.ProtectsPacketsBefore(1)); 212 EXPECT_FALSE(group.ProtectsPacketsBefore(2)); 213 EXPECT_TRUE(group.ProtectsPacketsBefore(3)); 214 EXPECT_TRUE(group.ProtectsPacketsBefore(4)); 215 EXPECT_TRUE(group.ProtectsPacketsBefore(5)); 216 EXPECT_TRUE(group.ProtectsPacketsBefore(50)); 217 } 218 219 } // namespace net 220