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.
5 #include "net/quic/quic_fec_group.h"
10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "testing/gmock/include/gmock/gmock.h"
16 using base::StringPiece
;
22 const char* kData
[] = {
31 const bool kEntropyFlag
[] = {
42 class QuicFecGroupTest
: public ::testing::Test
{
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 for (size_t packet
= 0; packet
< num_packets
; ++packet
) {
48 for (size_t i
= 0; i
< max_len
; i
++) {
50 // Initialize to the first packet.
51 redundancy
[i
] = kData
[0][i
];
54 // XOR in the remaining packets.
55 uint8 byte
= i
> strlen(kData
[packet
]) ? 0x00 : kData
[packet
][i
];
56 redundancy
[i
] = redundancy
[i
] ^ byte
;
62 // If we're out of order, send the FEC packet in the position of the
63 // lost packet. Otherwise send all (non-missing) packets, then FEC.
65 // Update the FEC state for each non-lost packet.
66 for (size_t packet
= 0; packet
< num_packets
; packet
++) {
67 if (packet
== lost_packet
) {
68 ASSERT_FALSE(group
.IsFinished());
71 fec
.redundancy
= StringPiece(redundancy
.get(), strlen(kData
[0]));
72 ASSERT_TRUE(group
.UpdateFec(num_packets
, fec
));
74 QuicPacketHeader header
;
75 header
.packet_sequence_number
= packet
;
76 header
.entropy_flag
= kEntropyFlag
[packet
];
77 ASSERT_TRUE(group
.Update(header
, kData
[packet
]));
79 ASSERT_TRUE(group
.CanRevive() == (packet
== num_packets
- 1));
82 // Update the FEC state for each non-lost packet.
83 for (size_t packet
= 0; packet
< num_packets
; packet
++) {
84 if (packet
== lost_packet
) {
88 QuicPacketHeader header
;
89 header
.packet_sequence_number
= packet
;
90 header
.entropy_flag
= kEntropyFlag
[packet
];
91 ASSERT_TRUE(group
.Update(header
, kData
[packet
]));
92 ASSERT_FALSE(group
.CanRevive());
95 ASSERT_FALSE(group
.IsFinished());
96 // Attempt to revive the missing packet.
99 fec
.redundancy
= StringPiece(redundancy
.get(), strlen(kData
[0]));
101 ASSERT_TRUE(group
.UpdateFec(num_packets
, fec
));
103 QuicPacketHeader header
;
104 char recovered
[kMaxPacketSize
];
105 ASSERT_TRUE(group
.CanRevive());
106 size_t len
= group
.Revive(&header
, recovered
, arraysize(recovered
));
108 << "Failed to revive packet " << lost_packet
<< " out of "
110 EXPECT_EQ(lost_packet
, header
.packet_sequence_number
)
111 << "Failed to revive packet " << lost_packet
<< " out of "
113 // Revived packets have an unknown entropy.
114 EXPECT_FALSE(header
.entropy_flag
);
115 ASSERT_GE(len
, strlen(kData
[lost_packet
])) << "Incorrect length";
116 for (size_t i
= 0; i
< strlen(kData
[lost_packet
]); i
++) {
117 EXPECT_EQ(kData
[lost_packet
][i
], recovered
[i
]);
119 ASSERT_TRUE(group
.IsFinished());
123 TEST_F(QuicFecGroupTest
, UpdateAndRevive
) {
124 RunTest(2, 0, false);
125 RunTest(2, 1, false);
127 RunTest(3, 0, false);
128 RunTest(3, 1, false);
129 RunTest(3, 2, false);
132 TEST_F(QuicFecGroupTest
, UpdateAndReviveOutOfOrder
) {
141 TEST_F(QuicFecGroupTest
, UpdateFecIfReceivedPacketIsNotCovered
) {
142 char data1
[] = "abc123";
143 char redundancy
[arraysize(data1
)];
144 for (size_t i
= 0; i
< arraysize(data1
); i
++) {
145 redundancy
[i
] = data1
[i
];
150 QuicPacketHeader header
;
151 header
.packet_sequence_number
= 3;
152 group
.Update(header
, data1
);
156 fec
.redundancy
= redundancy
;
158 header
.packet_sequence_number
= 2;
159 ASSERT_FALSE(group
.UpdateFec(2, fec
));
162 TEST_F(QuicFecGroupTest
, ProtectsPacketsBefore
) {
163 QuicPacketHeader header
;
164 header
.packet_sequence_number
= 3;
167 ASSERT_TRUE(group
.Update(header
, kData
[0]));
169 EXPECT_FALSE(group
.ProtectsPacketsBefore(1));
170 EXPECT_FALSE(group
.ProtectsPacketsBefore(2));
171 EXPECT_FALSE(group
.ProtectsPacketsBefore(3));
172 EXPECT_TRUE(group
.ProtectsPacketsBefore(4));
173 EXPECT_TRUE(group
.ProtectsPacketsBefore(5));
174 EXPECT_TRUE(group
.ProtectsPacketsBefore(50));
177 TEST_F(QuicFecGroupTest
, ProtectsPacketsBeforeWithSeveralPackets
) {
178 QuicPacketHeader header
;
179 header
.packet_sequence_number
= 3;
182 ASSERT_TRUE(group
.Update(header
, kData
[0]));
184 header
.packet_sequence_number
= 7;
185 ASSERT_TRUE(group
.Update(header
, kData
[0]));
187 header
.packet_sequence_number
= 5;
188 ASSERT_TRUE(group
.Update(header
, kData
[0]));
190 EXPECT_FALSE(group
.ProtectsPacketsBefore(1));
191 EXPECT_FALSE(group
.ProtectsPacketsBefore(2));
192 EXPECT_FALSE(group
.ProtectsPacketsBefore(3));
193 EXPECT_TRUE(group
.ProtectsPacketsBefore(4));
194 EXPECT_TRUE(group
.ProtectsPacketsBefore(5));
195 EXPECT_TRUE(group
.ProtectsPacketsBefore(6));
196 EXPECT_TRUE(group
.ProtectsPacketsBefore(7));
197 EXPECT_TRUE(group
.ProtectsPacketsBefore(8));
198 EXPECT_TRUE(group
.ProtectsPacketsBefore(9));
199 EXPECT_TRUE(group
.ProtectsPacketsBefore(50));
202 TEST_F(QuicFecGroupTest
, ProtectsPacketsBeforeWithFecData
) {
205 fec
.redundancy
= kData
[0];
208 ASSERT_TRUE(group
.UpdateFec(3, fec
));
210 EXPECT_FALSE(group
.ProtectsPacketsBefore(1));
211 EXPECT_FALSE(group
.ProtectsPacketsBefore(2));
212 EXPECT_TRUE(group
.ProtectsPacketsBefore(3));
213 EXPECT_TRUE(group
.ProtectsPacketsBefore(4));
214 EXPECT_TRUE(group
.ProtectsPacketsBefore(5));
215 EXPECT_TRUE(group
.ProtectsPacketsBefore(50));