blob: 6e14df7a9d610669b44d4f09e28c747f96e194ea [file] [log] [blame]
// Copyright (c) 2012 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/quic/quic_connection.h"
#include "net/base/net_errors.h"
#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
#include "net/quic/congestion_control/quic_send_scheduler.h"
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/quic_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
using std::map;
using testing::_;
using testing::ContainerEq;
using testing::Return;
using testing::StrictMock;
namespace net {
// Peer to make public a number of otherwise private QuicConnection methods.
class QuicConnectionPeer {
public:
static void SendAck(QuicConnection* connection) {
connection->SendAck();
}
static void SetCollector(QuicConnection* connection,
QuicReceiptMetricsCollector* collector) {
connection->collector_.reset(collector);
}
static void SetScheduler(QuicConnection* connection,
QuicSendScheduler* scheduler) {
connection->scheduler_.reset(scheduler);
}
static QuicAckFrame* GetOutgoingAck(QuicConnection* connection) {
return &connection->outgoing_ack_;
}
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
namespace test {
namespace {
const char data1[] = "foo";
const char data2[] = "bar";
class TestCollector : public QuicReceiptMetricsCollector {
public:
explicit TestCollector(QuicCongestionFeedbackFrame* feedback)
: QuicReceiptMetricsCollector(&clock_, kFixRate),
feedback_(feedback) {
}
bool GenerateCongestionFeedback(
QuicCongestionFeedbackFrame* congestion_feedback) {
if (feedback_ == NULL) {
return false;
}
*congestion_feedback = *feedback_;
return true;
}
MOCK_METHOD4(RecordIncomingPacket,
void(size_t, QuicPacketSequenceNumber, QuicTime, bool));
private:
MockClock clock_;
QuicCongestionFeedbackFrame* feedback_;
DISALLOW_COPY_AND_ASSIGN(TestCollector);
};
class TestConnectionHelper : public QuicConnectionHelperInterface {
public:
explicit TestConnectionHelper(MockClock* clock)
: clock_(clock),
blocked_(false) {
}
// QuicConnectionHelperInterface
virtual void SetConnection(QuicConnection* connection) {}
virtual const QuicClock* GetClock() const {
return clock_;
}
virtual int WritePacketToWire(const QuicEncryptedPacket& packet,
int* error) {
QuicFramer framer(QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL));
FramerVisitorCapturingAcks visitor;
framer.set_visitor(&visitor);
EXPECT_TRUE(framer.ProcessPacket(IPEndPoint(), IPEndPoint(), packet));
header_ = *visitor.header();
if (visitor.ack()) {
ack_.reset(new QuicAckFrame(*visitor.ack()));
}
if (visitor.feedback()) {
feedback_.reset(new QuicCongestionFeedbackFrame(*visitor.feedback()));
}
if (blocked_) {
*error = ERR_IO_PENDING;
return -1;
}
return packet.length();
}
virtual void SetResendAlarm(QuicPacketSequenceNumber sequence_number,
QuicTime::Delta delay) {
resend_alarms_[sequence_number] = clock_->Now().Add(delay);
}
virtual void SetSendAlarm(QuicTime::Delta delay) {
send_alarm_ = clock_->Now().Add(delay);
}
virtual void SetTimeoutAlarm(QuicTime::Delta delay) {
timeout_alarm_ = clock_->Now().Add(delay);
}
virtual bool IsSendAlarmSet() {
return send_alarm_ > clock_->Now();
}
virtual void UnregisterSendAlarmIfRegistered() {
send_alarm_ = QuicTime();
}
const map<QuicPacketSequenceNumber, QuicTime>& resend_alarms() const {
return resend_alarms_;
}
QuicTime timeout_alarm() const { return timeout_alarm_; }
QuicPacketHeader* header() { return &header_; }
QuicAckFrame* ack() { return ack_.get(); }
QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); }
void set_blocked(bool blocked) { blocked_ = blocked; }
private:
MockClock* clock_;
map<QuicPacketSequenceNumber, QuicTime> resend_alarms_;
QuicTime send_alarm_;
QuicTime timeout_alarm_;
QuicPacketHeader header_;
scoped_ptr<QuicAckFrame> ack_;
scoped_ptr<QuicCongestionFeedbackFrame> feedback_;
bool blocked_;
DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
};
class TestConnection : public QuicConnection {
public:
TestConnection(QuicGuid guid,
IPEndPoint address,
TestConnectionHelper* helper)
: QuicConnection(guid, address, helper) {
}
void SendAck() {
QuicConnectionPeer::SendAck(this);
}
void SetCollector(QuicReceiptMetricsCollector* collector) {
QuicConnectionPeer::SetCollector(this, collector);
}
void SetScheduler(QuicSendScheduler* scheduler) {
QuicConnectionPeer::SetScheduler(this, scheduler);
}
bool SendPacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
bool should_resend,
bool force,
bool is_retransmit) {
return QuicConnection::SendPacket(
sequence_number, packet, should_resend, force, is_retransmit);
}
private:
DISALLOW_COPY_AND_ASSIGN(TestConnection);
};
class QuicConnectionTest : public ::testing::Test {
protected:
QuicConnectionTest()
: guid_(42),
framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
creator_(guid_, &framer_),
scheduler_(new StrictMock<MockScheduler>),
helper_(new TestConnectionHelper(&clock_)),
connection_(guid_, IPEndPoint(), helper_.get()),
frame1_(1, false, 0, data1),
frame2_(1, false, 3, data2),
accept_packet_(true) {
connection_.set_visitor(&visitor_);
connection_.SetScheduler(scheduler_);
// Simplify tests by not sending feedback unless specifically configured.
SetFeedback(NULL);
EXPECT_CALL(*scheduler_, TimeUntilSend(_)).WillRepeatedly(Return(
QuicTime::Delta()));
}
QuicAckFrame* last_ack() {
return helper_->ack();
}
QuicCongestionFeedbackFrame* last_feedback() {
return helper_->feedback();
}
QuicPacketHeader* last_header() {
return helper_->header();
}
void ProcessPacket(QuicPacketSequenceNumber number) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _))
.WillOnce(Return(accept_packet_));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
ProcessDataPacket(number, 0);
}
void ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
bool expect_revival) {
if (expect_revival) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(2).WillRepeatedly(
Return(accept_packet_));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(2);
} else {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(
Return(accept_packet_));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
}
ProcessDataPacket(number, 1);
}
void ProcessDataPacket(QuicPacketSequenceNumber number,
QuicFecGroupNumber fec_group) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(number, fec_group));
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
// Sends an FEC packet that covers the packets that would have been sent.
void ProcessFecPacket(QuicPacketSequenceNumber number,
QuicPacketSequenceNumber min_protected_packet,
bool expect_revival) {
if (expect_revival) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(
Return(accept_packet_));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
}
// Construct the decrypted data packet so we can compute the correct
// redundancy.
scoped_ptr<QuicPacket> data_packet(ConstructDataPacket(number, 1));
header_.guid = guid_;
header_.packet_sequence_number = number;
header_.flags = PACKET_FLAGS_FEC;
header_.fec_group = 1;
QuicFecData fec_data;
fec_data.min_protected_packet_sequence_number = min_protected_packet;
fec_data.fec_group = 1;
// Since all data packets in this test have the same payload, the
// redundancy is either equal to that payload or the xor of that payload
// with itself, depending on the number of packets.
if (((number - min_protected_packet) % 2) == 0) {
for (size_t i = kStartOfFecProtectedData; i < data_packet->length();
++i) {
data_packet->mutable_data()[i] ^= data_packet->data()[i];
}
}
fec_data.redundancy = data_packet->FecProtectedData();
scoped_ptr<QuicPacket> fec_packet(
framer_.ConstructFecPacket(header_, fec_data));
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(*fec_packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
void SendStreamDataToPeer(QuicStreamId id, StringPiece data,
QuicStreamOffset offset, bool fin,
QuicPacketSequenceNumber* last_packet) {
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
connection_.SendStreamData(id, data, offset, fin, last_packet);
}
void SendAckPacketToPeer() {
EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(num_packets_per_ack_);
connection_.SendAck();
}
void ProcessAckPacket(QuicAckFrame* frame, bool expect_success = true) {
if (expect_success) {
EXPECT_CALL(*scheduler_, OnIncomingAckFrame(_));
}
scoped_ptr<QuicPacket> packet(creator_.AckPacket(frame).second);
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
bool IsMissing(QuicPacketSequenceNumber number) {
return last_ack()->received_info.IsAwaitingPacket(number);
}
QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number,
QuicFecGroupNumber fec_group) {
header_.guid = guid_;
header_.packet_sequence_number = number;
header_.flags = PACKET_FLAGS_NONE;
header_.fec_group = fec_group;
QuicFrames frames;
QuicFrame frame(&frame1_);
frames.push_back(frame);
QuicPacket* packet = framer_.ConstructFrameDataPacket(header_, frames);
EXPECT_TRUE(packet != NULL);
return packet;
}
void SetFeedback(QuicCongestionFeedbackFrame* feedback) {
num_packets_per_ack_ = feedback != NULL ? 2 : 1;
collector_ = new TestCollector(feedback);
connection_.SetCollector(collector_);
}
QuicGuid guid_;
QuicFramer framer_;
QuicPacketCreator creator_;
MockScheduler* scheduler_;
TestCollector* collector_;
MockClock clock_;
scoped_ptr<TestConnectionHelper> helper_;
TestConnection connection_;
testing::StrictMock<MockConnectionVisitor> visitor_;
QuicPacketHeader header_;
QuicStreamFrame frame1_;
QuicStreamFrame frame2_;
bool accept_packet_;
size_t num_packets_per_ack_;
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionTest);
};
TEST_F(QuicConnectionTest, PacketsInOrder) {
ProcessPacket(1);
EXPECT_EQ(1u, last_ack()->received_info.largest_received);
EXPECT_EQ(0u, last_ack()->received_info.missing_packets.size());
ProcessPacket(2);
EXPECT_EQ(2u, last_ack()->received_info.largest_received);
EXPECT_EQ(0u, last_ack()->received_info.missing_packets.size());
ProcessPacket(3);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_EQ(0u, last_ack()->received_info.missing_packets.size());
}
TEST_F(QuicConnectionTest, PacketsRejected) {
ProcessPacket(1);
EXPECT_EQ(1u, last_ack()->received_info.largest_received);
EXPECT_EQ(0u, last_ack()->received_info.missing_packets.size());
accept_packet_ = false;
ProcessPacket(2);
// We should not have an ack for two.
EXPECT_EQ(1u, last_ack()->received_info.largest_received);
EXPECT_EQ(0u, last_ack()->received_info.missing_packets.size());
}
TEST_F(QuicConnectionTest, PacketsOutOfOrder) {
ProcessPacket(3);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(2));
EXPECT_TRUE(IsMissing(1));
ProcessPacket(2);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_FALSE(IsMissing(2));
EXPECT_TRUE(IsMissing(1));
ProcessPacket(1);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_FALSE(IsMissing(2));
EXPECT_FALSE(IsMissing(1));
}
TEST_F(QuicConnectionTest, DuplicatePacket) {
ProcessPacket(3);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(2));
EXPECT_TRUE(IsMissing(1));
// Send packet 3 again, but do not set the expectation that
// the visitor OnPacket() will be called.
ProcessDataPacket(3, 0);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(2));
EXPECT_TRUE(IsMissing(1));
}
TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
ProcessPacket(3);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(2));
EXPECT_TRUE(IsMissing(1));
ProcessPacket(2);
EXPECT_EQ(3u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(1));
ProcessPacket(5);
EXPECT_EQ(5u, last_ack()->received_info.largest_received);
EXPECT_TRUE(IsMissing(1));
EXPECT_TRUE(IsMissing(4));
// Pretend at this point the client has gotten acks for 2 and 3 and 1 is a
// packet the peer will not retransmit. It indicates this by sending 'least
// awaiting' is 4. The connection should then realize 1 will not be
// retransmitted, and will remove it from the missing list.
creator_.set_sequence_number(5);
QuicAckFrame frame(0, 4);
ProcessAckPacket(&frame);
// Force an ack to be sent.
SendAckPacketToPeer();
EXPECT_TRUE(IsMissing(4));
}
TEST_F(QuicConnectionTest, RejectPacketTooFarOut) {
// Call ProcessDataPacket rather than ProcessPacket, as we should not get a
// packet call to the visitor.
ProcessDataPacket(6000, 0);
SendAckPacketToPeer(); // Packet 2
EXPECT_EQ(0u, last_ack()->received_info.largest_received);
}
TEST_F(QuicConnectionTest, LeastUnackedLower) {
SendStreamDataToPeer(1, "foo", 0, false, NULL);
SendStreamDataToPeer(1, "bar", 3, false, NULL);
SendStreamDataToPeer(1, "eep", 6, false, NULL);
// Start out saying the least unacked is 2
creator_.set_sequence_number(5);
QuicAckFrame frame(0, 2);
ProcessAckPacket(&frame);
// Change it to 1, but lower the sequence number to fake out-of-order packets.
// This should be fine.
creator_.set_sequence_number(1);
QuicAckFrame frame2(0, 1);
// The scheduler will not process out of order acks.
ProcessAckPacket(&frame2, false);
// Now claim it's one, but set the ordering so it was sent "after" the first
// one. This should cause a connection error.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
creator_.set_sequence_number(7);
ProcessAckPacket(&frame2, false);
}
TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) {
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
// Create an ack with least_unacked is 2 in packet number 1.
creator_.set_sequence_number(0);
QuicAckFrame frame(0, 2);
ProcessAckPacket(&frame, false);
}
TEST_F(QuicConnectionTest,
DISABLED_NackSequenceNumberGreaterThanLargestReceived) {
SendStreamDataToPeer(1, "foo", 0, false, NULL);
SendStreamDataToPeer(1, "bar", 3, false, NULL);
SendStreamDataToPeer(1, "eep", 6, false, NULL);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
QuicAckFrame frame(0, 1);
frame.received_info.missing_packets.insert(3);
ProcessAckPacket(&frame, false);
}
TEST_F(QuicConnectionTest, AckUnsentData) {
// Ack a packet which has not been sent.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
QuicAckFrame frame(1, 0);
ProcessAckPacket(&frame, false);
}
TEST_F(QuicConnectionTest, AckAll) {
ProcessPacket(1);
creator_.set_sequence_number(1);
QuicAckFrame frame1(1, 1);
ProcessAckPacket(&frame1);
}
TEST_F(QuicConnectionTest, BasicSending) {
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
SendAckPacketToPeer(); // Packet 2
EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
SendAckPacketToPeer(); // Packet 3
EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
SendStreamDataToPeer(1u, "bar", 3, false, &last_packet); // Packet 4
EXPECT_EQ(4u, last_packet);
SendAckPacketToPeer(); // Packet 5
EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
QuicConnectionVisitorInterface::AckedPackets expected_acks;
expected_acks.insert(1);
// Client acks up to packet 3
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
QuicAckFrame frame(3, 0);
ProcessAckPacket(&frame);
SendAckPacketToPeer(); // Packet 6
// As soon as we've acked one, we skip ack packets 2 and 3 and note lack of
// ack for 4.
EXPECT_EQ(4u, last_ack()->sent_info.least_unacked);
expected_acks.clear();
expected_acks.insert(4);
// Client acks up to packet 4, the last packet
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
QuicAckFrame frame2(6, 0);
ProcessAckPacket(&frame2);
SendAckPacketToPeer(); // Packet 7
// The least packet awaiting ack should now be 7
EXPECT_EQ(7u, last_ack()->sent_info.least_unacked);
// If we force an ack, we shouldn't change our retransmit state.
SendAckPacketToPeer(); // Packet 8
EXPECT_EQ(8u, last_ack()->sent_info.least_unacked);
// But if we send more data it should.
SendStreamDataToPeer(1, "eep", 6, false, &last_packet); // Packet 9
EXPECT_EQ(9u, last_packet);
SendAckPacketToPeer(); // Packet10
EXPECT_EQ(9u, last_ack()->sent_info.least_unacked);
}
TEST_F(QuicConnectionTest, ResendOnNack) {
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1
SendStreamDataToPeer(1, "foos", 3, false, &last_packet); // Packet 2
SendStreamDataToPeer(1, "fooos", 7, false, &last_packet); // Packet 3
QuicConnectionVisitorInterface::AckedPackets expected_acks;
expected_acks.insert(1);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
// Client acks one but not two or three. Right now we only resend on explicit
// nack, so it should not trigger resend.
QuicAckFrame ack_one(1, 0);
ProcessAckPacket(&ack_one);
ProcessAckPacket(&ack_one);
ProcessAckPacket(&ack_one);
expected_acks.clear();
expected_acks.insert(3);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
// Client acks up to 3 with two explicitly missing. Two nacks should cause no
// change.
QuicAckFrame nack_two(3, 0);
nack_two.received_info.missing_packets.insert(2);
ProcessAckPacket(&nack_two);
ProcessAckPacket(&nack_two);
// The third nack should trigger resend.
EXPECT_CALL(*scheduler_, SentPacket(4, 37, true)).Times(1);
ProcessAckPacket(&nack_two);
}
TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
int offset = 0;
// Send packets 1 to 12
for (int i = 0; i < 12; ++i) {
SendStreamDataToPeer(1, "foo", offset, false, NULL);
offset += 3;
}
// Ack 12, nack 1-11
QuicAckFrame nack(12, 0);
for (int i = 1; i < 12; ++i) {
nack.received_info.missing_packets.insert(i);
}
QuicConnectionVisitorInterface::AckedPackets expected_acks;
expected_acks.insert(12);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
// Nack three times.
ProcessAckPacket(&nack);
ProcessAckPacket(&nack);
// The third call should trigger resending 10 packets and an updated ack.
EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(11);
ProcessAckPacket(&nack);
// The fourth call should triggre resending the 11th packet.
EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(1);
ProcessAckPacket(&nack);
}
// Test sending multiple acks from the connection to the session.
TEST_F(QuicConnectionTest, MultipleAcks) {
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1u, "foo", 0, false, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
SendStreamDataToPeer(3u, "foo", 0, false, &last_packet); // Packet 2
EXPECT_EQ(2u, last_packet);
SendAckPacketToPeer(); // Packet 3
SendStreamDataToPeer(5u, "foo", 0, false, &last_packet); // Packet 4
EXPECT_EQ(4u, last_packet);
SendStreamDataToPeer(1u, "foo", 3, false, &last_packet); // Packet 5
EXPECT_EQ(5u, last_packet);
SendStreamDataToPeer(3u, "foo", 3, false, &last_packet); // Packet 6
EXPECT_EQ(6u, last_packet);
// Client will ack packets 1, [!2], 3, 4, 5
QuicAckFrame frame1(5, 0);
frame1.received_info.missing_packets.insert(2);
// The connection should pass up acks for 1, 4, 5. 2 is not acked, and 3 was
// an ackframe so should not be passed up.
QuicConnectionVisitorInterface::AckedPackets expected_acks;
expected_acks.insert(1);
expected_acks.insert(4);
expected_acks.insert(5);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
ProcessAckPacket(&frame1);
// Now the client implicitly acks 2, and explicitly acks 6
QuicAckFrame frame2(6, 0);
expected_acks.clear();
// Both acks should be passed up.
expected_acks.insert(2);
expected_acks.insert(6);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
ProcessAckPacket(&frame2);
}
TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
SendStreamDataToPeer(1, "foo", 0, false, NULL); // Packet 1;
SendAckPacketToPeer(); // Packet 2
// This sets least unacked to 2, the ack packet.
QuicConnectionVisitorInterface::AckedPackets expected_acks;
expected_acks.insert(1);
// Client acks packet 1
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
QuicAckFrame frame(1, 0);
ProcessAckPacket(&frame);
// Verify that our internal state has least-unacked as 2.
QuicAckFrame* outgoing_ack = QuicConnectionPeer::GetOutgoingAck(&connection_);
EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked);
// When we send an ack, we make sure our least-unacked makes sense. In this
// case since we're not waiting on an ack for 2 and all packets are acked, we
// set it to 3.
SendAckPacketToPeer(); // Packet 3
EXPECT_EQ(3u, outgoing_ack->sent_info.least_unacked);
EXPECT_EQ(3u, last_ack()->sent_info.least_unacked);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
// Don't send missing packet 1.
ProcessFecPacket(2, 1, true);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
ProcessFecProtectedPacket(1, false);
// Don't send missing packet 2.
ProcessFecPacket(3, 1, true);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
ProcessFecProtectedPacket(1, false);
// Don't send missing packet 2.
ProcessFecProtectedPacket(3, false);
ProcessFecPacket(4, 1, true);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
// Don't send missing packet 1.
ProcessFecPacket(3, 1, false); // out of order
ProcessFecProtectedPacket(2, true);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
ProcessFecProtectedPacket(1, false);
// Don't send missing packet 2.
ProcessFecPacket(6, 1, false);
ProcessFecProtectedPacket(3, false);
ProcessFecProtectedPacket(4, false);
ProcessFecProtectedPacket(5, true);
}
TEST_F(QuicConnectionTest, TestResend) {
// TODO(rch): make this work
// FLAGS_fake_packet_loss_percentage = 100;
const QuicTime::Delta kDefaultResendTime =
QuicTime::Delta::FromMilliseconds(500);
QuicTime default_resend_time = clock_.Now().Add(kDefaultResendTime);
QuicAckFrame* outgoing_ack = QuicConnectionPeer::GetOutgoingAck(&connection_);
SendStreamDataToPeer(1, "foo", 0, false, NULL);
EXPECT_EQ(1u, outgoing_ack->sent_info.least_unacked);
EXPECT_EQ(1u, last_header()->packet_sequence_number);
EXPECT_EQ(1u, helper_->resend_alarms().size());
EXPECT_EQ(default_resend_time,
helper_->resend_alarms().find(1)->second);
// Simulate the resend alarm firing
clock_.AdvanceTime(kDefaultResendTime);
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
connection_.MaybeResendPacket(1);
EXPECT_EQ(2u, last_header()->packet_sequence_number);
EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked);
}
// TODO(rch): Enable after we get non-blocking sockets.
TEST_F(QuicConnectionTest, DISABLED_TestQueued) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
helper_->set_blocked(true);
SendStreamDataToPeer(1, "foo", 0, false, NULL);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Attempt to send all packets, but since we're actually still
// blocked, they should all remain queued.
EXPECT_FALSE(connection_.OnCanWrite());
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Unblock the writes and actually send.
helper_->set_blocked(false);
EXPECT_CALL(visitor_, OnCanWrite());
EXPECT_TRUE(connection_.OnCanWrite());
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, CloseFecGroup) {
// Don't send missing packet 1
// Don't send missing packet 2
ProcessFecProtectedPacket(3, false);
// Don't send missing FEC packet 3
ASSERT_EQ(1u, connection_.NumFecGroups());
// Now send non-fec protected ack packet and close the group
QuicAckFrame frame(0, 5);
creator_.set_sequence_number(4);
ProcessAckPacket(&frame);
ASSERT_EQ(0u, connection_.NumFecGroups());
}
TEST_F(QuicConnectionTest, NoQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
EXPECT_TRUE(last_feedback() == NULL);
}
TEST_F(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
QuicCongestionFeedbackFrame info;
info.type = kFixRate;
info.fix_rate.bitrate_in_bytes_per_second = 123;
SetFeedback(&info);
SendAckPacketToPeer();
EXPECT_EQ(kFixRate, last_feedback()->type);
EXPECT_EQ(info.fix_rate.bitrate_in_bytes_per_second,
last_feedback()->fix_rate.bitrate_in_bytes_per_second);
}
TEST_F(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
EXPECT_CALL(*collector_, RecordIncomingPacket(_, _, _, _));
ProcessPacket(1);
}
TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
SendAckPacketToPeer();
// Process an FEC packet, and revive the missing data packet
// but only contact the collector once.
EXPECT_CALL(*collector_, RecordIncomingPacket(_, _, _, _));
ProcessFecPacket(2, 1, true);
}
TEST_F(QuicConnectionTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
QuicTime default_timeout = clock_.Now().Add(
QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
EXPECT_EQ(default_timeout, helper_->timeout_alarm());
// Simulate the timeout alarm firing
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
EXPECT_TRUE(connection_.CheckForTimeout());
EXPECT_FALSE(connection_.connected());
}
TEST_F(QuicConnectionTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_.connected());
QuicTime default_timeout = clock_.Now().Add(
QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
// When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
// Send an ack so we don't set the resend alarm.
SendAckPacketToPeer();
EXPECT_EQ(default_timeout, helper_->timeout_alarm());
// The original alarm will fire. We should not time out because we had a
// network event at t=5000. The alarm will reregister.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
kDefaultTimeoutUs - 5000));
EXPECT_EQ(default_timeout, clock_.Now());
EXPECT_FALSE(connection_.CheckForTimeout());
EXPECT_TRUE(connection_.connected());
EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
helper_->timeout_alarm());
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
clock_.Now());
EXPECT_TRUE(connection_.CheckForTimeout());
EXPECT_FALSE(connection_.connected());
}
// TODO(ianswett): Add scheduler tests when resend is false.
TEST_F(QuicConnectionTest, SendScheduler) {
// Test that if we send a packet without delay, it is not queued.
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta()));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelay) {
// Test that if we send a packet with a delay, it ends up queued.
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerForce) {
// Test that if we force send a packet, it is not queued.
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).Times(0);
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
connection_.SendPacket(1, packet.get(), true, true, false);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
// TODO(rch): Enable after we get non-blocking sockets.
TEST_F(QuicConnectionTest, DISABLED_SendSchedulerEAGAIN) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
helper_->set_blocked(true);
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta()));
EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Test that if we send a packet with a delay, it ends up queued.
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
// Test that if we send a retransmit with a delay, it ends up queued.
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
connection_.SendPacket(1, packet.get(), true, false, true);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta()));
// Ensure the scheduler is notified this is a retransmit.
EXPECT_CALL(*scheduler_, SentPacket(1, _, true));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Attempt to send another packet and make sure that it gets queued.
connection_.SendPacket(2, packet.get(), true, false, false);
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to resend 3.
// The far end should stop waiting for it.
QuicAckFrame frame(0, 1);
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillRepeatedly(testing::Return(
QuicTime::Delta()));
EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
ProcessAckPacket(&frame);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
// Ensure alarm is not set
EXPECT_FALSE(helper_->IsSendAlarmSet());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-resending information, that we're not going to resend 3.
// The far end should stop waiting for it.
QuicAckFrame frame(0, 1);
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
EXPECT_CALL(visitor_, OnCanWrite());
ProcessAckPacket(&frame);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(1, 0));
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(1, packet.get(), true, false, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// OnCanWrite should not send the packet (because of the delay)
// but should still return true.
EXPECT_CALL(visitor_, OnCanWrite());
EXPECT_TRUE(connection_.OnCanWrite());
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// Limit to one byte per packet.
size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
connection_.options()->max_packet_length =
ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
// Queue the first packet.
EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
EXPECT_EQ(6u,
connection_.SendStreamData(1, "EnoughDataToQueue", 0, false, NULL));
EXPECT_EQ(6u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
// Limit to one byte per packet.
size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
connection_.options()->max_packet_length =
ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
// Queue the first packet.
EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(17);
EXPECT_EQ(17u,
connection_.SendStreamData(1, "EnoughDataToQueue", 0, false, NULL));
}
} // namespace
} // namespace test
} // namespace net