Bug 1457129 - Correct WebRTC getStats WPT to wait for remote stats before comparing. r=jib, a=test-only
authorNico Grunbaum <na-g@nostrum.com>
Thu, 01 Nov 2018 22:04:14 +0000
changeset 501067 2f1f32b76f7ee4fa06d9ad1e7a7929554293f48a
parent 501066 5b42d14602aacbaf0aa2bbdcbfb7cf2100cb162e
child 501068 9ca3d0b3e93a8561ad1f18bcdace54e73f025ecc
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, test-only
bugs1457129
milestone64.0
Bug 1457129 - Correct WebRTC getStats WPT to wait for remote stats before comparing. r=jib, a=test-only If care is not taken to wait for remote stats on senders and receivers, then the contents of the stats reports will not be stable. Waiting for this stability should fix our intermittent failures checking that RTCRtpSender/Receiver.getStats() returns the same dictionaries that RTCPeerConnection.getStats(sender/receiver.track) does. Differential Revision: https://phabricator.services.mozilla.com/D5804
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/webrtc/RTCPeerConnection-helper.js
testing/web-platform/tests/webrtc/RTCPeerConnection-track-stats.https.html
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -405069,17 +405069,19 @@
     [
      "/webrtc/RTCPeerConnection-setRemoteDescription.html",
      {}
     ]
    ],
    "webrtc/RTCPeerConnection-track-stats.https.html": [
     [
      "/webrtc/RTCPeerConnection-track-stats.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "webrtc/RTCPeerConnection-transceivers.https.html": [
     [
      "/webrtc/RTCPeerConnection-transceivers.https.html",
      {}
     ]
    ],
@@ -657640,17 +657642,17 @@
    "62ddaffb443c94505383083923dc13fcb1cf5660",
    "support"
   ],
   "tools/wptrunner/wptrunner/testloader.py": [
    "2313a80c745bfac9946119926411234c506c6654",
    "support"
   ],
   "tools/wptrunner/wptrunner/testrunner.py": [
-   "7e386b881d4c83a93d2543b7e5b9afd01623a5bc",
+   "90f7e4615e078840f9804f791422f9f2f3464a72",
    "support"
   ],
   "tools/wptrunner/wptrunner/tests/__init__.py": [
    "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
   ],
   "tools/wptrunner/wptrunner/tests/base.py": [
    "84dc4f2e7f82ee2e3a2aa6f4d8bdda76b1581da1",
@@ -663668,17 +663670,17 @@
    "247402b83be0a2655fa8d4ad43fa166b6459c587",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-getTransceivers.html": [
    "381b42b0cff4e7103ceffc14a45eaa5a6cb56b27",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-helper.js": [
-   "27ff1873790cfc4f71a07e1735ec4389ee330a18",
+   "1d740f00d1a8fab386bc7fdae2b94faa52824e70",
    "support"
   ],
   "webrtc/RTCPeerConnection-iceConnectionState.html": [
    "4071033a3c9eff6e5b848531127c1b70ee90bb20",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-iceGatheringState.html": [
    "fb9e514194b98062acc3fdd33111a2d740bb9d52",
@@ -663752,17 +663754,17 @@
    "7179f1ef78ccd5b5b956df6241d0b2b47c7425a4",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setRemoteDescription.html": [
    "ad9cdff5fb0a4cf90e977fd0cdde7d3d685e9f4d",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-track-stats.https.html": [
-   "682e7e57e465ccde77c3d8887ce80cb5ea01bf54",
+   "4b610b474a61a291798ff8258fb5edc423d44cb7",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-transceivers.https.html": [
    "c89737c99fcebe76b1156499cb7269e7b0a67af1",
    "testharness"
   ],
   "webrtc/RTCPeerConnectionIceEvent-constructor.html": [
    "07e9736441285536e0549c55b110a562b49276cc",
--- a/testing/web-platform/tests/webrtc/RTCPeerConnection-helper.js
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-helper.js
@@ -276,16 +276,29 @@ function createDataChannelPair(
     channel1.addEventListener('error', reject);
 
     pc2.addEventListener('datachannel', onDataChannel);
 
     doSignalingHandshake(pc1, pc2);
   });
 }
 
+// Wait for RTP and RTCP stats to arrive
+async function waitForRtpAndRtcpStats(pc) {
+  while (true) {
+    const report = await pc.getStats();
+    const stats = [...report.values()].filter(({type}) => type.endsWith("bound-rtp"));
+    // Each RTP and RTCP stat has a reference
+    // to the matching stat in the other direction
+    if (stats.length && stats.every(({localId, remoteId}) => localId || remoteId)) {
+      break;
+    }
+  }
+}
+
 // Wait for a single message event and return
 // a promise that resolve when the event fires
 function awaitMessage(channel) {
   return new Promise((resolve, reject) => {
     channel.addEventListener('message',
       event => resolve(event.data),
       { once: true });
 
--- a/testing/web-platform/tests/webrtc/RTCPeerConnection-track-stats.https.html
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-track-stats.https.html
@@ -1,22 +1,24 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCPeerConnection.prototype.getStats</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="RTCPeerConnection-helper.js"></script>
 <script src="dictionary-helper.js"></script>
 <script src="RTCStats-helper.js"></script>
 <script>
   'use strict';
 
   // The following helper functions are called from RTCPeerConnection-helper.js:
   //   doSignalingHandshake
   //   getUserMediaTracksAndStreams
+  //   waitForRtpAndRtcpStats
 
   // The following helper functions are called from RTCStats-helper.js
   // (depends on dictionary-helper.js):
   //   validateRtcStats
 
   async_test(t => {
     const pc = new RTCPeerConnection();
     t.add_cleanup(() => pc.close());
@@ -499,16 +501,20 @@
     t.add_cleanup(() => callee.close());
     let [tracks, streams] = await getUserMediaTracksAndStreams(2);
     let sender = caller.addTrack(tracks[0], streams[0]);
     callee.addTrack(tracks[1], streams[1]);
     exchangeIceCandidates(caller, callee);
     await doSignalingHandshake(caller, callee);
     await onIceConnectionStateCompleted(caller);
 
+    // Wait until RTCP has arrived so that it can not arrive between
+    // the two get stats calls.
+    await waitForRtpAndRtcpStats(caller);
+
     let senderReport = await sender.getStats();
     let trackReport = await caller.getStats(sender.track);
 
     // Verify the same stats objects are returned but don't compare each
     // individual metric because timestamps and counters could have gone up
     // between the two getStats() calls.
     senderReport.forEach(senderReportStat => {
       assert_true(trackReport.has(senderReportStat.id));
@@ -527,16 +533,20 @@
     let [tracks, streams] = await getUserMediaTracksAndStreams(2);
     let sender = caller.addTrack(tracks[0], streams[0]);
     callee.addTrack(tracks[1], streams[1]);
     exchangeIceCandidates(caller, callee);
     await doSignalingHandshake(caller, callee);
     await onIceConnectionStateCompleted(caller);
     let receiver = caller.getReceivers()[0];
 
+    // Wait until RTCP has arrived so that it can not arrive between
+    // the two get stats calls.
+    await waitForRtpAndRtcpStats(caller);
+
     let receiverReport = await receiver.getStats();
     let trackReport = await caller.getStats(receiver.track);
 
     // Verify the same stats objects are returned but don't compare each
     // individual metric because timestamps and counters could have gone up
     // between the two getStats() calls.
     receiverReport.forEach(receiverReportStat => {
       assert_true(trackReport.has(receiverReportStat.id));