| <!doctype html> |
| <meta charset=utf-8> |
| <title>RTCConfiguration iceServers</title> |
| <script src='/resources/testharness.js'></script> |
| <script src='/resources/testharnessreport.js'></script> |
| <script src='RTCConfiguration-helper.js'></script> |
| <script> |
| 'use strict'; |
| |
| // Test is based on the following editor's draft: |
| // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html |
| |
| // The following helper function is called from |
| // RTCConfiguration-helper.js: |
| // config_test |
| |
| /* |
| 4.3.2. Interface Definition |
| [Constructor(optional RTCConfiguration configuration)] |
| interface RTCPeerConnection : EventTarget { |
| ... |
| }; |
| |
| 4.2.1. RTCConfiguration Dictionary |
| dictionary RTCConfiguration { |
| sequence<RTCIceServer> iceServers; |
| ... |
| }; |
| |
| 4.2.2. RTCIceCredentialType Enum |
| enum RTCIceCredentialType { |
| "password", |
| "oauth" |
| }; |
| |
| 4.2.3. RTCOAuthCredential Dictionary |
| dictionary RTCOAuthCredential { |
| required DOMString macKey; |
| required DOMString accessToken; |
| }; |
| |
| 4.2.4. RTCIceServer Dictionary |
| dictionary RTCIceServer { |
| required (DOMString or sequence<DOMString>) urls; |
| DOMString username; |
| (DOMString or RTCOAuthCredential) credential; |
| RTCIceCredentialType credentialType = "password"; |
| }; |
| */ |
| |
| test(() => { |
| const pc = new RTCPeerConnection(); |
| assert_equals(pc.getConfiguration().iceServers, undefined); |
| }, 'new RTCPeerConnection() should have default configuration.iceServers of undefined'); |
| |
| config_test(makePc => { |
| makePc({}); |
| }, '{} should succeed'); |
| |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: null })); |
| }, '{ iceServers: null } should throw TypeError'); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: undefined }); |
| assert_equals(pc.getConfiguration().iceServers, undefined); |
| }, '{ iceServers: undefined } should succeed'); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [] }); |
| assert_array_equals(pc.getConfiguration().iceServers, []); |
| }, '{ iceServers: [] } should succeed'); |
| |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [null] })); |
| }, '{ iceServers: [null] } should throw TypeError'); |
| |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [undefined] })); |
| }, '{ iceServers: [undefined] } should throw TypeError'); |
| |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [{}] })); |
| }, '{ iceServers: [{}] } should throw TypeError'); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'stun:stun1.example.net' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'password'); |
| |
| }, `with stun server should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: ['stun:stun1.example.net'] |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'password'); |
| |
| }, `with stun server array should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: ['stun:stun1.example.net', 'stun:stun2.example.net'] |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['stun:stun1.example.net', 'stun:stun2.example.net']); |
| assert_equals(server.credentialType, 'password'); |
| |
| }, `with 2 stun servers should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'turn:turn.example.org', |
| username: 'user', |
| credential: 'cred' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turn:turn.example.org']); |
| assert_equals(server.credentialType, 'password'); |
| assert_equals(server.username, 'user'); |
| assert_equals(server.credential, 'cred'); |
| |
| }, `with turn server, username, credential should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'turns:turn.example.org', |
| username: '', |
| credential: '' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turns:turn.example.org']); |
| assert_equals(server.username, ''); |
| assert_equals(server.credential, ''); |
| |
| }, `with turns server and empty string username, credential should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'turn:turn.example.org', |
| username: '', |
| credential: '' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turn:turn.example.org']); |
| assert_equals(server.username, ''); |
| assert_equals(server.credential, ''); |
| |
| }, `with turn server and empty string username, credential should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: ['turns:turn.example.org', 'turn:turn.example.net'], |
| username: 'user', |
| credential: 'cred' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turns:turn.example.org', 'turn:turn.example.net']); |
| assert_equals(server.username, 'user'); |
| assert_equals(server.credential, 'cred'); |
| |
| }, `with one turns server, one turn server, username, credential should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'stun:stun1.example.net', |
| credentialType: 'password' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'password'); |
| |
| }, `with stun server and credentialType password should succeed`); |
| |
| /* |
| 4.3.2. To set a configuration |
| 11.4. If scheme name is turn or turns, and either of server.username or |
| server.credential are omitted, then throw an InvalidAccessError. |
| */ |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turn:turn.example.net' |
| }] })); |
| }, 'with turn server and no credentials should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turn:turn.example.net', |
| username: 'user' |
| }] })); |
| }, 'with turn server and only username should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turn:turn.example.net', |
| credential: 'cred' |
| }] })); |
| }, 'with turn server and only credential should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turns:turn.example.net' |
| }] })); |
| }, 'with turns server and no credentials should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turns:turn.example.net', |
| username: 'user' |
| }] })); |
| }, 'with turns server and only username should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turns:turn.example.net', |
| credential: 'cred' |
| }] })); |
| }, 'with turns server and only credential should throw InvalidAccessError'); |
| |
| /* |
| 4.3.2. To set a configuration |
| 11.3. For each url in server.urls parse url and obtain scheme name. |
| - If the scheme name is not implemented by the browser, throw a SyntaxError. |
| - or if parsing based on the syntax defined in [ RFC7064] and [RFC7065] fails, |
| throw a SyntaxError. |
| |
| [RFC7064] URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol |
| 3.1. URI Scheme Syntax |
| stunURI = scheme ":" host [ ":" port ] |
| scheme = "stun" / "stuns" |
| |
| [RFC7065] Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers |
| 3.1. URI Scheme Syntax |
| turnURI = scheme ":" host [ ":" port ] |
| [ "?transport=" transport ] |
| scheme = "turn" / "turns" |
| transport = "udp" / "tcp" / transport-ext |
| transport-ext = 1*unreserved |
| */ |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: '' |
| }] })); |
| }, 'with "" url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: ['stun:stun1.example.net', ''] |
| }] })); |
| }, 'with ["stun:stun1.example.net", ""] url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: 'relative-url' |
| }] })); |
| }, 'with relative url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: 'http://example.com' |
| }] })); |
| }, 'with http url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: 'turn://example.org/foo?x=y' |
| }] })); |
| }, 'with invalid turn url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: 'stun://example.org/foo?x=y' |
| }] })); |
| }, 'with invalid stun url should throw SyntaxError'); |
| |
| config_test(makePc => { |
| assert_throws(new SyntaxError(), () => |
| makePc({ iceServers: [{ |
| urls: [] |
| }] })); |
| }, `with empty urls should throw SyntaxError`); |
| |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [{ |
| urls: [], |
| credentialType: 'invalid' |
| }] })); |
| }, 'with invalid credentialType should throw TypeError'); |
| |
| // token credentialType was removed from the spec since 20170508 |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [{ |
| urls: [], |
| credentialType: 'token' |
| }] })); |
| }, 'with credentialType token should throw TypeError'); |
| |
| // Blink and Gecko fall back to url, but it's not in the spec. |
| config_test(makePc => { |
| assert_throws(new TypeError(), () => |
| makePc({ iceServers: [{ |
| url: 'stun:stun1.example.net' |
| }] })); |
| }, 'with url field should throw TypeError'); |
| |
| /* |
| 4.3.2. To set a configuration |
| 11.5. If scheme name is turn or turns, and server.credentialType is "password", |
| and server.credential is not a DOMString, then throw an InvalidAccessError |
| and abort these steps. |
| */ |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turns:turn.example.org', |
| credentialType: 'password', |
| username: 'user', |
| credential: { |
| macKey: '', |
| accessToken: '' |
| } |
| }] })); |
| }, 'with turns server, credentialType password, and RTCOauthCredential credential should throw InvalidAccessError'); |
| |
| /* |
| 4.3.2. To set a configuration |
| 11.6. If scheme name is turn or turns, and server.credentialType is "oauth", |
| and server.credential is not an RTCOAuthCredential, then throw an |
| InvalidAccessError and abort these steps. |
| */ |
| config_test(makePc => { |
| assert_throws('InvalidAccessError', () => |
| makePc({ iceServers: [{ |
| urls: 'turns:turn.example.org', |
| credentialType: 'oauth', |
| username: 'user', |
| credential: 'cred' |
| }] })); |
| }, 'with turns server, credentialType oauth, and string credential should throw InvalidAccessError'); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'turns:turn.example.org', |
| credentialType: 'oauth', |
| username: 'user', |
| credential: { |
| macKey: 'mac', |
| accessToken: 'token' |
| } |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turns:turn.example.org']); |
| assert_equals(server.credentialType, 'oauth'); |
| assert_equals(server.username, 'user'); |
| |
| const { credential } = server; |
| assert_equals(credential.macKey, 'mac'); |
| assert_equals(credential.accessToken, 'token'); |
| |
| }, `with turns server, credentialType oauth and RTCOAuthCredential credential should succeed`); |
| |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: ['turns:turn.example.org', 'stun:stun1.example.net'], |
| credentialType: 'oauth', |
| username: 'user', |
| credential: { |
| macKey: 'mac', |
| accessToken: 'token' |
| } |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['turns:turn.example.org', 'stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'oauth'); |
| assert_equals(server.username, 'user'); |
| |
| const { credential } = server; |
| assert_equals(credential.macKey, 'mac'); |
| assert_equals(credential.accessToken, 'token'); |
| |
| }, `with both turns and stun server, credentialType oauth and RTCOAuthCredential credential should succeed`); |
| |
| // credential type validation is ignored when scheme name is stun |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'stun:stun1.example.net', |
| credentialType: 'oauth', |
| username: 'user', |
| credential: 'cred' |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| const server = iceServers[0]; |
| |
| assert_array_equals(server.urls, ['stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'oauth'); |
| assert_equals(server.username, 'user'); |
| assert_equals(server.credential, 'cred'); |
| |
| }, 'with stun server, credentialType oauth, and string credential should succeed'); |
| |
| // credential type validation is ignored when scheme name is stun |
| config_test(makePc => { |
| const pc = makePc({ iceServers: [{ |
| urls: 'stun:stun1.example.net', |
| credentialType: 'password', |
| username: 'user', |
| credential: { |
| macKey: '', |
| accessToken: '' |
| } |
| }] }); |
| |
| const { iceServers } = pc.getConfiguration(); |
| assert_equals(iceServers.length, 1); |
| |
| const server = iceServers[0]; |
| assert_array_equals(server.urls, ['stun:stun1.example.net']); |
| assert_equals(server.credentialType, 'password'); |
| assert_equals(server.username, 'user'); |
| |
| const { credential } = server; |
| assert_equals(credential.macKey, ''); |
| assert_equals(credential.accessToken, ''); |
| |
| }, 'with stun server, credentialType password, and RTCOAuthCredential credential should succeed'); |
| |
| /* |
| Tested |
| 4.3.2. To set a configuration |
| 11.1-6. |
| |
| Untestable |
| 4.3.2. To set a configuration |
| 11.7. Append server to validatedServers. |
| |
| Coverage Report |
| Tested 9 |
| Not Tested 0 |
| Untestable 1 |
| Total 10 |
| */ |
| |
| </script> |