Adding an end-to-end connection time test.

The test uses a fake clock and simulates network and signaling delays in
order to get a repeatable measurement of the time to establish a
connection (including DTLS). This will help ensure that various
optimizations continue to work as expected, and no new delays are
introduced.

This CL depends on: https://codereview.webrtc.org/2140283002/

R=honghaiz@webrtc.org, pthatcher@webrtc.org, skvlad@webrtc.org

Review URL: https://codereview.webrtc.org/2141863003 .

Cr-Commit-Position: refs/heads/master@{#14270}
diff --git a/webrtc/api/peerconnection_unittest.cc b/webrtc/api/peerconnection_unittest.cc
index fb3c188..981cec7 100644
--- a/webrtc/api/peerconnection_unittest.cc
+++ b/webrtc/api/peerconnection_unittest.cc
@@ -30,6 +30,7 @@
 #include "webrtc/api/test/fakertccertificategenerator.h"
 #include "webrtc/api/test/fakevideotrackrenderer.h"
 #include "webrtc/api/test/mockpeerconnectionobservers.h"
+#include "webrtc/base/fakenetwork.h"
 #include "webrtc/base/gunit.h"
 #include "webrtc/base/helpers.h"
 #include "webrtc/base/physicalsocketserver.h"
@@ -38,9 +39,10 @@
 #include "webrtc/base/thread.h"
 #include "webrtc/base/virtualsocketserver.h"
 #include "webrtc/media/engine/fakewebrtcvideoengine.h"
-#include "webrtc/p2p/base/fakeportallocator.h"
 #include "webrtc/p2p/base/p2pconstants.h"
 #include "webrtc/p2p/base/sessiondescription.h"
+#include "webrtc/p2p/base/testturnserver.h"
+#include "webrtc/p2p/client/basicportallocator.h"
 #include "webrtc/pc/mediasession.h"
 
 #define MAYBE_SKIP_TEST(feature)                    \
@@ -104,6 +106,20 @@
 static const int kDefaultSrtpCryptoSuiteGcm = rtc::SRTP_AEAD_AES_256_GCM;
 #endif
 
+// Used to simulate signaling ICE/SDP between two PeerConnections.
+enum Message { MSG_SDP_MESSAGE, MSG_ICE_MESSAGE };
+
+struct SdpMessage {
+  std::string type;
+  std::string msg;
+};
+
+struct IceMessage {
+  std::string sdp_mid;
+  int sdp_mline_index;
+  std::string msg;
+};
+
 static void RemoveLinesFromSdp(const std::string& line_start,
                                std::string* sdp) {
   const char kSdpLineEnd[] = "\r\n";
@@ -169,13 +185,15 @@
 
 class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
                                  public SignalingMessageReceiver,
-                                 public ObserverInterface {
+                                 public ObserverInterface,
+                                 public rtc::MessageHandler {
  public:
+  // If |config| is not provided, uses a default constructed RTCConfiguration.
   static PeerConnectionTestClient* CreateClientWithDtlsIdentityStore(
       const std::string& id,
       const MediaConstraintsInterface* constraints,
       const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration& config,
+      const PeerConnectionInterface::RTCConfiguration* config,
       std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
       bool prefer_constraint_apis,
       rtc::Thread* network_thread,
@@ -193,7 +211,7 @@
       const std::string& id,
       const MediaConstraintsInterface* constraints,
       const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration& config,
+      const PeerConnectionInterface::RTCConfiguration* config,
       rtc::Thread* network_thread,
       rtc::Thread* worker_thread) {
     std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
@@ -208,14 +226,13 @@
   static PeerConnectionTestClient* CreateClientPreferNoConstraints(
       const std::string& id,
       const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration& config,
       rtc::Thread* network_thread,
       rtc::Thread* worker_thread) {
     std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
         rtc::SSLStreamAdapter::HaveDtlsSrtp() ?
             new FakeRTCCertificateGenerator() : nullptr);
 
-    return CreateClientWithDtlsIdentityStore(id, nullptr, options, config,
+    return CreateClientWithDtlsIdentityStore(id, nullptr, options, nullptr,
                                              std::move(cert_generator), false,
                                              network_thread, worker_thread);
   }
@@ -239,8 +256,64 @@
     std::string sdp;
     EXPECT_TRUE(offer->ToString(&sdp));
     EXPECT_TRUE(DoSetLocalDescription(offer.release()));
-    signaling_message_receiver_->ReceiveSdpMessage(
-        webrtc::SessionDescriptionInterface::kOffer, sdp);
+    SendSdpMessage(webrtc::SessionDescriptionInterface::kOffer, sdp);
+  }
+
+  void SendSdpMessage(const std::string& type, std::string& msg) {
+    if (signaling_delay_ms_ == 0) {
+      if (signaling_message_receiver_) {
+        signaling_message_receiver_->ReceiveSdpMessage(type, msg);
+      }
+    } else {
+      rtc::Thread::Current()->PostDelayed(
+          RTC_FROM_HERE, signaling_delay_ms_, this, MSG_SDP_MESSAGE,
+          new rtc::TypedMessageData<SdpMessage>({type, msg}));
+    }
+  }
+
+  void SendIceMessage(const std::string& sdp_mid,
+                      int sdp_mline_index,
+                      const std::string& msg) {
+    if (signaling_delay_ms_ == 0) {
+      if (signaling_message_receiver_) {
+        signaling_message_receiver_->ReceiveIceMessage(sdp_mid, sdp_mline_index,
+                                                       msg);
+      }
+    } else {
+      rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, signaling_delay_ms_,
+                                          this, MSG_ICE_MESSAGE,
+                                          new rtc::TypedMessageData<IceMessage>(
+                                              {sdp_mid, sdp_mline_index, msg}));
+    }
+  }
+
+  // MessageHandler callback.
+  void OnMessage(rtc::Message* msg) override {
+    switch (msg->message_id) {
+      case MSG_SDP_MESSAGE: {
+        auto sdp_message =
+            static_cast<rtc::TypedMessageData<SdpMessage>*>(msg->pdata);
+        if (signaling_message_receiver_) {
+          signaling_message_receiver_->ReceiveSdpMessage(
+              sdp_message->data().type, sdp_message->data().msg);
+        }
+        delete sdp_message;
+        break;
+      }
+      case MSG_ICE_MESSAGE: {
+        auto ice_message =
+            static_cast<rtc::TypedMessageData<IceMessage>*>(msg->pdata);
+        if (signaling_message_receiver_) {
+          signaling_message_receiver_->ReceiveIceMessage(
+              ice_message->data().sdp_mid, ice_message->data().sdp_mline_index,
+              ice_message->data().msg);
+        }
+        delete ice_message;
+        break;
+      }
+      default:
+        RTC_CHECK(false);
+    }
   }
 
   // SignalingMessageReceiver callback.
@@ -299,8 +372,7 @@
       // Remote party may be deleted.
       return;
     }
-    signaling_message_receiver_->ReceiveIceMessage(
-        candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
+    SendIceMessage(candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
   }
 
   // MediaStreamInterface callback
@@ -375,6 +447,8 @@
     signaling_message_receiver_ = signaling_message_receiver;
   }
 
+  void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
+
   void EnableVideoDecoderFactory() {
     video_decoder_factory_enabled_ = true;
     fake_video_decoder_factory_->AddSupportedVideoCodecType(
@@ -402,6 +476,9 @@
   bool ExpectIceRenomination() { return expect_ice_renomination_; }
   bool ExpectRemoteIceRenomination() { return expect_remote_ice_renomination_; }
 
+  // The below 3 methods assume streams will be offered.
+  // Thus they'll only set the "offer to receive" flag to true if it's
+  // currently false, not if it's just unset.
   void SetReceiveAudioVideo(bool audio, bool video) {
     SetReceiveAudio(audio);
     SetReceiveVideo(video);
@@ -410,15 +487,24 @@
   }
 
   void SetReceiveAudio(bool audio) {
-    if (audio && can_receive_audio())
+    if (audio && can_receive_audio()) {
       return;
+    }
     offer_answer_constraints_.SetMandatoryReceiveAudio(audio);
     offer_answer_options_.offer_to_receive_audio = audio ? 1 : 0;
   }
 
   void SetReceiveVideo(bool video) {
-    if (video && can_receive_video())
+    if (video && can_receive_video()) {
       return;
+    }
+    offer_answer_constraints_.SetMandatoryReceiveVideo(video);
+    offer_answer_options_.offer_to_receive_video = video ? 1 : 0;
+  }
+
+  void SetOfferToReceiveAudioVideo(bool audio, bool video) {
+    offer_answer_constraints_.SetMandatoryReceiveAudio(audio);
+    offer_answer_options_.offer_to_receive_audio = audio ? 1 : 0;
     offer_answer_constraints_.SetMandatoryReceiveVideo(video);
     offer_answer_options_.offer_to_receive_video = video ? 1 : 0;
   }
@@ -896,7 +982,7 @@
   bool Init(
       const MediaConstraintsInterface* constraints,
       const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration& config,
+      const PeerConnectionInterface::RTCConfiguration* config,
       std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
       bool prefer_constraint_apis,
       rtc::Thread* network_thread,
@@ -908,8 +994,11 @@
     }
     prefer_constraint_apis_ = prefer_constraint_apis;
 
+    fake_network_manager_.reset(new rtc::FakeNetworkManager());
+    fake_network_manager_->AddInterface(rtc::SocketAddress("192.168.1.1", 0));
+
     std::unique_ptr<cricket::PortAllocator> port_allocator(
-        new cricket::FakePortAllocator(network_thread, nullptr));
+        new cricket::BasicPortAllocator(fake_network_manager_.get()));
     fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
 
     if (fake_audio_capture_module_ == nullptr) {
@@ -931,17 +1020,23 @@
     peer_connection_ =
         CreatePeerConnection(std::move(port_allocator), constraints, config,
                              std::move(cert_generator));
-
     return peer_connection_.get() != nullptr;
   }
 
   rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
       std::unique_ptr<cricket::PortAllocator> port_allocator,
       const MediaConstraintsInterface* constraints,
-      const PeerConnectionInterface::RTCConfiguration& config,
+      const PeerConnectionInterface::RTCConfiguration* config,
       std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) {
+    // CreatePeerConnection with RTCConfiguration.
+    PeerConnectionInterface::RTCConfiguration default_config;
+
+    if (!config) {
+      config = &default_config;
+    }
+
     return peer_connection_factory_->CreatePeerConnection(
-        config, constraints, std::move(port_allocator),
+        *config, constraints, std::move(port_allocator),
         std::move(cert_generator), this);
   }
 
@@ -961,10 +1056,7 @@
     std::string sdp;
     EXPECT_TRUE(answer->ToString(&sdp));
     EXPECT_TRUE(DoSetLocalDescription(answer.release()));
-    if (signaling_message_receiver_) {
-      signaling_message_receiver_->ReceiveSdpMessage(
-          webrtc::SessionDescriptionInterface::kAnswer, sdp);
-    }
+    SendSdpMessage(webrtc::SessionDescriptionInterface::kAnswer, sdp);
   }
 
   void HandleIncomingAnswer(const std::string& msg) {
@@ -1065,6 +1157,8 @@
 
   std::string id_;
 
+  std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
+
   rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
   rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
       peer_connection_factory_;
@@ -1095,6 +1189,7 @@
 
   // For remote peer communication.
   SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
+  int signaling_delay_ms_ = 0;
 
   // Store references to the video capturers we've created, so that we can stop
   // them, if required.
@@ -1129,9 +1224,6 @@
         worker_thread_(rtc::Thread::Create()) {
     RTC_CHECK(network_thread_->Start());
     RTC_CHECK(worker_thread_->Start());
-    webrtc::PeerConnectionInterface::IceServer ice_server;
-    ice_server.uri = "stun:stun.l.google.com:19302";
-    config_.servers.push_back(ice_server);
   }
 
   bool SessionActive() {
@@ -1234,19 +1326,24 @@
 
   bool CreateTestClients(MediaConstraintsInterface* init_constraints,
                          MediaConstraintsInterface* recv_constraints) {
-    return CreateTestClients(init_constraints, nullptr, recv_constraints,
-                             nullptr);
+    return CreateTestClients(init_constraints, nullptr, nullptr,
+                             recv_constraints, nullptr, nullptr);
+  }
+
+  bool CreateTestClients(
+      const PeerConnectionInterface::RTCConfiguration& init_config,
+      const PeerConnectionInterface::RTCConfiguration& recv_config) {
+    return CreateTestClients(nullptr, nullptr, &init_config, nullptr, nullptr,
+                             &recv_config);
   }
 
   bool CreateTestClientsThatPreferNoConstraints() {
     initiating_client_.reset(
         PeerConnectionTestClient::CreateClientPreferNoConstraints(
-            "Caller: ", nullptr, config_, network_thread_.get(),
-            worker_thread_.get()));
+            "Caller: ", nullptr, network_thread_.get(), worker_thread_.get()));
     receiving_client_.reset(
         PeerConnectionTestClient::CreateClientPreferNoConstraints(
-            "Callee: ", nullptr, config_, network_thread_.get(),
-            worker_thread_.get()));
+            "Callee: ", nullptr, network_thread_.get(), worker_thread_.get()));
     if (!initiating_client_ || !receiving_client_) {
       return false;
     }
