test_peerConnection_close.html (5461B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 </head> 6 <body> 7 <pre id="test"> 8 <script type="application/javascript"> 9 createHTML({ 10 bug: "991877", 11 title: "Basic RTCPeerConnection.close() tests" 12 }); 13 14 runNetworkTest(function () { 15 var pc = new RTCPeerConnection(); 16 var sender = pc.addTrack(getSilentTrack(), new MediaStream()); 17 var exception = null; 18 var eTimeout = null; 19 20 // everything should be in initial state 21 is(pc.signalingState, "stable", "Initial signalingState is 'stable'"); 22 is(pc.iceConnectionState, "new", "Initial iceConnectionState is 'new'"); 23 is(pc.iceGatheringState, "new", "Initial iceGatheringState is 'new'"); 24 25 var finish; 26 var finished = new Promise(resolve => finish = resolve); 27 28 var mustNotSettle = (p, ms, msg) => Promise.race([ 29 p.then(() => ok(false, msg + " must not settle"), 30 e => ok(false, msg + " must not settle. Got " + e.name)), 31 wait(ms).then(() => ok(true, msg + " must not settle")) 32 ]); 33 34 var silence = mustNotSettle(pc.createOffer(), 1000, 35 "createOffer immediately followed by close"); 36 try { 37 pc.close(); 38 } catch (e) { 39 exception = e; 40 } 41 is(exception, null, "closing the connection raises no exception"); 42 is(pc.signalingState, "closed", "Final signalingState is 'closed'"); 43 is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'"); 44 45 // test that pc is really closed (and doesn't crash, bug 1259728) 46 try { 47 pc.getLocalStreams(); 48 } catch (e) { 49 exception = e; 50 } 51 is(exception && exception.name, "InvalidStateError", 52 "pc.getLocalStreams should throw when closed"); 53 exception = null; 54 55 try { 56 pc.close(); 57 } catch (e) { 58 exception = e; 59 } 60 is(exception, null, "A second close() should not raise an exception"); 61 is(pc.signalingState, "closed", "Final signalingState stays at 'closed'"); 62 is(pc.iceConnectionState, "closed", "Final iceConnectionState stays at 'closed'"); 63 64 // Due to a limitation in our WebIDL compiler that prevents overloads with 65 // both Promise and non-Promise return types, legacy APIs with callbacks 66 // are unable to continue to throw exceptions. Luckily the spec uses 67 // exceptions solely for "programming errors" so this should not hinder 68 // working code from working, which is the point of the legacy API. All 69 // new code should use the promise API. 70 // 71 // The legacy methods that no longer throw on programming errors like 72 // "invalid-on-close" are: 73 // - createOffer 74 // - createAnswer 75 // - setLocalDescription 76 // - setRemoteDescription 77 // - addIceCandidate 78 // - getStats 79 // 80 // These legacy methods fire the error callback instead. This is not 81 // entirely to spec but is better than ignoring programming errors. 82 83 var offer = new RTCSessionDescription({ sdp: "sdp", type: "offer" }); 84 var answer = new RTCSessionDescription({ sdp: "sdp", type: "answer" }); 85 var candidate = new RTCIceCandidate({ candidate: "dummy", 86 sdpMid: "test", 87 sdpMLineIndex: 3 }); 88 89 var doesFail = (p, msg) => p.then(generateErrorCallback(msg), 90 r => is(r.name, "InvalidStateError", msg)); 91 Promise.all([ 92 [pc.createOffer(), "createOffer"], 93 [pc.createOffer({offerToReceiveAudio: true}), "createOffer({offerToReceiveAudio: true})"], 94 [pc.createOffer({offerToReceiveAudio: false}), "createOffer({offerToReceiveAudio: false})"], 95 [pc.createOffer({offerToReceiveVideo: true}), "createOffer({offerToReceiveVideo: true})"], 96 [pc.createOffer({offerToReceiveVideo: false}), "createOffer({offerToReceiveVideo: false})"], 97 [pc.createAnswer(), "createAnswer"], 98 [pc.setLocalDescription(offer), "setLocalDescription"], 99 [pc.setRemoteDescription(answer), "setRemoteDescription"], 100 [pc.addIceCandidate(candidate), "addIceCandidate"], 101 [new Promise((y, n) => pc.createOffer(y, n)), "Legacy createOffer"], 102 [new Promise((y, n) => pc.createAnswer(y, n)), "Legacy createAnswer"], 103 [new Promise((y, n) => pc.setLocalDescription(offer, y, n)), "Legacy setLocalDescription"], 104 [new Promise((y, n) => pc.setRemoteDescription(answer, y, n)), "Legacy setRemoteDescription"], 105 [new Promise((y, n) => pc.addIceCandidate(candidate, y, n)), "Legacy addIceCandidate"], 106 [sender.replaceTrack(getSilentTrack()), "replaceTrack"], 107 ].map(([p, name]) => doesFail(p, name + " fails on close"))) 108 .catch(reason => ok(false, "unexpected failure: " + reason)) 109 .then(finish); 110 111 // Other methods are unaffected. 112 113 SimpleTest.doesThrow(function() { 114 pc.updateIce("Invalid RTC Configuration")}, 115 "updateIce() on closed PC raised expected exception"); 116 117 SimpleTest.doesThrow(function() { 118 pc.addStream("Invalid Media Stream")}, 119 "addStream() on closed PC raised expected exception"); 120 121 SimpleTest.doesThrow(function() { 122 pc.createDataChannel({})}, 123 "createDataChannel() on closed PC raised expected exception"); 124 125 SimpleTest.doesThrow(function() { 126 pc.setIdentityProvider("Invalid Provider")}, 127 "setIdentityProvider() on closed PC raised expected exception"); 128 129 return Promise.all([finished, silence]); 130 }); 131 </script> 132 </pre> 133 </body> 134 </html>