xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/batch_writer/quic_batch_writer_test.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 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 #ifndef QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
6 #define QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
7 
8 #include <sys/socket.h>
9 #include <sys/types.h>
10 
11 #include <cstddef>
12 #include <iostream>
13 #include <utility>
14 
15 #include "absl/base/optimization.h"
16 #include "quiche/quic/core/batch_writer/quic_batch_writer_base.h"
17 #include "quiche/quic/core/quic_udp_socket.h"
18 #include "quiche/quic/platform/api/quic_test.h"
19 
20 namespace quic {
21 namespace test {
22 
IsAddressFamilySupported(int address_family)23 static bool IsAddressFamilySupported(int address_family) {
24   static auto check_function = [](int address_family) {
25     int fd = socket(address_family, SOCK_STREAM, 0);
26     if (fd < 0) {
27       QUIC_LOG(ERROR) << "address_family not supported: " << address_family
28                       << ", error: " << strerror(errno);
29       EXPECT_EQ(EAFNOSUPPORT, errno);
30       return false;
31     }
32     close(fd);
33     return true;
34   };
35 
36   if (address_family == AF_INET) {
37     static const bool ipv4_supported = check_function(AF_INET);
38     return ipv4_supported;
39   }
40 
41   static const bool ipv6_supported = check_function(AF_INET6);
42   return ipv6_supported;
43 }
44 
CreateSocket(int family,QuicSocketAddress * address,int * fd)45 static bool CreateSocket(int family, QuicSocketAddress* address, int* fd) {
46   if (family == AF_INET) {
47     *address = QuicSocketAddress(QuicIpAddress::Loopback4(), 0);
48   } else {
49     QUICHE_DCHECK_EQ(family, AF_INET6);
50     *address = QuicSocketAddress(QuicIpAddress::Loopback6(), 0);
51   }
52 
53   QuicUdpSocketApi socket_api;
54   *fd = socket_api.Create(family,
55                           /*receive_buffer_size=*/kDefaultSocketReceiveBuffer,
56                           /*send_buffer_size=*/kDefaultSocketReceiveBuffer);
57   if (*fd < 0) {
58     QUIC_LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
59     return false;
60   }
61   socket_api.EnableDroppedPacketCount(*fd);
62 
63   if (!socket_api.Bind(*fd, *address)) {
64     QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno);
65     return false;
66   }
67 
68   if (address->FromSocket(*fd) != 0) {
69     QUIC_LOG(ERROR) << "Unable to get self address.  Error: "
70                     << strerror(errno);
71     return false;
72   }
73   return true;
74 }
75 
76 struct QuicUdpBatchWriterIOTestParams;
77 class QUICHE_EXPORT QuicUdpBatchWriterIOTestDelegate {
78  public:
~QuicUdpBatchWriterIOTestDelegate()79   virtual ~QuicUdpBatchWriterIOTestDelegate() {}
80 
ShouldSkip(const QuicUdpBatchWriterIOTestParams &)81   virtual bool ShouldSkip(const QuicUdpBatchWriterIOTestParams& /*params*/) {
82     return false;
83   }
84 
85   virtual void ResetWriter(int fd) = 0;
86 
87   virtual QuicUdpBatchWriter* GetWriter() = 0;
88 };
89 
90 struct QUICHE_EXPORT QuicUdpBatchWriterIOTestParams {
91   // Use shared_ptr because gtest makes copies of test params.
92   std::shared_ptr<QuicUdpBatchWriterIOTestDelegate> delegate;
93   int address_family;
94   int data_size;
95   int packet_size;
96 
97   QUICHE_EXPORT friend std::ostream& operator<<(
98       std::ostream& os, const QuicUdpBatchWriterIOTestParams& p) {
99     os << "{ address_family: " << p.address_family
100        << " data_size: " << p.data_size << " packet_size: " << p.packet_size
101        << " }";
102     return os;
103   }
104 };
105 
106 template <class QuicUdpBatchWriterIOTestDelegateT>
107 static std::vector<QuicUdpBatchWriterIOTestParams>
MakeQuicBatchWriterTestParams()108 MakeQuicBatchWriterTestParams() {
109   static_assert(std::is_base_of<QuicUdpBatchWriterIOTestDelegate,
110                                 QuicUdpBatchWriterIOTestDelegateT>::value,
111                 "<QuicUdpBatchWriterIOTestDelegateT> needs to derive from "
112                 "QuicUdpBatchWriterIOTestDelegate");
113 
114   std::vector<QuicUdpBatchWriterIOTestParams> params;
115   for (int address_family : {AF_INET, AF_INET6}) {
116     for (int data_size : {1, 150, 1500, 15000, 64000, 512 * 1024}) {
117       for (int packet_size : {1, 50, 1350, 1452}) {
118         if (packet_size <= data_size && (data_size / packet_size < 2000)) {
119           params.push_back(
120               {std::make_unique<QuicUdpBatchWriterIOTestDelegateT>(),
121                address_family, data_size, packet_size});
122         }
123       }
124     }
125   }
126   return params;
127 }
128 
129 // QuicUdpBatchWriterIOTest is a value parameterized test fixture that can be
130 // used by tests of derived classes of QuicUdpBatchWriter, to verify basic
131 // packet IO capabilities.
132 class QUICHE_EXPORT QuicUdpBatchWriterIOTest
133     : public QuicTestWithParam<QuicUdpBatchWriterIOTestParams> {
134  protected:
QuicUdpBatchWriterIOTest()135   QuicUdpBatchWriterIOTest()
136       : address_family_(GetParam().address_family),
137         data_size_(GetParam().data_size),
138         packet_size_(GetParam().packet_size),
139         self_socket_(-1),
140         peer_socket_(-1) {
141     QUIC_LOG(INFO) << "QuicUdpBatchWriterIOTestParams: " << GetParam();
142     EXPECT_TRUE(address_family_ == AF_INET || address_family_ == AF_INET6);
143     EXPECT_LE(packet_size_, data_size_);
144     EXPECT_LE(packet_size_, sizeof(packet_buffer_));
145   }
146 
~QuicUdpBatchWriterIOTest()147   ~QuicUdpBatchWriterIOTest() override {
148     if (self_socket_ > 0) {
149       close(self_socket_);
150     }
151     if (peer_socket_ > 0) {
152       close(peer_socket_);
153     }
154   }
155 
156   // Whether this test should be skipped. A test is passed if skipped.
157   // A test can be skipped when e.g. it exercises a kernel feature that is not
158   // available on the system.
ShouldSkip()159   bool ShouldSkip() {
160     if (!IsAddressFamilySupported(address_family_)) {
161       QUIC_LOG(WARNING)
162           << "Test skipped since address_family is not supported.";
163       return true;
164     }
165 
166     return GetParam().delegate->ShouldSkip(GetParam());
167   }
168 
169   // Initialize a test.
170   // To fail the test in Initialize, use ASSERT_xx macros.
Initialize()171   void Initialize() {
172     ASSERT_TRUE(CreateSocket(address_family_, &self_address_, &self_socket_));
173     ASSERT_TRUE(CreateSocket(address_family_, &peer_address_, &peer_socket_));
174 
175     QUIC_DLOG(INFO) << "Self address: " << self_address_.ToString() << ", fd "
176                     << self_socket_;
177     QUIC_DLOG(INFO) << "Peer address: " << peer_address_.ToString() << ", fd "
178                     << peer_socket_;
179     GetParam().delegate->ResetWriter(self_socket_);
180   }
181 
GetWriter()182   QuicUdpBatchWriter* GetWriter() { return GetParam().delegate->GetWriter(); }
183 
ValidateWrite()184   void ValidateWrite() {
185     char this_packet_content = '\0';
186     int this_packet_size;
187     int num_writes = 0;
188     size_t bytes_flushed = 0;
189     WriteResult result;
190 
191     for (size_t bytes_sent = 0; bytes_sent < data_size_;
192          bytes_sent += this_packet_size, ++this_packet_content) {
193       this_packet_size = std::min(packet_size_, data_size_ - bytes_sent);
194       memset(&packet_buffer_[0], this_packet_content, this_packet_size);
195 
196       result = GetWriter()->WritePacket(&packet_buffer_[0], this_packet_size,
197                                         self_address_.host(), peer_address_,
198                                         nullptr, QuicPacketWriterParams());
199 
200       ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code);
201       bytes_flushed += result.bytes_written;
202       ++num_writes;
203 
204       QUIC_DVLOG(1) << "[write #" << num_writes
205                     << "] this_packet_size: " << this_packet_size
206                     << ", total_bytes_sent: " << bytes_sent + this_packet_size
207                     << ", bytes_flushed: " << bytes_flushed
208                     << ", pkt content:" << std::hex << int(this_packet_content);
209     }
210 
211     result = GetWriter()->Flush();
212     ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code);
213     bytes_flushed += result.bytes_written;
214     ASSERT_EQ(data_size_, bytes_flushed);
215 
216     QUIC_LOG(INFO) << "Sent " << data_size_ << " bytes in " << num_writes
217                    << " writes.";
218   }
219 
ValidateRead()220   void ValidateRead() {
221     char this_packet_content = '\0';
222     int this_packet_size;
223     int packets_received = 0;
224     for (size_t bytes_received = 0; bytes_received < data_size_;
225          bytes_received += this_packet_size, ++this_packet_content) {
226       this_packet_size = std::min(packet_size_, data_size_ - bytes_received);
227       SCOPED_TRACE(testing::Message()
228                    << "Before ReadPacket: bytes_received=" << bytes_received
229                    << ", this_packet_size=" << this_packet_size);
230 
231       QuicUdpSocketApi::ReadPacketResult result;
232       result.packet_buffer = {&packet_buffer_[0], sizeof(packet_buffer_)};
233       result.control_buffer = {&control_buffer_[0], sizeof(control_buffer_)};
234       ASSERT_TRUE(QuicUdpSocketApi().WaitUntilReadable(
235           peer_socket_, QuicTime::Delta::FromSeconds(1)));
236       QuicUdpSocketApi().ReadPacket(
237           peer_socket_,
238           quic::QuicUdpPacketInfoBitMask({QuicUdpPacketInfoBit::V4_SELF_IP,
239                                           QuicUdpPacketInfoBit::V6_SELF_IP,
240                                           QuicUdpPacketInfoBit::PEER_ADDRESS}),
241           &result);
242       ASSERT_TRUE(result.ok);
243       ASSERT_TRUE(
244           result.packet_info.HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS));
245       QuicSocketAddress read_peer_address = result.packet_info.peer_address();
246       QuicIpAddress read_self_address = read_peer_address.host().IsIPv6()
247                                             ? result.packet_info.self_v6_ip()
248                                             : result.packet_info.self_v4_ip();
249 
250       EXPECT_EQ(read_self_address, peer_address_.host());
251       EXPECT_EQ(read_peer_address, self_address_);
252       for (int i = 0; i < this_packet_size; ++i) {
253         EXPECT_EQ(this_packet_content, packet_buffer_[i]);
254       }
255       packets_received += this_packet_size;
256     }
257 
258     QUIC_LOG(INFO) << "Received " << data_size_ << " bytes in "
259                    << packets_received << " packets.";
260   }
261 
262   QuicSocketAddress self_address_;
263   QuicSocketAddress peer_address_;
264   ABSL_CACHELINE_ALIGNED char packet_buffer_[1500];
265   ABSL_CACHELINE_ALIGNED char
266       control_buffer_[kDefaultUdpPacketControlBufferSize];
267   int address_family_;
268   const size_t data_size_;
269   const size_t packet_size_;
270   int self_socket_;
271   int peer_socket_;
272 };
273 
TEST_P(QuicUdpBatchWriterIOTest,WriteAndRead)274 TEST_P(QuicUdpBatchWriterIOTest, WriteAndRead) {
275   if (ShouldSkip()) {
276     return;
277   }
278 
279   Initialize();
280 
281   ValidateWrite();
282   ValidateRead();
283 }
284 
285 }  // namespace test
286 }  // namespace quic
287 
288 #endif  // QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_
289