@@ -1256,20 +1353,18 @@
     return true;
   }
 
-  void SetSignalingReceivers() {
-    initiating_client_->set_signaling_message_receiver(receiving_client_.get());
-    receiving_client_->set_signaling_message_receiver(initiating_client_.get());
-  }
-
-  bool CreateTestClients(MediaConstraintsInterface* init_constraints,
-                         PeerConnectionFactory::Options* init_options,
-                         MediaConstraintsInterface* recv_constraints,
-                         PeerConnectionFactory::Options* recv_options) {
+  bool CreateTestClients(
+      MediaConstraintsInterface* init_constraints,
+      PeerConnectionFactory::Options* init_options,
+      const PeerConnectionInterface::RTCConfiguration* init_config,
+      MediaConstraintsInterface* recv_constraints,
+      PeerConnectionFactory::Options* recv_options,
+      const PeerConnectionInterface::RTCConfiguration* recv_config) {
     initiating_client_.reset(PeerConnectionTestClient::CreateClient(
-        "Caller: ", init_constraints, init_options, config_,
+        "Caller: ", init_constraints, init_options, init_config,
         network_thread_.get(), worker_thread_.get()));
     receiving_client_.reset(PeerConnectionTestClient::CreateClient(
-        "Callee: ", recv_constraints, recv_options, config_,
+        "Callee: ", recv_constraints, recv_options, recv_config,
         network_thread_.get(), worker_thread_.get()));
     if (!initiating_client_ || !receiving_client_) {
       return false;
@@ -1278,6 +1373,16 @@
     return true;
   }
 
+  void SetSignalingReceivers() {
+    initiating_client_->set_signaling_message_receiver(receiving_client_.get());
+    receiving_client_->set_signaling_message_receiver(initiating_client_.get());
+  }
+
+  void SetSignalingDelayMs(int delay_ms) {
+    initiating_client_->set_signaling_delay_ms(delay_ms);
+    receiving_client_->set_signaling_delay_ms(delay_ms);
+  }
+
   void SetVideoConstraints(const webrtc::FakeConstraints& init_constraints,
                            const webrtc::FakeConstraints& recv_constraints) {
     initiating_client_->SetVideoConstraints(init_constraints);
@@ -1370,7 +1475,7 @@
 
     // Make sure the new client is using a different certificate.
     return PeerConnectionTestClient::CreateClientWithDtlsIdentityStore(
-        "New Peer: ", &setup_constraints, nullptr, config_,
+        "New Peer: ", &setup_constraints, nullptr, nullptr,
         std::move(cert_generator), prefer_constraint_apis_,
         network_thread_.get(), worker_thread_.get());
   }
@@ -1385,6 +1490,8 @@
     }
   }
 
