Add SetConfig method to FakeNetworkPipe and to DirectTransport

This method allow the user to change the network configuration
during run-time. This is useful when testing how components react
to changing bandwidth.

BUG=2636
R=mflodman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/9049004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5612 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/test/direct_transport.cc b/webrtc/test/direct_transport.cc
index 96852ed..fd59815 100644
--- a/webrtc/test/direct_transport.cc
+++ b/webrtc/test/direct_transport.cc
@@ -42,6 +42,10 @@
 
 DirectTransport::~DirectTransport() { StopSending(); }
 
+void DirectTransport::SetConfig(const FakeNetworkPipe::Config& config) {
+  fake_network_.SetConfig(config);
+}
+
 void DirectTransport::StopSending() {
   {
     CriticalSectionScoped crit_(lock_.get());
diff --git a/webrtc/test/direct_transport.h b/webrtc/test/direct_transport.h
index 660ffec..9dc9e1f 100644
--- a/webrtc/test/direct_transport.h
+++ b/webrtc/test/direct_transport.h
@@ -34,6 +34,8 @@
   explicit DirectTransport(const FakeNetworkPipe::Config& config);
   ~DirectTransport();
 
+  void SetConfig(const FakeNetworkPipe::Config& config);
+
   virtual void StopSending();
   virtual void SetReceiver(PacketReceiver* receiver);
 
diff --git a/webrtc/test/fake_network_pipe.cc b/webrtc/test/fake_network_pipe.cc
index 5a2424e..c5caef2 100644
--- a/webrtc/test/fake_network_pipe.cc
+++ b/webrtc/test/fake_network_pipe.cc
@@ -93,6 +93,11 @@
   packet_receiver_ = receiver;
 }
 
+void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
+  CriticalSectionScoped crit(lock_.get());
+  config_ = config;  // Shallow copy of the struct.
+}
+
 void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
   // A NULL packet_receiver_ means that this pipe will terminate the flow of
   // packets.
diff --git a/webrtc/test/fake_network_pipe.h b/webrtc/test/fake_network_pipe.h
index e750457..3dcda298 100644
--- a/webrtc/test/fake_network_pipe.h
+++ b/webrtc/test/fake_network_pipe.h
@@ -57,6 +57,9 @@
   // Must not be called in parallel with SendPacket or Process.
   void SetReceiver(PacketReceiver* receiver);
 
+  // Sets a new configuration. This won't affect packets already in the pipe.
+  void SetConfig(const FakeNetworkPipe::Config& config);
+
   // Sends a new packet to the link.
   void SendPacket(const uint8_t* packet, size_t packet_length);
 
diff --git a/webrtc/test/fake_network_pipe_unittest.cc b/webrtc/test/fake_network_pipe_unittest.cc
index 1245f61..5076bc0 100644
--- a/webrtc/test/fake_network_pipe_unittest.cc
+++ b/webrtc/test/fake_network_pipe_unittest.cc
@@ -53,7 +53,7 @@
     }
   }
 
-  int PacketTimeMs(int capacity_kbps, int kPacketSize) {
+  int PacketTimeMs(int capacity_kbps, int kPacketSize) const {
     return 8 * kPacketSize / capacity_kbps;
   }
 
@@ -193,4 +193,114 @@
   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) {
+  FakeNetworkPipe::Config config;
+  config.queue_length = 20;
+  config.link_capacity_kbps = 80;
+  scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+  pipe->SetReceiver(receiver_.get());
+
+  // 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) {
+    TickTime::AdvanceFakeClock(packet_time_ms);
+    EXPECT_CALL(*receiver_, DeliverPacket(_, _)).Times(1);
+    pipe->Process();
+  }
+
+  // Change the capacity.
+  config.link_capacity_kbps /= 2;  // Reduce to 50%.
+  pipe->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) {
+    TickTime::AdvanceFakeClock(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->sent_packets());
+  TickTime::AdvanceFakeClock(pipe->TimeUntilNextProcess());
+  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) {
+  FakeNetworkPipe::Config config;
+  config.queue_length = 20;
+  config.link_capacity_kbps = 80;
+  scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+  pipe->SetReceiver(receiver_.get());
+
+  // Add 10 packets of 1000 bytes, = 80 kb.
+  const int kNumPackets = 10;
+  const int kPacketSize = 1000;
+  SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+  // Time to get one packet through the link at the initial speed.
+  int packet_time_1_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+  // Change the capacity.
+  config.link_capacity_kbps *= 2;  // Double the capacity.
+  pipe->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 at the new capacity.
+  int packet_time_2_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) {
+    TickTime::AdvanceFakeClock(packet_time_1_ms);
+    EXPECT_CALL(*receiver_, DeliverPacket(_, _)).Times(1);
+    pipe->Process();
+  }
+
+  // Advance time in steps to release one packet at a time.
+  for (int i = 0; i < kNumPackets; ++i) {
+    TickTime::AdvanceFakeClock(packet_time_2_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->sent_packets());
+  TickTime::AdvanceFakeClock(pipe->TimeUntilNextProcess());
+  EXPECT_CALL(*receiver_, DeliverPacket(_, _)).Times(0);
+  pipe->Process();
+}
 }  // namespace webrtc