* Copyright 2022 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "call/simulated_network.h"
#include <algorithm>
#include <map>
#include <optional>
#include <set>
#include <vector>
#include "absl/algorithm/container.h"
#include "api/test/simulated_network.h"
#include "api/units/data_rate.h"
#include "api/units/time_delta.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAre;
PacketInFlightInfo PacketWithSize(size_t size) {
return PacketInFlightInfo(size, 0, 1);
}
TEST(SimulatedNetworkTest, NextDeliveryTimeIsUnknownOnEmptyNetwork) {
SimulatedNetwork network = SimulatedNetwork({});
EXPECT_EQ(network.NextDeliveryTimeUs(), absl::nullopt);
}
TEST(SimulatedNetworkTest, EnqueueFirstPacketOnNetworkWithInfiniteCapacity) {
SimulatedNetwork network = SimulatedNetwork({});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(1'000)));
EXPECT_EQ(network.NextDeliveryTimeUs(), 0);
}
TEST(SimulatedNetworkTest, EnqueueFirstPacketOnNetworkWithLimitedCapacity) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
}
TEST(SimulatedNetworkTest,
EnqueuePacketsButNextDeliveryIsBasedOnFirstEnqueuedPacket) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 100, 2)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo(
125, TimeDelta::Seconds(2).us(),
3)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
}
TEST(SimulatedNetworkTest, EnqueueFailsWhenQueueLengthIsReached) {
SimulatedNetwork network =
SimulatedNetwork({.queue_length_packets = 1, .link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
EXPECT_FALSE(network.EnqueuePacket(
PacketInFlightInfo(125,
TimeDelta::Seconds(0.5).us(),
2)));
EXPECT_FALSE(network.EnqueuePacket(
PacketInFlightInfo(125,
TimeDelta::Seconds(2).us(),
3)));
}
TEST(SimulatedNetworkTest, PacketOverhead) {
SimulatedNetwork network =
SimulatedNetwork({.link_capacity_kbps = 1, .packet_overhead = 125});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(2).us());
}
TEST(SimulatedNetworkTest,
DequeueDeliverablePacketsLeavesPacketsInCapacityLink) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125,
TimeDelta::Seconds(1).us(),
2)));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(1).us());
ASSERT_EQ(delivered_packets.size(), 1ul);
EXPECT_EQ(delivered_packets[0].packet_id, 1ul);
EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(1).us());
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(2).us());
}
TEST(SimulatedNetworkTest,
DequeueDeliverablePacketsAppliesConfigChangesToCapacityLink) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
const PacketInFlightInfo packet_1 =
PacketInFlightInfo(125, 0, 1);
ASSERT_TRUE(network.EnqueuePacket(packet_1));
PacketInFlightInfo packet_2 =
PacketInFlightInfo(125,
TimeDelta::Seconds(1).us(),
2);
ASSERT_TRUE(network.EnqueuePacket(packet_2));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
network.SetConfig({.link_capacity_kbps = 10});
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Millis(100).us());
ASSERT_EQ(delivered_packets.size(), 1ul);
EXPECT_THAT(delivered_packets,
ElementsAre(PacketDeliveryInfo(
packet_1,
TimeDelta::Millis(100).us())));
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Millis(1100).us());
delivered_packets = network.DequeueDeliverablePackets(
TimeDelta::Millis(1100).us());
ASSERT_EQ(delivered_packets.size(), 1ul);
EXPECT_THAT(delivered_packets,
ElementsAre(PacketDeliveryInfo(
packet_2,
TimeDelta::Millis(1100).us())));
}
TEST(SimulatedNetworkTest, NetworkEmptyAfterLastPacketDequeued) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(1).us());
EXPECT_EQ(delivered_packets.size(), 1ul);
EXPECT_EQ(network.NextDeliveryTimeUs(), absl::nullopt);
}
TEST(SimulatedNetworkTest, DequeueDeliverablePacketsOnLateCall) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125,
TimeDelta::Seconds(1).us(),
2)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(3).us());
EXPECT_EQ(delivered_packets.size(), 2ul);
}
TEST(SimulatedNetworkTest,
DequeueDeliverablePacketsOnEarlyCallReturnsNoPackets) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(0.5).us());
EXPECT_EQ(delivered_packets.size(), 0ul);
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
}
TEST(SimulatedNetworkTest, QueueDelayMsWithoutStandardDeviation) {
SimulatedNetwork network =
SimulatedNetwork({.queue_delay_ms = 100, .link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(PacketWithSize(125)));
ASSERT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(1).us());
EXPECT_EQ(delivered_packets.size(), 0ul);
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Millis(1100).us());
delivered_packets = network.DequeueDeliverablePackets(
TimeDelta::Millis(1100).us());
EXPECT_EQ(delivered_packets.size(), 1ul);
}
TEST(SimulatedNetworkTest,
QueueDelayMsWithStandardDeviationAndReorderNotAllowed) {
SimulatedNetwork network =
SimulatedNetwork({.queue_delay_ms = 100,
.delay_standard_deviation_ms = 90,
.link_capacity_kbps = 1,
.allow_reordering = false});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 2)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 3)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 4)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(5).us());
ASSERT_EQ(delivered_packets.size(), 4ul);
EXPECT_EQ(delivered_packets[0].packet_id, 1ul);
EXPECT_EQ(delivered_packets[1].packet_id, 2ul);
EXPECT_GE(delivered_packets[1].receive_time_us,
delivered_packets[0].receive_time_us);
EXPECT_EQ(delivered_packets[2].packet_id, 3ul);
EXPECT_GE(delivered_packets[2].receive_time_us,
delivered_packets[1].receive_time_us);
EXPECT_EQ(delivered_packets[3].packet_id, 4ul);
EXPECT_GE(delivered_packets[3].receive_time_us,
delivered_packets[2].receive_time_us);
}
TEST(SimulatedNetworkTest, QueueDelayMsWithStandardDeviationAndReorderAllowed) {
SimulatedNetwork network =
SimulatedNetwork({.queue_delay_ms = 100,
.delay_standard_deviation_ms = 90,
.link_capacity_kbps = 1,
.allow_reordering = true},
1);
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 2)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 3)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(1, 0, 4)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(5).us());
ASSERT_EQ(delivered_packets.size(), 4ul);
EXPECT_EQ(delivered_packets[0].packet_id, 3ul);
EXPECT_EQ(delivered_packets[1].packet_id, 1ul);
EXPECT_GE(delivered_packets[1].receive_time_us,
delivered_packets[0].receive_time_us);
EXPECT_EQ(delivered_packets[2].packet_id, 2ul);
EXPECT_GE(delivered_packets[2].receive_time_us,
delivered_packets[1].receive_time_us);
EXPECT_EQ(delivered_packets[3].packet_id, 4ul);
EXPECT_GE(delivered_packets[3].receive_time_us,
delivered_packets[2].receive_time_us);
}
TEST(SimulatedNetworkTest, PacketLoss) {
SimulatedNetwork network = SimulatedNetwork({.loss_percent = 50});
for (int i = 0; i < 8; i++) {
ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo(
1, 0, i + 1)));
}
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(5).us());
EXPECT_EQ(delivered_packets.size(), 8ul);
int lost_packets = 0;
for (const auto& packet : delivered_packets) {
if (packet.receive_time_us == PacketDeliveryInfo::kNotReceived) {
lost_packets++;
}
}
EXPECT_EQ(lost_packets, 4);
}
TEST(SimulatedNetworkTest, PacketLossBurst) {
SimulatedNetwork network = SimulatedNetwork(
{.loss_percent = 50, .avg_burst_loss_length = 100}, 1);
for (int i = 0; i < 20; i++) {
ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo(
1, 0, i + 1)));
}
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(5).us());
EXPECT_EQ(delivered_packets.size(), 20ul);
int current_packet = 0;
for (const auto& packet : delivered_packets) {
if (current_packet < 12) {
EXPECT_NE(packet.receive_time_us, PacketDeliveryInfo::kNotReceived);
current_packet++;
} else {
EXPECT_EQ(packet.receive_time_us, PacketDeliveryInfo::kNotReceived);
current_packet++;
}
}
}
TEST(SimulatedNetworkTest, PauseTransmissionUntil) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 1)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 2)));
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, 3)));
ASSERT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(1).us());
network.PauseTransmissionUntil(TimeDelta::Seconds(5).us());
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(1).us());
EXPECT_EQ(delivered_packets.size(), 0ul);
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(5).us());
delivered_packets = network.DequeueDeliverablePackets(
TimeDelta::Seconds(5).us());
EXPECT_EQ(delivered_packets.size(), 1ul);
EXPECT_EQ(network.NextDeliveryTimeUs(), TimeDelta::Seconds(6).us());
delivered_packets = network.DequeueDeliverablePackets(
TimeDelta::Seconds(7).us());
EXPECT_EQ(delivered_packets.size(), 2ul);
}
TEST(SimulatedNetworkTest, CongestedNetworkRespectsLinkCapacity) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
for (size_t i = 0; i < 1'000; ++i) {
ASSERT_TRUE(network.EnqueuePacket(
PacketInFlightInfo(125, 0, i)));
}
PacketDeliveryInfo last_delivered_packet{
PacketInFlightInfo(0, 0, 0), 0};
while (network.NextDeliveryTimeUs().has_value()) {
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
network.NextDeliveryTimeUs().value());
if (!delivered_packets.empty()) {
last_delivered_packet = delivered_packets.back();
}
}
EXPECT_EQ(last_delivered_packet.receive_time_us,
TimeDelta::Seconds(1000).us());
EXPECT_EQ(last_delivered_packet.packet_id, 999ul);
}
TEST(SimulatedNetworkTest, EnqueuePacketWithSubSecondNonMonotonicBehaviour) {
SimulatedNetwork network = SimulatedNetwork({.link_capacity_kbps = 1});
ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo(
125, TimeDelta::Seconds(1).us(),
0)));
ASSERT_TRUE(network.EnqueuePacket(PacketInFlightInfo(
125, TimeDelta::Seconds(1).us() - 1,
1)));
std::vector<PacketDeliveryInfo> delivered_packets =
network.DequeueDeliverablePackets(
TimeDelta::Seconds(2).us());
ASSERT_EQ(delivered_packets.size(), 1ul);
EXPECT_EQ(delivered_packets[0].packet_id, 0ul);
EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(2).us());
delivered_packets = network.DequeueDeliverablePackets(
TimeDelta::Seconds(3).us());
ASSERT_EQ(delivered_packets.size(), 1ul);
EXPECT_EQ(delivered_packets[0].packet_id, 1ul);
EXPECT_EQ(delivered_packets[0].receive_time_us, TimeDelta::Seconds(3).us());
}
}
}