Bug 1231981 - Part 3: Set up TURN server for webrtc mochitests, when configured to. r=drno

MozReview-Commit-ID: CVbAYPrwpuB
This commit is contained in:
Byron Campen [:bwc]
2016-03-04 15:45:57 -06:00
parent fdd7508c86
commit bb1364fbce
8 changed files with 118 additions and 32 deletions

View File

@@ -337,9 +337,12 @@ function run_test(is_initiator,timeout) {
function runTestWhenReady(testFunc) { function runTestWhenReady(testFunc) {
setupEnvironment(); setupEnvironment();
return testConfigured.then(options => testFunc(options)) return testConfigured.then(options => testFunc(options))
.catch(e => ok(false, 'Error executing test: ' + e + .catch(e => {
ok(false, 'Error executing test: ' + e +
((typeof e.stack === 'string') ? ((typeof e.stack === 'string') ?
(' ' + e.stack.split('\n').join(' ... ')) : ''))); (' ' + e.stack.split('\n').join(' ... ')) : ''));
SimpleTest.finish();
});
} }

View File

@@ -64,7 +64,13 @@ function PeerConnectionTest(options) {
options.rtcpmux = "rtcpmux" in options ? options.rtcpmux : true; options.rtcpmux = "rtcpmux" in options ? options.rtcpmux : true;
options.opus = "opus" in options ? options.opus : true; options.opus = "opus" in options ? options.opus : true;
if (typeof turnServers !== "undefined") { if (iceServersArray.length) {
options.config_remote = options.config_remote || {}
options.config_local = options.config_local || {}
options.config_remote.iceServers = iceServersArray;
options.config_local.iceServers = iceServersArray;
}
else if (typeof turnServers !== "undefined") {
if ((!options.turn_disabled_local) && (turnServers.local)) { if ((!options.turn_disabled_local) && (turnServers.local)) {
if (!options.hasOwnProperty("config_local")) { if (!options.hasOwnProperty("config_local")) {
options.config_local = {}; options.config_local = {};
@@ -1679,7 +1685,7 @@ PeerConnectionWrapper.prototype = {
* @param {object} stats * @param {object} stats
* The stats to be verified for relayed vs. direct connection. * The stats to be verified for relayed vs. direct connection.
*/ */
checkStatsIceConnectionType : function(stats) { checkStatsIceConnectionType : function(stats, expectedLocalCandidateType) {
let lId; let lId;
let rId; let rId;
for (let stat of stats.values()) { for (let stat of stats.values()) {
@@ -1698,21 +1704,25 @@ PeerConnectionWrapper.prototype = {
"failed to find candidatepair IDs or stats for local: "+ lId +" remote: "+ rId); "failed to find candidatepair IDs or stats for local: "+ lId +" remote: "+ rId);
return; return;
} }
info("checkStatsIceConnectionType verifying: local=" + info("checkStatsIceConnectionType verifying: local=" +
JSON.stringify(lCand) + " remote=" + JSON.stringify(rCand)); JSON.stringify(lCand) + " remote=" + JSON.stringify(rCand));
if ((this.configuration) && (typeof this.configuration.iceServers !== 'undefined')) { expectedLocalCandidateType = expectedLocalCandidateType || "host";
info("Ice Server configured"); var candidateType = lCand.candidateType;
// Note: the IP comparising is a workaround for bug 1097333 if ((lCand.mozLocalTransport === "tcp") && (candidateType === "relayed")) {
// And this will fail if a TURN server address is a DNS name! candidateType = "relayed-tcp";
var serverIp = this.configuration.iceServers[0].url.split(':')[1];
ok(lCand.candidateType == "relayed" || rCand.candidateType == "relayed" ||
lCand.ipAddress === serverIp || rCand.ipAddress === serverIp,
"One peer uses a relay");
} else {
info("P2P configured");
ok(lCand.candidateType != "relayed" && rCand.candidateType != "relayed",
"Pure peer to peer call without a relay");
} }
if ((expectedLocalCandidateType === "serverreflexive") &&
(candidateType === "peerreflexive")) {
// Be forgiving of prflx when expecting srflx, since that can happen due
// to timing.
candidateType = "serverreflexive";
}
is(candidateType,
expectedLocalCandidateType,
"Local candidate type is what we expected for selected pair");
}, },
/** /**
@@ -1845,10 +1855,59 @@ function createHTML(options) {
return scriptsReady.then(() => realCreateHTML(options)); return scriptsReady.then(() => realCreateHTML(options));
} }
function runNetworkTest(testFunction) { var iceServerWebsocket;
var iceServersArray = [];
var setupIceServerConfig = useIceServer => {
// We disable ICE support for HTTP proxy when using a TURN server, because
// mochitest uses a fake HTTP proxy to serve content, which will eat our STUN
// packets for TURN TCP.
var enableHttpProxy = enable => new Promise(resolve => {
SpecialPowers.pushPrefEnv(
{'set': [['media.peerconnection.disable_http_proxy', !enable]]},
resolve);
});
var spawnIceServer = () => new Promise( (resolve, reject) => {
iceServerWebsocket = new WebSocket("ws://localhost:8191/");
iceServerWebsocket.onopen = (event) => {
info("websocket/process bridge open, starting ICE Server...");
iceServerWebsocket.send("iceserver");
}
iceServerWebsocket.onmessage = event => {
// The first message will contain the iceServers configuration, subsequent
// messages are just logging.
info("ICE Server: " + event.data);
resolve(event.data);
}
iceServerWebsocket.onerror = () => {
reject("ICE Server error: Is the ICE server websocket up?");
}
iceServerWebsocket.onclose = () => {
info("ICE Server websocket closed");
reject("ICE Server gone before getting configuration");
}
});
if (!useIceServer) {
info("Skipping ICE Server for this test");
return enableHttpProxy(true);
}
return enableHttpProxy(false)
.then(spawnIceServer)
.then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); });
};
function runNetworkTest(testFunction, fixtureOptions) {
fixtureOptions = fixtureOptions || {}
return scriptsReady.then(() => return scriptsReady.then(() =>
runTestWhenReady(options => runTestWhenReady(options =>
startNetworkAndTest() startNetworkAndTest()
.then(() => setupIceServerConfig(fixtureOptions.useIceServer))
.then(() => testFunction(options)) .then(() => testFunction(options))
) )
); );

View File

@@ -441,13 +441,15 @@ var commandsPeerConnectionOfferAnswer = [
function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) { function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) {
return test.pcLocal.getStats().then(stats => { return test.pcLocal.getStats().then(stats => {
test.pcLocal.checkStatsIceConnectionType(stats); test.pcLocal.checkStatsIceConnectionType(stats,
test.testOptions.expectedLocalCandidateType);
}); });
}, },
function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) { function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) {
return test.pcRemote.getStats().then(stats => { return test.pcRemote.getStats().then(stats => {
test.pcRemote.checkStatsIceConnectionType(stats); test.pcRemote.checkStatsIceConnectionType(stats,
test.testOptions.expectedRemoteCandidateType);
}); });
}, },

View File

@@ -215,8 +215,8 @@ int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket
nr_ice_candidate_compute_codeword(cand); nr_ice_candidate_compute_codeword(cand);
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): created candidate %s with type %s", r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): created candidate %s with type %s",
ctx->label,cand->label,nr_ctype_name(ctype)); ctx->label,cand->codeword,cand->label,nr_ctype_name(ctype));
*candp=cand; *candp=cand;

View File

@@ -515,6 +515,7 @@ void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg)
ctx = cand->ctx; ctx = cand->ctx;
ctx->uninitialized_candidates--; ctx->uninitialized_candidates--;
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): initialized, %d remaining",ctx->label,cand->codeword,ctx->uninitialized_candidates);
/* Avoid the need for yet another initialization function */ /* Avoid the need for yet another initialization function */
if (cand->state == NR_ICE_CAND_STATE_INITIALIZING && cand->type == HOST) if (cand->state == NR_ICE_CAND_STATE_INITIALIZING && cand->type == HOST)

View File

@@ -243,10 +243,20 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
mIceRestartState(ICE_RESTART_NONE) { mIceRestartState(ICE_RESTART_NONE) {
} }
nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers, nsresult
const std::vector<NrIceTurnServer>& turn_servers, PeerConnectionMedia::InitProxy()
NrIceCtx::Policy policy)
{ {
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// Allow mochitests to disable this, since mochitest configures a fake proxy
// that serves up content.
bool disable = Preferences::GetBool("media.peerconnection.disable_http_proxy",
false);
if (disable) {
mProxyResolveCompleted = true;
return NS_OK;
}
#endif
nsresult rv; nsresult rv;
nsCOMPtr<nsIProtocolProxyService> pps = nsCOMPtr<nsIProtocolProxyService> pps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
@@ -304,6 +314,16 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
return NS_OK;
}
nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
const std::vector<NrIceTurnServer>& turn_servers,
NrIceCtx::Policy policy)
{
nsresult rv = InitProxy();
NS_ENSURE_SUCCESS(rv, rv);
#if !defined(MOZILLA_EXTERNAL_LINKAGE) #if !defined(MOZILLA_EXTERNAL_LINKAGE)
bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false); bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
#else #else

View File

@@ -484,6 +484,7 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
SignalEndOfLocalCandidates; SignalEndOfLocalCandidates;
private: private:
nsresult InitProxy();
class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback { class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback {
public: public:
explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) : explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) :

View File

@@ -529,7 +529,7 @@ class MochitestBase(object):
self.update_mozinfo() self.update_mozinfo()
self.server = None self.server = None
self.wsserver = None self.wsserver = None
self.websocketProcessBridge = None self.websocketprocessbridge = None
self.sslTunnel = None self.sslTunnel = None
self._active_tests = None self._active_tests = None
self._locations = None self._locations = None
@@ -815,11 +815,11 @@ class MochitestBase(object):
command = [sys.executable, command = [sys.executable,
os.path.join("websocketprocessbridge", os.path.join("websocketprocessbridge",
"websocketprocessbridge.py")] "websocketprocessbridge.py")]
self.websocketProcessBridge = mozprocess.ProcessHandler(command, self.websocketprocessbridge = mozprocess.ProcessHandler(command,
cwd=SCRIPT_DIR) cwd=SCRIPT_DIR)
self.websocketProcessBridge.run() self.websocketprocessbridge.run()
self.log.info("runtests.py | websocket/process bridge pid: %d" self.log.info("runtests.py | websocket/process bridge pid: %d"
% self.websocketProcessBridge.pid) % self.websocketprocessbridge.pid)
# ensure the server is up, wait for at most ten seconds # ensure the server is up, wait for at most ten seconds
for i in range(1,100): for i in range(1,100):
@@ -893,12 +893,12 @@ class MochitestBase(object):
except Exception: except Exception:
self.log.critical('Exception stopping ssltunnel') self.log.critical('Exception stopping ssltunnel')
if self.websocketProcessBridge is not None: if self.websocketprocessbridge is not None:
try: try:
self.log.info('Stopping websocketProcessBridge') self.log.info('Stopping websocket/process bridge')
self.websocketProcessBridge.kill() self.websocketprocessbridge.kill()
except Exception: except Exception:
self.log.critical('Exception stopping websocketProcessBridge') self.log.critical('Exception stopping websocket/process bridge')
def copyExtraFilesToProfile(self, options): def copyExtraFilesToProfile(self, options):
"Copy extra files or dirs specified on the command line to the testing profile." "Copy extra files or dirs specified on the command line to the testing profile."