diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc')
-rw-r--r-- | chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc b/chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc new file mode 100644 index 00000000000..823c190fe34 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc @@ -0,0 +1,207 @@ +// 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 "quiche/quic/test_tools/simulator/quic_endpoint.h" + +#include <utility> + +#include "quiche/quic/platform/api/quic_flags.h" +#include "quiche/quic/platform/api/quic_test.h" +#include "quiche/quic/test_tools/quic_connection_peer.h" +#include "quiche/quic/test_tools/quic_test_utils.h" +#include "quiche/quic/test_tools/simulator/simulator.h" +#include "quiche/quic/test_tools/simulator/switch.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; + +namespace quic { +namespace simulator { + +const QuicBandwidth kDefaultBandwidth = + QuicBandwidth::FromKBitsPerSecond(10 * 1000); +const QuicTime::Delta kDefaultPropagationDelay = + QuicTime::Delta::FromMilliseconds(20); +const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay; + +// A simple test harness where all hosts are connected to a switch with +// identical links. +class QuicEndpointTest : public QuicTest { + public: + QuicEndpointTest() + : simulator_(), switch_(&simulator_, "Switch", 8, kDefaultBdp * 2) {} + + protected: + Simulator simulator_; + Switch switch_; + + std::unique_ptr<SymmetricLink> Link(Endpoint* a, Endpoint* b) { + return std::make_unique<SymmetricLink>(a, b, kDefaultBandwidth, + kDefaultPropagationDelay); + } + + std::unique_ptr<SymmetricLink> CustomLink(Endpoint* a, Endpoint* b, + uint64_t extra_rtt_ms) { + return std::make_unique<SymmetricLink>( + a, b, kDefaultBandwidth, + kDefaultPropagationDelay + + QuicTime::Delta::FromMilliseconds(extra_rtt_ms)); + } +}; + +// Test transmission from one host to another. +TEST_F(QuicEndpointTest, OneWayTransmission) { + QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B", + Perspective::IS_CLIENT, test::TestConnectionId(42)); + QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A", + Perspective::IS_SERVER, test::TestConnectionId(42)); + auto link_a = Link(&endpoint_a, switch_.port(1)); + auto link_b = Link(&endpoint_b, switch_.port(2)); + + // First transmit a small, packet-size chunk of data. + endpoint_a.AddBytesToTransfer(600); + QuicTime end_time = + simulator_.GetClock()->Now() + QuicTime::Delta::FromMilliseconds(1000); + simulator_.RunUntil( + [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; }); + + EXPECT_EQ(600u, endpoint_a.bytes_transferred()); + ASSERT_EQ(600u, endpoint_b.bytes_received()); + EXPECT_FALSE(endpoint_a.wrong_data_received()); + EXPECT_FALSE(endpoint_b.wrong_data_received()); + + // After a small chunk succeeds, try to transfer 2 MiB. + endpoint_a.AddBytesToTransfer(2 * 1024 * 1024); + end_time = simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5); + simulator_.RunUntil( + [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; }); + + const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024; + EXPECT_EQ(total_bytes_transferred, endpoint_a.bytes_transferred()); + EXPECT_EQ(total_bytes_transferred, endpoint_b.bytes_received()); + EXPECT_EQ(0u, endpoint_a.write_blocked_count()); + EXPECT_FALSE(endpoint_a.wrong_data_received()); + EXPECT_FALSE(endpoint_b.wrong_data_received()); +} + +// Test the situation in which the writer becomes write-blocked. +TEST_F(QuicEndpointTest, WriteBlocked) { + QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B", + Perspective::IS_CLIENT, test::TestConnectionId(42)); + QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A", + Perspective::IS_SERVER, test::TestConnectionId(42)); + auto link_a = Link(&endpoint_a, switch_.port(1)); + auto link_b = Link(&endpoint_b, switch_.port(2)); + + // Will be owned by the sent packet manager. + auto* sender = new NiceMock<test::MockSendAlgorithm>(); + EXPECT_CALL(*sender, CanSend(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(*sender, PacingRate(_)) + .WillRepeatedly(Return(10 * kDefaultBandwidth)); + EXPECT_CALL(*sender, BandwidthEstimate()) + .WillRepeatedly(Return(10 * kDefaultBandwidth)); + EXPECT_CALL(*sender, GetCongestionWindow()) + .WillRepeatedly(Return(kMaxOutgoingPacketSize * + GetQuicFlag(FLAGS_quic_max_congestion_window))); + test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(), sender); + + // First transmit a small, packet-size chunk of data. + QuicByteCount bytes_to_transfer = 3 * 1024 * 1024; + endpoint_a.AddBytesToTransfer(bytes_to_transfer); + QuicTime end_time = + simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30); + simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() { + return endpoint_b.bytes_received() == bytes_to_transfer || + simulator_.GetClock()->Now() >= end_time; + }); + + EXPECT_EQ(bytes_to_transfer, endpoint_a.bytes_transferred()); + EXPECT_EQ(bytes_to_transfer, endpoint_b.bytes_received()); + EXPECT_GT(endpoint_a.write_blocked_count(), 0u); + EXPECT_FALSE(endpoint_a.wrong_data_received()); + EXPECT_FALSE(endpoint_b.wrong_data_received()); +} + +// Test transmission of 1 MiB of data between two hosts simultaneously in both +// directions. +TEST_F(QuicEndpointTest, TwoWayTransmission) { + QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B", + Perspective::IS_CLIENT, test::TestConnectionId(42)); + QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A", + Perspective::IS_SERVER, test::TestConnectionId(42)); + auto link_a = Link(&endpoint_a, switch_.port(1)); + auto link_b = Link(&endpoint_b, switch_.port(2)); + + endpoint_a.RecordTrace(); + endpoint_b.RecordTrace(); + + endpoint_a.AddBytesToTransfer(1024 * 1024); + endpoint_b.AddBytesToTransfer(1024 * 1024); + QuicTime end_time = + simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5); + simulator_.RunUntil( + [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; }); + + EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_transferred()); + EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_transferred()); + EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_received()); + EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_received()); + EXPECT_FALSE(endpoint_a.wrong_data_received()); + EXPECT_FALSE(endpoint_b.wrong_data_received()); +} + +// Simulate three hosts trying to send data to a fourth one simultaneously. +TEST_F(QuicEndpointTest, Competition) { + auto endpoint_a = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT, + test::TestConnectionId(42)); + auto endpoint_b = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint B", "Endpoint D (B)", Perspective::IS_CLIENT, + test::TestConnectionId(43)); + auto endpoint_c = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint C", "Endpoint D (C)", Perspective::IS_CLIENT, + test::TestConnectionId(44)); + auto endpoint_d_a = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint D (A)", "Endpoint A", Perspective::IS_SERVER, + test::TestConnectionId(42)); + auto endpoint_d_b = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint D (B)", "Endpoint B", Perspective::IS_SERVER, + test::TestConnectionId(43)); + auto endpoint_d_c = std::make_unique<QuicEndpoint>( + &simulator_, "Endpoint D (C)", "Endpoint C", Perspective::IS_SERVER, + test::TestConnectionId(44)); + QuicEndpointMultiplexer endpoint_d( + "Endpoint D", + {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}); + + // Create links with slightly different RTTs in order to avoid pathological + // side-effects of packets entering the queue at the exactly same time. + auto link_a = CustomLink(endpoint_a.get(), switch_.port(1), 0); + auto link_b = CustomLink(endpoint_b.get(), switch_.port(2), 1); + auto link_c = CustomLink(endpoint_c.get(), switch_.port(3), 2); + auto link_d = Link(&endpoint_d, switch_.port(4)); + + endpoint_a->AddBytesToTransfer(2 * 1024 * 1024); + endpoint_b->AddBytesToTransfer(2 * 1024 * 1024); + endpoint_c->AddBytesToTransfer(2 * 1024 * 1024); + QuicTime end_time = + simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(12); + simulator_.RunUntil( + [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; }); + + for (QuicEndpoint* endpoint : + {endpoint_a.get(), endpoint_b.get(), endpoint_c.get()}) { + EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_transferred()); + EXPECT_GE(endpoint->connection()->GetStats().packets_lost, 0u); + } + for (QuicEndpoint* endpoint : + {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}) { + EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_received()); + EXPECT_FALSE(endpoint->wrong_data_received()); + } +} + +} // namespace simulator +} // namespace quic |