|  | // Copyright (c) 2019 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/quartc/test/quartc_peer.h" | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_constants.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_time.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" | 
|  | #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | class QuartcPeerTest : public QuicTest { | 
|  | protected: | 
|  | QuartcPeerTest() | 
|  | : client_transport_(&simulator_, | 
|  | "client_transport", | 
|  | "server_transport", | 
|  | 10 * kDefaultMaxPacketSize), | 
|  | server_transport_(&simulator_, | 
|  | "server_transport", | 
|  | "client_transport", | 
|  | 10 * kDefaultMaxPacketSize), | 
|  | client_server_link_(&client_transport_, | 
|  | &server_transport_, | 
|  | QuicBandwidth::FromKBitsPerSecond(512), | 
|  | QuicTime::Delta::FromMilliseconds(100)) { | 
|  | SetQuicReloadableFlag(quic_default_to_bbr, true); | 
|  | simulator_.set_random_generator(&rng_); | 
|  | } | 
|  |  | 
|  | void CreatePeers(const std::vector<QuartcDataSource::Config>& configs) { | 
|  | client_peer_ = QuicMakeUnique<QuartcPeer>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), | 
|  | simulator_.GetStreamSendBufferAllocator(), configs); | 
|  | server_peer_ = QuicMakeUnique<QuartcPeer>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), | 
|  | simulator_.GetStreamSendBufferAllocator(), configs); | 
|  | } | 
|  |  | 
|  | void Connect() { | 
|  | DCHECK(client_peer_); | 
|  | DCHECK(server_peer_); | 
|  |  | 
|  | server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( | 
|  | simulator_.GetAlarmFactory(), simulator_.GetClock(), | 
|  | simulator_.GetRandomGenerator(), server_peer_.get(), | 
|  | QuartcSessionConfig()); | 
|  | client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( | 
|  | simulator_.GetAlarmFactory(), simulator_.GetClock(), | 
|  | simulator_.GetRandomGenerator(), client_peer_.get(), | 
|  | QuartcSessionConfig(), server_endpoint_->server_crypto_config()); | 
|  |  | 
|  | server_endpoint_->Connect(&server_transport_); | 
|  | client_endpoint_->Connect(&client_transport_); | 
|  | } | 
|  |  | 
|  | SimpleRandom rng_; | 
|  | simulator::Simulator simulator_; | 
|  | simulator::SimulatedQuartcPacketTransport client_transport_; | 
|  | simulator::SimulatedQuartcPacketTransport server_transport_; | 
|  | simulator::SymmetricLink client_server_link_; | 
|  |  | 
|  | std::unique_ptr<QuartcClientEndpoint> client_endpoint_; | 
|  | std::unique_ptr<QuartcPeer> client_peer_; | 
|  |  | 
|  | std::unique_ptr<QuartcServerEndpoint> server_endpoint_; | 
|  | std::unique_ptr<QuartcPeer> server_peer_; | 
|  | }; | 
|  |  | 
|  | const ReceivedMessage& FindLastMessageFromSource( | 
|  | const std::vector<ReceivedMessage>& messages, | 
|  | int32_t source_id) { | 
|  | const auto& it = std::find_if(messages.rbegin(), messages.rend(), | 
|  | [source_id](const ReceivedMessage& r) { | 
|  | return r.frame.source_id == source_id; | 
|  | }); | 
|  | return *it; | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, SendReceiveMessages) { | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  |  | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | ASSERT_TRUE(simulator_.RunUntil([this] { | 
|  | return !client_peer_->received_messages().empty() && | 
|  | !server_peer_->received_messages().empty(); | 
|  | })); | 
|  |  | 
|  | QuicTime end_time = simulator_.GetClock()->Now(); | 
|  |  | 
|  | // Sanity checks on messages. | 
|  | const ReceivedMessage& client_message = client_peer_->received_messages()[0]; | 
|  | EXPECT_EQ(client_message.frame.source_id, 1); | 
|  | EXPECT_EQ(client_message.frame.sequence_number, 0); | 
|  | EXPECT_GE(client_message.frame.send_time, start_time); | 
|  | EXPECT_LE(client_message.receive_time, end_time); | 
|  |  | 
|  | const ReceivedMessage& server_message = server_peer_->received_messages()[0]; | 
|  | EXPECT_EQ(server_message.frame.source_id, 1); | 
|  | EXPECT_EQ(server_message.frame.sequence_number, 0); | 
|  | EXPECT_GE(server_message.frame.send_time, start_time); | 
|  | EXPECT_LE(server_message.receive_time, end_time); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, MaxFrameSizeUnset) { | 
|  | // Configure the source with no max frame size, and a framerate and max | 
|  | // bandwidth that allows very large frames (larger than will fit in a packet). | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(20); | 
|  | config.max_bandwidth = QuicBandwidth::FromBytesAndTimeDelta( | 
|  | 2 * kDefaultMaxPacketSize, config.frame_interval); | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | // Run long enough for the bandwidth estimate to ramp up. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | // The peers generate frames that fit in one packet. | 
|  | EXPECT_LT(client_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | EXPECT_LT(server_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, MaxFrameSizeLargerThanPacketSize) { | 
|  | // Configure the source with a max frame size larger than the packet size. | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  | config.max_frame_size = 2 * kDefaultMaxPacketSize; | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | // Run long enough for the bandwidth estimate to ramp up. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | // The peers generate frames that fit in one packet. | 
|  | EXPECT_LT(client_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | EXPECT_LT(server_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, MaxFrameSizeSmallerThanPacketSize) { | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  | config.max_frame_size = 100; | 
|  | // Note that a long frame interval helps to ensure that the test produces | 
|  | // enough bytes per frame to reach max_frame_size. | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(100); | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | // Run long enough for the bandwidth estimate to ramp up. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | EXPECT_EQ(client_peer_->received_messages().back().frame.size, 100u); | 
|  | EXPECT_EQ(server_peer_->received_messages().back().frame.size, 100u); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, MaxFrameSizeSmallerThanFrameHeader) { | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  | config.max_frame_size = kDataFrameHeaderSize - 1; | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | // Run long enough for the bandwidth estimate to ramp up. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | // Max frame sizes smaller than the header are ignored, and the frame size is | 
|  | // limited by packet size. | 
|  | EXPECT_LT(client_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | EXPECT_LT(server_peer_->received_messages().back().frame.size, | 
|  | kDefaultMaxPacketSize); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, SendReceiveMultipleSources) { | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  |  | 
|  | // Note: use of really long frame intervals means that each source should send | 
|  | // one frame during this test.  This simplifies expectations for received | 
|  | // data. | 
|  | QuartcDataSource::Config config_1; | 
|  | config_1.id = 1; | 
|  | config_1.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(32); | 
|  | config_1.frame_interval = QuicTime::Delta::FromSeconds(10); | 
|  |  | 
|  | QuartcDataSource::Config config_2; | 
|  | config_2.id = 2; | 
|  | config_2.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(64); | 
|  | config_2.frame_interval = QuicTime::Delta::FromSeconds(10); | 
|  |  | 
|  | QuartcDataSource::Config config_3; | 
|  | config_3.id = 3; | 
|  | config_3.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(128); | 
|  | config_3.frame_interval = QuicTime::Delta::FromSeconds(10); | 
|  |  | 
|  | CreatePeers({config_1, config_2, config_3}); | 
|  | Connect(); | 
|  |  | 
|  | ASSERT_TRUE(simulator_.RunUntil([this] { | 
|  | return client_peer_->received_messages().size() == 3 && | 
|  | server_peer_->received_messages().size() == 3; | 
|  | })); | 
|  |  | 
|  | QuicTime end_time = simulator_.GetClock()->Now(); | 
|  |  | 
|  | // Sanity checks on messages. | 
|  | const auto& order = [](const ReceivedMessage& lhs, | 
|  | const ReceivedMessage& rhs) { | 
|  | return lhs.frame.source_id < rhs.frame.source_id; | 
|  | }; | 
|  |  | 
|  | std::vector<ReceivedMessage> client_messages = | 
|  | client_peer_->received_messages(); | 
|  | std::sort(client_messages.begin(), client_messages.end(), order); | 
|  | for (size_t i = 0; i < client_messages.size(); ++i) { | 
|  | EXPECT_EQ(client_messages[i].frame.source_id, static_cast<int32_t>(i + 1)); | 
|  | EXPECT_EQ(client_messages[i].frame.sequence_number, 0); | 
|  | EXPECT_GE(client_messages[i].frame.send_time, start_time); | 
|  | EXPECT_LE(client_messages[i].receive_time, end_time); | 
|  | } | 
|  |  | 
|  | std::vector<ReceivedMessage> server_messages = | 
|  | server_peer_->received_messages(); | 
|  | std::sort(server_messages.begin(), server_messages.end(), order); | 
|  | for (size_t i = 0; i < server_messages.size(); ++i) { | 
|  | EXPECT_EQ(server_messages[i].frame.source_id, static_cast<int32_t>(i + 1u)); | 
|  | EXPECT_EQ(server_messages[i].frame.sequence_number, 0); | 
|  | EXPECT_GE(server_messages[i].frame.send_time, start_time); | 
|  | EXPECT_LE(server_messages[i].receive_time, end_time); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, BandwidthAllocationWithEnoughAvailable) { | 
|  | QuartcDataSource::Config config_1; | 
|  | config_1.id = 1; | 
|  | config_1.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(32); | 
|  | config_1.frame_interval = QuicTime::Delta::FromMilliseconds(100); | 
|  |  | 
|  | QuartcDataSource::Config config_2; | 
|  | config_2.id = 2; | 
|  | config_2.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(64); | 
|  | config_2.frame_interval = QuicTime::Delta::FromMilliseconds(25); | 
|  |  | 
|  | QuartcDataSource::Config config_3; | 
|  | config_3.id = 3; | 
|  | config_3.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(128); | 
|  | config_3.frame_interval = QuicTime::Delta::FromMilliseconds(10); | 
|  |  | 
|  | CreatePeers({config_1, config_2, config_3}); | 
|  | Connect(); | 
|  |  | 
|  | // Run for long enough that bandwidth ramps up and meets the requirements of | 
|  | // all three sources. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | // The last message from each source should be the size allowed by that | 
|  | // source's maximum bandwidth and frame interval. | 
|  | QuicByteCount source_1_size = | 
|  | config_1.max_bandwidth.ToBytesPerPeriod(config_1.frame_interval); | 
|  | QuicByteCount source_2_size = | 
|  | config_2.max_bandwidth.ToBytesPerPeriod(config_2.frame_interval); | 
|  | QuicByteCount source_3_size = | 
|  | config_3.max_bandwidth.ToBytesPerPeriod(config_3.frame_interval); | 
|  |  | 
|  | const std::vector<ReceivedMessage>& client_messages = | 
|  | client_peer_->received_messages(); | 
|  | EXPECT_EQ(FindLastMessageFromSource(client_messages, 1).frame.size, | 
|  | source_1_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(client_messages, 2).frame.size, | 
|  | source_2_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(client_messages, 3).frame.size, | 
|  | source_3_size); | 
|  |  | 
|  | const std::vector<ReceivedMessage>& server_messages = | 
|  | server_peer_->received_messages(); | 
|  | EXPECT_EQ(FindLastMessageFromSource(server_messages, 1).frame.size, | 
|  | source_1_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(server_messages, 2).frame.size, | 
|  | source_2_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(server_messages, 3).frame.size, | 
|  | source_3_size); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, BandwidthAllocationWithoutEnoughAvailable) { | 
|  | QuartcDataSource::Config config_1; | 
|  | config_1.id = 1; | 
|  | config_1.max_bandwidth = client_server_link_.bandwidth() * 0.5; | 
|  | config_1.frame_interval = QuicTime::Delta::FromMilliseconds(10); | 
|  |  | 
|  | QuartcDataSource::Config config_2; | 
|  | config_2.id = 2; | 
|  | config_2.min_bandwidth = QuicBandwidth::FromKBitsPerSecond(32); | 
|  | config_2.max_bandwidth = client_server_link_.bandwidth(); | 
|  | config_2.frame_interval = QuicTime::Delta::FromMilliseconds(5); | 
|  |  | 
|  | QuartcDataSource::Config config_3; | 
|  | config_3.id = 3; | 
|  | config_3.min_bandwidth = QuicBandwidth::FromKBitsPerSecond(32); | 
|  | config_3.max_bandwidth = client_server_link_.bandwidth() * 2; | 
|  | config_3.frame_interval = QuicTime::Delta::FromMilliseconds(20); | 
|  |  | 
|  | CreatePeers({config_1, config_2, config_3}); | 
|  | Connect(); | 
|  |  | 
|  | // Run for long enough that bandwidth ramps up to link capacity. | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | const std::vector<ReceivedMessage>& client_messages = | 
|  | client_peer_->received_messages(); | 
|  | const std::vector<ReceivedMessage>& server_messages = | 
|  | server_peer_->received_messages(); | 
|  |  | 
|  | // Source 1 eventually ramps up to full bandwidth. | 
|  | const QuicByteCount source_1_size = | 
|  | config_1.max_bandwidth.ToBytesPerPeriod(config_1.frame_interval); | 
|  | EXPECT_EQ(FindLastMessageFromSource(client_messages, 1).frame.size, | 
|  | source_1_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(server_messages, 1).frame.size, | 
|  | source_1_size); | 
|  |  | 
|  | // Source 2 takes the remainder of available bandwidth.  However, the exact | 
|  | // value depends on the bandwidth estimate. | 
|  | const QuicByteCount source_2_min = | 
|  | config_2.min_bandwidth.ToBytesPerPeriod(config_2.frame_interval); | 
|  | const QuicByteCount source_2_max = | 
|  | config_2.max_bandwidth.ToBytesPerPeriod(config_2.frame_interval); | 
|  | EXPECT_GT(FindLastMessageFromSource(client_messages, 2).frame.size, | 
|  | source_2_min); | 
|  | EXPECT_LT(FindLastMessageFromSource(client_messages, 2).frame.size, | 
|  | source_2_max); | 
|  | EXPECT_GT(FindLastMessageFromSource(server_messages, 2).frame.size, | 
|  | source_2_min); | 
|  | EXPECT_LT(FindLastMessageFromSource(server_messages, 2).frame.size, | 
|  | source_2_max); | 
|  |  | 
|  | // Source 3 gets only its minimum bandwidth. | 
|  | const QuicByteCount source_3_size = | 
|  | config_3.min_bandwidth.ToBytesPerPeriod(config_3.frame_interval); | 
|  | EXPECT_EQ(FindLastMessageFromSource(client_messages, 3).frame.size, | 
|  | source_3_size); | 
|  | EXPECT_EQ(FindLastMessageFromSource(server_messages, 3).frame.size, | 
|  | source_3_size); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcPeerTest, DisableAndDrainMessages) { | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 1; | 
|  | config.max_bandwidth = client_server_link_.bandwidth() * 0.5; | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(10); | 
|  |  | 
|  | CreatePeers({config}); | 
|  | Connect(); | 
|  |  | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | // After these calls, we should observe no new messages. | 
|  | server_peer_->SetEnabled(false); | 
|  | client_peer_->SetEnabled(false); | 
|  |  | 
|  | std::map<int32_t, int64_t> last_sent_by_client = | 
|  | client_peer_->GetLastSequenceNumbers(); | 
|  | std::map<int32_t, int64_t> last_sent_by_server = | 
|  | server_peer_->GetLastSequenceNumbers(); | 
|  |  | 
|  | simulator_.RunFor(QuicTime::Delta::FromSeconds(10)); | 
|  |  | 
|  | ASSERT_FALSE(client_peer_->received_messages().empty()); | 
|  | EXPECT_EQ(client_peer_->received_messages().back().frame.sequence_number, | 
|  | last_sent_by_server[1]); | 
|  |  | 
|  | ASSERT_FALSE(server_peer_->received_messages().empty()); | 
|  | EXPECT_EQ(server_peer_->received_messages().back().frame.sequence_number, | 
|  | last_sent_by_client[1]); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace quic |