/work/testing/support/doubles/fake_sockets_test.cc
Line | Count | Source |
1 | | #include "fake_sockets.hh" |
2 | | |
3 | | #include <gtest/gtest.h> |
4 | | |
5 | | #include "network_universe.hh" |
6 | | |
7 | | namespace tox::test { |
8 | | namespace { |
9 | | |
10 | | class FakeTcpSocketTest : public ::testing::Test { |
11 | | public: |
12 | | ~FakeTcpSocketTest() override; |
13 | | |
14 | | protected: |
15 | | NetworkUniverse universe; |
16 | | FakeTcpSocket server{universe}; |
17 | | FakeTcpSocket client{universe}; |
18 | | }; |
19 | | |
20 | 5 | FakeTcpSocketTest::~FakeTcpSocketTest() = default; |
21 | | |
22 | | TEST_F(FakeTcpSocketTest, ConnectAndAccept) |
23 | 1 | { |
24 | 1 | IP_Port server_addr; |
25 | 1 | ip_init(&server_addr.ip, false); |
26 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
27 | 1 | server_addr.port = net_htons(8080); |
28 | | |
29 | 1 | ASSERT_EQ(server.bind(&server_addr), 0); |
30 | 1 | ASSERT_EQ(server.listen(5), 0); |
31 | | |
32 | | // Client connects |
33 | 1 | ASSERT_EQ(client.connect(&server_addr), -1); |
34 | 1 | ASSERT_EQ(errno, EINPROGRESS); |
35 | | |
36 | | // Process events (Client SYN -> Server) |
37 | 1 | universe.process_events(0); |
38 | | |
39 | | // Server accepts (SYN-ACK -> Client) |
40 | 1 | universe.process_events(0); |
41 | | |
42 | | // Client receives SYN-ACK, sends ACK (ACK -> Server) |
43 | 1 | universe.process_events(0); |
44 | | |
45 | | // Server receives ACK, connection established |
46 | 1 | IP_Port client_addr; |
47 | 1 | auto accepted = server.accept(&client_addr); |
48 | 1 | ASSERT_NE(accepted, nullptr); |
49 | 1 | auto *accepted_tcp = static_cast<FakeTcpSocket *>(accepted.get()); |
50 | 1 | EXPECT_EQ(accepted_tcp->state(), FakeTcpSocket::ESTABLISHED); |
51 | | |
52 | 1 | EXPECT_EQ(client.state(), FakeTcpSocket::ESTABLISHED); |
53 | 1 | } |
54 | | |
55 | | TEST_F(FakeTcpSocketTest, DataTransfer) |
56 | 1 | { |
57 | 1 | IP_Port server_addr; |
58 | 1 | ip_init(&server_addr.ip, false); |
59 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
60 | 1 | server_addr.port = net_htons(8081); |
61 | | |
62 | 1 | server.bind(&server_addr); |
63 | 1 | server.listen(5); |
64 | 1 | client.connect(&server_addr); |
65 | | |
66 | | // Handshake |
67 | 1 | universe.process_events(0); // SYN |
68 | 1 | universe.process_events(0); // SYN-ACK |
69 | 1 | universe.process_events(0); // ACK |
70 | | |
71 | 1 | auto accepted = server.accept(nullptr); |
72 | 1 | ASSERT_NE(accepted, nullptr); |
73 | | |
74 | | // Send data Client -> Server |
75 | 1 | uint8_t send_buf[] = "Hello"; |
76 | 1 | ASSERT_EQ(client.send(send_buf, 5), 5); |
77 | | |
78 | 1 | universe.process_events(0); // Data packet |
79 | | |
80 | 1 | uint8_t recv_buf[10]; |
81 | 1 | ASSERT_EQ(accepted->recv(recv_buf, 10), 5); |
82 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 5), "Hello"); |
83 | 1 | } |
84 | | |
85 | | TEST_F(FakeTcpSocketTest, RecvBuffering) |
86 | 1 | { |
87 | 1 | IP_Port server_addr; |
88 | 1 | ip_init(&server_addr.ip, false); |
89 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
90 | 1 | server_addr.port = net_htons(8082); |
91 | | |
92 | 1 | server.bind(&server_addr); |
93 | 1 | server.listen(5); |
94 | 1 | client.connect(&server_addr); |
95 | | |
96 | 1 | universe.process_events(0); // SYN |
97 | 1 | universe.process_events(0); // SYN-ACK |
98 | 1 | universe.process_events(0); // ACK |
99 | | |
100 | 1 | auto accepted = server.accept(nullptr); |
101 | 1 | ASSERT_NE(accepted, nullptr); |
102 | | |
103 | 1 | uint8_t msg1[] = "Part1"; |
104 | 1 | uint8_t msg2[] = "Part2"; |
105 | 1 | client.send(msg1, 5); |
106 | 1 | client.send(msg2, 5); |
107 | | |
108 | 1 | universe.process_events(0); // Deliver Part1 |
109 | 1 | universe.process_events(0); // Deliver Part2 |
110 | | |
111 | 1 | EXPECT_EQ(accepted->recv_buffer_size(), 10); |
112 | | |
113 | 1 | uint8_t recv_buf[20]; |
114 | | // Read partial |
115 | 1 | ASSERT_EQ(accepted->recv(recv_buf, 3), 3); |
116 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 3), "Par"); |
117 | 1 | EXPECT_EQ(accepted->recv_buffer_size(), 7); |
118 | | |
119 | | // Read rest |
120 | 1 | ASSERT_EQ(accepted->recv(recv_buf, 7), 7); |
121 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 7), "t1Part2"); |
122 | 1 | EXPECT_EQ(accepted->recv_buffer_size(), 0); |
123 | 1 | } |
124 | | |
125 | | class FakeUdpSocketTest : public ::testing::Test { |
126 | | public: |
127 | | ~FakeUdpSocketTest() override; |
128 | | |
129 | | protected: |
130 | | NetworkUniverse universe; |
131 | | FakeUdpSocket server{universe}; |
132 | | FakeUdpSocket client{universe}; |
133 | | }; |
134 | | |
135 | 3 | FakeUdpSocketTest::~FakeUdpSocketTest() = default; |
136 | | |
137 | | TEST_F(FakeUdpSocketTest, BindAndSendTo) |
138 | 1 | { |
139 | 1 | IP_Port server_addr; |
140 | 1 | ip_init(&server_addr.ip, false); |
141 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
142 | 1 | server_addr.port = net_htons(9000); |
143 | | |
144 | 1 | ASSERT_EQ(server.bind(&server_addr), 0); |
145 | | |
146 | 1 | const char *message = "UDP Packet"; |
147 | 1 | ASSERT_EQ(client.sendto( |
148 | 1 | reinterpret_cast<const uint8_t *>(message), strlen(message), &server_addr), |
149 | 1 | strlen(message)); |
150 | | |
151 | 1 | universe.process_events(0); |
152 | | |
153 | 1 | IP_Port sender_addr; |
154 | 1 | uint8_t recv_buf[100]; |
155 | 1 | int len = server.recvfrom(recv_buf, sizeof(recv_buf), &sender_addr); |
156 | | |
157 | 1 | ASSERT_GT(len, 0); |
158 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), len), message); |
159 | 1 | EXPECT_EQ(sender_addr.port, net_htons(client.local_port())); |
160 | 1 | } |
161 | | |
162 | | TEST_F(FakeUdpSocketTest, RecvBuffering) |
163 | 1 | { |
164 | 1 | IP_Port server_addr; |
165 | 1 | ip_init(&server_addr.ip, false); |
166 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
167 | 1 | server_addr.port = net_htons(9001); |
168 | | |
169 | 1 | server.bind(&server_addr); |
170 | | |
171 | 1 | const char *msg1 = "Msg1"; |
172 | 1 | const char *msg2 = "Msg2"; |
173 | | |
174 | 1 | client.sendto(reinterpret_cast<const uint8_t *>(msg1), strlen(msg1), &server_addr); |
175 | 1 | client.sendto(reinterpret_cast<const uint8_t *>(msg2), strlen(msg2), &server_addr); |
176 | | |
177 | 1 | universe.process_events(0); // Deliver msg1 |
178 | 1 | universe.process_events(0); // Deliver msg2 |
179 | | |
180 | 1 | EXPECT_EQ(server.recv_buffer_size(), 2); |
181 | | |
182 | 1 | IP_Port sender; |
183 | 1 | uint8_t buf[10]; |
184 | | |
185 | 1 | int len = server.recvfrom(buf, sizeof(buf), &sender); |
186 | 1 | ASSERT_EQ(len, 4); |
187 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(buf), len), "Msg1"); |
188 | 1 | EXPECT_EQ(server.recv_buffer_size(), 1); |
189 | | |
190 | 1 | len = server.recvfrom(buf, sizeof(buf), &sender); |
191 | 1 | ASSERT_EQ(len, 4); |
192 | 1 | EXPECT_EQ(std::string(reinterpret_cast<char *>(buf), len), "Msg2"); |
193 | 1 | EXPECT_EQ(server.recv_buffer_size(), 0); |
194 | 1 | } |
195 | | |
196 | | TEST_F(FakeUdpSocketTest, QueueLimit) |
197 | 1 | { |
198 | 1 | IP_Port server_addr; |
199 | 1 | ip_init(&server_addr.ip, false); |
200 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
201 | 1 | server_addr.port = net_htons(9002); |
202 | | |
203 | 1 | ASSERT_EQ(server.bind(&server_addr), 0); |
204 | | |
205 | | // Fill the queue |
206 | 1.02k | for (std::size_t i = 0; i < FakeUdpSocket::kMaxQueueSize; ++i) { |
207 | 1.02k | uint8_t data = static_cast<uint8_t>(i % 256); |
208 | 1.02k | ASSERT_EQ(client.sendto(&data, 1, &server_addr), 1); |
209 | 1.02k | } |
210 | | |
211 | 1 | universe.process_events(0); |
212 | | |
213 | | // This packet should be dropped |
214 | 1 | uint8_t dropped_data = 0xFF; |
215 | 1 | ASSERT_EQ(client.sendto(&dropped_data, 1, &server_addr), 1); |
216 | 1 | universe.process_events(0); |
217 | | |
218 | | // Verify we can read MaxQueueSize packets |
219 | 1.02k | for (std::size_t i = 0; i < FakeUdpSocket::kMaxQueueSize; ++i) { |
220 | 1.02k | uint8_t recv_buf[1]; |
221 | 1.02k | IP_Port from; |
222 | 1.02k | ASSERT_EQ(server.recvfrom(recv_buf, 1, &from), 1); |
223 | 1.02k | } |
224 | | |
225 | | // The queue should now be empty |
226 | 1 | uint8_t dummy[1]; |
227 | 1 | IP_Port from; |
228 | 1 | EXPECT_EQ(server.recvfrom(dummy, 1, &from), -1); |
229 | 1 | EXPECT_EQ(errno, EWOULDBLOCK); |
230 | 1 | } |
231 | | |
232 | | TEST_F(FakeTcpSocketTest, BacklogLimit) |
233 | 1 | { |
234 | 1 | IP_Port server_addr; |
235 | 1 | ip_init(&server_addr.ip, false); |
236 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
237 | 1 | server_addr.port = net_htons(8082); |
238 | | |
239 | 1 | ASSERT_EQ(server.bind(&server_addr), 0); |
240 | | // Small backlog for testing |
241 | 1 | ASSERT_EQ(server.listen(2), 0); |
242 | | |
243 | | // Client 1 |
244 | 1 | FakeTcpSocket client1{universe}; |
245 | 1 | client1.connect(&server_addr); |
246 | | // Client 2 |
247 | 1 | FakeTcpSocket client2{universe}; |
248 | 1 | client2.connect(&server_addr); |
249 | | // Client 3 (Should be dropped) |
250 | 1 | FakeTcpSocket client3{universe}; |
251 | 1 | client3.connect(&server_addr); |
252 | | |
253 | 1 | universe.process_events(0); // Deliver SYNs |
254 | 1 | universe.process_events(0); // Deliver SYN-ACKs |
255 | 1 | universe.process_events(0); // Deliver ACKs |
256 | | |
257 | | // Accept first two |
258 | 1 | ASSERT_NE(server.accept(nullptr), nullptr); |
259 | 1 | ASSERT_NE(server.accept(nullptr), nullptr); |
260 | | |
261 | | // Third should not be there |
262 | 1 | EXPECT_EQ(server.accept(nullptr), nullptr); |
263 | 1 | EXPECT_EQ(errno, EWOULDBLOCK); |
264 | 1 | } |
265 | | |
266 | | TEST_F(FakeTcpSocketTest, BufferLimit) |
267 | 1 | { |
268 | 1 | IP_Port server_addr; |
269 | 1 | ip_init(&server_addr.ip, false); |
270 | 1 | server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001); |
271 | 1 | server_addr.port = net_htons(8083); |
272 | | |
273 | 1 | server.bind(&server_addr); |
274 | 1 | server.listen(5); |
275 | 1 | client.connect(&server_addr); |
276 | | |
277 | | // Handshake |
278 | 1 | universe.process_events(0); // SYN |
279 | 1 | universe.process_events(0); // SYN-ACK |
280 | 1 | universe.process_events(0); // ACK |
281 | | |
282 | 1 | auto accepted = server.accept(nullptr); |
283 | 1 | ASSERT_NE(accepted, nullptr); |
284 | | |
285 | | // Fill buffer to just below limit |
286 | 1 | std::vector<uint8_t> large_data(FakeTcpSocket::kMaxBufferSize - 10, 'A'); |
287 | 1 | ASSERT_EQ(client.send(large_data.data(), large_data.size()), large_data.size()); |
288 | 1 | universe.process_events(0); |
289 | | |
290 | 1 | EXPECT_EQ(accepted->recv_buffer_size(), FakeTcpSocket::kMaxBufferSize - 10); |
291 | | |
292 | | // Send 20 more bytes, total would exceed limit |
293 | 1 | uint8_t extra_data[20]; |
294 | 1 | ASSERT_EQ(client.send(extra_data, 20), 20); |
295 | 1 | universe.process_events(0); |
296 | | |
297 | | // Size should remain the same |
298 | 1 | EXPECT_EQ(accepted->recv_buffer_size(), FakeTcpSocket::kMaxBufferSize - 10); |
299 | 1 | } |
300 | | |
301 | | } // namespace |
302 | | } // namespace tox::test |
303 | | |
304 | | // end of file |