Refactor TurnPort tests.

This commit makes the following changes:
1. Splits TestReconstructedServerUrl into 3 tests that individually
   check the reconstructed URL for UDP IPv4, UDP IPv6, and TCP.
2. Factors out common code between protocols for release allocation and
   reconstructed URL tests.
3. Provides functions for getting the expected RTT of various operations
   based on the protocol used. TurnPort tests use a fake clock in part
   to check tight bounds on the number of network round trips it takes
   to complete operations like getting TURN candidates and trying
   alternate servers. These RTTs are highly dependent on the
   characteristics of the transport-layer protocol used, so these
   details have been moved to dedicated functions with comments
   explaining how the numbers are calculated.

Bug: webrtc:7584
Change-Id: I3b065e25446cb5ecd955f359625a35fb0ad46777
Reviewed-on: https://chromium-review.googlesource.com/611500
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Zhi Huang <zhihuang@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19395}
diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc
index 7e0e291..fccf041 100644
--- a/webrtc/p2p/base/turnport_unittest.cc
+++ b/webrtc/p2p/base/turnport_unittest.cc
@@ -320,18 +320,48 @@
     // turn_port_ should have been created.
     ASSERT_TRUE(turn_port_ != nullptr);
     turn_port_->PrepareAddress();
-    // Two round trips are required to allocate a TURN candidate.
-    // Plus, an extra round trip is needed for TCP.
     ASSERT_TRUE_SIMULATED_WAIT(
-        turn_ready_,
-        protocol_type == PROTO_TCP ? kSimulatedRtt * 3 : kSimulatedRtt * 2,
-        fake_clock_);
+        turn_ready_, TimeToGetTurnCandidate(protocol_type), fake_clock_);
 
     CreateUdpPort();
     udp_port_->PrepareAddress();
     ASSERT_TRUE_SIMULATED_WAIT(udp_ready_, kSimulatedRtt, fake_clock_);
   }
 
+  // Returns the fake clock time to establish a connection over the given
+  // protocol.
+  int TimeToConnect(ProtocolType protocol_type) {
+    switch (protocol_type) {
+      case PROTO_TCP:
+        // The virtual socket server will delay by a fixed half a round trip
+        // for a TCP connection.
+        return kSimulatedRtt / 2;
+      case PROTO_UDP:
+      default:
+        // UDP requires no round trips to set up the connection.
+        return 0;
+    }
+  }
+
+  // Returns the total fake clock time to establish a connection with a TURN
+  // server over the given protocol and to allocate a TURN candidate.
+  int TimeToGetTurnCandidate(ProtocolType protocol_type) {
+    // For a simple allocation, the first Allocate message will return with an
+    // error asking for credentials and will succeed after the second Allocate
+    // message.
+    return 2 * kSimulatedRtt + TimeToConnect(protocol_type);
+  }
+
+  // Total fake clock time to do the following:
+  // 1. Connect to primary TURN server
+  // 2. Send Allocate and receive a redirect from the primary TURN server
+  // 3. Connect to alternate TURN server
+  // 4. Send Allocate and receive a request for credentials
+  // 5. Send Allocate with credentials and receive allocation
+  int TimeToGetAlternateTurnCandidate(ProtocolType protocol_type) {
+    return 3 * kSimulatedRtt + 2 * TimeToConnect(protocol_type);
+  }
+
   bool CheckConnectionFailedAndPruned(Connection* conn) {
     return conn && !conn->active() &&
            conn->state() == IceCandidatePairState::FAILED;
@@ -352,6 +382,15 @@
     return true;
   }
 
+  void TestReconstructedServerUrl(ProtocolType protocol_type,
+                                  const char* expected_url) {
+    turn_port_->PrepareAddress();
+    ASSERT_TRUE_SIMULATED_WAIT(
+        turn_ready_, TimeToGetTurnCandidate(protocol_type), fake_clock_);
+    ASSERT_EQ(1U, turn_port_->Candidates().size());
+    EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_url);
+  }
+
   void TestTurnAlternateServer(ProtocolType protocol_type) {
     std::vector<rtc::SocketAddress> redirect_addresses;
     redirect_addresses.push_back(kTurnAlternateIntAddr);
@@ -368,11 +407,9 @@
     const SocketAddress old_addr = turn_port_->server_address().address;
 
     turn_port_->PrepareAddress();
-    // Extra round trip due to "use alternate server" error response.
-    EXPECT_TRUE_SIMULATED_WAIT(
-        turn_ready_,
-        (protocol_type == PROTO_TCP ? kSimulatedRtt * 4 : kSimulatedRtt * 3),
-        fake_clock_);
+    EXPECT_TRUE_SIMULATED_WAIT(turn_ready_,
+                               TimeToGetAlternateTurnCandidate(protocol_type),
+                               fake_clock_);
     // Retrieve the address again, the turn port's address should be
     // changed.
     const SocketAddress new_addr = turn_port_->server_address().address;
@@ -393,7 +430,10 @@
     CreateTurnPort(kTurnUsername, kTurnPassword,
                    ProtocolAddress(kTurnIntAddr, protocol_type));
     turn_port_->PrepareAddress();
-    EXPECT_TRUE_SIMULATED_WAIT(turn_error_, kSimulatedRtt * 2, fake_clock_);
+    // Need time to connect to TURN server, send Allocate request and receive
+    // redirect notice.
+    EXPECT_TRUE_SIMULATED_WAIT(
+        turn_error_, kSimulatedRtt + TimeToConnect(protocol_type), fake_clock_);
   }
 
   void TestTurnAlternateServerPingPong(ProtocolType protocol_type) {
@@ -410,11 +450,9 @@
                    ProtocolAddress(kTurnIntAddr, protocol_type));
 
     turn_port_->PrepareAddress();