+  rtc::Thread* network_thread() { return network_thread_.get(); }
+
   rtc::VirtualSocketServer* virtual_socket_server() { return ss_.get(); }
 
   PeerConnectionTestClient* initializing_client() {
@@ -1412,9 +1519,6 @@
     receiving_client_.reset(client);
     return old;
   }
-  webrtc::PeerConnectionInterface::RTCConfiguration* config() {
-    return &config_;
-  }
 
   bool AllObserversReceived(
       const std::vector<std::unique_ptr<MockRtpReceiverObserver>>& observers) {
@@ -1432,8 +1536,8 @@
     init_options.crypto_options.enable_gcm_crypto_suites = local_gcm_enabled;
     PeerConnectionFactory::Options recv_options;
     recv_options.crypto_options.enable_gcm_crypto_suites = remote_gcm_enabled;
-    ASSERT_TRUE(
-        CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
+    ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
+                                  &recv_options, nullptr));
     rtc::scoped_refptr<webrtc::FakeMetricsObserver>
         init_observer =
             new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
@@ -1460,7 +1564,6 @@
   std::unique_ptr<PeerConnectionTestClient> initiating_client_;
   std::unique_ptr<PeerConnectionTestClient> receiving_client_;
   bool prefer_constraint_apis_ = true;
-  webrtc::PeerConnectionInterface::RTCConfiguration config_;
 };
 
 // Disable for TSan v2, see
