Backed out changesets baa6c68ec413,5b8583070c9e,2942bb31152c,dd2ad6863f53,c68772362633,c8db6695b991 (bug 1231981) a=backout
authorWes Kocher <wkocher@mozilla.com>
Wed, 27 Apr 2016 10:24:37 -0700
changeset 295059 86730d0a82093d705e44f33a34973d28b269f1ea
parent 295058 a8d0cda0ef764a00b9ca133878581109698c295f
child 295082 2a3eb80dc9653ee0edc9f4a8b657b80f817b000e
child 295200 48724fa154b19c52e57e4db48ade1940a15f5e4e
push id30218
push userkwierso@gmail.com
push dateWed, 27 Apr 2016 17:27:03 +0000
treeherdermozilla-central@86730d0a8209 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1231981
milestone49.0a1
backs outbaa6c68ec41333ffc90107a3343fe38e0c060f99
5b8583070c9ea1d28305e5d41c9f841048f47bd0
2942bb31152c2bd0a79b381aef727ab6930c52ec
dd2ad6863f532c36d1abbb19b14fc92448d462cb
c6877236263383f2e08955b6c96ac5d843bde888
c8db6695b99186f5a9257111acfbafc28da1101e
first release with
nightly linux32
86730d0a8209 / 49.0a1 / 20160428030218 / files
nightly linux64
86730d0a8209 / 49.0a1 / 20160428030218 / files
nightly mac
86730d0a8209 / 49.0a1 / 20160428030218 / files
nightly win32
86730d0a8209 / 49.0a1 / 20160428030218 / files
nightly win64
86730d0a8209 / 49.0a1 / 20160428030218 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changesets baa6c68ec413,5b8583070c9e,2942bb31152c,dd2ad6863f53,c68772362633,c8db6695b991 (bug 1231981) a=backout MozReview-Commit-ID: EoGyz071RoN
dom/media/tests/mochitest/head.js
dom/media/tests/mochitest/pc.js
dom/media/tests/mochitest/templates.js
media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
python/mozbuild/mozbuild/virtualenv.py
testing/mochitest/mach_commands.py
testing/mochitest/moz.build
testing/mochitest/runtests.py
testing/mozharness/configs/unittests/win_unittest.py
testing/mozharness/scripts/android_emulator_unittest.py
testing/mozharness/scripts/androidx86_emulator_unittest.py
testing/mozharness/scripts/desktop_unittest.py
testing/tools/iceserver/iceserver.py
testing/tools/websocketprocessbridge/websocketprocessbridge.py
testing/tools/websocketprocessbridge/websocketprocessbridge_requirements.txt
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -332,22 +332,19 @@ function run_test(is_initiator,timeout) 
   s.src = "/test.js";
   s.onload = () => setTestOptions(options);
   document.head.appendChild(s);
 }
 
 function runTestWhenReady(testFunc) {
   setupEnvironment();
   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') ?
-        (' ' + e.stack.split('\n').join(' ... ')) : ''));
-      SimpleTest.finish();
-    });
+        (' ' + e.stack.split('\n').join(' ... ')) : '')));
 }
 
 
 /**
  * Checks that the media stream tracks have the expected amount of tracks
  * with the correct kind and id based on the type and constraints given.
  *
  * @param {Object} constraints specifies whether the stream should have
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -59,23 +59,17 @@ function PeerConnectionTest(options) {
   options.is_local = "is_local" in options ? options.is_local : true;
   options.is_remote = "is_remote" in options ? options.is_remote : true;
 
   options.h264 = "h264" in options ? options.h264 : false;
   options.bundle = "bundle" in options ? options.bundle : true;
   options.rtcpmux = "rtcpmux" in options ? options.rtcpmux : true;
   options.opus = "opus" in options ? options.opus : true;
 
-  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 (typeof turnServers !== "undefined") {
     if ((!options.turn_disabled_local) && (turnServers.local)) {
       if (!options.hasOwnProperty("config_local")) {
         options.config_local = {};
       }
       if (!options.config_local.hasOwnProperty("iceServers")) {
         options.config_local.iceServers = turnServers.local.iceServers;
       }
     }
@@ -1680,17 +1674,17 @@ PeerConnectionWrapper.prototype = {
 
   /**
    * Compares the Ice server configured for this PeerConnectionWrapper
    * with the ICE candidates received in the RTCP stats.
    *
    * @param {object} stats
    *        The stats to be verified for relayed vs. direct connection.
    */