-    // Extra round trip due to "use alternate server" error response.
-    EXPECT_TRUE_SIMULATED_WAIT(
-        turn_error_,
-        (protocol_type == PROTO_TCP ? kSimulatedRtt * 4 : kSimulatedRtt * 3),
-        fake_clock_);
+    EXPECT_TRUE_SIMULATED_WAIT(turn_error_,
+                               TimeToGetAlternateTurnCandidate(protocol_type),
+                               fake_clock_);
     ASSERT_EQ(0U, turn_port_->Candidates().size());
     rtc::SocketAddress address;
     // Verify that we have exhausted all alternate servers instead of
@@ -436,11 +474,9 @@
                    ProtocolAddress(kTurnIntAddr, protocol_type));
 
     turn_port_->PrepareAddress();
-    // Extra round trip due to "use alternate server" error response.
-    EXPECT_TRUE_SIMULATED_WAIT(
-        turn_error_,
-        (protocol_type == PROTO_TCP ? kSimulatedRtt * 4 : kSimulatedRtt * 3),
-        fake_clock_);
+    EXPECT_TRUE_SIMULATED_WAIT(turn_error_,
+                               TimeToGetAlternateTurnCandidate(protocol_type),
+                               fake_clock_);
     ASSERT_EQ(0U, turn_port_->Candidates().size());
   }
 
@@ -479,9 +515,7 @@
 
     turn_port_->PrepareAddress();
     EXPECT_TRUE_SIMULATED_WAIT(
-        turn_error_,
-        (protocol_type == PROTO_TCP ? kSimulatedRtt * 3 : kSimulatedRtt * 2),
-        fake_clock_);
+        turn_error_, TimeToGetTurnCandidate(protocol_type), fake_clock_);
 
     // Wait for some extra time, and make sure no packets were received on the
     // loopback port we created (or in the case of TCP, no connection attempt
@@ -616,6 +650,14 @@
     }
   }
 
+  // Test that a TURN allocation is released when the port is closed.
+  void TestTurnReleaseAllocation(ProtocolType protocol_type) {
+    PrepareTurnAndUdpPorts(protocol_type);
+    turn_port_.reset();
+    EXPECT_EQ_SIMULATED_WAIT(0U, turn_server_.server()->allocations().size(),
+                             kSimulatedRtt, fake_clock_);
+  }
+
  protected:
   rtc::ScopedFakeClock fake_clock_;
   // When a "create port" helper method is called with an IP, we create a
@@ -648,36 +690,24 @@
 
 // Tests that the URL of the servers can be correctly reconstructed when
 // gathering the candidates.
-TEST_F(TurnPortTest, TestReconstructedServerUrl) {
-  // Connect the TURN server using UDP.
+TEST_F(TurnPortTest, TestReconstructedServerUrlForUdpIPv4) {
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_);
-  std::string expected_server_url = "turn:99.99.99.3:3478?transport=udp";
-  EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url);
+  TestReconstructedServerUrl(PROTO_UDP, "turn:99.99.99.3:3478?transport=udp");
+}
 
-  // Connect the server with IPV6 using UDP.
-  turn_ready_ = false;
+TEST_F(TurnPortTest, TestReconstructedServerUrlForUdpIPv6) {
   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP);
   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
                  kTurnUdpIPv6ProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_);
-  ASSERT_EQ(1U, turn_port_->Candidates().size());
-  expected_server_url =
-      "turn:2400:4030:1:2c00:be30:abcd:efab:cdef:3478?transport=udp";
-  EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url);
+  TestReconstructedServerUrl(
+      PROTO_UDP,
+      "turn:2400:4030:1:2c00:be30:abcd:efab:cdef:3478?transport=udp");
+}
 
-  // Connection the server using TCP.
-  turn_ready_ = false;
+TEST_F(TurnPortTest, TestReconstructedServerUrlForTcp) {
   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_);
-  ASSERT_EQ(1U, turn_port_->Candidates().size());
-  expected_server_url = "turn:99.99.99.4:3478?transport=tcp";
-  EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url);
-  turn_ready_ = false;
+  TestReconstructedServerUrl(PROTO_TCP, "turn:99.99.99.4:3478?transport=tcp");
 }
 
 // Do a normal TURN allocation.
@@ -1317,26 +1347,14 @@
 // Test that a TURN allocation is released when the port is closed.
 TEST_F(TurnPortTest, TestTurnReleaseAllocation) {
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_);
-
-  ASSERT_GT(turn_server_.server()->allocations().size(), 0U);
-  turn_port_.reset();
-  EXPECT_EQ_SIMULATED_WAIT(0U, turn_server_.server()->allocations().size(),
-                           kSimulatedRtt, fake_clock_);
+  TestTurnReleaseAllocation(PROTO_UDP);
 }
 
 // Test that a TURN TCP allocation is released when the port is closed.
 TEST_F(TurnPortTest, TestTurnTCPReleaseAllocation) {
   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_);
-
-  ASSERT_GT(turn_server_.server()->allocations().size(), 0U);
-  turn_port_.reset();
-  EXPECT_EQ_SIMULATED_WAIT(0U, turn_server_.server()->allocations().size(),
-                           kSimulatedRtt, fake_clock_);
+  TestTurnReleaseAllocation(PROTO_TCP);
 }
 
 // This test verifies any FD's are not leaked after TurnPort is destroyed.