summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/tests/mochitests/test_peerConnection_close.html
blob: 3edf677203bd5d46cf6b7a4c8ff767f86e2ecb98 (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
<!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 sender = pc.addTrack(getSilentTrack(), new MediaStream());
    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);

    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'");

    // 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(msg),
                                      r => is(r.name, "InvalidStateError", msg));
    Promise.all([
      [pc.createOffer(), "createOffer"],
      [pc.createOffer({offerToReceiveAudio: true}), "createOffer({offerToReceiveAudio: true})"],
      [pc.createOffer({offerToReceiveAudio: false}), "createOffer({offerToReceiveAudio: false})"],
      [pc.createOffer({offerToReceiveVideo: true}), "createOffer({offerToReceiveVideo: true})"],
      [pc.createOffer({offerToReceiveVideo: false}), "createOffer({offerToReceiveVideo: false})"],
      [pc.createAnswer(), "createAnswer"],
      [pc.setLocalDescription(offer), "setLocalDescription"],
      [pc.setRemoteDescription(answer), "setRemoteDescription"],
      [pc.addIceCandidate(candidate), "addIceCandidate"],
      [new Promise((y, n) => pc.createOffer(y, n)), "Legacy createOffer"],
      [new Promise((y, n) => pc.createAnswer(y, n)), "Legacy createAnswer"],
      [new Promise((y, n) => pc.setLocalDescription(offer, y, n)), "Legacy setLocalDescription"],
      [new Promise((y, n) => pc.setRemoteDescription(answer, y, n)), "Legacy setRemoteDescription"],
      [new Promise((y, n) => pc.addIceCandidate(candidate, y, n)), "Legacy addIceCandidate"],
      [sender.replaceTrack(getSilentTrack()), "replaceTrack"],
    ].map(([p, name]) => doesFail(p, name + " 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");

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