summaryrefslogtreecommitdiffstats
path: root/dom/media/tests/mochitest/test_peerConnection_close.html
blob: 54cae5637dfd74a28a6df0611b85fd60c8ba0fa1 (plain)
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>