Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_packet_generator_test.cc
index 4b64c15..0e44d39 100644 (file)
@@ -11,6 +11,8 @@
 #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"
@@ -31,7 +33,7 @@ namespace {
 class MockDelegate : public QuicPacketGenerator::DelegateInterface {
  public:
   MockDelegate() {}
-  virtual ~MockDelegate() {}
+  virtual ~MockDelegate() OVERRIDE {}
 
   MOCK_METHOD3(ShouldGeneratePacket,
                bool(TransmissionType transmission_type,
@@ -39,7 +41,8 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
                     IsHandshake handshake));
   MOCK_METHOD0(CreateAckFrame, QuicAckFrame*());
   MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
-  MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
+  MOCK_METHOD0(CreateStopWaitingFrame, QuicStopWaitingFrame*());
+  MOCK_METHOD1(OnSerializedPacket, void(const SerializedPacket& packet));
   MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool));
 
   void SetCanWriteAnything() {
@@ -81,6 +84,7 @@ struct PacketContents {
         num_feedback_frames(0),
         num_goaway_frames(0),
         num_rst_stream_frames(0),
+        num_stop_waiting_frames(0),
         num_stream_frames(0),
         fec_group(0) {
   }
@@ -90,6 +94,7 @@ struct PacketContents {
   size_t num_feedback_frames;
   size_t num_goaway_frames;
   size_t num_rst_stream_frames;
+  size_t num_stop_waiting_frames;
   size_t num_stream_frames;
 
   QuicFecGroupNumber fec_group;
@@ -101,16 +106,18 @@ class QuicPacketGeneratorTest : public ::testing::Test {
  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;
@@ -121,17 +128,28 @@ class QuicPacketGeneratorTest : public ::testing::Test {
     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;
+  }
+
+  QuicStopWaitingFrame* CreateStopWaitingFrame() {
+    QuicStopWaitingFrame* frame = new QuicStopWaitingFrame();
+    frame->entropy_hash = 0;
+    frame->least_unacked = 0;
     return frame;
   }
 
@@ -149,7 +167,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
         contents.num_goaway_frames + contents.num_rst_stream_frames +
         contents.num_stream_frames;
     size_t num_frames = contents.num_feedback_frames + contents.num_ack_frames +
-        num_retransmittable_frames;
+        contents.num_stop_waiting_frames + num_retransmittable_frames;
 
     if (num_retransmittable_frames == 0) {
       ASSERT_TRUE(packet.retransmittable_frames == NULL);
@@ -173,6 +191,8 @@ class QuicPacketGeneratorTest : public ::testing::Test {
               simple_framer_.rst_stream_frames().size());
     EXPECT_EQ(contents.num_stream_frames,
               simple_framer_.stream_frames().size());
+    EXPECT_EQ(contents.num_stop_waiting_frames,
+              simple_framer_.stop_waiting_frames().size());
     EXPECT_EQ(contents.fec_group, simple_framer_.header().fec_group);
   }
 
@@ -204,21 +224,23 @@ class QuicPacketGeneratorTest : public ::testing::Test {
 
   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&));
@@ -227,7 +249,7 @@ class MockDebugDelegate : public QuicPacketGenerator::DebugDelegateInterface {
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
   delegate_.SetCanNotWrite();
 
-  generator_.SetShouldSendAck(false);
+  generator_.SetShouldSendAck(false, false);
   EXPECT_TRUE(generator_.HasQueuedFrames());
 }
 
@@ -241,7 +263,7 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
   EXPECT_CALL(debug_delegate, OnFrameAddedToPacket(_)).Times(1);
 
-  generator_.SetShouldSendAck(false);
+  generator_.SetShouldSendAck(false, false);
   EXPECT_TRUE(generator_.HasQueuedFrames());
 }
 
@@ -249,10 +271,9 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
   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);
+  generator_.SetShouldSendAck(false, false);
   EXPECT_FALSE(generator_.HasQueuedFrames());
 
   PacketContents contents;
@@ -269,7 +290,7 @@ TEST_F(QuicPacketGeneratorTest,
   EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
       Return(CreateFeedbackFrame()));
 
-  generator_.SetShouldSendAck(true);
+  generator_.SetShouldSendAck(true, false);
   EXPECT_TRUE(generator_.HasQueuedFrames());
 }
 
@@ -280,16 +301,18 @@ TEST_F(QuicPacketGeneratorTest,
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
   EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
       Return(CreateFeedbackFrame()));
+  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);
+  generator_.SetShouldSendAck(true, true);
   EXPECT_FALSE(generator_.HasQueuedFrames());
 
   PacketContents contents;
   contents.num_ack_frames = 1;
   contents.num_feedback_frames = 1;
+  contents.num_stop_waiting_frames = 1;
   CheckPacketContains(contents, packet_);
 }
 
@@ -324,8 +347,7 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
   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());
 
@@ -337,8 +359,7 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
 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());
@@ -351,8 +372,8 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
 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());
@@ -362,8 +383,8 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
   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());
@@ -372,10 +393,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
 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());
@@ -390,9 +410,10 @@ TEST_F(QuicPacketGeneratorTest,
   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());
@@ -402,16 +423,16 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
   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());
 
@@ -424,26 +445,28 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataFEC) {
   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());
@@ -459,23 +482,24 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataFEC) {
 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());
@@ -488,29 +512,30 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) {
 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_guid_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());
@@ -518,7 +543,8 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
   // 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());
@@ -529,10 +555,323 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
   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();
 
-  generator_.SetShouldSendAck(true);
+  generator_.SetShouldSendAck(true, false);
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
   EXPECT_TRUE(generator_.HasQueuedFrames());
 
@@ -547,12 +886,12 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
       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());
 
@@ -568,7 +907,7 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
 TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
   delegate_.SetCanNotWrite();
 
-  generator_.SetShouldSendAck(true);
+  generator_.SetShouldSendAck(true, false);
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
   EXPECT_TRUE(generator_.HasQueuedFrames());
 
@@ -584,17 +923,18 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
 
   {
     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()));