| // 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 |