Adding 20-second timeout to Java and Objective-C tests.

This is the same sort of thing we do in C++ end-to-end PeerConnection
tests.

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

Cr-Commit-Position: refs/heads/master@{#10098}
diff --git a/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java b/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
index 7affbd9..001980f 100644
--- a/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
+++ b/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
@@ -50,6 +50,7 @@
 public class PeerConnectionTest {
   // Set to true to render video.
   private static final boolean RENDER_TO_GUI = false;
+  private static final int TIMEOUT_SECONDS = 20;
   private TreeSet<String> threadsBeforeTest = null;
 
   private static class ObserverExpectations implements PeerConnection.Observer,
@@ -347,7 +348,7 @@
       return stillWaitingForExpectations;
     }
 
-    public void waitForAllExpectationsToBeSatisfied() {
+    public boolean waitForAllExpectationsToBeSatisfied(int timeoutSeconds) {
       // TODO(fischman): problems with this approach:
       // - come up with something better than a poll loop
       // - avoid serializing expectations explicitly; the test is not as robust
@@ -357,6 +358,7 @@
       //   stall a wait).  Use callbacks to fire off dependent steps instead of
       //   explicitly waiting, so there can be just a single wait at the end of
       //   the test.
+      long endTime = System.currentTimeMillis() + 1000 * timeoutSeconds;
       TreeSet<String> prev = null;
       TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations();
       while (!stillWaitingForExpectations.isEmpty()) {
@@ -367,6 +369,11 @@
               "\n    for: " +
               Arrays.toString(stillWaitingForExpectations.toArray()));
         }
+        if (endTime < System.currentTimeMillis()) {
+          System.out.println(name + " timed out waiting for: "
+              + Arrays.toString(stillWaitingForExpectations.toArray()));
+          return false;
+        }
         try {
           Thread.sleep(10);
         } catch (InterruptedException e) {
@@ -379,6 +386,7 @@
         System.out.println(name + " didn't need to wait at\n    " +
                            (new Throwable()).getStackTrace()[1]);
       }
+      return true;
     }
 
     // This methods return a list of all currently gathered ice candidates or waits until
@@ -661,8 +669,8 @@
       offeringPC.addIceCandidate(candidate);
     }
 