-  checkStatsIceConnectionType : function(stats, expectedLocalCandidateType) {
+  checkStatsIceConnectionType : function(stats) {
     let lId;
     let rId;
     for (let stat of stats.values()) {
       if (stat.type == "candidatepair" && stat.selected) {
         lId = stat.localCandidateId;
         rId = stat.remoteCandidateId;
         break;
       }
@@ -1699,35 +1693,31 @@ PeerConnectionWrapper.prototype = {
     isnot(rId, undefined, "Got remote candidate ID " + rId + " for selected pair");
     let lCand = stats.get(lId);
     let rCand = stats.get(rId);
     if (!lCand || !rCand) {
       ok(false,
          "failed to find candidatepair IDs or stats for local: "+ lId +" remote: "+ rId);
       return;
     }
-
     info("checkStatsIceConnectionType verifying: local=" +
          JSON.stringify(lCand) + " remote=" + JSON.stringify(rCand));
-    expectedLocalCandidateType = expectedLocalCandidateType || "host";
-    var candidateType = lCand.candidateType;
-    if ((lCand.mozLocalTransport === "tcp") && (candidateType === "relayed")) {
-      candidateType = "relayed-tcp";
+    if ((this.configuration) && (typeof this.configuration.iceServers !== 'undefined')) {
+      info("Ice Server configured");
+      // Note: the IP comparising is a workaround for bug 1097333
+      //       And this will fail if a TURN server address is a DNS name!
+      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");
   },
 
   /**
    * Compares amount of established ICE connection according to ICE candidate
    * pairs in the stats reporting with the expected amount of connection based
    * on the constraints.
    *
    * @param {object} stats
@@ -1850,65 +1840,16 @@ var scriptsReady = Promise.all([
   document.head.appendChild(el);
   return new Promise(r => { el.onload = r; el.onerror = r; });
 }));
 
 function createHTML(options) {
   return scriptsReady.then(() => realCreateHTML(options));
 }
 
-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 || {}
+function runNetworkTest(testFunction) {
   return scriptsReady.then(() =>
     runTestWhenReady(options =>
       startNetworkAndTest()
-        .then(() => setupIceServerConfig(fixtureOptions.useIceServer))
         .then(() => testFunction(options))
     )
   );
 }
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -436,25 +436,23 @@ var commandsPeerConnectionOfferAnswer = 
   function PC_REMOTE_CHECK_STATS(test) {
     return test.pcRemote.getStats().then(stats => {
       test.pcRemote.checkStats(stats, test.testOptions.steeplechase);
     });
   },
 
   function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) {
     return test.pcLocal.getStats().then(stats => {
-      test.pcLocal.checkStatsIceConnectionType(stats,
-          test.testOptions.expectedLocalCandidateType);
+      test.pcLocal.checkStatsIceConnectionType(stats);
     });
   },
 
   function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) {
     return test.pcRemote.getStats().then(stats => {
-      test.pcRemote.checkStatsIceConnectionType(stats,
-          test.testOptions.expectedRemoteCandidateType);
+      test.pcRemote.checkStatsIceConnectionType(stats);
     });
   },
 
   function PC_LOCAL_CHECK_ICE_CONNECTIONS(test) {
     return test.pcLocal.getStats().then(stats => {
       test.pcLocal.checkStatsIceConnections(stats,
                                             test._offer_constraints,
                                             test._offer_options,
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -210,18 +210,18 @@ int nr_ice_candidate_create(nr_ice_ctx *
       cand->u.relayed.turn_sock=osock;
 
 
     /* Add the candidate to the isock list*/
     TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
 
     nr_ice_candidate_compute_codeword(cand);
 
-    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): created candidate %s with type %s",
-      ctx->label,cand->codeword,cand->label,nr_ctype_name(ctype));
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): created candidate %s with type %s",
+      ctx->label,cand->label,nr_ctype_name(ctype));
 
     *candp=cand;
 
     _status=0;
   abort:
     if (_status){
       r_log(LOG_ICE,LOG_ERR,"ICE(%s): Failed to create candidate of type %s", ctx->label,nr_ctype_name(ctype));
       nr_ice_candidate_destroy(&cand);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -512,17 +512,16 @@ void nr_ice_gather_finished_cb(NR_SOCKET
 
 
     assert(cb_arg);
     if (!cb_arg)
       return;
     ctx = cand->ctx;
 
     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 */
     if (cand->state == NR_ICE_CAND_STATE_INITIALIZING && cand->type == HOST)
       cand->state = NR_ICE_CAND_STATE_INITIALIZED;
 
     if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
       int was_pruned = 0;
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -238,30 +238,20 @@ PeerConnectionMedia::PeerConnectionMedia
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false),
       mIceRestartState(ICE_RESTART_NONE) {
 }
 
-nsresult
-PeerConnectionMedia::InitProxy()
+nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
+                                   const std::vector<NrIceTurnServer>& turn_servers,
+                                   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;
   nsCOMPtr<nsIProtocolProxyService> pps =
     do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to get proxy service: %d", __FUNCTION__, (int)rv);
     return NS_ERROR_FAILURE;
   }
 
@@ -309,26 +299,16 @@ PeerConnectionMedia::InitProxy()
                          nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
                          nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
                          handler, getter_AddRefs(mProxyRequest));
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to resolve protocol proxy: %d", __FUNCTION__, (int)rv);
     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)
   bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
 #else
   bool ice_tcp = false;
 #endif
   bool default_address_only = GetPrefDefaultAddressOnly();
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -479,17 +479,16 @@ class PeerConnectionMedia : public sigsl
   // This passes address, port, level of the default candidate.
   sigslot::signal5<const std::string&, uint16_t,
                    const std::string&, uint16_t, uint16_t>
       SignalUpdateDefaultCandidate;
   sigslot::signal1<uint16_t>
       SignalEndOfLocalCandidates;
 
  private:
