| /* | 
 |  *  Copyright (c) 2012 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/fake_network_pipe.h" | 
 |  | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #include "call/simulated_network.h" | 
 | #include "system_wrappers/include/clock.h" | 
 | #include "test/gmock.h" | 
 | #include "test/gtest.h" | 
 |  | 
 | using ::testing::_; | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | class MockReceiver : public PacketReceiver { | 
 |  public: | 
 |   MOCK_METHOD3(DeliverPacket, | 
 |                DeliveryStatus(MediaType, rtc::CopyOnWriteBuffer, int64_t)); | 
 |   virtual ~MockReceiver() = default; | 
 | }; | 
 |  | 
 | class ReorderTestReceiver : public MockReceiver { | 
 |  public: | 
 |   DeliveryStatus DeliverPacket(MediaType media_type, | 
 |                                rtc::CopyOnWriteBuffer packet, | 
 |                                int64_t /* packet_time_us */) override { | 
 |     RTC_DCHECK_GE(packet.size(), sizeof(int)); | 
 |     int seq_num; | 
 |     memcpy(&seq_num, packet.data<uint8_t>(), sizeof(int)); | 
 |     delivered_sequence_numbers_.push_back(seq_num); | 
 |     return DeliveryStatus::DELIVERY_OK; | 
 |   } | 
 |   std::vector<int> delivered_sequence_numbers_; | 
 | }; | 
 |  | 
 | class FakeNetworkPipeTest : public ::testing::Test { | 
 |  public: | 
 |   FakeNetworkPipeTest() : fake_clock_(12345) {} | 
 |  | 
 |  protected: | 
 |   void SendPackets(FakeNetworkPipe* pipe, int number_packets, int packet_size) { | 
 |     RTC_DCHECK_GE(packet_size, sizeof(int)); | 
 |     std::unique_ptr<uint8_t[]> packet(new uint8_t[packet_size]); | 
 |     for (int i = 0; i < number_packets; ++i) { | 
 |       // Set a sequence number for the packets by | 
 |       // using the first bytes in the packet. | 
 |       memcpy(packet.get(), &i, sizeof(int)); | 
 |       rtc::CopyOnWriteBuffer buffer(packet.get(), packet_size); | 
 |       pipe->DeliverPacket(MediaType::ANY, buffer, /* packet_time_us */ -1); | 
 |     } | 
 |   } | 
 |  | 
 |   int PacketTimeMs(int capacity_kbps, int packet_size) const { | 
 |     return 8 * packet_size / capacity_kbps; | 
 |   } | 
 |  | 
 |   SimulatedClock fake_clock_; | 
 | }; | 
 |  | 
 | // Test the capacity link and verify we get as many packets as we expect. | 
 | TEST_F(FakeNetworkPipeTest, CapacityTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 20; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to | 
 |   // get through the pipe. | 
 |   const int kNumPackets = 10; | 
 |   const int kPacketSize = 1000; | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |  | 
 |   // Time to get one packet through the link. | 
 |   const int kPacketTimeMs = | 
 |       PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Time haven't increased yet, so we souldn't get any packets. | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance enough time to release one packet. | 
 |   fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 |  | 
 |   // Release all but one packet | 
 |   fake_clock_.AdvanceTimeMilliseconds(9 * kPacketTimeMs - 1); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(8); | 
 |   pipe->Process(); | 
 |  | 
 |   // And the last one. | 
 |   fake_clock_.AdvanceTimeMilliseconds(1); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | // Test the extra network delay. | 
 | TEST_F(FakeNetworkPipeTest, ExtraDelayTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 20; | 
 |   config.queue_delay_ms = 100; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   const int kNumPackets = 2; | 
 |   const int kPacketSize = 1000; | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |  | 
 |   // Time to get one packet through the link. | 
 |   const int kPacketTimeMs = | 
 |       PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Increase more than kPacketTimeMs, but not more than the extra delay. | 
 |   fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance the network delay to get the first packet. | 
 |   fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance one more kPacketTimeMs to get the last packet. | 
 |   fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | // Test the number of buffers and packets are dropped when sending too many | 
 | // packets too quickly. | 
 | TEST_F(FakeNetworkPipeTest, QueueLengthTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 2; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   const int kPacketSize = 1000; | 
 |   const int kPacketTimeMs = | 
 |       PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Send three packets and verify only 2 are delivered. | 
 |   SendPackets(pipe.get(), 3, kPacketSize); | 
 |  | 
 |   // Increase time enough to deliver all three packets, verify only two are | 
 |   // delivered. | 
 |   fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(2); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | // Test we get statistics as expected. | 
 | TEST_F(FakeNetworkPipeTest, StatisticsTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 2; | 
 |   config.queue_delay_ms = 20; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   const int kPacketSize = 1000; | 
 |   const int kPacketTimeMs = | 
 |       PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Send three packets and verify only 2 are delivered. | 
 |   SendPackets(pipe.get(), 3, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs + | 
 |                                       config.queue_delay_ms); | 
 |  | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(2); | 
 |   pipe->Process(); | 
 |  | 
 |   // Packet 1: kPacketTimeMs + config.queue_delay_ms, | 
 |   // packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average. | 
 |   EXPECT_EQ(pipe->AverageDelay(), 170); | 
 |   EXPECT_EQ(pipe->SentPackets(), 2u); | 
 |   EXPECT_EQ(pipe->DroppedPackets(), 1u); | 
 |   EXPECT_EQ(pipe->PercentageLoss(), 1 / 3.f); | 
 | } | 
 |  | 
 | // Change the link capacity half-way through the test and verify that the | 
 | // delivery times change accordingly. | 
 | TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 20; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); | 
 |   SimulatedNetwork* simulated_network = network.get(); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe( | 
 |       new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); | 
 |  | 
 |   // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to | 
 |   // get through the pipe. | 
 |   const int kNumPackets = 10; | 
 |   const int kPacketSize = 1000; | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |  | 
 |   // Time to get one packet through the link. | 
 |   int packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Time hasn't increased yet, so we souldn't get any packets. | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance time in steps to release one packet at a time. | 
 |   for (int i = 0; i < kNumPackets; ++i) { | 
 |     fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); | 
 |     EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |     pipe->Process(); | 
 |   } | 
 |  | 
 |   // Change the capacity. | 
 |   config.link_capacity_kbps /= 2;  // Reduce to 50%. | 
 |   simulated_network->SetConfig(config); | 
 |  | 
 |   // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two | 
 |   // seconds to get them through the pipe. | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |  | 
 |   // Time to get one packet through the link. | 
 |   packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |  | 
 |   // Time hasn't increased yet, so we souldn't get any packets. | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance time in steps to release one packet at a time. | 
 |   for (int i = 0; i < kNumPackets; ++i) { | 
 |     fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); | 
 |     EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |     pipe->Process(); | 
 |   } | 
 |  | 
 |   // Check that all the packets were sent. | 
 |   EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->SentPackets()); | 
 |   EXPECT_FALSE(pipe->TimeUntilNextProcess().has_value()); | 
 |   fake_clock_.AdvanceTimeMilliseconds(1000); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | // Change the link capacity half-way through the test and verify that the | 
 | // delivery times change accordingly. | 
 | TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 20; | 
 |   config.link_capacity_kbps = 80; | 
 |   MockReceiver receiver; | 
 |   std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); | 
 |   SimulatedNetwork* simulated_network = network.get(); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe( | 
 |       new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); | 
 |  | 
 |   // Add 20 packets of 1000 bytes, = 80 kb. | 
 |   const int kNumPackets = 20; | 
 |   const int kPacketSize = 1000; | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |  | 
 |   // Time hasn't increased yet, so we souldn't get any packets. | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 |  | 
 |   // Advance time in steps to release half of the packets one at a time. | 
 |   int step_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |   for (int i = 0; i < kNumPackets / 2; ++i) { | 
 |     fake_clock_.AdvanceTimeMilliseconds(step_ms); | 
 |     EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |     pipe->Process(); | 
 |   } | 
 |  | 
 |   // Change the capacity. | 
 |   config.link_capacity_kbps *= 2;  // Double the capacity. | 
 |   simulated_network->SetConfig(config); | 
 |  | 
 |   // Advance time in steps to release remaining packets one at a time. | 
 |   step_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |   for (int i = 0; i < kNumPackets / 2; ++i) { | 
 |     fake_clock_.AdvanceTimeMilliseconds(step_ms); | 
 |     EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |     pipe->Process(); | 
 |   } | 
 |  | 
 |   // Check that all the packets were sent. | 
 |   EXPECT_EQ(static_cast<size_t>(kNumPackets), pipe->SentPackets()); | 
 |   EXPECT_FALSE(pipe->TimeUntilNextProcess().has_value()); | 
 |   fake_clock_.AdvanceTimeMilliseconds(1000); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | // At first disallow reordering and then allow reordering. | 
 | TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = 1000; | 
 |   config.link_capacity_kbps = 800; | 
 |   config.queue_delay_ms = 100; | 
 |   config.delay_standard_deviation_ms = 10; | 
 |   ReorderTestReceiver receiver; | 
 |   std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); | 
 |   SimulatedNetwork* simulated_network = network.get(); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe( | 
 |       new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); | 
 |  | 
 |   const uint32_t kNumPackets = 100; | 
 |   const int kPacketSize = 10; | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(1000); | 
 |   pipe->Process(); | 
 |  | 
 |   // Confirm that all packets have been delivered in order. | 
 |   EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size()); | 
 |   int last_seq_num = -1; | 
 |   for (int seq_num : receiver.delivered_sequence_numbers_) { | 
 |     EXPECT_GT(seq_num, last_seq_num); | 
 |     last_seq_num = seq_num; | 
 |   } | 
 |  | 
 |   config.allow_reordering = true; | 
 |   simulated_network->SetConfig(config); | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(1000); | 
 |   receiver.delivered_sequence_numbers_.clear(); | 
 |   pipe->Process(); | 
 |  | 
 |   // Confirm that all packets have been delivered | 
 |   // and that reordering has occured. | 
 |   EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size()); | 
 |   bool reordering_has_occured = false; | 
 |   last_seq_num = -1; | 
 |   for (int seq_num : receiver.delivered_sequence_numbers_) { | 
 |     if (last_seq_num > seq_num) { | 
 |       reordering_has_occured = true; | 
 |       break; | 
 |     } | 
 |     last_seq_num = seq_num; | 
 |   } | 
 |   EXPECT_TRUE(reordering_has_occured); | 
 | } | 
 |  | 
 | TEST_F(FakeNetworkPipeTest, BurstLoss) { | 
 |   const int kLossPercent = 5; | 
 |   const int kAvgBurstLength = 3; | 
 |   const int kNumPackets = 10000; | 
 |   const int kPacketSize = 10; | 
 |  | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.queue_length_packets = kNumPackets; | 
 |   config.loss_percent = kLossPercent; | 
 |   config.avg_burst_loss_length = kAvgBurstLength; | 
 |   ReorderTestReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   SendPackets(pipe.get(), kNumPackets, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(1000); | 
 |   pipe->Process(); | 
 |  | 
 |   // Check that the average loss is |kLossPercent| percent. | 
 |   int lost_packets = kNumPackets - receiver.delivered_sequence_numbers_.size(); | 
 |   double loss_fraction = lost_packets / static_cast<double>(kNumPackets); | 
 |  | 
 |   EXPECT_NEAR(kLossPercent / 100.0, loss_fraction, 0.05); | 
 |  | 
 |   // Find the number of bursts that has occurred. | 
 |   size_t received_packets = receiver.delivered_sequence_numbers_.size(); | 
 |   int num_bursts = 0; | 
 |   for (size_t i = 0; i < received_packets - 1; ++i) { | 
 |     int diff = receiver.delivered_sequence_numbers_[i + 1] - | 
 |                receiver.delivered_sequence_numbers_[i]; | 
 |     if (diff > 1) | 
 |       ++num_bursts; | 
 |   } | 
 |  | 
 |   double average_burst_length = static_cast<double>(lost_packets) / num_bursts; | 
 |  | 
 |   EXPECT_NEAR(kAvgBurstLength, average_burst_length, 0.3); | 
 | } | 
 |  | 
 | TEST_F(FakeNetworkPipeTest, SetReceiver) { | 
 |   BuiltInNetworkBehaviorConfig config; | 
 |   config.link_capacity_kbps = 800; | 
 |   MockReceiver receiver; | 
 |   auto simulated_network = std::make_unique<SimulatedNetwork>(config); | 
 |   std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( | 
 |       &fake_clock_, std::move(simulated_network), &receiver)); | 
 |  | 
 |   const int kPacketSize = 1000; | 
 |   const int kPacketTimeMs = | 
 |       PacketTimeMs(config.link_capacity_kbps, kPacketSize); | 
 |   SendPackets(pipe.get(), 1, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 |  | 
 |   MockReceiver new_receiver; | 
 |   pipe->SetReceiver(&new_receiver); | 
 |  | 
 |   SendPackets(pipe.get(), 1, kPacketSize); | 
 |   fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); | 
 |   EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); | 
 |   EXPECT_CALL(new_receiver, DeliverPacket(_, _, _)).Times(1); | 
 |   pipe->Process(); | 
 | } | 
 |  | 
 | }  // namespace webrtc |