@@ -1803,8 +1906,8 @@
   init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
   PeerConnectionFactory::Options recv_options;
   recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
-  ASSERT_TRUE(
-      CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
+  ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
+                                &recv_options, nullptr));
   rtc::scoped_refptr<webrtc::FakeMetricsObserver>
       init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
   initializing_client()->pc()->RegisterUMAObserver(init_observer);
@@ -1828,8 +1931,8 @@
   init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
   PeerConnectionFactory::Options recv_options;
   recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
-  ASSERT_TRUE(
-      CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
+  ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
+                                &recv_options, nullptr));
   rtc::scoped_refptr<webrtc::FakeMetricsObserver>
       init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
   initializing_client()->pc()->RegisterUMAObserver(init_observer);
@@ -1854,8 +1957,8 @@
   init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
   PeerConnectionFactory::Options recv_options;
   recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
-  ASSERT_TRUE(
-      CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
+  ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
+                                &recv_options, nullptr));
   rtc::scoped_refptr<webrtc::FakeMetricsObserver>
       init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
   initializing_client()->pc()->RegisterUMAObserver(init_observer);
@@ -1880,8 +1983,8 @@
   init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
   PeerConnectionFactory::Options recv_options;
   recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
-  ASSERT_TRUE(
-      CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
+  ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
+                                &recv_options, nullptr));
   rtc::scoped_refptr<webrtc::FakeMetricsObserver>
       init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
   initializing_client()->pc()->RegisterUMAObserver(init_observer);