-  nsresult InitProxy();
   class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback {
    public:
     explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) :
       pcm_(pcm) {}
 
     NS_IMETHODIMP OnProxyAvailable(nsICancelable *request,
                                    nsIChannel *aChannel,
                                    nsIProxyInfo *proxyinfo,
--- a/python/mozbuild/mozbuild/virtualenv.py
+++ b/python/mozbuild/mozbuild/virtualenv.py
@@ -457,27 +457,16 @@ class VirtualenvManager(object):
         virtualenv, you can simply instantiate an instance of this class
         and call .ensure() and .activate() to make the virtualenv active.
         """
 
         execfile(self.activate_path, dict(__file__=self.activate_path))
         if isinstance(os.environ['PATH'], unicode):
             os.environ['PATH'] = os.environ['PATH'].encode('utf-8')
 
-    def install_pip_requirements_file(self, requirements_filename):
-        """Installs packages in |requirements_filename| via pip."""
-
-        args = [
-            'install',
-            '-r',
-            requirements_filename
-        ]
-
-        return self._run_pip(args)
-
     def install_pip_package(self, package):
         """Install a package via pip.
 
         The supplied package is specified using a pip requirement specifier.
         e.g. 'foo' or 'foo==1.0'.
 
         If the package is already installed, this is a no-op.
         """
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -150,22 +150,16 @@ class MochitestRunner(MozbuildObject):
 
         self.tests_dir = os.path.join(self.topobjdir, '_tests')
         self.mochitest_dir = os.path.join(
             self.tests_dir,
             'testing',
             'mochitest')
         self.bin_dir = os.path.join(self.topobjdir, 'dist', 'bin')
 
-        self._activate_virtualenv()
-        self.virtualenv_manager.install_pip_requirements_file(
-                os.path.join(self.mochitest_dir,
-                             'websocketprocessbridge',
-                             'websocketprocessbridge_requirements.txt'))
-
     def resolve_tests(self, test_paths, test_objects=None, cwd=None):
         if test_objects:
             return test_objects
 
         from mozbuild.testing import TestResolver
         resolver = self._spawn(TestResolver)
         tests = list(resolver.resolve_tests(paths=test_paths, cwd=cwd))
         return tests
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -148,18 +148,8 @@ TEST_HARNESS_FILES.testing.mochitest.tes
     'tests/MochiKit-1.4.2/MochiKit/Position.js',
     'tests/MochiKit-1.4.2/MochiKit/Selector.js',
     'tests/MochiKit-1.4.2/MochiKit/Signal.js',
     'tests/MochiKit-1.4.2/MochiKit/Sortable.js',
     'tests/MochiKit-1.4.2/MochiKit/Style.js',
     'tests/MochiKit-1.4.2/MochiKit/Test.js',
     'tests/MochiKit-1.4.2/MochiKit/Visual.js',
 ]
-
-TEST_HARNESS_FILES.testing.mochitest.iceserver += [
-    '/testing/tools/iceserver/iceserver.py',
-]
-
-TEST_HARNESS_FILES.testing.mochitest.websocketprocessbridge += [
-    '/testing/tools/websocketprocessbridge/websocketprocessbridge.py',
-    '/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements.txt',
-]
-
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -21,17 +21,16 @@ import mozdebug
 import mozinfo
 import mozprocess
 import mozrunner
 import numbers
 import platform
 import re
 import shutil
 import signal
-import socket
 import subprocess
 import sys
 import tempfile
 import time
 import traceback
 import urllib2
 import uuid
 import zipfile
@@ -524,17 +523,16 @@ class MochitestBase(object):
     CHROME_PATH = "redirect.html"
     urlOpts = []
     log = None
 
     def __init__(self, logger_options):
         self.update_mozinfo()
         self.server = None
         self.wsserver = None
-        self.websocketprocessbridge = None
         self.sslTunnel = None
         self._active_tests = None
         self._locations = None
 
         self.marionette = None
         self.start_script = None
         self.mozLogs = None
         self.start_script_args = []
@@ -802,45 +800,16 @@ class MochitestBase(object):
 
         self.server = MochitestServer(options, self.log)
         self.server.start()
 
         if options.pidFile != "":
             with open(options.pidFile + ".xpcshell.pid", 'w') as f:
                 f.write("%s" % self.server._process.pid)
 
-    def startWebsocketProcessBridge(self, options):
-        """Create a websocket server that can launch various processes that
-        JS needs (eg; ICE server for webrtc testing)
-        """
-
-        command = [sys.executable,
-                   os.path.join("websocketprocessbridge",
-                                "websocketprocessbridge.py")]
-        os.environ['PYTHONPATH'] = os.pathsep.join(p for p in sys.path)
-        self.websocketprocessbridge = mozprocess.ProcessHandler(command,
-                                                                cwd=SCRIPT_DIR)
-        self.websocketprocessbridge.run()
-        self.log.info("runtests.py | websocket/process bridge pid: %d"
-                      % self.websocketprocessbridge.pid)
-
-        # ensure the server is up, wait for at most ten seconds
-        for i in range(1,100):
-            try:
-                sock = socket.create_connection(("127.0.0.1", 8191))
-                sock.close()
-                break
-            except:
-                time.sleep(0.1)
-        else:
-            self.log.error("runtests.py | Timed out while waiting for "
-                           "websocket/process bridge startup.")
-            self.stopServers()
-            sys.exit(1)
-
     def startServers(self, options, debuggerInfo, ignoreSSLTunnelExts=False):
         # start servers and set ports
         # TODO: pass these values, don't set on `self`
         self.webServer = options.webServer
         self.httpPort = options.httpPort
         self.sslPort = options.sslPort
         self.webSocketPort = options.webSocketPort
 
@@ -848,17 +817,16 @@ class MochitestBase(object):
         # on the command line to select a particular version of httpd.js. If not
         # specified, try to select the one from hostutils.zip, as required in
         # bug 882932.
         if not options.httpdPath:
             options.httpdPath = os.path.join(options.utilityPath, "components")
 
         self.startWebServer(options)
         self.startWebSocketServer(options, debuggerInfo)
-        self.startWebsocketProcessBridge(options)
 
         # start SSL pipe
         self.sslTunnel = SSLTunnel(
             options,
             logger=self.log,
             ignoreSSLTunnelExts=ignoreSSLTunnelExts)
         self.sslTunnel.buildConfig(self.locations)
         self.sslTunnel.start()
@@ -889,23 +857,16 @@ class MochitestBase(object):
 
         if self.sslTunnel is not None:
             try:
                 self.log.info('Stopping ssltunnel')
                 self.sslTunnel.stop()
             except Exception:
                 self.log.critical('Exception stopping ssltunnel')
 
-        if self.websocketprocessbridge is not None:
-            try:
-                self.log.info('Stopping websocket/process bridge')
-                self.websocketprocessbridge.kill()
-            except Exception:
-                self.log.critical('Exception stopping websocket/process bridge')
-
     def copyExtraFilesToProfile(self, options):
         "Copy extra files or dirs specified on the command line to the testing profile."
         for f in options.extraProfileFiles:
             abspath = self.getFullPath(f)
             if os.path.isfile(abspath):
                 shutil.copy2(abspath, options.profilePath)
             elif os.path.isdir(abspath):
                 dest = os.path.join(
--- a/testing/mozharness/configs/unittests/win_unittest.py
+++ b/testing/mozharness/configs/unittests/win_unittest.py
@@ -21,18 +21,16 @@ config = {
         'tooltool.py': [sys.executable, 'C:/mozilla-build/tooltool.py'],
     },
     ###
     "installer_path": INSTALLER_PATH,
     "binary_path": BINARY_PATH,
     "xpcshell_name": XPCSHELL_NAME,
     "virtualenv_path": 'venv',
     "virtualenv_python_dll": os.path.join(os.path.dirname(sys.executable), "python27.dll"),
-    "virtualenv_modules": ['pywin32'],
-
     "find_links": [
         "http://pypi.pvt.build.mozilla.org/pub",
         "http://pypi.pub.build.mozilla.org/pub",
     ],
     "pip_index": False,
     "exe_suffix": EXE_SUFFIX,
     "run_file_names": {
         "mochitest": "runtests.py",
--- a/testing/mozharness/scripts/android_emulator_unittest.py
+++ b/testing/mozharness/scripts/android_emulator_unittest.py
@@ -17,17 +17,17 @@ import time
 import tempfile
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
 
 from mozprocess import ProcessHandler
 
 from mozharness.base.log import FATAL
-from mozharness.base.script import BaseScript, PreScriptAction
+from mozharness.base.script import BaseScript
 from mozharness.base.vcs.vcsbase import VCSMixin
 from mozharness.mozilla.blob_upload import BlobUploadMixin, blobupload_config_options
 from mozharness.mozilla.mozbase import MozbaseMixin
 from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
 from mozharness.mozilla.testing.unittest import EmulatorMixin
 
 
 class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin, BaseScript, MozbaseMixin):
@@ -131,44 +131,29 @@ class AndroidEmulatorTest(BlobUploadMixi
         dirs['abs_xre_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'hostutils')
         dirs['abs_modules_dir'] = os.path.join(
             dirs['abs_test_install_dir'], 'modules')
         dirs['abs_blob_upload_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'blobber_upload_dir')
         dirs['abs_emulator_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'emulator')
-        dirs['abs_mochitest_dir'] = os.path.join(
-            dirs['abs_test_install_dir'], 'mochitest')
 
         if self.config.get("developer_mode"):
             dirs['abs_avds_dir'] = os.path.join(
                 abs_dirs['abs_work_dir'], "avds_dir")
         else:
             dirs['abs_avds_dir'] = "/home/cltbld/.android"
 
         for key in dirs.keys():
             if key not in abs_dirs:
                 abs_dirs[key] = dirs[key]
         self.abs_dirs = abs_dirs
         return self.abs_dirs
 
-    @PreScriptAction('create-virtualenv')
-    def _pre_create_virtualenv(self, action):
-        dirs = self.query_abs_dirs()
-
-        if os.path.isdir(dirs['abs_mochitest_dir']):
-            # mochitest is the only thing that needs this
-            requirements = os.path.join(dirs['abs_mochitest_dir'],
-                        'websocketprocessbridge',
-                        'websocketprocessbridge_requirements.txt')
-
-            self.register_virtualenv_module(requirements=[requirements],
-                                            two_pass=True)
-
     def _launch_emulator(self):
         env = self.query_env()
 
         # Set $LD_LIBRARY_PATH to self.dirs['abs_work_dir'] so that
         # the emulator picks up the symlink to libGL.so.1 that we
         # constructed in start_emulator.
         env['LD_LIBRARY_PATH'] = self.abs_dirs['abs_work_dir']
 
--- a/testing/mozharness/scripts/androidx86_emulator_unittest.py
+++ b/testing/mozharness/scripts/androidx86_emulator_unittest.py
@@ -16,17 +16,17 @@ import time
 import tempfile
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
 
 from mozprocess import ProcessHandler
 
 from mozharness.base.log import FATAL
-from mozharness.base.script import BaseScript, PostScriptRun, PreScriptAction
+from mozharness.base.script import BaseScript, PostScriptRun
 from mozharness.base.vcs.vcsbase import VCSMixin
 from mozharness.mozilla.blob_upload import BlobUploadMixin, blobupload_config_options
 from mozharness.mozilla.mozbase import MozbaseMixin
 from mozharness.mozilla.buildbot import TBPL_WORST_LEVEL_TUPLE
 from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
 from mozharness.mozilla.testing.unittest import EmulatorMixin
 
 
@@ -138,44 +138,29 @@ class AndroidEmulatorTest(BlobUploadMixi
         dirs['abs_xre_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'hostutils')
         dirs['abs_modules_dir'] = os.path.join(
             dirs['abs_test_install_dir'], 'modules')
         dirs['abs_blob_upload_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'blobber_upload_dir')
         dirs['abs_emulator_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'emulator')
-        dirs['abs_mochitest_dir'] = os.path.join(
-            dirs['abs_test_install_dir'], 'mochitest')
 
         if self.config.get("developer_mode"):
             dirs['abs_avds_dir'] = os.path.join(
                 abs_dirs['abs_work_dir'], "avds_dir")
         else:
             dirs['abs_avds_dir'] = "/home/cltbld/.android"
 
         for key in dirs.keys():
             if key not in abs_dirs:
                 abs_dirs[key] = dirs[key]
         self.abs_dirs = abs_dirs
         return self.abs_dirs
 
-    @PreScriptAction('create-virtualenv')
-    def _pre_create_virtualenv(self, action):
-        dirs = self.query_abs_dirs()
-
-        if os.path.isdir(dirs['abs_mochitest_dir']):
-            # mochitest is the only thing that needs this
-            requirements = os.path.join(dirs['abs_mochitest_dir'],
-                        'websocketprocessbridge',
-                        'websocketprocessbridge_requirements.txt')
-
-            self.register_virtualenv_module(requirements=[requirements],
-                                            two_pass=True)
-
     def _build_arg(self, option, value):
         """
         Build a command line argument
         """
         if not value:
             return []
         return [str(option), str(value)]
 
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -255,30 +255,21 @@ class DesktopUnittest(TestingMixin, Merc
     def _pre_create_virtualenv(self, action):
         dirs = self.query_abs_dirs()
 
         self.register_virtualenv_module(name='pip>=1.5')
         self.register_virtualenv_module('psutil==3.1.1', method='pip')
         self.register_virtualenv_module(name='mock')
         self.register_virtualenv_module(name='simplejson')
 
-        requirements_files = [
-                os.path.join(dirs['abs_test_install_dir'],
-                    'config',
-                    'marionette_requirements.txt')]
-
-        if os.path.isdir(dirs['abs_mochitest_dir']):
-            # mochitest is the only thing that needs this
-            requirements_files.append(
-                os.path.join(dirs['abs_mochitest_dir'],
-                             'websocketprocessbridge',
-                             'websocketprocessbridge_requirements.txt'))
-
-        for requirements_file in requirements_files:
-            self.register_virtualenv_module(requirements=[requirements_file],
+        requirements = os.path.join(dirs['abs_test_install_dir'],
+                                    'config',
+                                    'marionette_requirements.txt')
+        if os.path.isfile(requirements):
+            self.register_virtualenv_module(requirements=[requirements],
                                             two_pass=True)
 
     def _query_symbols_url(self):
         """query the full symbols URL based upon binary URL"""
         # may break with name convention changes but is one less 'input' for script
         if self.symbols_url:
             return self.symbols_url
 
deleted file mode 100644
--- a/testing/tools/iceserver/iceserver.py
+++ /dev/null
@@ -1,759 +0,0 @@
-# vim: set ts=4 et sw=4 tw=80
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import ipaddr
-import socket
-import hmac
-import hashlib
-import passlib.utils # for saslprep
-import copy
-import random
-import operator
-import platform
-import time
-from string import Template
-from twisted.internet import reactor, protocol
-from twisted.internet.task import LoopingCall
-from twisted.internet.address import IPv4Address
-
-MAGIC_COOKIE = 0x2112A442
-
-REQUEST = 0
-INDICATION = 1
-SUCCESS_RESPONSE = 2
-ERROR_RESPONSE = 3
-
-BINDING = 0x001
-ALLOCATE = 0x003
-REFRESH = 0x004
-SEND = 0x006
-DATA_MSG = 0x007
-CREATE_PERMISSION = 0x008
-CHANNEL_BIND = 0x009
-
-IPV4 = 1
-IPV6 = 2
-
-MAPPED_ADDRESS = 0x0001
-USERNAME = 0x0006
-MESSAGE_INTEGRITY = 0x0008
-ERROR_CODE = 0x0009
-UNKNOWN_ATTRIBUTES = 0x000A
-LIFETIME = 0x000D
-DATA_ATTR = 0x0013
-XOR_PEER_ADDRESS = 0x0012
-REALM = 0x0014
-NONCE = 0x0015
-XOR_RELAYED_ADDRESS = 0x0016
-REQUESTED_TRANSPORT = 0x0019
-DONT_FRAGMENT = 0x001A
-XOR_MAPPED_ADDRESS = 0x0020
-SOFTWARE = 0x8022
-ALTERNATE_SERVER = 0x8023
-FINGERPRINT = 0x8028
-
-def unpack_uint(bytes_buf):
-    result = 0
-    for byte in bytes_buf:
-        result = (result << 8) + byte
-    return result
-
-def pack_uint(value, width):
-    if value < 0:
-        raise ValueError("Invalid value: {}".format(value))
-    buf = bytearray([0]*width)
-    for i in range(0, width):
-        buf[i] = (value >> (8*(width - i - 1))) & 0xFF
-
-    return buf
-
-def unpack(bytes_buf, format_array):
-    results = ()
-    for width in format_array:
-        results = results + (unpack_uint(bytes_buf[0:width]),)
-        bytes_buf = bytes_buf[width:]
-    return results
-
-def pack(values, format_array):
-    if len(values) != len(format_array):
-        raise ValueError()
-    buf = bytearray()
-    for i in range(0, len(values)):
-        buf.extend(pack_uint(values[i], format_array[i]))
-    return buf
-
-def bitwise_pack(source, dest, start_bit, num_bits):
-    if num_bits <= 0 or num_bits > start_bit + 1:
-        raise ValueError("Invalid num_bits: {}, start_bit = {}"
-                         .format(num_bits, start_bit))
-    last_bit = start_bit - num_bits + 1
-    source = source >> last_bit
-    dest = dest << num_bits
-    mask = (1 << num_bits) - 1
-    dest += source & mask
-    return dest
-
-
-class StunAttribute(object):
-    """
-    Represents a STUN attribute in a raw format, according to the following:
-
-     0                   1                   2                   3
-     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    |   StunAttribute.attr_type     |  Length (derived as needed)   |
-    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    |           StunAttribute.data (variable length)             ....
-    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    """
-
-    __attr_header_fmt = [2,2]
-    __attr_header_size = reduce(operator.add, __attr_header_fmt)
-
-    def __init__(self, attr_type=0, buf=bytearray()):
-        self.attr_type = attr_type
-        self.data = buf
-
-    def build(self):
-        buf = pack((self.attr_type, len(self.data)), self.__attr_header_fmt)
-        buf.extend(self.data)
-        # add padding if necessary
-        if len(buf) % 4:
-            buf.extend([0]*(4 - (len(buf) % 4)))
-        return buf
-
-    def parse(self, buf):
-        if self.__attr_header_size  > len(buf):
-            raise Exception('truncated at attribute: incomplete header')
-
-        self.attr_type, length = unpack(buf, self.__attr_header_fmt)
-        length += self.__attr_header_size
-
-        if length > len(buf):
-            raise Exception('truncated at attribute: incomplete contents')
-
-        self.data = buf[self.__attr_header_size:length]
-
-        # verify padding
-        while length % 4:
-            if buf[length]:
-                raise ValueError("Non-zero padding")
-            length += 1
-
-        return length
-
-
-class StunMessage(object):
-    """
-    Represents a STUN message. Contains a method, msg_class, cookie,
-    transaction_id, and attributes (as an array of StunAttribute).
-
-    Has various functions for getting/adding attributes.
-    """
-
-    def __init__(self):
-        self.method = 0
-        self.msg_class = 0
-        self.cookie = MAGIC_COOKIE
-        self.transaction_id = 0
-        self.attributes = []
-
-#      0                   1                   2                   3
-#      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#     |0 0|M M M M M|C|M M M|C|M M M M|         Message Length        |
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#     |                         Magic Cookie                          |
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#     |                                                               |
-#     |                     Transaction ID (96 bits)                  |
-#     |                                                               |
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    __header_fmt = [2, 2, 4, 12]
-    __header_size = reduce(operator.add, __header_fmt)
-
-    # Returns how many bytes were parsed if buf was large enough, or how many
-    # bytes we would have needed if not. Throws if buf is malformed.
-    def parse(self, buf):
-        min_buf_size = self.__header_size
-        if len(buf) < min_buf_size:
-            return min_buf_size
-
-        message_type, length, cookie, self.transaction_id = unpack(
-                buf, self.__header_fmt)
-        min_buf_size += length
-        if len(buf) < min_buf_size:
-            return min_buf_size
-
-        # Avert your eyes...
-        self.method = bitwise_pack(message_type, 0, 13, 5)
-        self.msg_class = bitwise_pack(message_type, 0, 8, 1)
-        self.method = bitwise_pack(message_type, self.method, 7, 3)
-        self.msg_class = bitwise_pack(message_type, self.msg_class, 4, 1)
-        self.method = bitwise_pack(message_type, self.method, 3, 4)
-
-        if cookie != self.cookie:
-            raise Exception('Invalid cookie: {}'.format(cookie))
-
-        buf = buf[self.__header_size:min_buf_size]
-        while len(buf):
-            attr = StunAttribute()
-            length = attr.parse(buf)
-            buf = buf[length:]
-            self.attributes.append(attr)
-
-        return min_buf_size
-
-    # stop_after_attr_type is useful for calculating MESSAGE-DIGEST
-    def build(self, stop_after_attr_type=0):
-        attrs = bytearray()
-        for attr in self.attributes:
-            attrs.extend(attr.build())
-            if attr.attr_type == stop_after_attr_type:
-                break
-
-        message_type = bitwise_pack(self.method, 0, 11, 5)
-        message_type = bitwise_pack(self.msg_class, message_type, 1, 1)
-        message_type = bitwise_pack(self.method, message_type, 6, 3)
-        message_type = bitwise_pack(self.msg_class, message_type, 0, 1)
-        message_type = bitwise_pack(self.method, message_type, 3, 4)
-
-        message = pack((message_type,
-                        len(attrs),
-                        self.cookie,
-                        self.transaction_id), self.__header_fmt)
-        message.extend(attrs)
-
-        return message
-
-    def add_error_code(self, code, phrase=None):
-#      0                   1                   2                   3
-#      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#     |           Reserved, should be 0         |Class|     Number    |
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#     |      Reason Phrase (variable)                                ..
-#     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-        error_code_fmt = [3, 1]
-        error_code = pack((code // 100, code % 100), error_code_fmt)
-        if phrase != None:
-            error_code.extend(bytearray(phrase))
-        self.attributes.append(StunAttribute(ERROR_CODE, error_code))
-
-#     0                   1                   2                   3
-#     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-#    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#    |x x x x x x x x|    Family     |         X-Port                |
-#    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-#    |                X-Address (Variable)
-#    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    __xor_v4addr_fmt = [1, 1, 2, 4]
-    __xor_v6addr_fmt = [1, 1, 2, 16]
-    __xor_v4addr_size = reduce(operator.add, __xor_v4addr_fmt)
-    __xor_v6addr_size = reduce(operator.add, __xor_v6addr_fmt)
-
-    def get_xaddr(self, ip_addr, version):
-        if version == IPV4:
-            return self.cookie ^ ip_addr
-        elif version == IPV6:
-            return ((self.cookie << 96) + self.transaction_id) ^ ip_addr
-        else:
-            raise ValueError("Invalid family: {}".format(family))
-
-    def get_xport(self, port):
-        return (self.cookie >> 16) ^ port
-
-    def add_xor_address(self, addr_port, attr_type):
-        ip_address = ipaddr.IPAddress(addr_port.host)
-        xport = self.get_xport(addr_port.port)
-
-        if ip_address.version == 4:
-            xaddr = self.get_xaddr(int(ip_address), IPV4)
-            xor_address = pack((0, IPV4, xport, xaddr), self.__xor_v4addr_fmt)
-        elif ip_address.version == 6:
-            xaddr = self.get_xaddr(int(ip_address), IPV6)
-            xor_address = pack((0, IPV6, xport, xaddr), self.__xor_v6addr_fmt)
-        else:
-            raise ValueError("Invalid ip version: {}"
-                             .format(ip_address.version))
-
-        self.attributes.append(StunAttribute(attr_type, xor_address))
-
-    def add_data(self, buf):
-        self.attributes.append(StunAttribute(DATA_ATTR, buf))
-
-    def find(self, attr_type):
-        for attr in self.attributes:
-            if attr.attr_type == attr_type:
-                return attr
-        return None
-
-    def get_xor_address(self, attr_type):
-        addr_attr = self.find(attr_type)
-        if not addr_attr:
-            return None
-
-        padding, family, xport, xaddr = unpack(addr_attr.data,
-                                               self.__xor_v4addr_fmt)
-        addr_ctor = IPv4Address
-        if family == IPV6:
-            from twisted.internet.address import IPv6Address
-            padding, family, xport, xaddr = unpack(addr_attr.data,
-                                                   self.__xor_v6addr_fmt)
-            addr_ctor = IPv6Address
-        elif family != IPV4:
-            raise ValueError("Invalid family: {}".format(family))
-
-        return addr_ctor('UDP',
-                         str(ipaddr.IPAddress(self.get_xaddr(xaddr, family))),
-                         self.get_xport(xport))
-
-    def add_nonce(self, nonce):
-        self.attributes.append(StunAttribute(NONCE, bytearray(nonce)))
-
-    def add_realm(self, realm):
-        self.attributes.append(StunAttribute(REALM, bytearray(realm)))
-
-    def calculate_message_digest(self, username, realm, password):
-        digest_buf = self.build(MESSAGE_INTEGRITY)
-        # Trim off the MESSAGE-INTEGRITY attr
-        digest_buf = digest_buf[:len(digest_buf) - 24]
-        password = passlib.utils.saslprep(unicode(password))
-        key_string = "{}:{}:{}".format(username, realm, password)
-        md5 = hashlib.md5()
-        md5.update(key_string)
-        key = md5.digest()
-        return bytearray(hmac.new(key, digest_buf, hashlib.sha1).digest())
-
-    def add_lifetime(self, lifetime):
-        self.attributes.append(StunAttribute(LIFETIME, pack_uint(lifetime, 4)))
-
-    def get_lifetime(self):
-        lifetime_attr = self.find(LIFETIME)
-        if not lifetime_attr:
-            return None
-        return unpack_uint(lifetime_attr.data[0:4])
-
-    def get_username(self):
-        username = self.find(USERNAME)
-        if not username:
-            return None
-        return str(username.data)
-
-    def add_message_integrity(self, username, realm, password):
-        dummy_value = bytearray([0]*20)
-        self.attributes.append(StunAttribute(MESSAGE_INTEGRITY, dummy_value))
-        digest = self.calculate_message_digest(username, realm, password)
-        self.find(MESSAGE_INTEGRITY).data = digest
-
-
-class Allocation(protocol.DatagramProtocol):
-    """
-    Comprises the socket for a TURN allocation, a back-reference to the
-    transport we will forward received traffic on, the allocator's address and
-    username, the set of permissions for the allocation, and the allocation's
-    expiry.
-    """
-
-    def __init__(self, other_transport_handler, allocator_address, username):
-        self.permissions = set() # str, int tuples
-        # Handler to use when sending stuff that arrives on the allocation
-        self.other_transport_handler = other_transport_handler
-        self.allocator_address = allocator_address
-        self.username = username
-        self.expiry = time.time()
-        self.port = reactor.listenUDP(0, self, interface=v4_address)
-
-    def datagramReceived(self, data, (host, port)):
-        if not host in self.permissions:
-            print("Dropping packet from {}:{}, no permission on allocation {}"
-                  .format(host, port, self.transport.getHost()))
-            return
-
-        data_indication = StunMessage()
-        data_indication.method = DATA_MSG
-        data_indication.msg_class = INDICATION
-        data_indication.transaction_id = random.getrandbits(96)
-
-        # Only handles UDP allocations. Doubtful that we need more than this.
-        data_indication.add_xor_address(IPv4Address('UDP', host, port),
-                                        XOR_PEER_ADDRESS)
-        data_indication.add_data(data)
-
-        self.other_transport_handler.write(data_indication.build(),
-                                           self.allocator_address)
-
-    def close(self):
-        self.port.stopListening()
-        self.port = None
-
-
-class StunHandler(object):
-    """
-    Frames and handles STUN messages. This is the core logic of the TURN
-    server, along with Allocation.
-    """
-
-    def __init__(self, transport_handler):
-        self.client_address = None
-        self.data = str()
-        self.transport_handler = transport_handler
-
-    def data_received(self, data, address):
-        self.data += bytearray(data)
-        while True:
-            stun_message = StunMessage()
-            parsed_len = stun_message.parse(self.data)
-            if parsed_len > len(self.data):
-                break
-            self.data = self.data[parsed_len:]
-
-            response = self.handle_stun(stun_message, address)
-            if response:
-                self.transport_handler.write(response, address)
-
-    def handle_stun(self, stun_message, address):
-        self.client_address = address
-        if stun_message.msg_class == INDICATION:
-            if stun_message.method == SEND:
-                self.handle_send_indication(stun_message)
-            else:
-                print("Dropping unknown indication method: {}"
-                      .format(stun_message.method))
-            return None
-
-        if stun_message.msg_class != REQUEST:
-            print("Dropping STUN response, method: {}"
-                  .format(stun_message.method))
-            return None
-
-        if stun_message.method == BINDING:
-            return self.make_success_response(stun_message).build()
-        elif stun_message.method == ALLOCATE:
-            return self.handle_allocation(stun_message).build()
-        elif stun_message.method == REFRESH:
-            return self.handle_refresh(stun_message).build()
-        elif stun_message.method == CREATE_PERMISSION:
-            return self.handle_permission(stun_message).build()
-        else:
-            return self.make_error_response(
-                    stun_message,
-                    400,
-                    ("Unsupported STUN request, method: {}"
-                     .format(stun_message.method))).build()
-
-    def get_allocation_tuple(self):
-        return (self.client_address.host,
-                self.client_address.port,
-                self.transport_handler.transport.getHost().type,
-                self.transport_handler.transport.getHost().host,
-                self.transport_handler.transport.getHost().port)
-
-    def handle_allocation(self, request):
-        allocate_response = self.check_long_term_auth(request)
-        if allocate_response.msg_class == SUCCESS_RESPONSE:
-            if self.get_allocation_tuple() in allocations:
-                return self.make_error_response(
-                        request,
-                        437,
-                        ("Duplicate allocation request for tuple {}"
-                         .format(self.get_allocation_tuple())))
-
-            allocation = Allocation(self.transport_handler,
-                                    self.client_address,
-                                    request.get_username())
-
-            allocate_response.add_xor_address(allocation.transport.getHost(),
-                                              XOR_RELAYED_ADDRESS)
-
-            lifetime = request.get_lifetime()
-            if lifetime == None:
-                return self.make_error_response(
-                        request,
-                        400,
-                        "Missing lifetime attribute in allocation request")
-
-            lifetime = min(lifetime, 3600)
-            allocate_response.add_lifetime(lifetime)
-            allocation.expiry = time.time() + lifetime
-
-            allocate_response.add_message_integrity(turn_user,
-                                                    turn_realm,
-                                                    turn_pass)
-            allocations[self.get_allocation_tuple()] = allocation
-        return allocate_response
-
-    def handle_refresh(self, request):
-        refresh_response = self.check_long_term_auth(request)
-        if refresh_response.msg_class == SUCCESS_RESPONSE:
-            try:
-                allocation = allocations[self.get_allocation_tuple()]
-            except KeyError:
-                return self.make_error_response(
-                        request,
-                        437,
-                        ("Refresh request for non-existing allocation, tuple {}"
-                         .format(self.get_allocation_tuple())))
-
-            if allocation.username != request.get_username():
-                return self.make_error_response(
-                        request,
-                        441,
-                        ("Refresh request with wrong user, exp {}, got {}"
-                         .format(allocation.username, request.get_username())))
-
-            lifetime = request.get_lifetime()
-            if lifetime == None:
-                return self.make_error_response(
-                        request,
-                        400,
-                        "Missing lifetime attribute in allocation request")
-
-            lifetime = min(lifetime, 3600)
-            refresh_response.add_lifetime(lifetime)
-            allocation.expiry = time.time() + lifetime
-
-            refresh_response.add_message_integrity(turn_user,
-                                                   turn_realm,
-                                                   turn_pass)
-        return refresh_response
-
-    def handle_permission(self, request):
-        permission_response = self.check_long_term_auth(request)
-        if permission_response.msg_class == SUCCESS_RESPONSE:
-            try:
-                allocation = allocations[self.get_allocation_tuple()]
-            except KeyError:
-                return self.make_error_response(
-                        request,
-                        437,
-                        ("No such allocation for permission request, tuple {}"
-                         .format(self.get_allocation_tuple())))
-
-            if allocation.username != request.get_username():
-                return self.make_error_response(
-                        request,
-                        441,
-                        ("Permission request with wrong user, exp {}, got {}"
-                         .format(allocation.username, request.get_username())))
-
-            # TODO: Handle multiple XOR-PEER-ADDRESS
-            peer_address = request.get_xor_address(XOR_PEER_ADDRESS)
-            if not peer_address:
-                return self.make_error_response(
-                        request,
-                        400,
-                        "Missing XOR-PEER-ADDRESS on permission request")
-
-            permission_response.add_message_integrity(turn_user,
-                                                      turn_realm,
-                                                      turn_pass)
-            allocation.permissions.add(peer_address.host)
-
-        return permission_response
-
-    def handle_send_indication(self, indication):
-        try:
-            allocation = allocations[self.get_allocation_tuple()]
-        except KeyError:
-            print("Dropping send indication; no allocation for tuple {}"
-                  .format(self.get_allocation_tuple()))
-            return
-
-        peer_address = indication.get_xor_address(XOR_PEER_ADDRESS)
-        if not peer_address:
-            print("Dropping send indication, missing XOR-PEER-ADDRESS")
-            return
-
-        data_attr = indication.find(DATA_ATTR)
-        if not data_attr:
-            print("Dropping send indication, missing DATA")
-            return
-
-        if indication.find(DONT_FRAGMENT):
-            print("Dropping send indication, DONT-FRAGMENT set")
-            return
-
-        if not peer_address.host in allocation.permissions:
-            print("Dropping send indication, no permission for {} on tuple {}"
-                  .format(peer_address.host, self.get_allocation_tuple()))
-            return
-
-        allocation.transport.write(data_attr.data,
-                                   (peer_address.host, peer_address.port))
-
-    def make_success_response(self, request):
-        response = copy.deepcopy(request)
-        response.attributes = []
-        response.add_xor_address(self.client_address, XOR_MAPPED_ADDRESS)
-        response.msg_class = SUCCESS_RESPONSE
-        return response
-
-    def make_error_response(self, request, code, reason=None):
-        if reason:
-            print("{}: rejecting with {}".format(reason, code))
-        response = copy.deepcopy(request)
-        response.attributes = []
-        response.add_error_code(code, reason)
-        response.msg_class = ERROR_RESPONSE
-        return response
-
-    def make_challenge_response(self, request, reason=None):
-        response = self.make_error_response(request, 401, reason)
-        # 65 means the hex encoding will need padding half the time
-        response.add_nonce("{:x}".format(random.getrandbits(65)))
-        response.add_realm(turn_realm)
-        return response
-
-    def check_long_term_auth(self, request):
-        message_integrity = request.find(MESSAGE_INTEGRITY)
-        if not message_integrity:
-            return self.make_challenge_response(request)
-
-        username = request.find(USERNAME)
-        realm = request.find(REALM)
-        nonce = request.find(NONCE)
-        if not username or not realm or not nonce:
-            return self.make_error_response(
-                    request,
-                    400,
-                    "Missing either USERNAME, NONCE, or REALM")
-
-        if str(username.data) != turn_user:
-            return self.make_challenge_response(
-                    request,
-                    "Wrong user {}, exp {}".format(username.data, turn_user))
-
-        expected_message_digest = request.calculate_message_digest(turn_user,
-                                                                  turn_realm,
-                                                                  turn_pass)
-        if message_integrity.data != expected_message_digest:
-            return self.make_challenge_response(request,
-                                                "Incorrect message disgest")
-
-        return self.make_success_response(request)
-
-
-class UdpStunHandler(protocol.DatagramProtocol):
-    """
-    Represents a UDP listen port for TURN.
-    """
-
-    def datagramReceived(self, data, address):
-        stun_handler = StunHandler(self)
-        stun_handler.data_received(data,
-                                   IPv4Address('UDP', address[0], address[1]))
-
-    def write(self, data, address):
-        self.transport.write(str(data), (address.host, address.port))
-
-
-class TcpStunHandlerFactory(protocol.Factory):
-    """
-    Represents a TCP listen port for TURN.
-    """
-
-    def buildProtocol(self, addr):
-        return TcpStunHandler(addr)
-
-
-class TcpStunHandler(protocol.Protocol):
-    """
-    Represents a connected TCP port for TURN.
-    """
-
-    def __init__(self, addr):
-        self.address = addr
-        self.stun_handler = None
-
-    def dataReceived(self, data):
-        # This needs to persist, since it handles framing
-        if not self.stun_handler:
-            self.stun_handler = StunHandler(self)
-        self.stun_handler.data_received(data, self.address)
-
-    def connectionLost(self, reason):
-        print("Lost connection from {}".format(self.address))
-        # Destroy allocations that this connection made
-        for key, allocation in allocations.items():
-            if allocation.other_transport_handler == self:
-                print("Closing allocation due to dropped connection: {}"
-                      .format(key))
-                del allocations[key]
-                allocation.close()
-
-    def write(self, data, address):
-        self.transport.write(str(data))
-
-def get_default_route(family):
-    dummy_socket = socket.socket(family, socket.SOCK_DGRAM)
-    if family is socket.AF_INET:
-        dummy_socket.connect(("8.8.8.8", 53))
-    else:
-        dummy_socket.connect(("2001:4860:4860::8888", 53))
-
-    default_route = dummy_socket.getsockname()[0]
-    dummy_socket.close()
-    return default_route
-
-turn_user="foo"
-turn_pass="bar"
-turn_realm="mozilla.invalid"
-allocations = {}
-v4_address = get_default_route(socket.AF_INET)
-try:
-    v6_address = get_default_route(socket.AF_INET6)
-except:
-    v6_address = ""
-
-def prune_allocations():
-    now = time.time()
-    for key, allocation in allocations.items():
-        if allocation.expiry < now:
-            print("Allocation expired: {}".format(key))
-            del allocations[key]
-            allocation.close()
-
-if __name__ == "__main__":
-    random.seed()
-
-    if platform.system() is "Windows":
-      # Windows is finicky about allowing real interfaces to talk to loopback.
-      interface_4 = v4_address
-      interface_6 = v6_address
-      hostname = socket.gethostname()
-    else:
-      # Our linux builders do not have a hostname that resolves to the real
-      # interface.
-      interface_4 = "127.0.0.1"
-      interface_6 = "::1"
-      hostname = "localhost"
-
-    reactor.listenUDP(3478, UdpStunHandler(), interface=interface_4)
-    reactor.listenTCP(3478, TcpStunHandlerFactory(), interface=interface_4)
-
-    try:
-        reactor.listenUDP(3478, UdpStunHandler(), interface=interface_6)
-        reactor.listenTCP(3478, TcpStunHandlerFactory(), interface=interface_6)
-    except:
-        pass
-
-    allocation_pruner = LoopingCall(prune_allocations)
-    allocation_pruner.start(1)
-
-    template = Template(
-'[\
-{"url":"stun:$hostname"}, \
-{"url":"stun:$hostname?transport=tcp"}, \
-{"username":"$user","credential":"$pwd","url":"turn:$hostname"}, \
-{"username":"$user","credential":"$pwd","url":"turn:$hostname?transport=tcp"}]'
-)
-
-    print(template.substitute(user=turn_user,
-                              pwd=turn_pass,
-                              hostname=hostname))
-
-    reactor.run()
-
deleted file mode 100644
--- a/testing/tools/websocketprocessbridge/websocketprocessbridge.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# vim: set ts=4 et sw=4 tw=80
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from twisted.internet import protocol, reactor
-from twisted.internet.task import LoopingCall
-import txws
-import psutil
-
-import sys
-import os
-
-# maps a command issued via websocket to running an executable with args
-commands = {
-    'iceserver' : [sys.executable,
-                   "-u",
-                   os.path.join("iceserver", "iceserver.py")]
-}
-
-class ProcessSide(protocol.ProcessProtocol):
-    """Handles the spawned process (I/O, process termination)"""
-
-    def __init__(self, socketSide):
-        self.socketSide = socketSide
-
-    def outReceived(self, data):
-        if self.socketSide:
-            lines = data.splitlines()
-            for line in lines:
-                self.socketSide.transport.write(line)
-
-    def errReceived(self, data):
-        self.outReceived(data)
-
-    def processEnded(self, reason):
-        if self.socketSide:
-            self.outReceived(str(reason))
-            self.socketSide.processGone()
-
-    def socketGone(self):
-        self.socketSide = None
-        self.transport.loseConnection()
-        self.transport.signalProcess("KILL")
-
-
-class SocketSide(protocol.Protocol):
-    """
-    Handles the websocket (I/O, closed connection), and spawning the process
-    """
-
-    def __init__(self):
-        self.processSide = None
-
-    def dataReceived(self, data):
-        if not self.processSide:
-            self.processSide = ProcessSide(self)
-            # We deliberately crash if |data| isn't on the "menu",
-            # or there is some problem spawning.
-            reactor.spawnProcess(self.processSide,
-                                 commands[data][0],
-                                 commands[data],
-                                 env=os.environ)
-
-    def connectionLost(self, reason):
-        if self.processSide:
-            self.processSide.socketGone()
-
-    def processGone(self):
-        self.processSide = None
-        self.transport.loseConnection()
-
-
-class ProcessSocketBridgeFactory(protocol.Factory):
-    """Builds sockets that can launch/bridge to a process"""
-
-    def buildProtocol(self, addr):
-        return SocketSide()
-
-# Parent process could have already exited, so this is slightly racy. Only
-# alternative is to set up a pipe between parent and child, but that requires
-# special cooperation from the parent.
-parent_process = psutil.Process(os.getpid()).parent()
-
-def check_parent():
-    """ Checks if parent process is still alive, and exits if not """
-    if not parent_process.is_running():
-        print("websocket/process bridge exiting because parent process is gone")
-        reactor.stop()
-
-if __name__ == "__main__":
-    parent_checker = LoopingCall(check_parent)
-    parent_checker.start(1)
-
-    bridgeFactory = ProcessSocketBridgeFactory()
-    reactor.listenTCP(8191, txws.WebSocketFactory(bridgeFactory))
-    print("websocket/process bridge listening on port 8191")
-    reactor.run()
-
-
deleted file mode 100644
--- a/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-twisted==10.2.0
-
-# websocket adapter for twisted, might be built into twisted someday
-txws==0.9.1
-
-psutil==3.1.1
-
-# needed by txws, but pypi doesn't know about it
-six==1.10.0
-
-# Needed by iceserver
-ipaddr==2.1.11
-passlib==1.6.5