blob: 2201c4ac8dd8c2385eb17d6d8671aca93f0afb33 [file] [log] [blame] [edit]
// 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 "quiche/quic/core/quic_control_frame_manager.h"
#include <memory>
#include <utility>
#include <vector>
#include "quiche/quic/core/crypto/null_encrypter.h"
#include "quiche/quic/core/frames/quic_ack_frequency_frame.h"
#include "quiche/quic/core/frames/quic_retire_connection_id_frame.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_expect_bug.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
using testing::_;
using testing::InSequence;
using testing::Invoke;
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 QuicRstStreamErrorCode kTestStopSendingCode =
QUIC_STREAM_ENCODER_STREAM_ERROR;
class QuicControlFrameManagerTest : public QuicTest {
public:
QuicControlFrameManagerTest()
: connection_(new MockQuicConnection(&helper_, &alarm_factory_,
Perspective::IS_SERVER)),
session_(std::make_unique<StrictMock<MockQuicSession>>(connection_)),
manager_(std::make_unique<QuicControlFrameManager>(session_.get())) {
connection_->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection_->perspective()));
}
protected:
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
MockQuicConnection* connection_;
std::unique_ptr<StrictMock<MockQuicSession>> session_;
std::unique_ptr<QuicControlFrameManager> manager_;
};
TEST_F(QuicControlFrameManagerTest, InitialState) {
EXPECT_EQ(0u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, WriteOrBufferRstStream) {
QuicRstStreamFrame rst_stream = {1, kTestStreamId, QUIC_STREAM_CANCELLED, 0};
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(
[&rst_stream](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(RST_STREAM_FRAME, frame.type);
EXPECT_EQ(rst_stream, *frame.rst_stream_frame);
ClearControlFrame(frame);
return true;
}));
manager_->WriteOrBufferRstStream(
rst_stream.stream_id,
QuicResetStreamError::FromInternal(rst_stream.error_code),
rst_stream.byte_offset);
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream)));
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, WriteOrBufferGoAway) {
QuicGoAwayFrame goaway = {1, QUIC_PEER_GOING_AWAY, kTestStreamId,
"Going away."};
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&goaway](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(GOAWAY_FRAME, frame.type);
EXPECT_EQ(goaway, *frame.goaway_frame);
ClearControlFrame(frame);
return true;
}));
manager_->WriteOrBufferGoAway(goaway.error_code, goaway.last_good_stream_id,
goaway.reason_phrase);
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway)));
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, WriteOrBufferWindowUpdate) {
QuicWindowUpdateFrame window_update = {1, kTestStreamId, 100};
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(
[&window_update](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(WINDOW_UPDATE_FRAME, frame.type);
EXPECT_EQ(window_update, frame.window_update_frame);
ClearControlFrame(frame);
return true;
}));
manager_->WriteOrBufferWindowUpdate(window_update.stream_id,
window_update.max_data);
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(window_update)));
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, WriteOrBufferBlocked) {
QuicBlockedFrame blocked = {1, kTestStreamId, 10};
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&blocked](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(BLOCKED_FRAME, frame.type);
EXPECT_EQ(blocked, frame.blocked_frame);
ClearControlFrame(frame);
return true;
}));
manager_->WriteOrBufferBlocked(blocked.stream_id, blocked.offset);
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(blocked)));
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, WriteOrBufferStopSending) {
QuicStopSendingFrame stop_sending = {1, kTestStreamId, kTestStopSendingCode};
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(
[&stop_sending](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(STOP_SENDING_FRAME, frame.type);
EXPECT_EQ(stop_sending, frame.stop_sending_frame);
ClearControlFrame(frame);
return true;
}));
manager_->WriteOrBufferStopSending(
QuicResetStreamError::FromInternal(stop_sending.error_code),
stop_sending.stream_id);
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(stop_sending)));
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, BufferWhenWriteControlFrameReturnsFalse) {
QuicBlockedFrame blocked = {1, kTestStreamId, 0};
// Attempt write a control frame, but since WriteControlFrame returns false,
// the frame will be buffered.
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
manager_->WriteOrBufferBlocked(blocked.stream_id, blocked.offset);
EXPECT_TRUE(manager_->WillingToWrite());
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(blocked)));
// OnCanWrite will send the frame.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, BufferThenSendThenBuffer) {
InSequence s;
QuicBlockedFrame frame1 = {1, kTestStreamId, 0};
QuicBlockedFrame frame2 = {2, kTestStreamId + 1, 1};
// Attempt write a control frame, but since WriteControlFrame returns false,
// the frame will be buffered.
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
manager_->WriteOrBufferBlocked(frame1.stream_id, frame1.offset);
manager_->WriteOrBufferBlocked(frame2.stream_id, frame2.offset);
EXPECT_TRUE(manager_->WillingToWrite());
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame1)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame2)));
// OnCanWrite will send the first frame, but WriteControlFrame will return
// false and the second frame will remain buffered.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
manager_->OnCanWrite();
EXPECT_TRUE(manager_->WillingToWrite());
// Now the second frame will finally be sent.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
QuicRstStreamFrame frame1 = {1, kTestStreamId, QUIC_STREAM_CANCELLED, 0};
QuicGoAwayFrame frame2 = {2, QUIC_PEER_GOING_AWAY, kTestStreamId,
"Going away."};
QuicWindowUpdateFrame frame3 = {3, kTestStreamId, 100};
QuicBlockedFrame frame4 = {4, kTestStreamId, 0};
QuicStopSendingFrame frame5 = {5, kTestStreamId, kTestStopSendingCode};
// Write 5 all frames.
InSequence s;
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.Times(5)
.WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferRstStream(
frame1.stream_id, QuicResetStreamError::FromInternal(frame1.error_code),
frame1.byte_offset);
manager_->WriteOrBufferGoAway(frame2.error_code, frame2.last_good_stream_id,
frame2.reason_phrase);
manager_->WriteOrBufferWindowUpdate(frame3.stream_id, frame3.max_data);
manager_->WriteOrBufferBlocked(frame4.stream_id, frame4.offset);
manager_->WriteOrBufferStopSending(
QuicResetStreamError::FromInternal(frame5.error_code), frame5.stream_id);
// Verify all 5 are still outstanding.
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&frame1)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&frame2)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame3)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame4)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame5)));
EXPECT_FALSE(manager_->HasPendingRetransmission());
// Ack the third frame, but since the first is still in the queue, the size
// will not shrink.
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(frame3)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(frame3)));
EXPECT_EQ(5, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Ack the second frame, but since the first is still in the queue, the size
// will not shrink.
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&frame2)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&frame2)));
EXPECT_EQ(5, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// 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_TRUE(manager_->OnControlFrameAcked(QuicFrame(&frame1)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&frame1)));
EXPECT_EQ(2, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Duplicate ack should change nothing.
EXPECT_FALSE(manager_->OnControlFrameAcked(QuicFrame(&frame2)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&frame1)));
EXPECT_EQ(2, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Ack the fourth frame which will shrink the queue.
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(frame4)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(frame4)));
EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Ack the fourth frame which will empty the queue.
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(frame5)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(frame5)));
EXPECT_EQ(0, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
}
TEST_F(QuicControlFrameManagerTest, OnControlFrameLost) {
QuicRstStreamFrame frame1 = {1, kTestStreamId, QUIC_STREAM_CANCELLED, 0};
QuicGoAwayFrame frame2 = {2, QUIC_PEER_GOING_AWAY, kTestStreamId,
"Going away."};
QuicWindowUpdateFrame frame3 = {3, kTestStreamId, 100};
QuicBlockedFrame frame4 = {4, kTestStreamId, 0};
QuicStopSendingFrame frame5 = {5, kTestStreamId, kTestStopSendingCode};
// Write the first 3 frames, but leave the second two buffered.
InSequence s;
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.Times(3)
.WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferRstStream(
frame1.stream_id, QuicResetStreamError::FromInternal(frame1.error_code),
frame1.byte_offset);
manager_->WriteOrBufferGoAway(frame2.error_code, frame2.last_good_stream_id,
frame2.reason_phrase);
manager_->WriteOrBufferWindowUpdate(frame3.stream_id, frame3.max_data);
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
manager_->WriteOrBufferBlocked(frame4.stream_id, frame4.offset);
manager_->WriteOrBufferStopSending(
QuicResetStreamError::FromInternal(frame5.error_code), frame5.stream_id);
// Lose frames 1, 2, 3.
manager_->OnControlFrameLost(QuicFrame(&frame1));
manager_->OnControlFrameLost(QuicFrame(&frame2));
manager_->OnControlFrameLost(QuicFrame(frame3));
EXPECT_TRUE(manager_->HasPendingRetransmission());
// Verify that the lost frames are still outstanding.
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&frame1)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&frame2)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(frame3)));
// Ack control frame 2.
manager_->OnControlFrameAcked(QuicFrame(&frame2));
// OnCanWrite will retransmit the lost frames, but will not sent the
// not-yet-sent frames.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame1](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(RST_STREAM_FRAME, frame.type);
EXPECT_EQ(frame1, *frame.rst_stream_frame);
ClearControlFrame(frame);
return true;
}));
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame3](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(WINDOW_UPDATE_FRAME, frame.type);
EXPECT_EQ(frame3, frame.window_update_frame);
ClearControlFrame(frame);
return true;
}));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
// Send control frames 4, and 5.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame4](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(BLOCKED_FRAME, frame.type);
EXPECT_EQ(frame4, frame.blocked_frame);
ClearControlFrame(frame);
return true;
}));
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame5](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(STOP_SENDING_FRAME, frame.type);
EXPECT_EQ(frame5, frame.stop_sending_frame);
ClearControlFrame(frame);
return true;
}));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, RetransmitControlFrame) {
QuicRstStreamFrame frame1 = {1, kTestStreamId, QUIC_STREAM_CANCELLED, 0};
QuicGoAwayFrame frame2 = {2, QUIC_PEER_GOING_AWAY, kTestStreamId,
"Going away."};
QuicWindowUpdateFrame frame3 = {3, kTestStreamId, 100};
QuicBlockedFrame frame4 = {4, kTestStreamId, 0};
// Send all 4 frames.
InSequence s;
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.Times(4)
.WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferRstStream(
frame1.stream_id, QuicResetStreamError::FromInternal(frame1.error_code),
frame1.byte_offset);
manager_->WriteOrBufferGoAway(frame2.error_code, frame2.last_good_stream_id,
frame2.reason_phrase);
manager_->WriteOrBufferWindowUpdate(frame3.stream_id, frame3.max_data);
manager_->WriteOrBufferBlocked(frame4.stream_id, frame4.offset);
// Ack control frame 2.
manager_->OnControlFrameAcked(QuicFrame(&frame2));
// Do not retransmit an acked frame
EXPECT_CALL(*session_, WriteControlFrame(_, _)).Times(0);
EXPECT_TRUE(
manager_->RetransmitControlFrame(QuicFrame(&frame2), PTO_RETRANSMISSION));
// Retransmit frame 3.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame3](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(WINDOW_UPDATE_FRAME, frame.type);
EXPECT_EQ(frame3, frame.window_update_frame);
ClearControlFrame(frame);
return true;
}));
EXPECT_TRUE(
manager_->RetransmitControlFrame(QuicFrame(frame3), PTO_RETRANSMISSION));
// Retransmit frame 4, but since WriteControlFrame returned false the
// frame will still need retransmission.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(
Invoke([&frame4](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(BLOCKED_FRAME, frame.type);
EXPECT_EQ(frame4, frame.blocked_frame);
return false;
}));
EXPECT_FALSE(
manager_->RetransmitControlFrame(QuicFrame(frame4), PTO_RETRANSMISSION));
}
TEST_F(QuicControlFrameManagerTest, SendAndAckAckFrequencyFrame) {
// Send AckFrequencyFrame
QuicAckFrequencyFrame frame_to_send;
frame_to_send.packet_tolerance = 10;
frame_to_send.max_ack_delay = QuicTime::Delta::FromMilliseconds(24);
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferAckFrequency(frame_to_send);
// Ack AckFrequencyFrame.
QuicAckFrequencyFrame expected_ack_frequency = frame_to_send;
expected_ack_frequency.control_frame_id = 1;
expected_ack_frequency.sequence_number = 1;
EXPECT_TRUE(
manager_->OnControlFrameAcked(QuicFrame(&expected_ack_frequency)));
}
TEST_F(QuicControlFrameManagerTest, NewAndRetireConnectionIdFrames) {
// Send NewConnectionIdFrame
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
QuicNewConnectionIdFrame new_connection_id_frame(
1, TestConnectionId(3), /*sequence_number=*/1,
/*stateless_reset_token=*/
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /*retire_prior_to=*/1);
manager_->WriteOrBufferNewConnectionId(
new_connection_id_frame.connection_id,
new_connection_id_frame.sequence_number,
new_connection_id_frame.retire_prior_to,
new_connection_id_frame.stateless_reset_token);
// Send RetireConnectionIdFrame
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
QuicRetireConnectionIdFrame retire_connection_id_frame(2,
/*sequence_number=*/0);
manager_->WriteOrBufferRetireConnectionId(
retire_connection_id_frame.sequence_number);
// Ack both frames.
EXPECT_TRUE(
manager_->OnControlFrameAcked(QuicFrame(&new_connection_id_frame)));
EXPECT_TRUE(
manager_->OnControlFrameAcked(QuicFrame(&retire_connection_id_frame)));
}
TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
// Send two window updates for the same stream.
QuicWindowUpdateFrame window_update1(1, kTestStreamId, 200);
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferWindowUpdate(window_update1.stream_id,
window_update1.max_data);
QuicWindowUpdateFrame window_update2(2, kTestStreamId, 300);
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferWindowUpdate(window_update2.stream_id,
window_update2.max_data);
// Mark both window updates as lost.
manager_->OnControlFrameLost(QuicFrame(window_update1));
manager_->OnControlFrameLost(QuicFrame(window_update2));
EXPECT_TRUE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
// Verify only the latest window update gets retransmitted.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(
[&window_update2](const QuicFrame& frame, TransmissionType /*type*/) {
EXPECT_EQ(WINDOW_UPDATE_FRAME, frame.type);
EXPECT_EQ(window_update2, frame.window_update_frame);
ClearControlFrame(frame);
return true;
}));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
// Send two window updates for different streams.
QuicWindowUpdateFrame window_update1(1, kTestStreamId + 2, 200);
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferWindowUpdate(window_update1.stream_id,
window_update1.max_data);
QuicWindowUpdateFrame window_update2(2, kTestStreamId + 4, 300);
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
manager_->WriteOrBufferWindowUpdate(window_update2.stream_id,
window_update2.max_data);
// Mark both window updates as lost.
manager_->OnControlFrameLost(QuicFrame(window_update1));
manager_->OnControlFrameLost(QuicFrame(window_update2));
EXPECT_TRUE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
// Verify both window updates get retransmitted.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.Times(2)
.WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
manager_->OnCanWrite();
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_FALSE(manager_->WillingToWrite());
}
TEST_F(QuicControlFrameManagerTest, TooManyBufferedControlFrames) {
// Write 1000 control frames.
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
for (size_t i = 0; i < 1000; ++i) {
manager_->WriteOrBufferRstStream(
kTestStreamId,
QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), 0);
}
// Verify that writing one more control frame causes connection close.
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES, _,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
manager_->WriteOrBufferRstStream(
kTestStreamId, QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED),
0);
}
TEST_F(QuicControlFrameManagerTest, NumBufferedMaxStreams) {
std::vector<QuicMaxStreamsFrame> max_streams_frames;
size_t expected_buffered_frames = 0;
for (int i = 0; i < 5; ++i) {
// Save the frame so it can be ACK'd later.
EXPECT_CALL(*session_, WriteControlFrame(_, _))
.WillOnce(Invoke([&max_streams_frames](const QuicFrame& frame,
TransmissionType /*type*/) {
max_streams_frames.push_back(frame.max_streams_frame);
ClearControlFrame(frame);
return true;
}));
// The contents of the frame don't matter for this test.
manager_->WriteOrBufferMaxStreams(0, false);
EXPECT_EQ(++expected_buffered_frames, manager_->NumBufferedMaxStreams());
}
for (const QuicMaxStreamsFrame& frame : max_streams_frames) {
manager_->OnControlFrameAcked(QuicFrame(frame));
EXPECT_EQ(--expected_buffered_frames, manager_->NumBufferedMaxStreams());
}
EXPECT_EQ(0, manager_->NumBufferedMaxStreams());
}
} // namespace
} // namespace test
} // namespace quic