| Index: net/quic/core/quic_buffered_packet_store_test.cc
|
| diff --git a/net/quic/core/quic_buffered_packet_store_test.cc b/net/quic/core/quic_buffered_packet_store_test.cc
|
| index 53cbe0c132d78e9209c05c784ed7510129303f4d..b039e48ad443a0851869f84bf32d0bb2e9de30da 100644
|
| --- a/net/quic/core/quic_buffered_packet_store_test.cc
|
| +++ b/net/quic/core/quic_buffered_packet_store_test.cc
|
| @@ -23,6 +23,8 @@ typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
|
| typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
|
|
|
| static const size_t kDefaultMaxConnectionsInStore = 100;
|
| +static const size_t kMaxConnectionsWithoutCHLO =
|
| + kDefaultMaxConnectionsInStore / 2;
|
|
|
| namespace test {
|
| namespace {
|
| @@ -57,6 +59,7 @@ class QuicBufferedPacketStoreTest : public ::testing::Test {
|
| packet_(packet_content_.data(), packet_content_.size(), packet_time_) {}
|
|
|
| protected:
|
| + QuicFlagSaver flags_; // Save/restore all QUIC flag values.
|
| QuicBufferedPacketStoreVisitor visitor_;
|
| MockClock clock_;
|
| MockAlarmFactory alarm_factory_;
|
| @@ -70,8 +73,8 @@ class QuicBufferedPacketStoreTest : public ::testing::Test {
|
|
|
| TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
|
| QuicConnectionId connection_id = 1;
|
| - store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - client_address_);
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
|
| + false);
|
| EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
|
| list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
|
| ASSERT_EQ(1u, queue.size());
|
| @@ -88,10 +91,10 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
|
| TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) {
|
| IPEndPoint addr_with_new_port(Loopback4(), 256);
|
| QuicConnectionId connection_id = 1;
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
|
| + false);
|
| store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - client_address_);
|
| - store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - addr_with_new_port);
|
| + addr_with_new_port, false);
|
| list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
|
| ASSERT_EQ(2u, queue.size());
|
| // The address migration path should be preserved.
|
| @@ -105,9 +108,9 @@ TEST_F(QuicBufferedPacketStoreTest,
|
| for (QuicConnectionId connection_id = 1; connection_id <= num_connections;
|
| ++connection_id) {
|
| store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - client_address_);
|
| + client_address_, false);
|
| store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - client_address_);
|
| + client_address_, false);
|
| }
|
|
|
| // Deliver packets in reversed order.
|
| @@ -124,10 +127,17 @@ TEST_F(QuicBufferedPacketStoreTest,
|
| // buffered.
|
| size_t num_packets = kDefaultMaxUndecryptablePackets + 1;
|
| QuicConnectionId connection_id = 1;
|
| + if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) {
|
| + // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can
|
| + // keep.
|
| + EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| + client_address_, true));
|
| + }
|
| for (size_t i = 1; i <= num_packets; ++i) {
|
| // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
|
| EnqueuePacketResult result = store_.EnqueuePacket(
|
| - connection_id, packet_, server_address_, client_address_);
|
| + connection_id, packet_, server_address_, client_address_, false);
|
| if (i <= kDefaultMaxUndecryptablePackets) {
|
| EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
|
| } else {
|
| @@ -135,32 +145,40 @@ TEST_F(QuicBufferedPacketStoreTest,
|
| }
|
| }
|
|
|
| - // Only first |kDefaultMaxUndecryptablePackets| packets are kept in the store
|
| - // and can be delivered.
|
| - EXPECT_EQ(kDefaultMaxUndecryptablePackets,
|
| + // Only first |kDefaultMaxUndecryptablePackets| non-CHLO packets and CHLO are
|
| + // buffered.
|
| + EXPECT_EQ(kDefaultMaxUndecryptablePackets +
|
| + (FLAGS_quic_limit_num_new_sessions_per_epoll_loop ? 1 : 0),
|
| store_.DeliverPackets(connection_id).size());
|
| }
|
|
|
| -TEST_F(QuicBufferedPacketStoreTest, FailToBufferPacketsForTooManyConnections) {
|
| +TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
|
| // Tests that store can only keep early arrived packets for limited number of
|
| // connections.
|
| - size_t num_connections = kDefaultMaxConnectionsInStore + 1;
|
| - for (size_t connection_id = 1; connection_id <= num_connections;
|
| + const size_t kNumConnections =
|
| + (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
|
| + ? kMaxConnectionsWithoutCHLO
|
| + : kDefaultMaxConnectionsInStore) +
|
| + 1;
|
| + for (size_t connection_id = 1; connection_id <= kNumConnections;
|
| ++connection_id) {
|
| EnqueuePacketResult result = store_.EnqueuePacket(
|
| - connection_id, packet_, server_address_, client_address_);
|
| - if (connection_id <= kDefaultMaxConnectionsInStore) {
|
| + connection_id, packet_, server_address_, client_address_, false);
|
| + if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
|
| + ? kMaxConnectionsWithoutCHLO
|
| + : kDefaultMaxConnectionsInStore)) {
|
| EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
|
| } else {
|
| EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
|
| }
|
| }
|
| - // Store only keeps early arrived packets upto |kDefaultMaxConnectionsInStore|
|
| - // connections.
|
| - for (size_t connection_id = 1; connection_id <= num_connections;
|
| + // Store only keeps early arrived packets upto |kNumConnections| connections.
|
| + for (size_t connection_id = 1; connection_id <= kNumConnections;
|
| ++connection_id) {
|
| list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
|
| - if (connection_id <= kDefaultMaxConnectionsInStore) {
|
| + if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
|
| + ? kMaxConnectionsWithoutCHLO
|
| + : kDefaultMaxConnectionsInStore)) {
|
| EXPECT_EQ(1u, queue.size());
|
| } else {
|
| EXPECT_EQ(0u, queue.size());
|
| @@ -168,10 +186,91 @@ TEST_F(QuicBufferedPacketStoreTest, FailToBufferPacketsForTooManyConnections) {
|
| }
|
| }
|
|
|
| -TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
|
| +TEST_F(QuicBufferedPacketStoreTest,
|
| + FullStoreFailToBufferDataPacketOnNewConnection) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + // Send enough CHLOs so that store gets full before number of connections
|
| + // without CHLO reaches its upper limit.
|
| + size_t num_chlos =
|
| + kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1;
|
| + for (size_t connection_id = 1; connection_id <= num_chlos; ++connection_id) {
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS,
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| + client_address_, true));
|
| + }
|
| +
|
| + // Send data packets on another |kMaxConnectionsWithoutCHLO| connections.
|
| + // Store should only be able to buffer till it's full.
|
| + for (size_t conn_id = num_chlos + 1;
|
| + conn_id <= (kDefaultMaxConnectionsInStore + 1); ++conn_id) {
|
| + EnqueuePacketResult result = store_.EnqueuePacket(
|
| + conn_id, packet_, server_address_, client_address_, true);
|
| + if (conn_id <= kDefaultMaxConnectionsInStore) {
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
|
| + } else {
|
| + EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + // Buffer data packets on different connections upto limit.
|
| + for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO;
|
| + ++conn_id) {
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS,
|
| + store_.EnqueuePacket(conn_id, packet_, server_address_,
|
| + client_address_, false));
|
| + }
|
| +
|
| + // Buffer CHLOs on other connections till store is full.
|
| + for (size_t i = kMaxConnectionsWithoutCHLO + 1;
|
| + i <= kDefaultMaxConnectionsInStore + 1; ++i) {
|
| + EnqueuePacketResult rs = store_.EnqueuePacket(
|
| + /*connection_id=*/i, packet_, server_address_, client_address_, true);
|
| + if (i <= kDefaultMaxConnectionsInStore) {
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs);
|
| + EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/i));
|
| + } else {
|
| + // Last CHLO can't be buffered because store is full.
|
| + EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, rs);
|
| + EXPECT_FALSE(store_.HasChloForConnection(/*connection_id=*/i));
|
| + }
|
| + }
|
| +
|
| + // But buffering a CHLO belonging to a connection already has data packet
|
| + // buffered in the store should success. This is the connection should be
|
| + // delivered at last.
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS,
|
| + store_.EnqueuePacket(/*connection_id=*/1, packet_, server_address_,
|
| + client_address_, true));
|
| + EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/1));
|
| +
|
| + QuicConnectionId delivered_conn_id;
|
| + for (size_t i = 0;
|
| + i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1;
|
| + ++i) {
|
| + if (i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO) {
|
| + // Only CHLO is buffered.
|
| + EXPECT_EQ(
|
| + 1u,
|
| + store_.DeliverPacketsForNextConnection(&delivered_conn_id).size());
|
| + EXPECT_EQ(i + kMaxConnectionsWithoutCHLO + 1, delivered_conn_id);
|
| + } else {
|
| + EXPECT_EQ(
|
| + 2u,
|
| + store_.DeliverPacketsForNextConnection(&delivered_conn_id).size());
|
| + EXPECT_EQ(1u, delivered_conn_id);
|
| + }
|
| + }
|
| + EXPECT_FALSE(store_.HasChlosBuffered());
|
| +}
|
| +
|
| +TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery1) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = false;
|
| QuicConnectionId connection_id = 1;
|
| - store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| - client_address_);
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
|
| + false);
|
| // Packet for another connection arrive 1ms later.
|
| clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
|
| QuicConnectionId connection_id2 = 2;
|
| @@ -179,7 +278,7 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
|
| // connections.
|
| IPEndPoint another_client_address(Loopback4(), 255);
|
| store_.EnqueuePacket(connection_id2, packet_, server_address_,
|
| - another_client_address);
|
| + another_client_address, false);
|
| // Advance clock to the time when connection 1 expires.
|
| clock_.AdvanceTime(
|
| QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
|
| @@ -205,9 +304,76 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
|
| // for them to expire.
|
| QuicConnectionId connection_id3 = 3;
|
| store_.EnqueuePacket(connection_id3, packet_, server_address_,
|
| - client_address_);
|
| + client_address_, false);
|
| store_.EnqueuePacket(connection_id3, packet_, server_address_,
|
| - client_address_);
|
| + client_address_, false);
|
| + clock_.AdvanceTime(
|
| + QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
|
| + clock_.ApproximateNow());
|
| + alarm_factory_.FireAlarm(
|
| + QuicBufferedPacketStorePeer::expiration_alarm(&store_));
|
| + // |last_expired_packet_queue_| should be updated.
|
| + EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size());
|
| +}
|
| +
|
| +// Tests that store expires long-staying connections appropriately for
|
| +// connections both with and without CHLOs.
|
| +TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery2) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + QuicConnectionId connection_id = 1;
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
|
| + false);
|
| + if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) {
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS,
|
| + store_.EnqueuePacket(connection_id, packet_, server_address_,
|
| + client_address_, true));
|
| + }
|
| + QuicConnectionId connection_id2 = 2;
|
| + EXPECT_EQ(EnqueuePacketResult::SUCCESS,
|
| + store_.EnqueuePacket(connection_id2, packet_, server_address_,
|
| + client_address_, false));
|
| +
|
| + // CHLO on connection 3 arrives 1ms later.
|
| + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
|
| + QuicConnectionId connection_id3 = 3;
|
| + // Use different client address to differetiate packets from different
|
| + // connections.
|
| + IPEndPoint another_client_address(Any4(), 255);
|
| + store_.EnqueuePacket(connection_id3, packet_, server_address_,
|
| + another_client_address, true);
|
| +
|
| + // Advance clock to the time when connection 1 and 2 expires.
|
| + clock_.AdvanceTime(
|
| + QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
|
| + clock_.ApproximateNow());
|
| + ASSERT_GE(clock_.ApproximateNow(),
|
| + QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
|
| + // Fire alarm to remove long-staying connection 1 and 2 packets.
|
| + alarm_factory_.FireAlarm(
|
| + QuicBufferedPacketStorePeer::expiration_alarm(&store_));
|
| + EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size());
|
| + EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
|
| + EXPECT_FALSE(store_.HasBufferedPackets(connection_id2));
|
| +
|
| + // Try to deliver packets, but packet queue has been removed so no
|
| + // packets can be returned.
|
| + ASSERT_EQ(0u, store_.DeliverPackets(connection_id).size());
|
| + ASSERT_EQ(0u, store_.DeliverPackets(connection_id2).size());
|
| + QuicConnectionId delivered_conn_id;
|
| + auto queue = store_.DeliverPacketsForNextConnection(&delivered_conn_id);
|
| + // Connection 3 is the next to be delivered as connection 1 already expired.
|
| + EXPECT_EQ(connection_id3, delivered_conn_id);
|
| + ASSERT_EQ(1u, queue.size());
|
| + // Packets in connection 3 should use another client address.
|
| + EXPECT_EQ(another_client_address, queue.front().client_address);
|
| +
|
| + // Test the alarm is reset by enqueueing 2 packets for 4th connection and wait
|
| + // for them to expire.
|
| + QuicConnectionId connection_id4 = 4;
|
| + store_.EnqueuePacket(connection_id4, packet_, server_address_,
|
| + client_address_, false);
|
| + store_.EnqueuePacket(connection_id4, packet_, server_address_,
|
| + client_address_, false);
|
| clock_.AdvanceTime(
|
| QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
|
| clock_.ApproximateNow());
|
|
|