-    offeringExpectations.waitForAllExpectationsToBeSatisfied();
-    answeringExpectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
+    assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
 
     assertEquals(
         PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
@@ -675,7 +683,7 @@
     DataChannel.Buffer buffer = new DataChannel.Buffer(
         ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
     assertTrue(offeringExpectations.dataChannel.send(buffer));
-    answeringExpectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
 
     // Construct this binary message two different ways to ensure no
     // shortcuts are taken.
@@ -688,7 +696,7 @@
     assertTrue(answeringExpectations.dataChannel.send(
         new DataChannel.Buffer(
             ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
-    offeringExpectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
 
     offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
     answeringExpectations.expectStateChange(DataChannel.State.CLOSING);
@@ -734,14 +742,14 @@
     expectations.dataChannel.dispose();
     expectations.expectStatsCallback();
     assertTrue(pc.getStats(expectations, null));
-    expectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
     expectations.expectIceConnectionChange(IceConnectionState.CLOSED);
     expectations.expectSignalingChange(SignalingState.CLOSED);
     pc.close();
-    expectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
     expectations.expectStatsCallback();
     assertTrue(pc.getStats(expectations, null));
-    expectations.waitForAllExpectationsToBeSatisfied();
+    assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
 
     System.out.println("FYI stats: ");
     int reportIndex = -1;
diff --git a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
index 436515f..7c49e1d 100644
--- a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
+++ b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
@@ -54,6 +54,7 @@
 - (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary;
 
 // Wait until all registered expectations above have been observed.
-- (void)waitForAllExpectationsToBeSatisfied;
+// Return false if expectations aren't met within |timeoutSeconds|.
+- (BOOL)waitForAllExpectationsToBeSatisfiedWithTimeout:(NSTimeInterval)timeout;
 
 @end
diff --git a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
index daebc95..892c461 100644
--- a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
+++ b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
@@ -139,14 +139,20 @@
   [_expectedMessages addObject:buffer];
 }
 
-- (void)waitForAllExpectationsToBeSatisfied {
+- (BOOL)waitForAllExpectationsToBeSatisfiedWithTimeout:(NSTimeInterval)timeout {
+  NSParameterAssert(timeout >= 0);
   // TODO (fischman):  Revisit.  Keeping in sync with the Java version, but
   // polling is not optimal.
   // https://code.google.com/p/libjingle/source/browse/trunk/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java?line=212#212
+  NSDate *startTime = [NSDate date];
   while (![self areAllExpectationsSatisfied]) {
+    if (startTime.timeIntervalSinceNow < -timeout) {
+      return NO;
+    }
     [[NSRunLoop currentRunLoop]
         runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
   }
+  return YES;
 }
 
 #pragma mark - RTCPeerConnectionDelegate methods
diff --git a/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm b/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
index f0703f5..c43a6fc 100644
--- a/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
+++ b/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
@@ -46,6 +46,8 @@
 #error "This file requires ARC support."
 #endif
 
+const NSTimeInterval kRTCPeerConnectionTestTimeout = 20;
+
 @interface RTCFakeRenderer : NSObject <RTCVideoRenderer>
 @end
 
@@ -238,8 +240,12 @@
     [pcOffer addICECandidate:candidate];
   }
 
-  [offeringExpectations waitForAllExpectationsToBeSatisfied];
-  [answeringExpectations waitForAllExpectationsToBeSatisfied];
+  EXPECT_TRUE(
+      [offeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                kRTCPeerConnectionTestTimeout]);
+  EXPECT_TRUE(
+      [answeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                 kRTCPeerConnectionTestTimeout]);
 
   EXPECT_EQ(pcOffer.signalingState, RTCSignalingStable);
   EXPECT_EQ(pcAnswer.signalingState, RTCSignalingStable);
@@ -251,7 +257,9 @@
       [[RTCDataBuffer alloc] initWithData:textData isBinary:NO];
   [answeringExpectations expectMessage:[textData copy] isBinary:NO];
   EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
-  [answeringExpectations waitForAllExpectationsToBeSatisfied];
+  EXPECT_TRUE(
+      [answeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                 kRTCPeerConnectionTestTimeout]);
 
   // Test send and receive binary data
   const size_t byteLength = 5;
@@ -260,7 +268,9 @@
   buffer = [[RTCDataBuffer alloc] initWithData:byteData isBinary:YES];
   [answeringExpectations expectMessage:[byteData copy] isBinary:YES];
   EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
-  [answeringExpectations waitForAllExpectationsToBeSatisfied];
+  EXPECT_TRUE(
+      [answeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                 kRTCPeerConnectionTestTimeout]);
 
   [offeringExpectations expectStateChange:kRTCDataChannelStateClosing];
   [answeringExpectations expectStateChange:kRTCDataChannelStateClosing];
@@ -270,8 +280,12 @@
   [answeringExpectations.dataChannel close];
   [offeringExpectations.dataChannel close];
 
-  [offeringExpectations waitForAllExpectationsToBeSatisfied];
-  [answeringExpectations waitForAllExpectationsToBeSatisfied];
+  EXPECT_TRUE(
+      [offeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                kRTCPeerConnectionTestTimeout]);
+  EXPECT_TRUE(
+      [answeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                 kRTCPeerConnectionTestTimeout]);
   // Don't need to listen to further state changes.
   // TODO(tkchin): figure out why Closed->Closing without this.
   offeringExpectations.dataChannel.delegate = nil;
@@ -291,8 +305,12 @@
   [pcOffer close];
   [pcAnswer close];
 
-  [offeringExpectations waitForAllExpectationsToBeSatisfied];
-  [answeringExpectations waitForAllExpectationsToBeSatisfied];
+  EXPECT_TRUE(
+      [offeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                kRTCPeerConnectionTestTimeout]);
+  EXPECT_TRUE(
+      [answeringExpectations waitForAllExpectationsToBeSatisfiedWithTimeout:
+                                 kRTCPeerConnectionTestTimeout]);
 
   capturer = nil;
   videoSource = nil;