| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "quic/test_tools/simulator/simulator.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "absl/container/node_hash_map.h" | 
 | #include "quic/platform/api/quic_containers.h" | 
 | #include "quic/platform/api/quic_logging.h" | 
 | #include "quic/platform/api/quic_test.h" | 
 | #include "quic/test_tools/quic_test_utils.h" | 
 | #include "quic/test_tools/simulator/alarm_factory.h" | 
 | #include "quic/test_tools/simulator/link.h" | 
 | #include "quic/test_tools/simulator/packet_filter.h" | 
 | #include "quic/test_tools/simulator/queue.h" | 
 | #include "quic/test_tools/simulator/switch.h" | 
 | #include "quic/test_tools/simulator/traffic_policer.h" | 
 |  | 
 | using testing::_; | 
 | using testing::Return; | 
 | using testing::StrictMock; | 
 |  | 
 | namespace quic { | 
 | namespace simulator { | 
 |  | 
 | // A simple counter that increments its value by 1 every specified period. | 
 | class Counter : public Actor { | 
 |  public: | 
 |   Counter(Simulator* simulator, std::string name, QuicTime::Delta period) | 
 |       : Actor(simulator, name), value_(-1), period_(period) { | 
 |     Schedule(clock_->Now()); | 
 |   } | 
 |   ~Counter() override {} | 
 |  | 
 |   inline int get_value() const { return value_; } | 
 |  | 
 |   void Act() override { | 
 |     ++value_; | 
 |     QUIC_DVLOG(1) << name_ << " has value " << value_ << " at time " | 
 |                   << clock_->Now().ToDebuggingValue(); | 
 |     Schedule(clock_->Now() + period_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int value_; | 
 |   QuicTime::Delta period_; | 
 | }; | 
 |  | 
 | class SimulatorTest : public QuicTest {}; | 
 |  | 
 | // Test that the basic event handling works, and that Actors can be created and | 
 | // destroyed mid-simulation. | 
 | TEST_F(SimulatorTest, Counters) { | 
 |   Simulator simulator; | 
 |   for (int i = 0; i < 2; ++i) { | 
 |     Counter fast_counter(&simulator, "fast_counter", | 
 |                          QuicTime::Delta::FromSeconds(3)); | 
 |     Counter slow_counter(&simulator, "slow_counter", | 
 |                          QuicTime::Delta::FromSeconds(10)); | 
 |  | 
 |     simulator.RunUntil( | 
 |         [&slow_counter]() { return slow_counter.get_value() >= 10; }); | 
 |  | 
 |     EXPECT_EQ(10, slow_counter.get_value()); | 
 |     EXPECT_EQ(10 * 10 / 3, fast_counter.get_value()); | 
 |   } | 
 | } | 
 |  | 
 | // A port which counts the number of packets received on it, both total and | 
 | // per-destination. | 
 | class CounterPort : public UnconstrainedPortInterface { | 
 |  public: | 
 |   CounterPort() { Reset(); } | 
 |   ~CounterPort() override {} | 
 |  | 
 |   inline QuicByteCount bytes() const { return bytes_; } | 
 |   inline QuicPacketCount packets() const { return packets_; } | 
 |  | 
 |   void AcceptPacket(std::unique_ptr<Packet> packet) override { | 
 |     bytes_ += packet->size; | 
 |     packets_ += 1; | 
 |  | 
 |     per_destination_packet_counter_[packet->destination] += 1; | 
 |   } | 
 |  | 
 |   void Reset() { | 
 |     bytes_ = 0; | 
 |     packets_ = 0; | 
 |     per_destination_packet_counter_.clear(); | 
 |   } | 
 |  | 
 |   QuicPacketCount CountPacketsForDestination(std::string destination) const { | 
 |     auto result_it = per_destination_packet_counter_.find(destination); | 
 |     if (result_it == per_destination_packet_counter_.cend()) { | 
 |       return 0; | 
 |     } | 
 |     return result_it->second; | 
 |   } | 
 |  | 
 |  private: | 
 |   QuicByteCount bytes_; | 
 |   QuicPacketCount packets_; | 
 |  | 
 |   absl::node_hash_map<std::string, QuicPacketCount> | 
 |       per_destination_packet_counter_; | 
 | }; | 
 |  | 
 | // Sends the packet to the specified destination at the uplink rate.  Provides a | 
 | // CounterPort as an Rx interface. | 
 | class LinkSaturator : public Endpoint { | 
 |  public: | 
 |   LinkSaturator(Simulator* simulator, | 
 |                 std::string name, | 
 |                 QuicByteCount packet_size, | 
 |                 std::string destination) | 
 |       : Endpoint(simulator, name), | 
 |         packet_size_(packet_size), | 
 |         destination_(std::move(destination)), | 
 |         bytes_transmitted_(0), | 
 |         packets_transmitted_(0) { | 
 |     Schedule(clock_->Now()); | 
 |   } | 
 |  | 
 |   void Act() override { | 
 |     if (tx_port_->TimeUntilAvailable().IsZero()) { | 
 |       auto packet = std::make_unique<Packet>(); | 
 |       packet->source = name_; | 
 |       packet->destination = destination_; | 
 |       packet->tx_timestamp = clock_->Now(); | 
 |       packet->size = packet_size_; | 
 |  | 
 |       tx_port_->AcceptPacket(std::move(packet)); | 
 |  | 
 |       bytes_transmitted_ += packet_size_; | 
 |       packets_transmitted_ += 1; | 
 |     } | 
 |  | 
 |     Schedule(clock_->Now() + tx_port_->TimeUntilAvailable()); | 
 |   } | 
 |  | 
 |   UnconstrainedPortInterface* GetRxPort() override { | 
 |     return static_cast<UnconstrainedPortInterface*>(&rx_port_); | 
 |   } | 
 |  | 
 |   void SetTxPort(ConstrainedPortInterface* port) override { tx_port_ = port; } | 
 |  | 
 |   CounterPort* counter() { return &rx_port_; } | 
 |  | 
 |   inline QuicByteCount bytes_transmitted() const { return bytes_transmitted_; } | 
 |   inline QuicPacketCount packets_transmitted() const { | 
 |     return packets_transmitted_; | 
 |   } | 
 |  | 
 |   void Pause() { Unschedule(); } | 
 |   void Resume() { Schedule(clock_->Now()); } | 
 |  | 
 |  private: | 
 |   QuicByteCount packet_size_; | 
 |   std::string destination_; | 
 |  | 
 |   ConstrainedPortInterface* tx_port_; | 
 |   CounterPort rx_port_; | 
 |  | 
 |   QuicByteCount bytes_transmitted_; | 
 |   QuicPacketCount packets_transmitted_; | 
 | }; | 
 |  | 
 | // Saturate a symmetric link and verify that the number of packets sent and | 
 | // received is correct. | 
 | TEST_F(SimulatorTest, DirectLinkSaturation) { | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B"); | 
 |   LinkSaturator saturator_b(&simulator, "Saturator B", 100, "Saturator A"); | 
 |   SymmetricLink link(&saturator_a, &saturator_b, | 
 |                      QuicBandwidth::FromKBytesPerSecond(1000), | 
 |                      QuicTime::Delta::FromMilliseconds(100) + | 
 |                          QuicTime::Delta::FromMicroseconds(1)); | 
 |  | 
 |   const QuicTime start_time = simulator.GetClock()->Now(); | 
 |   const QuicTime after_first_50_ms = | 
 |       start_time + QuicTime::Delta::FromMilliseconds(50); | 
 |   simulator.RunUntil([&simulator, after_first_50_ms]() { | 
 |     return simulator.GetClock()->Now() >= after_first_50_ms; | 
 |   }); | 
 |   EXPECT_LE(1000u * 50u, saturator_a.bytes_transmitted()); | 
 |   EXPECT_GE(1000u * 51u, saturator_a.bytes_transmitted()); | 
 |   EXPECT_LE(1000u * 50u, saturator_b.bytes_transmitted()); | 
 |   EXPECT_GE(1000u * 51u, saturator_b.bytes_transmitted()); | 
 |   EXPECT_LE(50u, saturator_a.packets_transmitted()); | 
 |   EXPECT_GE(51u, saturator_a.packets_transmitted()); | 
 |   EXPECT_LE(500u, saturator_b.packets_transmitted()); | 
 |   EXPECT_GE(501u, saturator_b.packets_transmitted()); | 
 |   EXPECT_EQ(0u, saturator_a.counter()->bytes()); | 
 |   EXPECT_EQ(0u, saturator_b.counter()->bytes()); | 
 |  | 
 |   simulator.RunUntil([&saturator_a, &saturator_b]() { | 
 |     if (saturator_a.counter()->packets() > 1000 || | 
 |         saturator_b.counter()->packets() > 100) { | 
 |       ADD_FAILURE() << "The simulation did not arrive at the expected " | 
 |                        "termination contidition. Saturator A counter: " | 
 |                     << saturator_a.counter()->packets() | 
 |                     << ", saturator B counter: " | 
 |                     << saturator_b.counter()->packets(); | 
 |       return true; | 
 |     } | 
 |  | 
 |     return saturator_a.counter()->packets() == 1000 && | 
 |            saturator_b.counter()->packets() == 100; | 
 |   }); | 
 |   EXPECT_EQ(201u, saturator_a.packets_transmitted()); | 
 |   EXPECT_EQ(2001u, saturator_b.packets_transmitted()); | 
 |   EXPECT_EQ(201u * 1000, saturator_a.bytes_transmitted()); | 
 |   EXPECT_EQ(2001u * 100, saturator_b.bytes_transmitted()); | 
 |  | 
 |   EXPECT_EQ(1000u, | 
 |             saturator_a.counter()->CountPacketsForDestination("Saturator A")); | 
 |   EXPECT_EQ(100u, | 
 |             saturator_b.counter()->CountPacketsForDestination("Saturator B")); | 
 |   EXPECT_EQ(0u, | 
 |             saturator_a.counter()->CountPacketsForDestination("Saturator B")); | 
 |   EXPECT_EQ(0u, | 
 |             saturator_b.counter()->CountPacketsForDestination("Saturator A")); | 
 |  | 
 |   const QuicTime end_time = simulator.GetClock()->Now(); | 
 |   const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta( | 
 |       saturator_a.bytes_transmitted(), end_time - start_time); | 
 |   EXPECT_APPROX_EQ(link.bandwidth(), observed_bandwidth, 0.01f); | 
 | } | 
 |  | 
 | // Accepts packets and stores them internally. | 
 | class PacketAcceptor : public ConstrainedPortInterface { | 
 |  public: | 
 |   void AcceptPacket(std::unique_ptr<Packet> packet) override { | 
 |     packets_.emplace_back(std::move(packet)); | 
 |   } | 
 |  | 
 |   QuicTime::Delta TimeUntilAvailable() override { | 
 |     return QuicTime::Delta::Zero(); | 
 |   } | 
 |  | 
 |   std::vector<std::unique_ptr<Packet>>* packets() { return &packets_; } | 
 |  | 
 |  private: | 
 |   std::vector<std::unique_ptr<Packet>> packets_; | 
 | }; | 
 |  | 
 | // Ensure the queue behaves correctly with accepting packets. | 
 | TEST_F(SimulatorTest, Queue) { | 
 |   Simulator simulator; | 
 |   Queue queue(&simulator, "Queue", 1000); | 
 |   PacketAcceptor acceptor; | 
 |   queue.set_tx_port(&acceptor); | 
 |  | 
 |   EXPECT_EQ(0u, queue.bytes_queued()); | 
 |   EXPECT_EQ(0u, queue.packets_queued()); | 
 |   EXPECT_EQ(0u, acceptor.packets()->size()); | 
 |  | 
 |   auto first_packet = std::make_unique<Packet>(); | 
 |   first_packet->size = 600; | 
 |   queue.AcceptPacket(std::move(first_packet)); | 
 |   EXPECT_EQ(600u, queue.bytes_queued()); | 
 |   EXPECT_EQ(1u, queue.packets_queued()); | 
 |   EXPECT_EQ(0u, acceptor.packets()->size()); | 
 |  | 
 |   // The second packet does not fit and is dropped. | 
 |   auto second_packet = std::make_unique<Packet>(); | 
 |   second_packet->size = 500; | 
 |   queue.AcceptPacket(std::move(second_packet)); | 
 |   EXPECT_EQ(600u, queue.bytes_queued()); | 
 |   EXPECT_EQ(1u, queue.packets_queued()); | 
 |   EXPECT_EQ(0u, acceptor.packets()->size()); | 
 |  | 
 |   auto third_packet = std::make_unique<Packet>(); | 
 |   third_packet->size = 400; | 
 |   queue.AcceptPacket(std::move(third_packet)); | 
 |   EXPECT_EQ(1000u, queue.bytes_queued()); | 
 |   EXPECT_EQ(2u, queue.packets_queued()); | 
 |   EXPECT_EQ(0u, acceptor.packets()->size()); | 
 |  | 
 |   // Run until there is nothing scheduled, so that the queue can deplete. | 
 |   simulator.RunUntil([]() { return false; }); | 
 |   EXPECT_EQ(0u, queue.bytes_queued()); | 
 |   EXPECT_EQ(0u, queue.packets_queued()); | 
 |   ASSERT_EQ(2u, acceptor.packets()->size()); | 
 |   EXPECT_EQ(600u, acceptor.packets()->at(0)->size); | 
 |   EXPECT_EQ(400u, acceptor.packets()->at(1)->size); | 
 | } | 
 |  | 
 | // Simulate a situation where the bottleneck link is 10 times slower than the | 
 | // uplink, and they are separated by a queue. | 
 | TEST_F(SimulatorTest, QueueBottleneck) { | 
 |   const QuicBandwidth local_bandwidth = | 
 |       QuicBandwidth::FromKBytesPerSecond(1000); | 
 |   const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth; | 
 |   const QuicTime::Delta local_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(1); | 
 |   const QuicTime::Delta bottleneck_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(20); | 
 |   const QuicByteCount bdp = | 
 |       bottleneck_bandwidth * | 
 |       (local_propagation_delay + bottleneck_propagation_delay); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter"); | 
 |   ASSERT_GE(bdp, 1000u); | 
 |   Queue queue(&simulator, "Queue", bdp); | 
 |   CounterPort counter; | 
 |  | 
 |   OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth, | 
 |                         local_propagation_delay); | 
 |   OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter, | 
 |                              bottleneck_bandwidth, | 
 |                              bottleneck_propagation_delay); | 
 |   saturator.SetTxPort(&local_link); | 
 |   queue.set_tx_port(&bottleneck_link); | 
 |  | 
 |   static const QuicPacketCount packets_received = 1000; | 
 |   simulator.RunUntil( | 
 |       [&counter]() { return counter.packets() == packets_received; }); | 
 |   const double loss_ratio = 1 - static_cast<double>(packets_received) / | 
 |                                     saturator.packets_transmitted(); | 
 |   EXPECT_NEAR(loss_ratio, 0.9, 0.001); | 
 | } | 
 |  | 
 | // Verify that the queue of exactly one packet allows the transmission to | 
 | // actually go through. | 
 | TEST_F(SimulatorTest, OnePacketQueue) { | 
 |   const QuicBandwidth local_bandwidth = | 
 |       QuicBandwidth::FromKBytesPerSecond(1000); | 
 |   const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth; | 
 |   const QuicTime::Delta local_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(1); | 
 |   const QuicTime::Delta bottleneck_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(20); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter"); | 
 |   Queue queue(&simulator, "Queue", 1000); | 
 |   CounterPort counter; | 
 |  | 
 |   OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth, | 
 |                         local_propagation_delay); | 
 |   OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter, | 
 |                              bottleneck_bandwidth, | 
 |                              bottleneck_propagation_delay); | 
 |   saturator.SetTxPort(&local_link); | 
 |   queue.set_tx_port(&bottleneck_link); | 
 |  | 
 |   static const QuicPacketCount packets_received = 10; | 
 |   // The deadline here is to prevent this tests from looping infinitely in case | 
 |   // the packets never reach the receiver. | 
 |   const QuicTime deadline = | 
 |       simulator.GetClock()->Now() + QuicTime::Delta::FromSeconds(10); | 
 |   simulator.RunUntil([&simulator, &counter, deadline]() { | 
 |     return counter.packets() == packets_received || | 
 |            simulator.GetClock()->Now() > deadline; | 
 |   }); | 
 |   ASSERT_EQ(packets_received, counter.packets()); | 
 | } | 
 |  | 
 | // Simulate a network where three endpoints are connected to a switch and they | 
 | // are sending traffic in circle (1 -> 2, 2 -> 3, 3 -> 1). | 
 | TEST_F(SimulatorTest, SwitchedNetwork) { | 
 |   const QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(10000); | 
 |   const QuicTime::Delta base_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(50); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2"); | 
 |   LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 3"); | 
 |   LinkSaturator saturator3(&simulator, "Saturator 3", 1000, "Saturator 1"); | 
 |   Switch network_switch(&simulator, "Switch", 8, | 
 |                         bandwidth * base_propagation_delay * 10); | 
 |  | 
 |   // For determinicity, make it so that the first packet will arrive from | 
 |   // Saturator 1, then from Saturator 2, and then from Saturator 3. | 
 |   SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, | 
 |                       base_propagation_delay); | 
 |   SymmetricLink link2(&saturator2, network_switch.port(2), bandwidth, | 
 |                       base_propagation_delay * 2); | 
 |   SymmetricLink link3(&saturator3, network_switch.port(3), bandwidth, | 
 |                       base_propagation_delay * 3); | 
 |  | 
 |   const QuicTime start_time = simulator.GetClock()->Now(); | 
 |   static const QuicPacketCount bytes_received = 64 * 1000; | 
 |   simulator.RunUntil([&saturator1]() { | 
 |     return saturator1.counter()->bytes() >= bytes_received; | 
 |   }); | 
 |   const QuicTime end_time = simulator.GetClock()->Now(); | 
 |  | 
 |   const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta( | 
 |       bytes_received, end_time - start_time); | 
 |   const double bandwidth_ratio = | 
 |       static_cast<double>(observed_bandwidth.ToBitsPerSecond()) / | 
 |       bandwidth.ToBitsPerSecond(); | 
 |   EXPECT_NEAR(1, bandwidth_ratio, 0.1); | 
 |  | 
 |   const double normalized_received_packets_for_saturator_2 = | 
 |       static_cast<double>(saturator2.counter()->packets()) / | 
 |       saturator1.counter()->packets(); | 
 |   const double normalized_received_packets_for_saturator_3 = | 
 |       static_cast<double>(saturator3.counter()->packets()) / | 
 |       saturator1.counter()->packets(); | 
 |   EXPECT_NEAR(1, normalized_received_packets_for_saturator_2, 0.1); | 
 |   EXPECT_NEAR(1, normalized_received_packets_for_saturator_3, 0.1); | 
 |  | 
 |   // Since Saturator 1 has its packet arrive first into the switch, switch will | 
 |   // always know how to route traffic to it. | 
 |   EXPECT_EQ(0u, | 
 |             saturator2.counter()->CountPacketsForDestination("Saturator 1")); | 
 |   EXPECT_EQ(0u, | 
 |             saturator3.counter()->CountPacketsForDestination("Saturator 1")); | 
 |  | 
 |   // Packets from the other saturators will be broadcast at least once. | 
 |   EXPECT_EQ(1u, | 
 |             saturator1.counter()->CountPacketsForDestination("Saturator 2")); | 
 |   EXPECT_EQ(1u, | 
 |             saturator3.counter()->CountPacketsForDestination("Saturator 2")); | 
 |   EXPECT_EQ(1u, | 
 |             saturator1.counter()->CountPacketsForDestination("Saturator 3")); | 
 |   EXPECT_EQ(1u, | 
 |             saturator2.counter()->CountPacketsForDestination("Saturator 3")); | 
 | } | 
 |  | 
 | // Toggle an alarm on and off at the specified interval.  Assumes that alarm is | 
 | // initially set and unsets it almost immediately after the object is | 
 | // instantiated. | 
 | class AlarmToggler : public Actor { | 
 |  public: | 
 |   AlarmToggler(Simulator* simulator, | 
 |                std::string name, | 
 |                QuicAlarm* alarm, | 
 |                QuicTime::Delta interval) | 
 |       : Actor(simulator, name), | 
 |         alarm_(alarm), | 
 |         interval_(interval), | 
 |         deadline_(alarm->deadline()), | 
 |         times_set_(0), | 
 |         times_cancelled_(0) { | 
 |     EXPECT_TRUE(alarm->IsSet()); | 
 |     EXPECT_GE(alarm->deadline(), clock_->Now()); | 
 |     Schedule(clock_->Now()); | 
 |   } | 
 |  | 
 |   void Act() override { | 
 |     if (deadline_ <= clock_->Now()) { | 
 |       return; | 
 |     } | 
 |  | 
 |     if (alarm_->IsSet()) { | 
 |       alarm_->Cancel(); | 
 |       times_cancelled_++; | 
 |     } else { | 
 |       alarm_->Set(deadline_); | 
 |       times_set_++; | 
 |     } | 
 |  | 
 |     Schedule(clock_->Now() + interval_); | 
 |   } | 
 |  | 
 |   inline int times_set() { return times_set_; } | 
 |   inline int times_cancelled() { return times_cancelled_; } | 
 |  | 
 |  private: | 
 |   QuicAlarm* alarm_; | 
 |   QuicTime::Delta interval_; | 
 |   QuicTime deadline_; | 
 |  | 
 |   // Counts the number of times the alarm was set. | 
 |   int times_set_; | 
 |   // Counts the number of times the alarm was cancelled. | 
 |   int times_cancelled_; | 
 | }; | 
 |  | 
 | // Counts the number of times an alarm has fired. | 
 | class CounterDelegate : public QuicAlarm::Delegate { | 
 |  public: | 
 |   explicit CounterDelegate(size_t* counter) : counter_(counter) {} | 
 |  | 
 |   void OnAlarm() override { *counter_ += 1; } | 
 |  | 
 |  private: | 
 |   size_t* counter_; | 
 | }; | 
 |  | 
 | // Verifies that the alarms work correctly, even when they are repeatedly | 
 | // toggled. | 
 | TEST_F(SimulatorTest, Alarms) { | 
 |   Simulator simulator; | 
 |   QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory(); | 
 |  | 
 |   size_t fast_alarm_counter = 0; | 
 |   size_t slow_alarm_counter = 0; | 
 |   std::unique_ptr<QuicAlarm> alarm_fast( | 
 |       alarm_factory->CreateAlarm(new CounterDelegate(&fast_alarm_counter))); | 
 |   std::unique_ptr<QuicAlarm> alarm_slow( | 
 |       alarm_factory->CreateAlarm(new CounterDelegate(&slow_alarm_counter))); | 
 |  | 
 |   const QuicTime start_time = simulator.GetClock()->Now(); | 
 |   alarm_fast->Set(start_time + QuicTime::Delta::FromMilliseconds(100)); | 
 |   alarm_slow->Set(start_time + QuicTime::Delta::FromMilliseconds(750)); | 
 |   AlarmToggler toggler(&simulator, "Toggler", alarm_slow.get(), | 
 |                        QuicTime::Delta::FromMilliseconds(100)); | 
 |  | 
 |   const QuicTime end_time = | 
 |       start_time + QuicTime::Delta::FromMilliseconds(1000); | 
 |   EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() { | 
 |     return simulator.GetClock()->Now() >= end_time; | 
 |   })); | 
 |   EXPECT_EQ(1u, slow_alarm_counter); | 
 |   EXPECT_EQ(1u, fast_alarm_counter); | 
 |  | 
 |   EXPECT_EQ(4, toggler.times_set()); | 
 |   EXPECT_EQ(4, toggler.times_cancelled()); | 
 | } | 
 |  | 
 | // Verifies that a cancelled alarm is never fired. | 
 | TEST_F(SimulatorTest, AlarmCancelling) { | 
 |   Simulator simulator; | 
 |   QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory(); | 
 |  | 
 |   size_t alarm_counter = 0; | 
 |   std::unique_ptr<QuicAlarm> alarm( | 
 |       alarm_factory->CreateAlarm(new CounterDelegate(&alarm_counter))); | 
 |  | 
 |   const QuicTime start_time = simulator.GetClock()->Now(); | 
 |   const QuicTime alarm_at = start_time + QuicTime::Delta::FromMilliseconds(300); | 
 |   const QuicTime end_time = start_time + QuicTime::Delta::FromMilliseconds(400); | 
 |  | 
 |   alarm->Set(alarm_at); | 
 |   alarm->Cancel(); | 
 |   EXPECT_FALSE(alarm->IsSet()); | 
 |  | 
 |   EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() { | 
 |     return simulator.GetClock()->Now() >= end_time; | 
 |   })); | 
 |  | 
 |   EXPECT_FALSE(alarm->IsSet()); | 
 |   EXPECT_EQ(0u, alarm_counter); | 
 | } | 
 |  | 
 | // Verifies that alarms can be scheduled into the past. | 
 | TEST_F(SimulatorTest, AlarmInPast) { | 
 |   Simulator simulator; | 
 |   QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory(); | 
 |  | 
 |   size_t alarm_counter = 0; | 
 |   std::unique_ptr<QuicAlarm> alarm( | 
 |       alarm_factory->CreateAlarm(new CounterDelegate(&alarm_counter))); | 
 |  | 
 |   const QuicTime start_time = simulator.GetClock()->Now(); | 
 |   simulator.RunFor(QuicTime::Delta::FromMilliseconds(400)); | 
 |  | 
 |   alarm->Set(start_time); | 
 |   simulator.RunFor(QuicTime::Delta::FromMilliseconds(1)); | 
 |   EXPECT_FALSE(alarm->IsSet()); | 
 |   EXPECT_EQ(1u, alarm_counter); | 
 | } | 
 |  | 
 | // Tests Simulator::RunUntilOrTimeout() interface. | 
 | TEST_F(SimulatorTest, RunUntilOrTimeout) { | 
 |   Simulator simulator; | 
 |   bool simulation_result; | 
 |  | 
 |   // Count the number of seconds since the beginning of the simulation. | 
 |   Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(1)); | 
 |  | 
 |   // Ensure that the counter reaches the value of 10 given a 20 second deadline. | 
 |   simulation_result = simulator.RunUntilOrTimeout( | 
 |       [&counter]() { return counter.get_value() == 10; }, | 
 |       QuicTime::Delta::FromSeconds(20)); | 
 |   ASSERT_TRUE(simulation_result); | 
 |  | 
 |   // Ensure that the counter will not reach the value of 100 given that the | 
 |   // starting value is 10 and the deadline is 20 seconds. | 
 |   simulation_result = simulator.RunUntilOrTimeout( | 
 |       [&counter]() { return counter.get_value() == 100; }, | 
 |       QuicTime::Delta::FromSeconds(20)); | 
 |   ASSERT_FALSE(simulation_result); | 
 | } | 
 |  | 
 | // Tests Simulator::RunFor() interface. | 
 | TEST_F(SimulatorTest, RunFor) { | 
 |   Simulator simulator; | 
 |  | 
 |   Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(3)); | 
 |  | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(100)); | 
 |  | 
 |   EXPECT_EQ(33, counter.get_value()); | 
 | } | 
 |  | 
 | class MockPacketFilter : public PacketFilter { | 
 |  public: | 
 |   MockPacketFilter(Simulator* simulator, std::string name, Endpoint* endpoint) | 
 |       : PacketFilter(simulator, name, endpoint) {} | 
 |   MOCK_METHOD(bool, FilterPacket, (const Packet&), (override)); | 
 | }; | 
 |  | 
 | // Set up two trivial packet filters, one allowing any packets, and one dropping | 
 | // all of them. | 
 | TEST_F(SimulatorTest, PacketFilter) { | 
 |   const QuicBandwidth bandwidth = | 
 |       QuicBandwidth::FromBytesPerSecond(1024 * 1024); | 
 |   const QuicTime::Delta base_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(5); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B"); | 
 |   LinkSaturator saturator_b(&simulator, "Saturator B", 1000, "Saturator A"); | 
 |  | 
 |   // Attach packets to the switch to create a delay between the point at which | 
 |   // the packet is generated and the point at which it is filtered.  Note that | 
 |   // if the saturators were connected directly, the link would be always | 
 |   // available for the endpoint which has all of its packets dropped, resulting | 
 |   // in saturator looping infinitely. | 
 |   Switch network_switch(&simulator, "Switch", 8, | 
 |                         bandwidth * base_propagation_delay * 10); | 
 |   StrictMock<MockPacketFilter> a_to_b_filter(&simulator, "A -> B filter", | 
 |                                              network_switch.port(1)); | 
 |   StrictMock<MockPacketFilter> b_to_a_filter(&simulator, "B -> A filter", | 
 |                                              network_switch.port(2)); | 
 |   SymmetricLink link_a(&a_to_b_filter, &saturator_b, bandwidth, | 
 |                        base_propagation_delay); | 
 |   SymmetricLink link_b(&b_to_a_filter, &saturator_a, bandwidth, | 
 |                        base_propagation_delay); | 
 |  | 
 |   // Allow packets from A to B, but not from B to A. | 
 |   EXPECT_CALL(a_to_b_filter, FilterPacket(_)).WillRepeatedly(Return(true)); | 
 |   EXPECT_CALL(b_to_a_filter, FilterPacket(_)).WillRepeatedly(Return(false)); | 
 |  | 
 |   // Run the simulation for a while, and expect that only B will receive any | 
 |   // packets. | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(10)); | 
 |   EXPECT_GE(saturator_b.counter()->packets(), 1u); | 
 |   EXPECT_EQ(saturator_a.counter()->packets(), 0u); | 
 | } | 
 |  | 
 | // Set up a traffic policer in one direction that throttles at 25% of link | 
 | // bandwidth, and put two link saturators at each endpoint. | 
 | TEST_F(SimulatorTest, TrafficPolicer) { | 
 |   const QuicBandwidth bandwidth = | 
 |       QuicBandwidth::FromBytesPerSecond(1024 * 1024); | 
 |   const QuicTime::Delta base_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(5); | 
 |   const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2"); | 
 |   LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 1"); | 
 |   Switch network_switch(&simulator, "Switch", 8, | 
 |                         bandwidth * base_propagation_delay * 10); | 
 |  | 
 |   static const QuicByteCount initial_burst = 1000 * 10; | 
 |   static const QuicByteCount max_bucket_size = 1000 * 100; | 
 |   static const QuicBandwidth target_bandwidth = bandwidth * 0.25; | 
 |   TrafficPolicer policer(&simulator, "Policer", initial_burst, max_bucket_size, | 
 |                          target_bandwidth, network_switch.port(2)); | 
 |  | 
 |   SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, | 
 |                       base_propagation_delay); | 
 |   SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay); | 
 |  | 
 |   // Ensure the initial burst passes without being dropped at all. | 
 |   bool simulator_result = simulator.RunUntilOrTimeout( | 
 |       [&saturator1]() { | 
 |         return saturator1.bytes_transmitted() == initial_burst; | 
 |       }, | 
 |       timeout); | 
 |   ASSERT_TRUE(simulator_result); | 
 |   saturator1.Pause(); | 
 |   simulator_result = simulator.RunUntilOrTimeout( | 
 |       [&saturator2]() { | 
 |         return saturator2.counter()->bytes() == initial_burst; | 
 |       }, | 
 |       timeout); | 
 |   ASSERT_TRUE(simulator_result); | 
 |   saturator1.Resume(); | 
 |  | 
 |   // Run for some time so that the initial burst is not visible. | 
 |   const QuicTime::Delta simulation_time = QuicTime::Delta::FromSeconds(10); | 
 |   simulator.RunFor(simulation_time); | 
 |  | 
 |   // Ensure we've transmitted the amount of data we expected. | 
 |   for (auto* saturator : {&saturator1, &saturator2}) { | 
 |     EXPECT_APPROX_EQ(bandwidth * simulation_time, | 
 |                      saturator->bytes_transmitted(), 0.01f); | 
 |   } | 
 |  | 
 |   // Check that only one direction is throttled. | 
 |   EXPECT_APPROX_EQ(saturator1.bytes_transmitted() / 4, | 
 |                    saturator2.counter()->bytes(), 0.1f); | 
 |   EXPECT_APPROX_EQ(saturator2.bytes_transmitted(), | 
 |                    saturator1.counter()->bytes(), 0.1f); | 
 | } | 
 |  | 
 | // Ensure that a larger burst is allowed when the policed saturator exits | 
 | // quiescence. | 
 | TEST_F(SimulatorTest, TrafficPolicerBurst) { | 
 |   const QuicBandwidth bandwidth = | 
 |       QuicBandwidth::FromBytesPerSecond(1024 * 1024); | 
 |   const QuicTime::Delta base_propagation_delay = | 
 |       QuicTime::Delta::FromMilliseconds(5); | 
 |   const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2"); | 
 |   LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 1"); | 
 |   Switch network_switch(&simulator, "Switch", 8, | 
 |                         bandwidth * base_propagation_delay * 10); | 
 |  | 
 |   const QuicByteCount initial_burst = 1000 * 10; | 
 |   const QuicByteCount max_bucket_size = 1000 * 100; | 
 |   const QuicBandwidth target_bandwidth = bandwidth * 0.25; | 
 |   TrafficPolicer policer(&simulator, "Policer", initial_burst, max_bucket_size, | 
 |                          target_bandwidth, network_switch.port(2)); | 
 |  | 
 |   SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, | 
 |                       base_propagation_delay); | 
 |   SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay); | 
 |  | 
 |   // Ensure at least one packet is sent on each side. | 
 |   bool simulator_result = simulator.RunUntilOrTimeout( | 
 |       [&saturator1, &saturator2]() { | 
 |         return saturator1.packets_transmitted() > 0 && | 
 |                saturator2.packets_transmitted() > 0; | 
 |       }, | 
 |       timeout); | 
 |   ASSERT_TRUE(simulator_result); | 
 |  | 
 |   // Wait until the bucket fills up. | 
 |   saturator1.Pause(); | 
 |   saturator2.Pause(); | 
 |   simulator.RunFor(1.5f * target_bandwidth.TransferTime(max_bucket_size)); | 
 |  | 
 |   // Send a burst. | 
 |   saturator1.Resume(); | 
 |   simulator.RunFor(bandwidth.TransferTime(max_bucket_size)); | 
 |   saturator1.Pause(); | 
 |   simulator.RunFor(2 * base_propagation_delay); | 
 |  | 
 |   // Expect the burst to pass without losses. | 
 |   EXPECT_APPROX_EQ(saturator1.bytes_transmitted(), | 
 |                    saturator2.counter()->bytes(), 0.1f); | 
 |  | 
 |   // Expect subsequent traffic to be policed. | 
 |   saturator1.Resume(); | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(10)); | 
 |   EXPECT_APPROX_EQ(saturator1.bytes_transmitted() / 4, | 
 |                    saturator2.counter()->bytes(), 0.1f); | 
 | } | 
 |  | 
 | // Test that the packet aggregation support in queues work. | 
 | TEST_F(SimulatorTest, PacketAggregation) { | 
 |   // Model network where the delays are dominated by transfer delay. | 
 |   const QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(1000); | 
 |   const QuicTime::Delta base_propagation_delay = | 
 |       QuicTime::Delta::FromMicroseconds(1); | 
 |   const QuicByteCount aggregation_threshold = 1000; | 
 |   const QuicTime::Delta aggregation_timeout = QuicTime::Delta::FromSeconds(30); | 
 |  | 
 |   Simulator simulator; | 
 |   LinkSaturator saturator1(&simulator, "Saturator 1", 10, "Saturator 2"); | 
 |   LinkSaturator saturator2(&simulator, "Saturator 2", 10, "Saturator 1"); | 
 |   Switch network_switch(&simulator, "Switch", 8, 10 * aggregation_threshold); | 
 |  | 
 |   // Make links with asymmetric propagation delay so that Saturator 2 only | 
 |   // receives packets addressed to it. | 
 |   SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, | 
 |                       base_propagation_delay); | 
 |   SymmetricLink link2(&saturator2, network_switch.port(2), bandwidth, | 
 |                       2 * base_propagation_delay); | 
 |  | 
 |   // Enable aggregation in 1 -> 2 direction. | 
 |   Queue* queue = network_switch.port_queue(2); | 
 |   queue->EnableAggregation(aggregation_threshold, aggregation_timeout); | 
 |  | 
 |   // Enable aggregation in 2 -> 1 direction in a way that all packets are larger | 
 |   // than the threshold, so that aggregation is effectively a no-op. | 
 |   network_switch.port_queue(1)->EnableAggregation(5, aggregation_timeout); | 
 |  | 
 |   // Fill up the aggregation buffer up to 90% (900 bytes). | 
 |   simulator.RunFor(0.9 * bandwidth.TransferTime(aggregation_threshold)); | 
 |   EXPECT_EQ(0u, saturator2.counter()->bytes()); | 
 |  | 
 |   // Stop sending, ensure that given a timespan much shorter than timeout, the | 
 |   // packets remain in the queue. | 
 |   saturator1.Pause(); | 
 |   saturator2.Pause(); | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(10)); | 
 |   EXPECT_EQ(0u, saturator2.counter()->bytes()); | 
 |   EXPECT_EQ(900u, queue->bytes_queued()); | 
 |  | 
 |   // Ensure that all packets have reached the saturator not affected by | 
 |   // aggregation.  Here, 10 extra bytes account for a misrouted packet in the | 
 |   // beginning. | 
 |   EXPECT_EQ(910u, saturator1.counter()->bytes()); | 
 |  | 
 |   // Send 500 more bytes.  Since the aggregation threshold is 1000 bytes, and | 
 |   // queue already has 900 bytes, 1000 bytes will be send and 400 will be in the | 
 |   // queue. | 
 |   saturator1.Resume(); | 
 |   simulator.RunFor(0.5 * bandwidth.TransferTime(aggregation_threshold)); | 
 |   saturator1.Pause(); | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(10)); | 
 |   EXPECT_EQ(1000u, saturator2.counter()->bytes()); | 
 |   EXPECT_EQ(400u, queue->bytes_queued()); | 
 |  | 
 |   // Actually time out, and cause all of the data to be received. | 
 |   simulator.RunFor(aggregation_timeout); | 
 |   EXPECT_EQ(1400u, saturator2.counter()->bytes()); | 
 |   EXPECT_EQ(0u, queue->bytes_queued()); | 
 |  | 
 |   // Run saturator for a longer time, to ensure that the logic to cancel and | 
 |   // reset alarms works correctly. | 
 |   saturator1.Resume(); | 
 |   simulator.RunFor(5.5 * bandwidth.TransferTime(aggregation_threshold)); | 
 |   saturator1.Pause(); | 
 |   simulator.RunFor(QuicTime::Delta::FromSeconds(10)); | 
 |   EXPECT_EQ(6400u, saturator2.counter()->bytes()); | 
 |   EXPECT_EQ(500u, queue->bytes_queued()); | 
 |  | 
 |   // Time out again. | 
 |   simulator.RunFor(aggregation_timeout); | 
 |   EXPECT_EQ(6900u, saturator2.counter()->bytes()); | 
 |   EXPECT_EQ(0u, queue->bytes_queued()); | 
 | } | 
 |  | 
 | }  // namespace simulator | 
 | }  // namespace quic |