xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/test_tools/simulator/quic_endpoint.h"
6 
7 #include <utility>
8 
9 #include "quiche/quic/platform/api/quic_flags.h"
10 #include "quiche/quic/platform/api/quic_test.h"
11 #include "quiche/quic/test_tools/quic_connection_peer.h"
12 #include "quiche/quic/test_tools/quic_test_utils.h"
13 #include "quiche/quic/test_tools/simulator/simulator.h"
14 #include "quiche/quic/test_tools/simulator/switch.h"
15 
16 using ::testing::_;
17 using ::testing::NiceMock;
18 using ::testing::Return;
19 
20 namespace quic {
21 namespace simulator {
22 
23 const QuicBandwidth kDefaultBandwidth =
24     QuicBandwidth::FromKBitsPerSecond(10 * 1000);
25 const QuicTime::Delta kDefaultPropagationDelay =
26     QuicTime::Delta::FromMilliseconds(20);
27 const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay;
28 
29 // A simple test harness where all hosts are connected to a switch with
30 // identical links.
31 class QuicEndpointTest : public quic::test::QuicTest {
32  public:
QuicEndpointTest()33   QuicEndpointTest()
34       : simulator_(), switch_(&simulator_, "Switch", 8, kDefaultBdp * 2) {}
35 
36  protected:
37   Simulator simulator_;
38   Switch switch_;
39 
Link(Endpoint * a,Endpoint * b)40   std::unique_ptr<SymmetricLink> Link(Endpoint* a, Endpoint* b) {
41     return std::make_unique<SymmetricLink>(a, b, kDefaultBandwidth,
42                                            kDefaultPropagationDelay);
43   }
44 
CustomLink(Endpoint * a,Endpoint * b,uint64_t extra_rtt_ms)45   std::unique_ptr<SymmetricLink> CustomLink(Endpoint* a, Endpoint* b,
46                                             uint64_t extra_rtt_ms) {
47     return std::make_unique<SymmetricLink>(
48         a, b, kDefaultBandwidth,
49         kDefaultPropagationDelay +
50             QuicTime::Delta::FromMilliseconds(extra_rtt_ms));
51   }
52 };
53 
54 // Test transmission from one host to another.
TEST_F(QuicEndpointTest,OneWayTransmission)55 TEST_F(QuicEndpointTest, OneWayTransmission) {
56   QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
57                           Perspective::IS_CLIENT, test::TestConnectionId(42));
58   QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
59                           Perspective::IS_SERVER, test::TestConnectionId(42));
60   auto link_a = Link(&endpoint_a, switch_.port(1));
61   auto link_b = Link(&endpoint_b, switch_.port(2));
62 
63   // First transmit a small, packet-size chunk of data.
64   endpoint_a.AddBytesToTransfer(600);
65   QuicTime end_time =
66       simulator_.GetClock()->Now() + QuicTime::Delta::FromMilliseconds(1000);
67   simulator_.RunUntil(
68       [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
69 
70   EXPECT_EQ(600u, endpoint_a.bytes_transferred());
71   ASSERT_EQ(600u, endpoint_b.bytes_received());
72   EXPECT_FALSE(endpoint_a.wrong_data_received());
73   EXPECT_FALSE(endpoint_b.wrong_data_received());
74 
75   // After a small chunk succeeds, try to transfer 2 MiB.
76   endpoint_a.AddBytesToTransfer(2 * 1024 * 1024);
77   end_time = simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
78   simulator_.RunUntil(
79       [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
80 
81   const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024;
82   EXPECT_EQ(total_bytes_transferred, endpoint_a.bytes_transferred());
83   EXPECT_EQ(total_bytes_transferred, endpoint_b.bytes_received());
84   EXPECT_EQ(0u, endpoint_a.write_blocked_count());
85   EXPECT_FALSE(endpoint_a.wrong_data_received());
86   EXPECT_FALSE(endpoint_b.wrong_data_received());
87 }
88 
89 // Test the situation in which the writer becomes write-blocked.
TEST_F(QuicEndpointTest,WriteBlocked)90 TEST_F(QuicEndpointTest, WriteBlocked) {
91   QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
92                           Perspective::IS_CLIENT, test::TestConnectionId(42));
93   QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
94                           Perspective::IS_SERVER, test::TestConnectionId(42));
95   auto link_a = Link(&endpoint_a, switch_.port(1));
96   auto link_b = Link(&endpoint_b, switch_.port(2));
97 
98   // Will be owned by the sent packet manager.
99   auto* sender = new NiceMock<test::MockSendAlgorithm>();
100   EXPECT_CALL(*sender, CanSend(_)).WillRepeatedly(Return(true));
101   EXPECT_CALL(*sender, PacingRate(_))
102       .WillRepeatedly(Return(10 * kDefaultBandwidth));
103   EXPECT_CALL(*sender, BandwidthEstimate())
104       .WillRepeatedly(Return(10 * kDefaultBandwidth));
105   EXPECT_CALL(*sender, GetCongestionWindow())
106       .WillRepeatedly(Return(kMaxOutgoingPacketSize *
107                              GetQuicFlag(quic_max_congestion_window)));
108   test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(), sender);
109 
110   // First transmit a small, packet-size chunk of data.
111   QuicByteCount bytes_to_transfer = 3 * 1024 * 1024;
112   endpoint_a.AddBytesToTransfer(bytes_to_transfer);
113   QuicTime end_time =
114       simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30);
115   simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() {
116     return endpoint_b.bytes_received() == bytes_to_transfer ||
117            simulator_.GetClock()->Now() >= end_time;
118   });
119 
120   EXPECT_EQ(bytes_to_transfer, endpoint_a.bytes_transferred());
121   EXPECT_EQ(bytes_to_transfer, endpoint_b.bytes_received());
122   EXPECT_GT(endpoint_a.write_blocked_count(), 0u);
123   EXPECT_FALSE(endpoint_a.wrong_data_received());
124   EXPECT_FALSE(endpoint_b.wrong_data_received());
125 }
126 
127 // Test transmission of 1 MiB of data between two hosts simultaneously in both
128 // directions.
TEST_F(QuicEndpointTest,TwoWayTransmission)129 TEST_F(QuicEndpointTest, TwoWayTransmission) {
130   QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
131                           Perspective::IS_CLIENT, test::TestConnectionId(42));
132   QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
133                           Perspective::IS_SERVER, test::TestConnectionId(42));
134   auto link_a = Link(&endpoint_a, switch_.port(1));
135   auto link_b = Link(&endpoint_b, switch_.port(2));
136 
137   endpoint_a.RecordTrace();
138   endpoint_b.RecordTrace();
139 
140   endpoint_a.AddBytesToTransfer(1024 * 1024);
141   endpoint_b.AddBytesToTransfer(1024 * 1024);
142   QuicTime end_time =
143       simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
144   simulator_.RunUntil(
145       [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
146 
147   EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_transferred());
148   EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_transferred());
149   EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_received());
150   EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_received());
151   EXPECT_FALSE(endpoint_a.wrong_data_received());
152   EXPECT_FALSE(endpoint_b.wrong_data_received());
153 }
154 
155 // Simulate three hosts trying to send data to a fourth one simultaneously.
TEST_F(QuicEndpointTest,Competition)156 TEST_F(QuicEndpointTest, Competition) {
157   auto endpoint_a = std::make_unique<QuicEndpoint>(
158       &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT,
159       test::TestConnectionId(42));
160   auto endpoint_b = std::make_unique<QuicEndpoint>(
161       &simulator_, "Endpoint B", "Endpoint D (B)", Perspective::IS_CLIENT,
162       test::TestConnectionId(43));
163   auto endpoint_c = std::make_unique<QuicEndpoint>(
164       &simulator_, "Endpoint C", "Endpoint D (C)", Perspective::IS_CLIENT,
165       test::TestConnectionId(44));
166   auto endpoint_d_a = std::make_unique<QuicEndpoint>(
167       &simulator_, "Endpoint D (A)", "Endpoint A", Perspective::IS_SERVER,
168       test::TestConnectionId(42));
169   auto endpoint_d_b = std::make_unique<QuicEndpoint>(
170       &simulator_, "Endpoint D (B)", "Endpoint B", Perspective::IS_SERVER,
171       test::TestConnectionId(43));
172   auto endpoint_d_c = std::make_unique<QuicEndpoint>(
173       &simulator_, "Endpoint D (C)", "Endpoint C", Perspective::IS_SERVER,
174       test::TestConnectionId(44));
175   QuicEndpointMultiplexer endpoint_d(
176       "Endpoint D",
177       {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()});
178 
179   // Create links with slightly different RTTs in order to avoid pathological
180   // side-effects of packets entering the queue at the exactly same time.
181   auto link_a = CustomLink(endpoint_a.get(), switch_.port(1), 0);
182   auto link_b = CustomLink(endpoint_b.get(), switch_.port(2), 1);
183   auto link_c = CustomLink(endpoint_c.get(), switch_.port(3), 2);
184   auto link_d = Link(&endpoint_d, switch_.port(4));
185 
186   endpoint_a->AddBytesToTransfer(2 * 1024 * 1024);
187   endpoint_b->AddBytesToTransfer(2 * 1024 * 1024);
188   endpoint_c->AddBytesToTransfer(2 * 1024 * 1024);
189   QuicTime end_time =
190       simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(12);
191   simulator_.RunUntil(
192       [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
193 
194   for (QuicEndpoint* endpoint :
195        {endpoint_a.get(), endpoint_b.get(), endpoint_c.get()}) {
196     EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_transferred());
197     EXPECT_GE(endpoint->connection()->GetStats().packets_lost, 0u);
198   }
199   for (QuicEndpoint* endpoint :
200        {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}) {
201     EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_received());
202     EXPECT_FALSE(endpoint->wrong_data_received());
203   }
204 }
205 
206 }  // namespace simulator
207 }  // namespace quic
208