Mirko Bonadei | 248fdb1 | 2022-10-13 13:06:08 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2022 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | #include "call/simulated_network.h" |
| 11 | |
| 12 | #include <algorithm> |
| 13 | #include <map> |
| 14 | #include <optional> |
| 15 | #include <set> |
| 16 | #include <vector> |
| 17 | |
| 18 | #include "absl/algorithm/container.h" |
| 19 | #include "api/test/simulated_network.h" |
| 20 | #include "api/units/data_rate.h" |
| 21 | #include "api/units/time_delta.h" |
| 22 | #include "test/gmock.h" |
| 23 | #include "test/gtest.h" |
| 24 | |
| 25 | namespace webrtc { |
| 26 | namespace { |
| 27 | |
| 28 | using ::testing::ElementsAre; |
| 29 | |
| 30 | PacketInFlightInfo PacketWithSize(size_t size) { |
| 31 | return PacketInFlightInfo(/*size=*/size, /*send_time_us=*/0, /*packet_id=*/1); |
| 32 | } |
| 33 | |
| 34 | TEST(SimulatedNetworkTest, NextDeliveryTimeIsUnknownOnEmptyNetwork) { |
| 35 | SimulatedNetwork network = SimulatedNetwork({}); |
| 36 | EXPECT_EQ(network.NextDeliveryTimeUs(), absl::nullopt); |
| 37 | } |
| 38 | |
| 39 | TEST(SimulatedNetworkTest, EnqueueFirstPacketOnNetworkWithInfiniteCapacity) { |
| 40 | // A packet of 1 kB that gets enqueued on a network with infinite capacity |
| 41 | // should be ready to exit the network immediately. |
| 42 | SimulatedNetwork network = SimulatedNetwork({}); |
| 43 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(1'000))); |
| 44 | |
| 45 | EXPECT_EQ(network.NextDeliveryTimeUs(), 0); |
| 46 | } |
| 47 | |
| 48 | TEST(SimulatedNetworkTest, EnqueueFirstPacketOnNetworkWithLimitedCapacity) { |
| 49 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 50 | // should be ready to exit the network in 1 second. |
| 51 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 52 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125))); |
| 53 | |
| 54 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 55 | } |
| 56 | |
| 57 | TEST(SimulatedNetworkTest, |
| 58 | EnqueuePacketsButNextDeliveryIsBasedOnFirstEnqueuedPacket) { |
| 59 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 60 | // should be ready to exit the network in 1 second. |
| 61 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 62 | ASSERT_TRUE(network.EnqueuePacket( |
| 63 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 64 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 65 | |
| 66 | // Enqueuing another packet after 100 us doesn't change the next delivery |
| 67 | // time. |
| 68 | ASSERT_TRUE(network.EnqueuePacket( |
| 69 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/100, /*packet_id=*/2))); |
| 70 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 71 | |
| 72 | // Enqueuing another packet after 2 seconds doesn't change the next delivery |
| 73 | // time since the first packet has not left the network yet. |
| 74 | ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 75 | /*size=*/125, /*send_time_us=*/TimeDelta::Seconds(2).us(), |
| 76 | /*packet_id=*/3))); |
| 77 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 78 | } |
| 79 | |
| 80 | TEST(SimulatedNetworkTest, EnqueueFailsWhenQueueLengthIsReached) { |
| 81 | SimulatedNetwork network = |
| 82 | SimulatedNetwork({.queue_length_packets = 1, .link_capacity_kbps = 1}); |
| 83 | ASSERT_TRUE(network.EnqueuePacket( |
| 84 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 85 | |
| 86 | // Until there is 1 packet in the queue, no other packets can be enqueued, |
| 87 | // the only way to make space for new packets is calling |
| 88 | // DequeueDeliverablePackets at a time greater than or equal to |
| 89 | // NextDeliveryTimeUs. |
| 90 | EXPECT_FALSE(network.EnqueuePacket( |
| 91 | PacketInFlightInfo(/*size=*/125, |
| 92 | /*send_time_us=*/TimeDelta::Seconds(0.5).us(), |
| 93 | /*packet_id=*/2))); |
| 94 | |
| 95 | // Even if the send_time_us is after NextDeliveryTimeUs, it is still not |
| 96 | // possible to enqueue a new packet since the client didn't deque any packet |
| 97 | // from the queue (in this case the client is introducing unbounded delay but |
| 98 | // the network cannot do anything about it). |
| 99 | EXPECT_FALSE(network.EnqueuePacket( |
| 100 | PacketInFlightInfo(/*size=*/125, |
| 101 | /*send_time_us=*/TimeDelta::Seconds(2).us(), |
| 102 | /*packet_id=*/3))); |
| 103 | } |
| 104 | |
| 105 | TEST(SimulatedNetworkTest, PacketOverhead) { |
| 106 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 107 | // should be ready to exit the network in 1 second, but since there is an |
| 108 | // overhead per packet of 125 bytes, it will exit the network after 2 seconds. |
| 109 | SimulatedNetwork network = |
| 110 | SimulatedNetwork({.link_capacity_kbps = 1, .packet_overhead = 125}); |
| 111 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125))); |
| 112 | |
| 113 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(2).us()); |
| 114 | } |
| 115 | |
| 116 | TEST(SimulatedNetworkTest, |
| 117 | DequeueDeliverablePacketsLeavesPacketsInCapacityLink) { |
| 118 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 119 | // should be ready to exit the network in 1 second. |
| 120 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 121 | ASSERT_TRUE(network.EnqueuePacket( |
| 122 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 123 | // Enqueue another packet of 125 bytes (this one should exit after 2 seconds). |
| 124 | ASSERT_TRUE(network.EnqueuePacket( |
| 125 | PacketInFlightInfo(/*size=*/125, |
| 126 | /*send_time_us=*/TimeDelta::Seconds(1).us(), |
| 127 | /*packet_id=*/2))); |
| 128 | |
| 129 | // The first packet will exit after 1 second, so that is the next delivery |
| 130 | // time. |
| 131 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 132 | |
| 133 | // After 1 seconds, we collect the delivered packets... |
| 134 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 135 | network.DequeueDeliverablePackets( |
| 136 | /*receive_time_us=*/TimeDelta::Seconds(1).us()); |
| 137 | ASSERT_EQ(delivered_packets.size(), 1ul); |
| 138 | EXPECT_EQ(delivered_packets[0].packet_id, 1ul); |
| 139 | EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(1).us()); |
| 140 | |
| 141 | // ... And after the first enqueued packet has left the network, the next |
| 142 | // delivery time reflects the delivery time of the next packet. |
| 143 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(2).us()); |
| 144 | } |
| 145 | |
| 146 | TEST(SimulatedNetworkTest, |
| 147 | DequeueDeliverablePacketsAppliesConfigChangesToCapacityLink) { |
| 148 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 149 | // should be ready to exit the network in 1 second. |
| 150 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 151 | const PacketInFlightInfo packet_1 = |
| 152 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1); |
| 153 | ASSERT_TRUE(network.EnqueuePacket(packet_1)); |
| 154 | |
| 155 | // Enqueue another packet of 125 bytes with send time 1 second so this should |
| 156 | // exit after 2 seconds. |
| 157 | PacketInFlightInfo packet_2 = |
| 158 | PacketInFlightInfo(/*size=*/125, |
| 159 | /*send_time_us=*/TimeDelta::Seconds(1).us(), |
| 160 | /*packet_id=*/2); |
| 161 | ASSERT_TRUE(network.EnqueuePacket(packet_2)); |
| 162 | |
| 163 | // The first packet will exit after 1 second, so that is the next delivery |
| 164 | // time. |
| 165 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 166 | |
| 167 | // Since the link capacity changes from 1 kbps to 10 kbps, packets will take |
| 168 | // 100 ms each to leave the network. |
| 169 | network.SetConfig({.link_capacity_kbps = 10}); |
| 170 | |
| 171 | // The next delivery time doesn't change (it will be updated, if needed at |
| 172 | // DequeueDeliverablePackets time). |
| 173 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 174 | |
| 175 | // Getting the first enqueued packet after 100 ms. |
| 176 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 177 | network.DequeueDeliverablePackets( |
| 178 | /*receive_time_us=*/TimeDelta::Millis(100).us()); |
| 179 | ASSERT_EQ(delivered_packets.size(), 1ul); |
| 180 | EXPECT_THAT(delivered_packets, |
| 181 | ElementsAre(PacketDeliveryInfo( |
| 182 | /*source=*/packet_1, |
| 183 | /*receive_time_us=*/TimeDelta::Millis(100).us()))); |
| 184 | |
| 185 | // Getting the second enqueued packet that cannot be delivered before its send |
| 186 | // time, hence it will be delivered after 1.1 seconds. |
| 187 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Millis(1100).us()); |
| 188 | delivered_packets = network.DequeueDeliverablePackets( |
| 189 | /*receive_time_us=*/TimeDelta::Millis(1100).us()); |
| 190 | ASSERT_EQ(delivered_packets.size(), 1ul); |
| 191 | EXPECT_THAT(delivered_packets, |
| 192 | ElementsAre(PacketDeliveryInfo( |
| 193 | /*source=*/packet_2, |
| 194 | /*receive_time_us=*/TimeDelta::Millis(1100).us()))); |
| 195 | } |
| 196 | |
| 197 | TEST(SimulatedNetworkTest, NetworkEmptyAfterLastPacketDequeued) { |
| 198 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 199 | // should be ready to exit the network in 1 second. |
| 200 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 201 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125))); |
| 202 | |
| 203 | // Collecting all the delivered packets ... |
| 204 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 205 | network.DequeueDeliverablePackets( |
| 206 | /*receive_time_us=*/TimeDelta::Seconds(1).us()); |
| 207 | EXPECT_EQ(delivered_packets.size(), 1ul); |
| 208 | |
| 209 | // ... leaves the network empty. |
| 210 | EXPECT_EQ(network.NextDeliveryTimeUs(), absl::nullopt); |
| 211 | } |
| 212 | |
| 213 | TEST(SimulatedNetworkTest, DequeueDeliverablePacketsOnLateCall) { |
| 214 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 215 | // should be ready to exit the network in 1 second. |
| 216 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 217 | ASSERT_TRUE(network.EnqueuePacket( |
| 218 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 219 | |
| 220 | // Enqueue another packet of 125 bytes with send time 1 second so this should |
| 221 | // exit after 2 seconds. |
| 222 | ASSERT_TRUE(network.EnqueuePacket( |
| 223 | PacketInFlightInfo(/*size=*/125, |
| 224 | /*send_time_us=*/TimeDelta::Seconds(1).us(), |
| 225 | /*packet_id=*/2))); |
| 226 | |
| 227 | // Collecting delivered packets after 3 seconds will result in the delivery of |
| 228 | // both the enqueued packets. |
| 229 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 230 | network.DequeueDeliverablePackets( |
| 231 | /*receive_time_us=*/TimeDelta::Seconds(3).us()); |
| 232 | EXPECT_EQ(delivered_packets.size(), 2ul); |
| 233 | } |
| 234 | |
| 235 | TEST(SimulatedNetworkTest, |
| 236 | DequeueDeliverablePacketsOnEarlyCallReturnsNoPackets) { |
| 237 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 238 | // should be ready to exit the network in 1 second. |
| 239 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 240 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125))); |
| 241 | |
| 242 | // Collecting delivered packets after 0.5 seconds will result in the delivery |
| 243 | // of 0 packets. |
| 244 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 245 | network.DequeueDeliverablePackets( |
| 246 | /*receive_time_us=*/TimeDelta::Seconds(0.5).us()); |
| 247 | EXPECT_EQ(delivered_packets.size(), 0ul); |
| 248 | |
| 249 | // Since the first enqueued packet was supposed to exit after 1 second. |
| 250 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 251 | } |
| 252 | |
| 253 | TEST(SimulatedNetworkTest, QueueDelayMsWithoutStandardDeviation) { |
| 254 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 255 | // should be ready to exit the network in 1 second. |
| 256 | SimulatedNetwork network = |
| 257 | SimulatedNetwork({.queue_delay_ms = 100, .link_capacity_kbps = 1}); |
| 258 | ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125))); |
| 259 | // The next delivery time is still 1 second even if there are 100 ms of |
| 260 | // extra delay but this will be applied at DequeueDeliverablePackets time. |
| 261 | ASSERT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 262 | |
| 263 | // Since all packets are delayed by 100 ms, after 1 second, no packets will |
| 264 | // exit the network. |
| 265 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 266 | network.DequeueDeliverablePackets( |
| 267 | /*receive_time_us=*/TimeDelta::Seconds(1).us()); |
| 268 | EXPECT_EQ(delivered_packets.size(), 0ul); |
| 269 | |
| 270 | // And the updated next delivery time takes into account the extra delay of |
| 271 | // 100 ms so the first packet in the network will be delivered after 1.1 |
| 272 | // seconds. |
| 273 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Millis(1100).us()); |
| 274 | delivered_packets = network.DequeueDeliverablePackets( |
| 275 | /*receive_time_us=*/TimeDelta::Millis(1100).us()); |
| 276 | EXPECT_EQ(delivered_packets.size(), 1ul); |
| 277 | } |
| 278 | |
| 279 | TEST(SimulatedNetworkTest, |
| 280 | QueueDelayMsWithStandardDeviationAndReorderNotAllowed) { |
| 281 | SimulatedNetwork network = |
| 282 | SimulatedNetwork({.queue_delay_ms = 100, |
| 283 | .delay_standard_deviation_ms = 90, |
| 284 | .link_capacity_kbps = 1, |
| 285 | .allow_reordering = false}); |
| 286 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 287 | // should be ready to exit the network in 1 second. |
| 288 | ASSERT_TRUE(network.EnqueuePacket( |
| 289 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 290 | |
| 291 | // But 3 more packets of size 1 byte are enqueued at the same time. |
| 292 | ASSERT_TRUE(network.EnqueuePacket( |
| 293 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/2))); |
| 294 | ASSERT_TRUE(network.EnqueuePacket( |
| 295 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/3))); |
| 296 | ASSERT_TRUE(network.EnqueuePacket( |
| 297 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/4))); |
| 298 | |
| 299 | // After 5 seconds all of them exit the network. |
| 300 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 301 | network.DequeueDeliverablePackets( |
| 302 | /*receive_time_us=*/TimeDelta::Seconds(5).us()); |
| 303 | ASSERT_EQ(delivered_packets.size(), 4ul); |
| 304 | |
| 305 | // And they are still in order even if the delay was applied. |
| 306 | EXPECT_EQ(delivered_packets[0].packet_id, 1ul); |
| 307 | EXPECT_EQ(delivered_packets[1].packet_id, 2ul); |
| 308 | EXPECT_GE(delivered_packets[1].receive_time_us, |
| 309 | delivered_packets[0].receive_time_us); |
| 310 | EXPECT_EQ(delivered_packets[2].packet_id, 3ul); |
| 311 | EXPECT_GE(delivered_packets[2].receive_time_us, |
| 312 | delivered_packets[1].receive_time_us); |
| 313 | EXPECT_EQ(delivered_packets[3].packet_id, 4ul); |
| 314 | EXPECT_GE(delivered_packets[3].receive_time_us, |
| 315 | delivered_packets[2].receive_time_us); |
| 316 | } |
| 317 | |
| 318 | TEST(SimulatedNetworkTest, QueueDelayMsWithStandardDeviationAndReorderAllowed) { |
| 319 | SimulatedNetwork network = |
| 320 | SimulatedNetwork({.queue_delay_ms = 100, |
| 321 | .delay_standard_deviation_ms = 90, |
| 322 | .link_capacity_kbps = 1, |
| 323 | .allow_reordering = true}, |
| 324 | /*random_seed=*/1); |
| 325 | // A packet of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 326 | // should be ready to exit the network in 1 second. |
| 327 | ASSERT_TRUE(network.EnqueuePacket( |
| 328 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 329 | |
| 330 | // But 3 more packets of size 1 byte are enqueued at the same time. |
| 331 | ASSERT_TRUE(network.EnqueuePacket( |
| 332 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/2))); |
| 333 | ASSERT_TRUE(network.EnqueuePacket( |
| 334 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/3))); |
| 335 | ASSERT_TRUE(network.EnqueuePacket( |
| 336 | PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/4))); |
| 337 | |
| 338 | // After 5 seconds all of them exit the network. |
| 339 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 340 | network.DequeueDeliverablePackets( |
| 341 | /*receive_time_us=*/TimeDelta::Seconds(5).us()); |
| 342 | ASSERT_EQ(delivered_packets.size(), 4ul); |
| 343 | |
| 344 | // And they have been reordered accorting to the applied extra delay. |
| 345 | EXPECT_EQ(delivered_packets[0].packet_id, 3ul); |
| 346 | EXPECT_EQ(delivered_packets[1].packet_id, 1ul); |
| 347 | EXPECT_GE(delivered_packets[1].receive_time_us, |
| 348 | delivered_packets[0].receive_time_us); |
| 349 | EXPECT_EQ(delivered_packets[2].packet_id, 2ul); |
| 350 | EXPECT_GE(delivered_packets[2].receive_time_us, |
| 351 | delivered_packets[1].receive_time_us); |
| 352 | EXPECT_EQ(delivered_packets[3].packet_id, 4ul); |
| 353 | EXPECT_GE(delivered_packets[3].receive_time_us, |
| 354 | delivered_packets[2].receive_time_us); |
| 355 | } |
| 356 | |
| 357 | TEST(SimulatedNetworkTest, PacketLoss) { |
| 358 | // On a network with 50% probablility of packet loss ... |
| 359 | SimulatedNetwork network = SimulatedNetwork({.loss_percent = 50}); |
| 360 | |
| 361 | // Enqueueing 8 packets ... |
| 362 | for (int i = 0; i < 8; i++) { |
| 363 | ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 364 | /*size=*/1, /*send_time_us=*/0, /*packet_id=*/i + 1))); |
| 365 | } |
| 366 | |
| 367 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 368 | network.DequeueDeliverablePackets( |
| 369 | /*receive_time_us=*/TimeDelta::Seconds(5).us()); |
| 370 | EXPECT_EQ(delivered_packets.size(), 8ul); |
| 371 | |
| 372 | // Results in the loss of 4 of them. |
| 373 | int lost_packets = 0; |
| 374 | for (const auto& packet : delivered_packets) { |
| 375 | if (packet.receive_time_us == PacketDeliveryInfo::kNotReceived) { |
| 376 | lost_packets++; |
| 377 | } |
| 378 | } |
| 379 | EXPECT_EQ(lost_packets, 4); |
| 380 | } |
| 381 | |
| 382 | TEST(SimulatedNetworkTest, PacketLossBurst) { |
| 383 | // On a network with 50% probablility of packet loss and an average burst loss |
| 384 | // length of 100 ... |
| 385 | SimulatedNetwork network = SimulatedNetwork( |
| 386 | {.loss_percent = 50, .avg_burst_loss_length = 100}, /*random_seed=*/1); |
| 387 | |
| 388 | // Enqueueing 20 packets ... |
| 389 | for (int i = 0; i < 20; i++) { |
| 390 | ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 391 | /*size=*/1, /*send_time_us=*/0, /*packet_id=*/i + 1))); |
| 392 | } |
| 393 | |
| 394 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 395 | network.DequeueDeliverablePackets( |
| 396 | /*receive_time_us=*/TimeDelta::Seconds(5).us()); |
| 397 | EXPECT_EQ(delivered_packets.size(), 20ul); |
| 398 | |
| 399 | // Results in a burst of lost packets after the first packet lost. |
| 400 | // With the current random seed, the first 12 are not lost, while the |
| 401 | // last 8 are. |
| 402 | int current_packet = 0; |
| 403 | for (const auto& packet : delivered_packets) { |
| 404 | if (current_packet < 12) { |
| 405 | EXPECT_NE(packet.receive_time_us, PacketDeliveryInfo::kNotReceived); |
| 406 | current_packet++; |
| 407 | } else { |
| 408 | EXPECT_EQ(packet.receive_time_us, PacketDeliveryInfo::kNotReceived); |
| 409 | current_packet++; |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | TEST(SimulatedNetworkTest, PauseTransmissionUntil) { |
| 415 | // 3 packets of 125 bytes that gets enqueued on a network with 1 kbps capacity |
| 416 | // should be ready to exit the network after 1, 2 and 3 seconds respectively. |
| 417 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 418 | ASSERT_TRUE(network.EnqueuePacket( |
| 419 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/1))); |
| 420 | ASSERT_TRUE(network.EnqueuePacket( |
| 421 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/2))); |
| 422 | ASSERT_TRUE(network.EnqueuePacket( |
| 423 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/3))); |
| 424 | ASSERT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us()); |
| 425 | |
| 426 | // The network gets paused for 5 seconds, which means that the first packet |
| 427 | // can exit after 5 seconds instead of 1 second. |
| 428 | network.PauseTransmissionUntil(TimeDelta::Seconds(5).us()); |
| 429 | |
| 430 | // No packets after 1 second. |
| 431 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 432 | network.DequeueDeliverablePackets( |
| 433 | /*receive_time_us=*/TimeDelta::Seconds(1).us()); |
| 434 | EXPECT_EQ(delivered_packets.size(), 0ul); |
| 435 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(5).us()); |
| 436 | |
| 437 | // The first packet exits after 5 seconds. |
| 438 | delivered_packets = network.DequeueDeliverablePackets( |
| 439 | /*receive_time_us=*/TimeDelta::Seconds(5).us()); |
| 440 | EXPECT_EQ(delivered_packets.size(), 1ul); |
| 441 | |
| 442 | // After the first packet is exited, the next delivery time reflects the |
| 443 | // delivery time of the next packet which accounts for the network pause. |
| 444 | EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(6).us()); |
| 445 | |
| 446 | // And 2 seconds after the exit of the first enqueued packet, the following 2 |
| 447 | // packets are also delivered. |
| 448 | delivered_packets = network.DequeueDeliverablePackets( |
| 449 | /*receive_time_us=*/TimeDelta::Seconds(7).us()); |
| 450 | EXPECT_EQ(delivered_packets.size(), 2ul); |
| 451 | } |
| 452 | |
| 453 | TEST(SimulatedNetworkTest, CongestedNetworkRespectsLinkCapacity) { |
| 454 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 455 | for (size_t i = 0; i < 1'000; ++i) { |
| 456 | ASSERT_TRUE(network.EnqueuePacket( |
| 457 | PacketInFlightInfo(/*size=*/125, /*send_time_us=*/0, /*packet_id=*/i))); |
| 458 | } |
| 459 | PacketDeliveryInfo last_delivered_packet{ |
| 460 | PacketInFlightInfo(/*size=*/0, /*send_time_us=*/0, /*packet_id=*/0), 0}; |
| 461 | while (network.NextDeliveryTimeUs().has_value()) { |
| 462 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 463 | network.DequeueDeliverablePackets( |
| 464 | /*receive_time_us=*/network.NextDeliveryTimeUs().value()); |
| 465 | if (!delivered_packets.empty()) { |
| 466 | last_delivered_packet = delivered_packets.back(); |
| 467 | } |
| 468 | } |
| 469 | // 1000 packets of 1000 bits each will take 1000 seconds to exit a 1 kpbs |
| 470 | // network. |
| 471 | EXPECT_EQ(last_delivered_packet.receive_time_us, |
| 472 | TimeDelta::Seconds(1000).us()); |
| 473 | EXPECT_EQ(last_delivered_packet.packet_id, 999ul); |
| 474 | } |
| 475 | |
| 476 | TEST(SimulatedNetworkTest, EnqueuePacketWithSubSecondNonMonotonicBehaviour) { |
| 477 | // On multi-core systems, different threads can experience sub-millisecond non |
| 478 | // monothonic behaviour when running on different cores. This test checks that |
| 479 | // when a non monotonic packet enqueue, the network continues to work and the |
| 480 | // out of order packet is sent anyway. |
| 481 | SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 482 | ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 483 | /*size=*/125, /*send_time_us=*/TimeDelta::Seconds(1).us(), |
| 484 | /*packet_id=*/0))); |
| 485 | ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 486 | /*size=*/125, /*send_time_us=*/TimeDelta::Seconds(1).us() - 1, |
| 487 | /*packet_id=*/1))); |
| 488 | |
| 489 | std::vector<PacketDeliveryInfo> delivered_packets = |
| 490 | network.DequeueDeliverablePackets( |
| 491 | /*receive_time_us=*/TimeDelta::Seconds(2).us()); |
| 492 | ASSERT_EQ(delivered_packets.size(), 1ul); |
| 493 | EXPECT_EQ(delivered_packets[0].packet_id, 0ul); |
| 494 | EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(2).us()); |
| 495 | |
| 496 | delivered_packets = network.DequeueDeliverablePackets( |
| 497 | /*receive_time_us=*/TimeDelta::Seconds(3).us()); |
| 498 | ASSERT_EQ(delivered_packets.size(), 1ul); |
| 499 | EXPECT_EQ(delivered_packets[0].packet_id, 1ul); |
| 500 | EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(3).us()); |
| 501 | } |
| 502 | |
| 503 | // TODO(bugs.webrtc.org/14525): Re-enable when the DCHECK will be uncommented |
| 504 | // and the non-monotonic events on real time clock tests is solved/understood. |
| 505 | // TEST(SimulatedNetworkDeathTest, EnqueuePacketExpectMonotonicSendTime) { |
| 506 | // SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1}); |
| 507 | // ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo( |
| 508 | // /*size=*/125, /*send_time_us=*/2'000'000, /*packet_id=*/0))); |
| 509 | // EXPECT_DEATH_IF_SUPPORTED(network.EnqueuePacket(PacketInFlightInfo( |
| 510 | // /*size=*/125, /*send_time_us=*/900'000, /*packet_id=*/1)), ""); |
| 511 | // } |
| 512 | } // namespace |
| 513 | } // namespace webrtc |