tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RTCPeerConnection-addIceCandidate-timing.https.html (5785B)


      1 <!doctype html>
      2 <script src="/resources/testharness.js"></script>
      3 <script src="/resources/testharnessreport.js"></script>
      4 <script>
      5 
      6 'use strict';
      7 
      8 // In this test, the promises should resolve in the execution order
      9 // (setLocalDescription, setLocalDescription, addIceCandidate) as is ensured by
     10 // the Operations Chain; if an operation is pending, executing another operation
     11 // will queue it. This test will fail if an Operations Chain is not implemented,
     12 // but it gives the implementation some slack: it only ensures that
     13 // addIceCandidate() is not resolved first, allowing timing issues in resolving
     14 // promises where the test still passes even if addIceCandidate() is resolved
     15 // *before* the second setLocalDescription().
     16 //
     17 // This test covers Chrome issue (https://crbug.com/1019222), but does not
     18 // require setLocalDescription-promises to resolve immediately which is another
     19 // Chrome bug (https://crbug.com/1019232). The true order is covered by the next
     20 // test.
     21 // TODO(https://crbug.com/1019232): Delete this test when the next test passes
     22 // in Chrome.
     23 promise_test(async t => {
     24  const caller = new RTCPeerConnection();
     25  t.add_cleanup(() => caller.close());
     26  const callee = new RTCPeerConnection();
     27  t.add_cleanup(() => callee.close());
     28  caller.addTransceiver('audio');
     29 
     30  const candidatePromise = new Promise(resolve => {
     31    caller.onicecandidate = e => resolve(e.candidate);
     32  });
     33  await caller.setLocalDescription(await caller.createOffer());
     34  await callee.setRemoteDescription(caller.localDescription);
     35  const candidate = await candidatePromise;
     36 
     37  // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
     38  // without performing await between the calls.
     39  const pendingPromises = [];
     40  const resolveOrder = [];
     41  pendingPromises.push(callee.setLocalDescription().then(() => {
     42    resolveOrder.push('setLocalDescription 1');
     43  }));
     44  pendingPromises.push(callee.setLocalDescription().then(() => {
     45    resolveOrder.push('setLocalDescription 2');
     46  }));
     47  pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
     48    resolveOrder.push('addIceCandidate');
     49  }));
     50  await Promise.all(pendingPromises);
     51 
     52  assert_equals(resolveOrder[0], 'setLocalDescription 1');
     53 }, 'addIceCandidate is not resolved first if 2x setLocalDescription ' +
     54   'operations are pending');
     55 
     56 promise_test(async t => {
     57  const caller = new RTCPeerConnection();
     58  t.add_cleanup(() => caller.close());
     59  const callee = new RTCPeerConnection();
     60  t.add_cleanup(() => callee.close());
     61  caller.addTransceiver('audio');
     62 
     63  const candidatePromise = new Promise(resolve => {
     64    caller.onicecandidate = e => resolve(e.candidate);
     65  });
     66  await caller.setLocalDescription(await caller.createOffer());
     67  await callee.setRemoteDescription(caller.localDescription);
     68  const candidate = await candidatePromise;
     69 
     70  // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
     71  // without performing await between the calls.
     72  const pendingPromises = [];
     73  const resolveOrder = [];
     74  pendingPromises.push(callee.setLocalDescription().then(() => {
     75    resolveOrder.push('setLocalDescription 1');
     76  }));
     77  pendingPromises.push(callee.setLocalDescription().then(() => {
     78    resolveOrder.push('setLocalDescription 2');
     79  }));
     80  pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
     81    resolveOrder.push('addIceCandidate');
     82  }));
     83  await Promise.all(pendingPromises);
     84 
     85  // This test verifies that both issues described in https://crbug.com/1019222
     86  // and https://crbug.com/1019232 are fixed. If this test passes in Chrome, the
     87  // ICE candidate exchange issues described in
     88  // https://github.com/web-platform-tests/wpt/issues/19866 should be resolved.
     89  assert_array_equals(
     90      resolveOrder,
     91      ['setLocalDescription 1', 'setLocalDescription 2', 'addIceCandidate']);
     92 }, 'addIceCandidate and setLocalDescription are resolved in the correct ' +
     93   'order, as defined by the operations chain specification');
     94 
     95 promise_test(async t => {
     96  const caller = new RTCPeerConnection();
     97  t.add_cleanup(() => caller.close());
     98  const callee = new RTCPeerConnection();
     99  t.add_cleanup(() => callee.close());
    100  caller.addTransceiver('audio');
    101  let events = [];
    102  let pendingPromises = [];
    103 
    104  const onCandidatePromise = new Promise(resolve => {
    105    caller.onicecandidate = () => {
    106      events.push('candidate generated');
    107      resolve();
    108    }
    109  });
    110  pendingPromises.push(onCandidatePromise);
    111  pendingPromises.push(caller.setLocalDescription().then(() => {
    112    events.push('setLocalDescription');
    113  }));
    114  await Promise.all(pendingPromises);
    115  assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
    116 }, 'onicecandidate fires after resolving setLocalDescription in offerer');
    117 
    118 promise_test(async t => {
    119  const caller = new RTCPeerConnection();
    120  t.add_cleanup(() => caller.close());
    121  const callee = new RTCPeerConnection();
    122  t.add_cleanup(() => callee.close());
    123  caller.addTransceiver('audio');
    124  let events = [];
    125  let pendingPromises = [];
    126 
    127  caller.onicecandidate = (ev) => {
    128    if (ev.candidate) {
    129      callee.addIceCandidate(ev.candidate);
    130    }
    131  }
    132  const offer = await caller.createOffer();
    133  const onCandidatePromise = new Promise(resolve => {
    134    callee.onicecandidate = () => {
    135      events.push('candidate generated');
    136      resolve();
    137    }
    138  });
    139  await callee.setRemoteDescription(offer);
    140  const answer = await callee.createAnswer();
    141  pendingPromises.push(onCandidatePromise);
    142  pendingPromises.push(callee.setLocalDescription(answer).then(() => {
    143    events.push('setLocalDescription');
    144  }));
    145  await Promise.all(pendingPromises);
    146  assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
    147 }, 'onicecandidate fires after resolving setLocalDescription in answerer');
    148 
    149 </script>