DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (5350524bb654)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
<!DOCTYPE HTML>
<html>
<head>
  <script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
  createHTML({
    bug: "991877",
    title: "Basic RTCPeerConnection.close() tests"
  });

  runNetworkTest(function () {
    var pc = new RTCPeerConnection();
    var exception = null;
    var eTimeout = null;

    // everything should be in initial state
    is(pc.signalingState, "stable", "Initial signalingState is 'stable'");
    is(pc.iceConnectionState, "new", "Initial iceConnectionState is 'new'");
    is(pc.iceGatheringState, "new", "Initial iceGatheringState is 'new'");

    var finish;
    var finished = new Promise(resolve => finish = resolve);

    pc.onsignalingstatechange = function(e) {
      clearTimeout(eTimeout);
      is(pc.signalingState, "closed", "signalingState is 'closed'");
      is(pc.iceConnectionState, "closed", "iceConnectionState is 'closed'");

      // test that pc is really closed (and doesn't crash, bug 1259728)
      try {
        pc.getLocalStreams();
      } catch (e) {
        exception = e;
      }
      is(exception && exception.name, "InvalidStateError",
         "pc.getLocalStreams should throw when closed");
      exception = null;

      try {
        pc.close();
      } catch (e) {
        exception = e;
      }
      is(exception, null, "A second close() should not raise an exception");
      is(pc.signalingState, "closed", "Final signalingState stays at 'closed'");
      is(pc.iceConnectionState, "closed", "Final iceConnectionState stays at 'closed'");

      // Due to a limitation in our WebIDL compiler that prevents overloads with
      // both Promise and non-Promise return types, legacy APIs with callbacks
      // are unable to continue to throw exceptions. Luckily the spec uses
      // exceptions solely for "programming errors" so this should not hinder
      // working code from working, which is the point of the legacy API. All
      // new code should use the promise API.
      //
      // The legacy methods that no longer throw on programming errors like
      // "invalid-on-close" are:
      // - createOffer
      // - createAnswer
      // - setLocalDescription
      // - setRemoteDescription
      // - addIceCandidate
      // - getStats
      //
      // These legacy methods fire the error callback instead. This is not
      // entirely to spec but is better than ignoring programming errors.

      var offer = new RTCSessionDescription({ sdp: "sdp", type: "offer" });
      var answer = new RTCSessionDescription({ sdp: "sdp", type: "answer" });
      var candidate = new RTCIceCandidate({ candidate: "dummy",
                                               sdpMid: "test",
                                               sdpMLineIndex: 3 });

      var doesFail = (p, msg) => p.then(generateErrorCallback(),
                                        r => is(r.name, "InvalidStateError", msg));

      doesFail(pc.createOffer(), "createOffer fails on close")
      .then(() => doesFail(pc.createAnswer(), "createAnswer fails on close"))
      .then(() => doesFail(pc.setLocalDescription(offer),
                           "setLocalDescription fails on close"))
      .then(() => doesFail(pc.setRemoteDescription(answer),
                           "setRemoteDescription fails on close"))
      .then(() => doesFail(pc.addIceCandidate(candidate),
                           "addIceCandidate fails on close"))
      .then(() => doesFail(new Promise((y, n) => pc.createOffer(y, n)),
                           "Legacy createOffer fails on close"))
      .then(() => doesFail(new Promise((y, n) => pc.createAnswer(y, n)),
                           "Legacy createAnswer fails on close"))
      .then(() => doesFail(new Promise((y, n) => pc.setLocalDescription(offer, y, n)),
                           "Legacy setLocalDescription fails on close"))
      .then(() => doesFail(new Promise((y, n) => pc.setRemoteDescription(answer, y, n)),
                           "Legacy setRemoteDescription fails on close"))
      .then(() => doesFail(new Promise((y, n) => pc.addIceCandidate(candidate, y, n)),
                           "Legacy addIceCandidate fails on close"))
      .catch(reason => ok(false, "unexpected failure: " + reason))
      .then(finish);

      // Other methods are unaffected.

      SimpleTest.doesThrow(function() {
        pc.updateIce("Invalid RTC Configuration")},
        "updateIce() on closed PC raised expected exception");

      SimpleTest.doesThrow(function() {
        pc.addStream("Invalid Media Stream")},
        "addStream() on closed PC raised expected exception");

      SimpleTest.doesThrow(function() {
        pc.createDataChannel({})},
        "createDataChannel() on closed PC raised expected exception");

      SimpleTest.doesThrow(function() {
        pc.setIdentityProvider("Invalid Provider")},
        "setIdentityProvider() on closed PC raised expected exception");
    };

    // This prevents a mochitest timeout in case the event does not fire
    eTimeout = setTimeout(function() {
      ok(false, "Failed to receive expected onsignalingstatechange event in 60s");
      finish();
    }, 60000);

    var mustNotSettle = (p, ms, msg) => Promise.race([
      p.then(() => ok(false, msg + " must not settle"),
             e => ok(false, msg + " must not settle. Got " + e.name)),
      wait(ms).then(() => ok(true, msg + " must not settle"))
    ]);

    var silence = mustNotSettle(pc.createOffer(), 1000,
                                "createOffer immediately followed by close");
    try {
      pc.close();
    } catch (e) {
      exception = e;
    }
    is(exception, null, "closing the connection raises no exception");
    is(pc.signalingState, "closed", "Final signalingState is 'closed'");
    is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'");

    Promise.all([finished, silence]).then(networkTestFinished);
  });
</script>
</pre>
</body>
</html>