Adds test for loss based controller under cross traffic induced loss.

Bug: webrtc:9883
Change-Id: I85a83dd15afe523e0ba5b3a723979317f0b98ab7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156501
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29465}
diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc
index 51f3cd7..9503ada 100644
--- a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc
+++ b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc
@@ -555,6 +555,58 @@
   EXPECT_GT(client->target_rate().kbps(), 100);
 }
 
+DataRate AverageBitrateAfterCrossInducedLoss(std::string name) {
+  Scenario s(name, false);
+  NetworkSimulationConfig net_conf;
+  net_conf.bandwidth = DataRate::kbps(1000);
+  net_conf.delay = TimeDelta::ms(100);
+  // Short queue length means that we'll induce loss when sudden TCP traffic
+  // spikes are induced. This corresponds to ca 200 ms for a packet size of 1000
+  // bytes. Such limited buffers are common on for instance wifi routers.
+  net_conf.packet_queue_length_limit = 25;
+
+  auto send_net = {s.CreateSimulationNode(net_conf)};
+  auto ret_net = {s.CreateSimulationNode(net_conf)};
+
+  auto* client = s.CreateClient("send", CallClientConfig());
+  auto* route = s.CreateRoutes(
+      client, send_net, s.CreateClient("return", CallClientConfig()), ret_net);
+  auto* video = s.CreateVideoStream(route->forward(), VideoStreamConfig());
+  s.RunFor(TimeDelta::seconds(10));
+  for (int i = 0; i < 4; ++i) {
+    // Sends TCP cross traffic inducing loss.
+    auto* tcp_traffic =
+        s.net()->StartFakeTcpCrossTraffic(send_net, ret_net, FakeTcpConfig());
+    s.RunFor(TimeDelta::seconds(2));
+    // Allow the ccongestion controller to recover.
+    s.net()->StopCrossTraffic(tcp_traffic);
+    s.RunFor(TimeDelta::seconds(20));
+  }
+  return DataSize::bytes(video->receive()
+                             ->GetStats()
+                             .rtp_stats.packet_counter.TotalBytes()) /
+         s.TimeSinceStart();
+}
+
+TEST_F(GoogCcNetworkControllerTest,
+       NoLossBasedRecoversSlowerAfterCrossInducedLoss) {
+  // This test acts as a reference for the test below, showing that wihtout the
+  // trial, we have worse behavior.
+  DataRate average_bitrate =
+      AverageBitrateAfterCrossInducedLoss("googcc_unit/no_cross_loss_based");
+  RTC_DCHECK_LE(average_bitrate, DataRate::kbps(650));
+}
+
+TEST_F(GoogCcNetworkControllerTest,
+       LossBasedRecoversFasterAfterCrossInducedLoss) {
+  // We recover bitrate better when subject to loss spikes from cross traffic
+  // when loss based controller is used.
+  ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
+  DataRate average_bitrate =
+      AverageBitrateAfterCrossInducedLoss("googcc_unit/cross_loss_based");
+  RTC_DCHECK_GE(average_bitrate, DataRate::kbps(750));
+}
+
 TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
   ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
   Scenario s("googcc_unit/moderate_loss_channel", false);
diff --git a/test/scenario/network_node.cc b/test/scenario/network_node.cc
index b936fcb..d381152 100644
--- a/test/scenario/network_node.cc
+++ b/test/scenario/network_node.cc
@@ -29,6 +29,8 @@
   sim_config.packet_overhead = config.packet_overhead.bytes<int>();
   sim_config.codel_active_queue_management =
       config.codel_active_queue_management;
+  sim_config.queue_length_packets =
+      config.packet_queue_length_limit.value_or(0);
   return sim_config;
 }
 }  // namespace
diff --git a/test/scenario/scenario_config.h b/test/scenario/scenario_config.h
index 13d85c3..e769e80 100644
--- a/test/scenario/scenario_config.h
+++ b/test/scenario/scenario_config.h
@@ -223,6 +223,7 @@
   TimeDelta delay_std_dev = TimeDelta::Zero();
   double loss_rate = 0;
   bool codel_active_queue_management = false;
+  absl::optional<int> packet_queue_length_limit;
   DataSize packet_overhead = DataSize::Zero();
 };
 }  // namespace test