Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_control_frame_manager_test.cc b/quic/core/quic_control_frame_manager_test.cc
new file mode 100644
index 0000000..ccddadd
--- /dev/null
+++ b/quic/core/quic_control_frame_manager_test.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_control_frame_manager.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+using testing::_;
+using testing::InSequence;
+using testing::Return;
+using testing::StrictMock;
+
+namespace quic {
+namespace test {
+
+class QuicControlFrameManagerPeer {
+ public:
+ static size_t QueueSize(QuicControlFrameManager* manager) {
+ return manager->control_frames_.size();
+ }
+};
+
+namespace {
+
+const QuicStreamId kTestStreamId = 5;
+const QuicStreamId kTestStopSendingCode = 321;
+
+class QuicControlFrameManagerTest : public QuicTest {
+ public:
+ bool ClearControlFrame(const QuicFrame& frame) {
+ DeleteFrame(&const_cast<QuicFrame&>(frame));
+ return true;
+ }
+ bool SaveControlFrame(const QuicFrame& frame) {
+ frame_ = frame;
+ return true;
+ }
+
+ protected:
+ // Pre-fills the control frame queue with the following frames:
+ // ID Type
+ // 1 RST_STREAM
+ // 2 GO_AWAY
+ // 3 WINDOW_UPDATE
+ // 4 BLOCKED
+ // 5 STOP_SENDING
+ // This is verified. The tests then perform manipulations on these.
+ void Initialize() {
+ connection_ = new MockQuicConnection(&helper_, &alarm_factory_,
+ Perspective::IS_SERVER);
+ session_ = QuicMakeUnique<StrictMock<MockQuicSession>>(connection_);
+ manager_ = QuicMakeUnique<QuicControlFrameManager>(session_.get());
+ EXPECT_EQ(0u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_FALSE(manager_->WillingToWrite());
+
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ manager_->WriteOrBufferRstStream(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
+ manager_->WriteOrBufferGoAway(QUIC_PEER_GOING_AWAY, kTestStreamId,
+ "Going away.");
+ manager_->WriteOrBufferWindowUpdate(kTestStreamId, 100);
+ manager_->WriteOrBufferBlocked(kTestStreamId);
+ manager_->WriteOrBufferStopSending(kTestStopSendingCode, kTestStreamId);
+ number_of_frames_ = 5u;
+ ping_frame_id_ = 6u;
+ EXPECT_EQ(number_of_frames_,
+ QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
+ EXPECT_TRUE(
+ manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&blocked_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&stop_sending_)));
+ EXPECT_FALSE(manager_->IsControlFrameOutstanding(
+ QuicFrame(QuicPingFrame(ping_frame_id_))));
+
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+ }
+
+ QuicRstStreamFrame rst_stream_ = {1, kTestStreamId, QUIC_STREAM_CANCELLED, 0};
+ QuicGoAwayFrame goaway_ = {2, QUIC_PEER_GOING_AWAY, kTestStreamId,
+ "Going away."};
+ QuicWindowUpdateFrame window_update_ = {3, kTestStreamId, 100};
+ QuicBlockedFrame blocked_ = {4, kTestStreamId};
+ QuicStopSendingFrame stop_sending_ = {5, kTestStreamId, kTestStopSendingCode};
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection* connection_;
+ std::unique_ptr<StrictMock<MockQuicSession>> session_;
+ std::unique_ptr<QuicControlFrameManager> manager_;
+ QuicFrame frame_;
+ size_t number_of_frames_;
+ int ping_frame_id_;
+};
+
+TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
+ Initialize();
+ InSequence s;
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(3)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ // Send control frames 1, 2, 3.
+ manager_->OnCanWrite();
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&blocked_)));
+ EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&stop_sending_)));
+
+ EXPECT_FALSE(manager_->IsControlFrameOutstanding(
+ QuicFrame(QuicPingFrame(ping_frame_id_))));
+ EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&window_update_)));
+ EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
+ EXPECT_EQ(number_of_frames_,
+ QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+
+ EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&goaway_)));
+ EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
+ EXPECT_EQ(number_of_frames_,
+ QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+ EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&rst_stream_)));
+ EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
+ // Only after the first frame in the queue is acked do the frames get
+ // removed ... now see that the length has been reduced by 3.
+ EXPECT_EQ(number_of_frames_ - 3u,
+ QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+ // Duplicate ack.
+ EXPECT_FALSE(manager_->OnControlFrameAcked(QuicFrame(&goaway_)));
+
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+
+ // Send control frames 4, 5.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+ manager_->WritePing();
+ EXPECT_FALSE(manager_->WillingToWrite());
+}
+
+TEST_F(QuicControlFrameManagerTest, OnControlFrameLost) {
+ Initialize();
+ InSequence s;
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(3)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ // Send control frames 1, 2, 3.
+ manager_->OnCanWrite();
+
+ // Lost control frames 1, 2, 3.
+ manager_->OnControlFrameLost(QuicFrame(&rst_stream_));
+ manager_->OnControlFrameLost(QuicFrame(&goaway_));
+ manager_->OnControlFrameLost(QuicFrame(&window_update_));
+ EXPECT_TRUE(manager_->HasPendingRetransmission());
+
+ // Ack control frame 2.
+ manager_->OnControlFrameAcked(QuicFrame(&goaway_));
+
+ // Retransmit control frames 1, 3.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+
+ // Send control frames 4, 5, and 6.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(number_of_frames_ - 2u)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+ manager_->WritePing();
+ EXPECT_FALSE(manager_->WillingToWrite());
+}
+
+TEST_F(QuicControlFrameManagerTest, RetransmitControlFrame) {
+ Initialize();
+ InSequence s;
+ // Send control frames 1, 2, 3, 4.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(number_of_frames_)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+
+ // Ack control frame 2.
+ manager_->OnControlFrameAcked(QuicFrame(&goaway_));
+ // Do not retransmit an acked frame.
+ EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+ EXPECT_TRUE(manager_->RetransmitControlFrame(QuicFrame(&goaway_)));
+
+ // Retransmit control frame 3.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ EXPECT_TRUE(manager_->RetransmitControlFrame(QuicFrame(&window_update_)));
+
+ // Retransmit control frame 4, and connection is write blocked.
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ EXPECT_FALSE(manager_->RetransmitControlFrame(QuicFrame(&window_update_)));
+}
+
+TEST_F(QuicControlFrameManagerTest, DonotSendPingWithBufferedFrames) {
+ Initialize();
+ InSequence s;
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ // Send control frame 1.
+ manager_->OnCanWrite();
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+
+ // Send PING when there is buffered frames.
+ manager_->WritePing();
+ // Verify only the buffered frames are sent.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(number_of_frames_ - 1)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_FALSE(manager_->WillingToWrite());
+}
+
+TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
+ Initialize();
+ // Send two more window updates of the same stream.
+ manager_->WriteOrBufferWindowUpdate(kTestStreamId, 200);
+ QuicWindowUpdateFrame window_update2(number_of_frames_ + 1, kTestStreamId,
+ 200);
+
+ manager_->WriteOrBufferWindowUpdate(kTestStreamId, 300);
+ QuicWindowUpdateFrame window_update3(number_of_frames_ + 2, kTestStreamId,
+ 300);
+ InSequence s;
+ // Flush all buffered control frames.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+
+ // Mark all 3 window updates as lost.
+ manager_->OnControlFrameLost(QuicFrame(&window_update_));
+ manager_->OnControlFrameLost(QuicFrame(&window_update2));
+ manager_->OnControlFrameLost(QuicFrame(&window_update3));
+ EXPECT_TRUE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+
+ // Verify only the latest window update gets retransmitted.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(this, &QuicControlFrameManagerTest::SaveControlFrame));
+ manager_->OnCanWrite();
+ EXPECT_EQ(number_of_frames_ + 2u,
+ frame_.window_update_frame->control_frame_id);
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_FALSE(manager_->WillingToWrite());
+ DeleteFrame(&frame_);
+}
+
+TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
+ Initialize();
+ // Send two more window updates of different streams.
+ manager_->WriteOrBufferWindowUpdate(kTestStreamId + 2, 200);
+ QuicWindowUpdateFrame window_update2(5, kTestStreamId + 2, 200);
+
+ manager_->WriteOrBufferWindowUpdate(kTestStreamId + 4, 300);
+ QuicWindowUpdateFrame window_update3(6, kTestStreamId + 4, 300);
+ InSequence s;
+ // Flush all buffered control frames.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+
+ // Mark all 3 window updates as lost.
+ manager_->OnControlFrameLost(QuicFrame(&window_update_));
+ manager_->OnControlFrameLost(QuicFrame(&window_update2));
+ manager_->OnControlFrameLost(QuicFrame(&window_update3));
+ EXPECT_TRUE(manager_->HasPendingRetransmission());
+ EXPECT_TRUE(manager_->WillingToWrite());
+
+ // Verify all 3 window updates get retransmitted.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(3)
+ .WillRepeatedly(
+ Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+ manager_->OnCanWrite();
+ EXPECT_FALSE(manager_->HasPendingRetransmission());
+ EXPECT_FALSE(manager_->WillingToWrite());
+}
+
+} // namespace
+} // namespace test
+} // namespace quic