#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
+#include "net/quic/test_tools/quic_packet_generator_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
#include "testing/gmock/include/gmock/gmock.h"
class MockDelegate : public QuicPacketGenerator::DelegateInterface {
public:
MockDelegate() {}
- virtual ~MockDelegate() {}
+ virtual ~MockDelegate() OVERRIDE {}
MOCK_METHOD3(ShouldGeneratePacket,
bool(TransmissionType transmission_type,
MOCK_METHOD0(CreateAckFrame, QuicAckFrame*());
MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
MOCK_METHOD0(CreateStopWaitingFrame, QuicStopWaitingFrame*());
- MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
+ MOCK_METHOD1(OnSerializedPacket, void(const SerializedPacket& packet));
MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool));
void SetCanWriteAnything() {
protected:
QuicPacketGeneratorTest()
: framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
- creator_(42, &framer_, &random_, false),
- generator_(&delegate_, NULL, &creator_),
+ generator_(42, &framer_, &random_, &delegate_),
+ creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)),
packet_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
packet2_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
packet3_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
packet4_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
- packet5_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL) {
+ packet5_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+ packet6_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+ packet7_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL) {
}
- ~QuicPacketGeneratorTest() {
+ virtual ~QuicPacketGeneratorTest() OVERRIDE {
delete packet_.packet;
delete packet_.retransmittable_frames;
delete packet2_.packet;
delete packet4_.retransmittable_frames;
delete packet5_.packet;
delete packet5_.retransmittable_frames;
+ delete packet6_.packet;
+ delete packet6_.retransmittable_frames;
+ delete packet7_.packet;
+ delete packet7_.retransmittable_frames;
}
QuicAckFrame* CreateAckFrame() {
// TODO(rch): Initialize this so it can be verified later.
- return new QuicAckFrame(0, QuicTime::Zero(), 0);
+ return new QuicAckFrame(MakeAckFrame(0));
}
QuicCongestionFeedbackFrame* CreateFeedbackFrame() {
QuicCongestionFeedbackFrame* frame = new QuicCongestionFeedbackFrame;
- frame->type = kFixRate;
- frame->fix_rate.bitrate = QuicBandwidth::FromBytesPerSecond(42);
+ frame->type = kTCP;
+ frame->tcp.receive_window = 0x4030;
return frame;
}
QuicFramer framer_;
MockRandom random_;
- QuicPacketCreator creator_;
StrictMock<MockDelegate> delegate_;
QuicPacketGenerator generator_;
+ QuicPacketCreator* creator_;
SimpleQuicFramer simple_framer_;
SerializedPacket packet_;
SerializedPacket packet2_;
SerializedPacket packet3_;
SerializedPacket packet4_;
SerializedPacket packet5_;
+ SerializedPacket packet6_;
+ SerializedPacket packet7_;
private:
scoped_ptr<char[]> data_array_;
};
-class MockDebugDelegate : public QuicPacketGenerator::DebugDelegateInterface {
+class MockDebugDelegate : public QuicPacketGenerator::DebugDelegate {
public:
MOCK_METHOD1(OnFrameAddedToPacket,
void(const QuicFrame&));
delegate_.SetCanWriteOnlyNonRetransmittable();
EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.SetShouldSendAck(false, false);
EXPECT_FALSE(generator_.HasQueuedFrames());
EXPECT_CALL(delegate_, CreateStopWaitingFrame()).WillOnce(
Return(CreateStopWaitingFrame()));
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.SetShouldSendAck(true, true);
EXPECT_FALSE(generator_.HasQueuedFrames());
generator_.FinishBatchOperations();
EXPECT_TRUE(generator_.HasQueuedFrames());
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.FlushAllQueuedFrames();
EXPECT_FALSE(generator_.HasQueuedFrames());
TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
delegate_.SetCanWriteAnything();
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
EXPECT_FALSE(generator_.HasQueuedFrames());
TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
- QuicConsumedData consumed = generator_.ConsumeData(1, MakeIOVector("foo"), 2,
- true, NULL);
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(0u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
- QuicConsumedData consumed = generator_.ConsumeData(1, MakeIOVector("foo"), 2,
- true, NULL);
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
delegate_.SetCanWriteAnything();
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
- QuicConsumedData consumed = generator_.ConsumeData(1, MakeIOVector("foo"), 2,
- true, NULL);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
- generator_.ConsumeData(1, MakeIOVector("foo"), 2, true, NULL);
- QuicConsumedData consumed = generator_.ConsumeData(3, MakeIOVector("quux"), 7,
- false, NULL);
+ generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
+ MAY_FEC_PROTECT, NULL);
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 3, MakeIOVector("quux"), 7, false, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
- generator_.ConsumeData(1, MakeIOVector("foo"), 2, true, NULL);
- QuicConsumedData consumed = generator_.ConsumeData(3, MakeIOVector("quux"), 7,
- false, NULL);
+ generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
+ MAY_FEC_PROTECT, NULL);
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 3, MakeIOVector("quux"), 7, false, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
// Now both frames will be flushed out.
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.FinishBatchOperations();
EXPECT_FALSE(generator_.HasQueuedFrames());
delegate_.SetCanWriteAnything();
// Send FEC every two packets.
- creator_.options()->max_packets_per_fec_group = 2;
+ creator_->set_max_packets_per_fec_group(2);
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ SaveArg<0>(&packet_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet2_), Return(true)));
+ SaveArg<0>(&packet2_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet3_), Return(true)));
+ SaveArg<0>(&packet3_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet4_), Return(true)));
+ SaveArg<0>(&packet4_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet5_), Return(true)));
+ SaveArg<0>(&packet5_));
}
- // Send enough data to create 3 packets: two full and one partial.
+ // Send enough data to create 3 packets: two full and one partial. Send
+ // with MUST_FEC_PROTECT flag.
size_t data_len = 2 * kDefaultMaxPacketSize + 100;
QuicConsumedData consumed =
- generator_.ConsumeData(3, CreateData(data_len), 0, true, NULL);
+ generator_.ConsumeData(3, CreateData(data_len), 0, true,
+ MUST_FEC_PROTECT, NULL);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) {
delegate_.SetCanWriteAnything();
- // Send FEC every six packets.
- creator_.options()->max_packets_per_fec_group = 6;
-
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(6);
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ SaveArg<0>(&packet_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet2_), Return(true)));
+ SaveArg<0>(&packet2_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet3_), Return(true)));
+ SaveArg<0>(&packet3_));
}
- // Send enough data to create 2 packets: one full and one partial.
+ // Send enough data to create 2 packets: one full and one partial. Send
+ // with MUST_FEC_PROTECT flag.
size_t data_len = 1 * kDefaultMaxPacketSize + 100;
QuicConsumedData consumed =
- generator_.ConsumeData(3, CreateData(data_len), 0, true, NULL);
+ generator_.ConsumeData(3, CreateData(data_len), 0, true,
+ MUST_FEC_PROTECT, NULL);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// Set the packet size be enough for two stream frames with 0 stream offset,
// but not enough for a stream frame of 0 offset and one with non-zero offset.
- creator_.options()->max_packet_length =
+ size_t length =
NullEncrypter().GetCiphertextSize(0) +
- GetPacketHeaderSize(creator_.options()->send_connection_id_length,
+ GetPacketHeaderSize(creator_->connection_id_length(),
true,
- creator_.options()->send_sequence_number_length,
+ creator_->next_sequence_number_length(),
NOT_IN_FEC_GROUP) +
// Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
// than the GetMinStreamFrameSize.
- QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, false) + 3 +
- QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, true) + 1;
+ QuicFramer::GetMinStreamFrameSize(1, 0, false, NOT_IN_FEC_GROUP) + 3 +
+ QuicFramer::GetMinStreamFrameSize(1, 0, true, NOT_IN_FEC_GROUP) + 1;
+ creator_->set_max_packet_length(length);
delegate_.SetCanWriteAnything();
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ SaveArg<0>(&packet_));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet2_), Return(true)));
+ SaveArg<0>(&packet2_));
}
generator_.StartBatchOperations();
// Queue enough data to prevent a stream frame with a non-zero offset from
// fitting.
- QuicConsumedData consumed = generator_.ConsumeData(1, MakeIOVector("foo"), 0,
- false, NULL);
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 0, false, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
// This frame will not fit with the existing frame, causing the queued frame
// to be serialized, and it will not fit with another frame like it, so it is
// serialized by itself.
- consumed = generator_.ConsumeData(1, MakeIOVector("bar"), 3, true, NULL);
+ consumed = generator_.ConsumeData(kHeadersStreamId, MakeIOVector("bar"), 3,
+ true, MAY_FEC_PROTECT, NULL);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
CheckPacketContains(contents, packet2_);
}
+TEST_F(QuicPacketGeneratorTest, FecGroupSizeOnCongestionWindowChange) {
+ delegate_.SetCanWriteAnything();
+ creator_->set_max_packets_per_fec_group(50);
+ EXPECT_EQ(50u, creator_->max_packets_per_fec_group());
+ EXPECT_FALSE(creator_->IsFecGroupOpen());
+
+ // On reduced cwnd.
+ generator_.OnCongestionWindowChange(7 * kDefaultTCPMSS);
+ EXPECT_EQ(3u, creator_->max_packets_per_fec_group());
+
+ // On increased cwnd.
+ generator_.OnCongestionWindowChange(100 * kDefaultTCPMSS);
+ EXPECT_EQ(50u, creator_->max_packets_per_fec_group());
+
+ // On collapsed cwnd.
+ generator_.OnCongestionWindowChange(1 * kDefaultTCPMSS);
+ EXPECT_EQ(2u, creator_->max_packets_per_fec_group());
+}
+
+TEST_F(QuicPacketGeneratorTest, FecGroupSizeChangeWithOpenGroup) {
+ delegate_.SetCanWriteAnything();
+ // TODO(jri): This starting of batch mode should not be required when
+ // FEC sending is separated from batching operations.
+ generator_.StartBatchOperations();
+ creator_->set_max_packets_per_fec_group(50);
+ EXPECT_EQ(50u, creator_->max_packets_per_fec_group());
+ EXPECT_FALSE(creator_->IsFecGroupOpen());
+
+ // Send enough data to create 4 packets with MUST_FEC_PROTECT flag.
+ // 3 packets are sent, one is queued in the creator.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet2_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet3_));
+ }
+ size_t data_len = 3 * kDefaultMaxPacketSize + 1;
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 7, CreateData(data_len), 0, true, MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(creator_->IsFecGroupOpen());
+
+ // Change FEC groupsize.
+ generator_.OnCongestionWindowChange(2 * kDefaultTCPMSS);
+ EXPECT_EQ(2u, creator_->max_packets_per_fec_group());
+
+ // Send enough data to trigger one unprotected data packet,
+ // causing the FEC packet to also be sent.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet4_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet5_));
+ }
+ consumed = generator_.ConsumeData(7, CreateData(kDefaultMaxPacketSize), 0,
+ true, MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(kDefaultMaxPacketSize, consumed.bytes_consumed);
+ // Verify that one FEC packet was sent.
+ CheckPacketIsFec(packet5_, /*fec_group=*/1u);
+ EXPECT_FALSE(creator_->IsFecGroupOpen());
+ EXPECT_FALSE(creator_->IsFecProtected());
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnOff) {
+ delegate_.SetCanWriteAnything();
+ creator_->set_max_packets_per_fec_group(2);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ // Send one unprotected data packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT,
+ NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(creator_->IsFecProtected());
+ // Verify that one data packet was sent.
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, packet_);
+
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet2_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet3_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet4_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet5_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet6_));
+ }
+ // Send enough data to create 3 packets with MUST_FEC_PROTECT flag.
+ size_t data_len = 2 * kDefaultMaxPacketSize + 100;
+ consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Verify that two FEC packets were sent.
+ CheckPacketHasSingleStreamFrame(packet2_);
+ CheckPacketHasSingleStreamFrame(packet3_);
+ CheckPacketIsFec(packet4_, /*fec_group=*/2u);
+ CheckPacketHasSingleStreamFrame(packet5_);
+ CheckPacketIsFec(packet6_, /*fec_group=*/5u); // Sent at the end of stream.
+
+ // Send one unprotected data packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet7_));
+ consumed = generator_.ConsumeData(7, CreateData(1u), 0, true,
+ MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(creator_->IsFecProtected());
+ // Verify that one unprotected data packet was sent.
+ CheckPacketContains(contents, packet7_);
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFrameInCreator) {
+ delegate_.SetCanWriteAnything();
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(2);
+
+ generator_.StartBatchOperations();
+ // Queue enough data to prevent a stream frame with a non-zero offset from
+ // fitting.
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 7, CreateData(1u), 0, true, MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ EXPECT_TRUE(creator_->HasPendingFrames());
+
+ // Queue protected data for sending. Should cause queued frames to be flushed.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ EXPECT_FALSE(creator_->IsFecProtected());
+ consumed = generator_.ConsumeData(7, CreateData(1u), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ // Transmitted packet was not FEC protected.
+ CheckPacketContains(contents, packet_);
+ EXPECT_TRUE(creator_->IsFecProtected());
+ EXPECT_TRUE(creator_->HasPendingFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFramesInGenerator) {
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(2);
+
+ // Queue control frames in generator.
+ delegate_.SetCanNotWrite();
+ generator_.SetShouldSendAck(true, true);
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ // Set up frames to write into the creator when control frames are written.
+ EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
+ EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
+ Return(CreateFeedbackFrame()));
+ EXPECT_CALL(delegate_, CreateStopWaitingFrame()).WillOnce(
+ Return(CreateStopWaitingFrame()));
+
+ // Generator should have queued control frames, and creator should be empty.
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(creator_->HasPendingFrames());
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ // Queue protected data for sending. Should cause queued frames to be flushed.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ QuicConsumedData consumed = generator_.ConsumeData(7, CreateData(1u), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ PacketContents contents;
+ contents.num_ack_frames = 1;
+ contents.num_feedback_frames = 1;
+ contents.num_stop_waiting_frames = 1;
+ CheckPacketContains(contents, packet_);
+
+ // FEC protection should be on in creator.
+ EXPECT_TRUE(creator_->IsFecProtected());
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentFramesProtected) {
+ delegate_.SetCanWriteAnything();
+
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(2);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ // Queue stream frame to be protected in creator.
+ generator_.StartBatchOperations();
+ QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ // Creator has a pending protected frame.
+ EXPECT_TRUE(creator_->HasPendingFrames());
+ EXPECT_TRUE(creator_->IsFecProtected());
+
+ // Add enough unprotected data to exceed size of current packet, so that
+ // current packet is sent. Both frames will be sent out in a single packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
+ size_t data_len = kDefaultMaxPacketSize;
+ consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
+ MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ PacketContents contents;
+ contents.num_stream_frames = 2u;
+ contents.fec_group = 1u;
+ CheckPacketContains(contents, packet_);
+ // FEC protection should still be on in creator.
+ EXPECT_TRUE(creator_->IsFecProtected());
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentPacketsProtected) {
+ delegate_.SetCanWriteAnything();
+
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(2);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ generator_.StartBatchOperations();
+ // Send first packet, FEC protected.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
+ // Write enough data to cause a packet to be emitted.
+ size_t data_len = kDefaultMaxPacketSize;
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 5, CreateData(data_len), 0, true, MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ PacketContents contents;
+ contents.num_stream_frames = 1u;
+ contents.fec_group = 1u;
+ CheckPacketContains(contents, packet_);
+
+ // FEC should still be on in creator.
+ EXPECT_TRUE(creator_->IsFecProtected());
+
+ // Send enough unprotected data to cause second packet to be sent, which gets
+ // protected because it happens to fall within an open FEC group. Data packet
+ // will be followed by FEC packet.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet2_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet3_));
+ }
+ consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
+ MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ contents.num_stream_frames = 2u;
+ CheckPacketContains(contents, packet2_);
+ CheckPacketIsFec(packet3_, /*fec_group=*/1u);
+
+ // FEC protection should be off in creator.
+ EXPECT_FALSE(creator_->IsFecProtected());
+}
+
+TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffThenOnWithCreatorProtectionOn) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ // Enable FEC.
+ creator_->set_max_packets_per_fec_group(2);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ // Queue one byte of FEC protected data.
+ QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_TRUE(creator_->HasPendingFrames());
+
+ // Add more unprotected data causing first packet to be sent, FEC protected.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ size_t data_len = kDefaultMaxPacketSize;
+ consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
+ MAY_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ PacketContents contents;
+ contents.num_stream_frames = 2u;
+ contents.fec_group = 1u;
+ CheckPacketContains(contents, packet_);
+
+ // FEC group is still open in creator.
+ EXPECT_TRUE(creator_->IsFecProtected());
+
+ // Add data that should be protected, large enough to cause second packet to
+ // be sent. Data packet should be followed by FEC packet.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet2_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet3_));
+ }
+ consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
+ MUST_FEC_PROTECT, NULL);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ CheckPacketContains(contents, packet2_);
+ CheckPacketIsFec(packet3_, /*fec_group=*/1u);
+
+ // FEC protection should remain on in creator.
+ EXPECT_TRUE(creator_->IsFecProtected());
+}
+
TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
delegate_.SetCanNotWrite();
Return(CreateFeedbackFrame()));
// Send some data and a control frame
- generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, NULL);
+ generator_.ConsumeData(3, MakeIOVector("quux"), 7, false,
+ MAY_FEC_PROTECT, NULL);
generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
// All five frames will be flushed out in a single packet.
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(SaveArg<0>(&packet_));
generator_.FinishBatchOperations();
EXPECT_FALSE(generator_.HasQueuedFrames());
{
InSequence dummy;
- // All five frames will be flushed out in a single packet
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet_), Return(true)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
- DoAll(SaveArg<0>(&packet2_), Return(true)));
+ // All five frames will be flushed out in a single packet
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet_));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ SaveArg<0>(&packet2_));
}
// Send enough data to exceed one packet
size_t data_len = kDefaultMaxPacketSize + 100;
QuicConsumedData consumed =
- generator_.ConsumeData(3, CreateData(data_len), 0, true, NULL);
+ generator_.ConsumeData(3, CreateData(data_len), 0, true,
+ MAY_FEC_PROTECT, NULL);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));