@@ -2176,8 +2279,9 @@
 }
 
 TEST_F(P2PTestConductor, IceRenominationDisabled) {
-  config()->enable_ice_renomination = false;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration config;
+  config.enable_ice_renomination = false;
+  ASSERT_TRUE(CreateTestClients(config, config));
   LocalP2PTest();
 
   initializing_client()->VerifyLocalIceRenomination();
@@ -2187,8 +2291,9 @@
 }
 
 TEST_F(P2PTestConductor, IceRenominationEnabled) {
-  config()->enable_ice_renomination = true;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration config;
+  config.enable_ice_renomination = true;
+  ASSERT_TRUE(CreateTestClients(config, config));
   initializing_client()->SetExpectIceRenomination(true);
   initializing_client()->SetExpectRemoteIceRenomination(true);
   receiving_client()->SetExpectIceRenomination(true);
@@ -2268,8 +2373,9 @@
 // This test sets up a call between two parties using QUIC instead of DTLS for
 // audio and video, and a QUIC data channel.
 TEST_F(P2PTestConductor, LocalP2PTestQuicDataChannel) {
-  config()->enable_quic = true;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration quic_config;
+  quic_config.enable_quic = true;
+  ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
   webrtc::DataChannelInit init;
   init.ordered = false;
   init.reliable = true;
@@ -2296,7 +2402,9 @@
 
 // Tests that negotiation of QUIC data channels is completed without error.
 TEST_F(P2PTestConductor, NegotiateQuicDataChannel) {
-  config()->enable_quic = true;
+  PeerConnectionInterface::RTCConfiguration quic_config;
+  quic_config.enable_quic = true;
+  ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
   FakeConstraints constraints;
   constraints.SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
   ASSERT_TRUE(CreateTestClients(&constraints, &constraints));
@@ -2310,16 +2418,18 @@
 
 // This test sets up a JSEP call using QUIC. The callee only receives video.
 TEST_F(P2PTestConductor, LocalP2PTestVideoOnlyWithQuic) {
-  config()->enable_quic = true;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration quic_config;
+  quic_config.enable_quic = true;
+  ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
   receiving_client()->SetReceiveAudioVideo(false, true);
   LocalP2PTest();
 }
 
 // This test sets up a JSEP call using QUIC. The callee only receives audio.
 TEST_F(P2PTestConductor, LocalP2PTestAudioOnlyWithQuic) {
-  config()->enable_quic = true;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration quic_config;
+  quic_config.enable_quic = true;
+  ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
   receiving_client()->SetReceiveAudioVideo(true, false);
   LocalP2PTest();
 }
@@ -2327,8 +2437,9 @@
 // This test sets up a JSEP call using QUIC. The callee rejects both audio and
 // video.
 TEST_F(P2PTestConductor, LocalP2PTestNoVideoAudioWithQuic) {
-  config()->enable_quic = true;
-  ASSERT_TRUE(CreateTestClients());
+  PeerConnectionInterface::RTCConfiguration quic_config;
+  quic_config.enable_quic = true;
+  ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
   receiving_client()->SetReceiveAudioVideo(false, false);
   LocalP2PTest();
 }
@@ -2368,6 +2479,102 @@
       kMaxWaitForFramesMs);
 }
 
+// Test that we achieve the expected end-to-end connection time, using a
+// fake clock and simulated latency on the media and signaling paths.
+// We use a TURN<->TURN connection because this is usually the quickest to
+// set up initially, especially when we're confident the connection will work
+// and can start sending media before we get a STUN response.
+//
+// With various optimizations enabled, here are the network delays we expect to
+// be on the critical path:
+// 1. 2 signaling trips: Signaling offer and offerer's TURN candidate, then
+//                       signaling answer (with DTLS fingerprint).
+// 2. 9 media hops: Rest of the DTLS handshake. 3 hops in each direction when
+//                  using TURN<->TURN pair, and DTLS exchange is 4 packets,
+//                  the first of which should have arrived before the answer.
+TEST_F(P2PTestConductor, EndToEndConnectionTimeWithTurnTurnPair) {
+  rtc::ScopedFakeClock fake_clock;
+  // Some things use a time of "0" as a special value, so we need to start out
+  // the fake clock at a nonzero time.
+  // TODO(deadbeef): Fix this.
+  fake_clock.AdvanceTime(rtc::TimeDelta::FromSeconds(1));
+
+  static constexpr int media_hop_delay_ms = 50;
+  static constexpr int signaling_trip_delay_ms = 500;
+  // For explanation of these values, see comment above.
+  static constexpr int required_media_hops = 9;
+  static constexpr int required_signaling_trips = 2;
+  // For internal delays (such as posting an event asychronously).
+  static constexpr int allowed_internal_delay_ms = 20;
+  static constexpr int total_connection_time_ms =
+      media_hop_delay_ms * required_media_hops +
+      signaling_trip_delay_ms * required_signaling_trips +
+      allowed_internal_delay_ms;
+
+  static const rtc::SocketAddress turn_server_1_internal_address{"88.88.88.0",
+                                                                 3478};
+  static const rtc::SocketAddress turn_server_1_external_address{"88.88.88.1",
+                                                                 0};
+  static const rtc::SocketAddress turn_server_2_internal_address{"99.99.99.0",
+                                                                 3478};
+  static const rtc::SocketAddress turn_server_2_external_address{"99.99.99.1",
+                                                                 0};
+  cricket::TestTurnServer turn_server_1(network_thread(),
+                                        turn_server_1_internal_address,
+                                        turn_server_1_external_address);
+  cricket::TestTurnServer turn_server_2(network_thread(),
+                                        turn_server_2_internal_address,
+                                        turn_server_2_external_address);
+  // Bypass permission check on received packets so media can be sent before
+  // the candidate is signaled.
+  turn_server_1.set_enable_permission_checks(false);
+  turn_server_2.set_enable_permission_checks(false);
+
+  PeerConnectionInterface::RTCConfiguration client_1_config;
+  webrtc::PeerConnectionInterface::IceServer ice_server_1;
+  ice_server_1.urls.push_back("turn:88.88.88.0:3478");
+  ice_server_1.username = "test";
+  ice_server_1.password = "test";
+  client_1_config.servers.push_back(ice_server_1);
+  client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
+  client_1_config.presume_writable_when_fully_relayed = true;
+
+  PeerConnectionInterface::RTCConfiguration client_2_config;
+  webrtc::PeerConnectionInterface::IceServer ice_server_2;
+  ice_server_2.urls.push_back("turn:99.99.99.0:3478");
+  ice_server_2.username = "test";
+  ice_server_2.password = "test";
+  client_2_config.servers.push_back(ice_server_2);
+  client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
+  client_2_config.presume_writable_when_fully_relayed = true;
+
+  ASSERT_TRUE(CreateTestClients(client_1_config, client_2_config));
+  // Set up the simulated delays.
+  SetSignalingDelayMs(signaling_trip_delay_ms);
+  virtual_socket_server()->set_delay_mean(media_hop_delay_ms);
+  virtual_socket_server()->UpdateDelayDistribution();
+
+  initializing_client()->SetOfferToReceiveAudioVideo(true, true);
+  initializing_client()->Negotiate();
+  // TODO(deadbeef): kIceConnectionConnected currently means both ICE and DTLS
+  // are connected. This is an important distinction. Once we have separate ICE
+  // and DTLS state, this check needs to use the DTLS state.
+  EXPECT_TRUE_SIMULATED_WAIT(
+      (receiving_client()->ice_connection_state() ==
+           webrtc::PeerConnectionInterface::kIceConnectionConnected ||
+       receiving_client()->ice_connection_state() ==
+           webrtc::PeerConnectionInterface::kIceConnectionCompleted) &&
+          (initializing_client()->ice_connection_state() ==
+               webrtc::PeerConnectionInterface::kIceConnectionConnected ||
+           initializing_client()->ice_connection_state() ==
+               webrtc::PeerConnectionInterface::kIceConnectionCompleted),
+      total_connection_time_ms, fake_clock);
+  // Need to free the clients here since they're using things we created on
+  // the stack.
+  delete set_initializing_client(nullptr);
+  delete set_receiving_client(nullptr);
+}
+
 class IceServerParsingTest : public testing::Test {
  public:
   // Convenience for parsing a single URL.
diff --git a/webrtc/base/fakenetwork.h b/webrtc/base/fakenetwork.h
index 1912dd0..108e738 100644
--- a/webrtc/base/fakenetwork.h
+++ b/webrtc/base/fakenetwork.h
@@ -31,7 +31,7 @@
 class FakeNetworkManager : public NetworkManagerBase,
                            public MessageHandler {
  public:
-  FakeNetworkManager() : thread_(Thread::Current()) {}
+  FakeNetworkManager() {}
 
   typedef std::vector<std::pair<SocketAddress, AdapterType>> IfaceList;
 
@@ -68,7 +68,7 @@
     ++start_count_;
     if (start_count_ == 1) {
       sent_first_update_ = false;
-      thread_->Post(RTC_FROM_HERE, this);
+      rtc::Thread::Current()->Post(RTC_FROM_HERE, this);
     } else {
       if (sent_first_update_) {
         SignalNetworksChanged();
@@ -115,7 +115,6 @@
     }
   }
 
-  Thread* thread_;
   IfaceList ifaces_;
   int next_index_ = 0;
   int start_count_ = 0;
diff --git a/webrtc/p2p/base/testturnserver.h b/webrtc/p2p/base/testturnserver.h
index 43d363c..9cd8203 100644
--- a/webrtc/p2p/base/testturnserver.h
+++ b/webrtc/p2p/base/testturnserver.h
@@ -52,10 +52,10 @@
                  const rtc::SocketAddress& int_addr,
                  const rtc::SocketAddress& udp_ext_addr,
                  ProtocolType int_protocol = PROTO_UDP)
-      : server_(thread) {
+      : server_(thread), thread_(thread) {
     AddInternalSocket(int_addr, int_protocol);
-    server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(),
-        udp_ext_addr);
+    server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(thread),
+                                     udp_ext_addr);
     server_.set_realm(kTestRealm);
     server_.set_software(kTestSoftware);
     server_.set_auth_hook(this);
@@ -77,15 +77,15 @@
 
   void AddInternalSocket(const rtc::SocketAddress& int_addr,
                          ProtocolType proto) {
-    rtc::Thread* thread = rtc::Thread::Current();
     if (proto == cricket::PROTO_UDP) {
-      server_.AddInternalSocket(rtc::AsyncUDPSocket::Create(
-          thread->socketserver(), int_addr), proto);
+      server_.AddInternalSocket(
+          rtc::AsyncUDPSocket::Create(thread_->socketserver(), int_addr),
+          proto);
     } else if (proto == cricket::PROTO_TCP) {
       // For TCP we need to create a server socket which can listen for incoming
       // new connections.
       rtc::AsyncSocket* socket =
-          thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+          thread_->socketserver()->CreateAsyncSocket(SOCK_STREAM);
       socket->Bind(int_addr);
       socket->Listen(5);
       server_.AddInternalServerSocket(socket, proto);
@@ -114,6 +114,7 @@
   }
 
   TurnServer server_;
+  rtc::Thread* thread_;
 };
 
 }  // namespace cricket