Bug 1191324 - Extend Marionette to allow automation of telemetry tests; r?maja_zf draft
authorAndré Reinald <areinald@mozilla.com>
Fri, 25 Mar 2016 14:50:15 +0100
changeset 345540 762ae81a07f6d749dd12f6b049c001dabb30328d
parent 345539 0787b764de2d177b04f3de852cd06204e5f7d463
child 349408 5329e23d3b0cbeef7cb22533578bb09d08b2a763
push id14105
push userareinald@mozilla.com
push dateTue, 29 Mar 2016 16:48:56 +0000
reviewersmaja_zf
bugs1191324
milestone48.0a1
Bug 1191324 - Extend Marionette to allow automation of telemetry tests; r?maja_zf This is the "change patch" over the duplicated files. MozReview-Commit-ID: LnTtewjfxPB
testing/marionette/harness/marionette/__init__.py
testing/marionette/harness/marionette/marionette2_test.py
testing/marionette/harness/marionette/runner/__init__.py
testing/marionette/harness/marionette/runner/base2.py
testing/marionette/harness/marionette/runtests2.py
testing/marionette/harness/marionette/tests2/test_marionette2.py
testing/marionette/harness/marionette/tests2/unit-tests.ini
testing/marionette/mach_commands.py
--- a/testing/marionette/harness/marionette/__init__.py
+++ b/testing/marionette/harness/marionette/__init__.py
@@ -9,21 +9,27 @@ from .marionette_test import (
     expectedFailure,
     MarionetteJSTestCase,
     MarionetteTestCase,
     skip,
     skip_if_b2g,
     SkipTest,
     skip_unless_protocol,
 )
+from .marionette2_test import (
+    Marionette2JSTestCase,
+    Marionette2TestCase,
+)
 from .runner import (
     B2GTestCaseMixin,
     B2GTestResultMixin,
     BaseMarionetteArguments,
     BaseMarionetteTestRunner,
+    BaseMarionette2Arguments,
+    BaseMarionette2TestRunner,
     BrowserMobProxyTestCaseMixin,
     EnduranceArguments,
     EnduranceTestCaseMixin,
     HTMLReportingArguments,
     HTMLReportingTestResultMixin,
     HTMLReportingTestRunnerMixin,
     Marionette,
     MarionetteTest,
--- a/testing/marionette/harness/marionette/marionette2_test.py
+++ b/testing/marionette/harness/marionette/marionette2_test.py
@@ -9,273 +9,59 @@ import functools
 import sys
 import socket
 import time
 import types
 import unittest
 import weakref
 import warnings
 
-
+from mozprofile import FirefoxProfile
+from mozrunner import FirefoxRunner
 from marionette_driver.errors import (
         MarionetteException, TimeoutException,
         JavascriptException, NoSuchElementException, NoSuchWindowException,
         StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
         NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
         InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
         MoveTargetOutOfBoundsException
         )
 from marionette_driver.marionette import Marionette
 from marionette_driver.wait import Wait
 from marionette_driver.expected import element_present, element_not_present
 from mozlog import get_default_logger
 
-
-class SkipTest(Exception):
-    """
-    Raise this exception in a test to skip it.
-
-    Usually you can use TestResult.skip() or one of the skipping decorators
-    instead of raising this directly.
-    """
-    pass
-
-class _ExpectedFailure(Exception):
-    """
-    Raise this when a test is expected to fail.
-
-    This is an implementation detail.
-    """
-
-    def __init__(self, exc_info):
-        super(_ExpectedFailure, self).__init__()
-        self.exc_info = exc_info
-
-class _UnexpectedSuccess(Exception):
-    """
-    The test was supposed to fail, but it didn't!
-    """
-    pass
-
-def skip(reason):
-    """Unconditionally skip a test."""
-    def decorator(test_item):
-        if not isinstance(test_item, (type, types.ClassType)):
-            @functools.wraps(test_item)
-            def skip_wrapper(*args, **kwargs):
-                raise SkipTest(reason)
-            test_item = skip_wrapper
-
-        test_item.__unittest_skip__ = True
-        test_item.__unittest_skip_why__ = reason
-        return test_item
-    return decorator
-
-def expectedFailure(func):
-    @functools.wraps(func)
-    def wrapper(*args, **kwargs):
-        try:
-            func(*args, **kwargs)
-        except Exception:
-            raise _ExpectedFailure(sys.exc_info())
-        raise _UnexpectedSuccess
-    return wrapper
-
-def skip_if_chrome(target):
-    def wrapper(self, *args, **kwargs):
-        if self.marionette._send_message("getContext", key="value") == "chrome":
-            raise SkipTest("skipping test in chrome context")
-        return target(self, *args, **kwargs)
-    return wrapper
-
-def skip_if_desktop(target):
-    def wrapper(self, *args, **kwargs):
-        if self.marionette.session_capabilities.get('b2g') is None:
-            raise SkipTest('skipping due to desktop')
-        return target(self, *args, **kwargs)
-    return wrapper
-
-def skip_if_b2g(target):
-    def wrapper(self, *args, **kwargs):
-        if self.marionette.session_capabilities.get('b2g') == True:
-            raise SkipTest('skipping due to b2g')
-        return target(self, *args, **kwargs)
-    return wrapper
-
-def skip_if_e10s(target):
-    def wrapper(self, *args, **kwargs):
-        with self.marionette.using_context('chrome'):
-            multi_process_browser = self.marionette.execute_script("""
-            try {
-              return Services.appinfo.browserTabsRemoteAutostart;
-            } catch (e) {
-              return false;
-            }""")
-
-        if multi_process_browser:
-            raise SkipTest('skipping due to e10s')
-        return target(self, *args, **kwargs)
-    return wrapper
-
-def skip_unless_protocol(predicate):
-    """Given a predicate passed the current protocol level, skip the
-    test if the predicate does not match."""
-    def decorator(test_item):
-        @functools.wraps(test_item)
-        def skip_wrapper(self):
-            level = self.marionette.client.protocol
-            if not predicate(level):
-                raise SkipTest('skipping because protocol level is %s' % level)
-            return self
-        return skip_wrapper
-    return decorator
-
-def skip_unless_browser_pref(pref, predicate=bool):
-    """
-    Skip a test based on the value of a browser preference.
-
-    :param pref: the preference name
-    :param predicate: a function that should return false to skip the test.
-                      The function takes one parameter, the preference value.
-                      Defaults to the python built-in bool function.
-
-    Note that the preference must exist, else a failure is raised.
-
-    Example: ::
+from marionette_test import (
+        SkipTest,
+        _ExpectedFailure,
+        _UnexpectedSuccess,
+        skip,
+        expectedFailure,
+        parameterized,
+        with_parameters,
+        wraps_parameterized,
+        MetaParameterized,
+        JSTest
+        )
 
-      class TestSomething(MarionetteTestCase):
-          @skip_unless_browser_pref("accessibility.tabfocus",
-                                    lambda value: value >= 7)
-          def test_foo(self):
-              pass  # test implementation here
-    """
-    def wrapper(target):
-        @functools.wraps(target)
-        def wrapped(self, *args, **kwargs):
-            value = self.marionette.get_pref(pref)
-            if value is None:
-                self.fail("No such browser preference: %r" % pref)
-            if not predicate(value):
-                raise SkipTest("browser preference %r: %r" % (pref, value))
-            return target(self, *args, **kwargs)
-        return wrapped
-    return wrapper
-
-def parameterized(func_suffix, *args, **kwargs):
-    """
-    A decorator that can generate methods given a base method and some data.
-
-    **func_suffix** is used as a suffix for the new created method and must be
-    unique given a base method. if **func_suffix** countains characters that
-    are not allowed in normal python function name, these characters will be
-    replaced with "_".
-
-    This decorator can be used more than once on a single base method. The class
-    must have a metaclass of :class:`MetaParameterized`.
-
-    Example::
-
-      # This example will generate two methods:
-      #
-      # - MyTestCase.test_it_1
-      # - MyTestCase.test_it_2
-      #
-      class MyTestCase(MarionetteTestCase):
-          @parameterized("1", 5, named='name')
-          @parameterized("2", 6, named='name2')
-          def test_it(self, value, named=None):
-              print value, named
-
-    :param func_suffix: will be used as a suffix for the new method
-    :param \*args: arguments to pass to the new method
-    :param \*\*kwargs: named arguments to pass to the new method
-    """
-    def wrapped(func):
-        if not hasattr(func, 'metaparameters'):
-            func.metaparameters = []
-        func.metaparameters.append((func_suffix, args, kwargs))
-        return func
-    return wrapped
-
-def with_parameters(parameters):
-    """
-    A decorator that can generate methods given a base method and some data.
-    Acts like :func:`parameterized`, but define all methods in one call.
-
-    Example::
-
-      # This example will generate two methods:
-      #
-      # - MyTestCase.test_it_1
-      # - MyTestCase.test_it_2
-      #
-
-      DATA = [("1", [5], {'named':'name'}), ("2", [6], {'named':'name2'})]
-
-      class MyTestCase(MarionetteTestCase):
-          @with_parameters(DATA)
-          def test_it(self, value, named=None):
-              print value, named
-
-    :param parameters: list of tuples (**func_suffix**, **args**, **kwargs**)
-                       defining parameters like in :func:`todo`.
-    """
-    def wrapped(func):
-        func.metaparameters = parameters
-        return func
-    return wrapped
-
-def wraps_parameterized(func, func_suffix, args, kwargs):
-    """Internal: for MetaParameterized"""
-    def wrapper(self):
-        return func(self, *args, **kwargs)
-    wrapper.__name__ = func.__name__ + '_' + str(func_suffix)
-    wrapper.__doc__ = '[%s] %s' % (func_suffix, func.__doc__)
-    return wrapper
-
-class MetaParameterized(type):
-    """
-    A metaclass that allow a class to use decorators like :func:`parameterized`
-    or :func:`with_parameters` to generate new methods.
-    """
-    RE_ESCAPE_BAD_CHARS = re.compile(r'[\.\(\) -/]')
-    def __new__(cls, name, bases, attrs):
-        for k, v in attrs.items():
-            if callable(v) and hasattr(v, 'metaparameters'):
-                for func_suffix, args, kwargs in v.metaparameters:
-                    func_suffix = cls.RE_ESCAPE_BAD_CHARS.sub('_', func_suffix)
-                    wrapper = wraps_parameterized(v, func_suffix, args, kwargs)
-                    if wrapper.__name__ in attrs:
-                        raise KeyError("%s is already a defined method on %s" %
-                                        (wrapper.__name__, name))
-                    attrs[wrapper.__name__] = wrapper
-                del attrs[k]
-
-        return type.__new__(cls, name, bases, attrs)
-
-class JSTest:
-    head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
-    context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
-    timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
-    inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
-
-class CommonTestCase(unittest.TestCase):
+class Common2TestCase(unittest.TestCase):
 
     __metaclass__ = MetaParameterized
     match_re = None
     failureException = AssertionError
     pydebugger = None
 
     def __init__(self, methodName, **kwargs):
         unittest.TestCase.__init__(self, methodName)
         self.loglines = []
         self.duration = 0
-        self.start_time = 0
         self.expected = kwargs.pop('expected', 'pass')
         self.logger = get_default_logger()
+        self.profile = FirefoxProfile()
+        self.binary = kwargs.pop('binary', None)
 
     def _enter_pm(self):
         if self.pydebugger:
             self.pydebugger.post_mortem(sys.exc_info()[2])
 
     def _addSkip(self, result, reason):
         addSkip = getattr(result, 'addSkip', None)
         if addSkip is not None:
@@ -408,17 +194,17 @@ class CommonTestCase(unittest.TestCase):
         using cls.match_re.
         """
         if not cls.match_re:
             return False
         m = cls.match_re.match(filename)
         return m is not None
 
     @classmethod
-    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars):
+    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, testvars):
         """
         Adds all the tests in the specified file to the specified suite.
         """
         raise NotImplementedError
 
     @property
     def test_name(self):
         if hasattr(self, 'jsFile'):
@@ -430,60 +216,31 @@ class CommonTestCase(unittest.TestCase):
 
     def id(self):
         # TBPL starring requires that the "test name" field of a failure message
         # not differ over time. The test name to be used is passed to
         # mozlog via the test id, so this is overriden to maintain
         # consistency.
         return self.test_name
 
-    def set_up_test_page(self, emulator, url="test.html", permissions=None):
-        emulator.set_context("content")
-        url = emulator.absolute_url(url)
-        emulator.navigate(url)
-
-        if not permissions:
-            return
+    def setUp(self):
+        self.start_time = time.time()
+        self.marionette = Marionette(bin=self.binary, profile=self.profile); #AR
 
-        emulator.set_context("chrome")
-        emulator.execute_script("""
-Components.utils.import("resource://gre/modules/Services.jsm");
-let [url, permissions] = arguments;
-let uri = Services.io.newURI(url, null, null);
-permissions.forEach(function (perm) {
-    Services.perms.add(uri, "sms", Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
-});
-        """, [url, permissions])
-        emulator.set_context("content")
-
-    def setUp(self):
-        # Convert the marionette weakref to an object, just for the
-        # duration of the test; this is deleted in tearDown() to prevent
-        # a persistent circular reference which in turn would prevent
-        # proper garbage collection.
-        self.start_time = time.time()
-        self.marionette = self._marionette_weakref()
         if self.marionette.session is None:
             self.marionette.start_session()
         if self.marionette.timeout is not None:
             self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, self.marionette.timeout)
             self.marionette.timeouts(self.marionette.TIMEOUT_SCRIPT, self.marionette.timeout)
             self.marionette.timeouts(self.marionette.TIMEOUT_PAGE, self.marionette.timeout)
         else:
             self.marionette.timeouts(self.marionette.TIMEOUT_PAGE, 30000)
 
-        if hasattr(self, 'test_container') and self.test_container:
-            self.switch_into_test_container()
-        elif hasattr(self, 'test_container') and self.test_container is False:
-            if self.marionette.session_capabilities.has_key('b2g') \
-            and self.marionette.session_capabilities['b2g'] == True:
-                self.close_test_container()
-
     def tearDown(self):
-        pass
+        self.marionette.cleanup()
 
     def cleanTest(self):
         self._deleteSession()
 
     def _deleteSession(self):
         if hasattr(self, 'start_time'):
             self.duration = time.time() - self.start_time
         if hasattr(self.marionette, 'session'):
@@ -498,68 +255,16 @@ permissions.forEach(function (perm) {
                     # Gecko has crashed?
                     self.marionette.session = None
                     try:
                         self.marionette.client.close()
                     except socket.error:
                         pass
         self.marionette = None
 
-    def switch_into_test_container(self):
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
-
-        frame = Wait(self.marionette, timeout=10, interval=0.2).until(element_present(
-            'css selector',
-            'iframe[src*="app://test-container.gaiamobile.org/index.html"]'
-        ))
-
-        self.marionette.switch_to_frame(frame)
-
-    def close_test_container(self):
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
-
-        result = self.marionette.execute_async_script("""
-if((navigator.mozSettings == undefined) || (navigator.mozSettings == null) || (navigator.mozApps == undefined) || (navigator.mozApps == null)) {
-    marionetteScriptFinished(false);
-    return;
-}
-let setReq = navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
-setReq.onsuccess = function() {
-    let appsReq = navigator.mozApps.mgmt.getAll();
-    appsReq.onsuccess = function() {
-        let apps = appsReq.result;
-        for (let i = 0; i < apps.length; i++) {
-            let app = apps[i];
-            if (app.manifest.name === 'Test Container') {
-                window.wrappedJSObject.Service.request('AppWindowManager:kill', app.origin).then(function() {
-                    marionetteScriptFinished(true);
-                }).catch(function() {
-                    marionetteScriptFinished(false);
-                });
-                return;
-            }
-        }
-        marionetteScriptFinished(false);
-    }
-    appsReq.onerror = function() {
-        marionetteScriptFinished(false);
-    }
-}
-setReq.onerror = function() {
-    marionetteScriptFinished(false);
-}""", script_timeout=60000)
-
-        if not result:
-            raise Exception('Failed to close Test Container app')
-
-        Wait(self.marionette, timeout=10, interval=0.2).until(element_not_present(
-            'css selector',
-            'iframe[src*="app://test-container.gaiamobile.org/index.html"]'
-        ))
-
     def setup_SpecialPowers_observer(self):
         self.marionette.set_context("chrome")
         self.marionette.execute_script("""
             let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
             Components.utils.import("resource://gre/modules/Preferences.jsm");
             Preferences.set(SECURITY_PREF, true);
 
             if (!testUtils.hasOwnProperty("specialPowersObserver")) {
@@ -687,33 +392,30 @@ setReq.onerror = function() {
                 pass
             else:
                 self.loglines = marionette.get_logs()
                 raise
         self.marionette.test_name = original_test_name
 
 
 
-class MarionetteTestCase(CommonTestCase):
+class Marionette2TestCase(Common2TestCase):
 
     match_re = re.compile(r"test_(.*)\.py$")
 
-    def __init__(self, marionette_weakref, methodName='runTest',
+    def __init__(self, methodName='runTest',
                  filepath='', **kwargs):
-        self._marionette_weakref = marionette_weakref
         self.marionette = None
-        self.extra_emulator_index = -1
         self.methodName = methodName
         self.filepath = filepath
         self.testvars = kwargs.pop('testvars', None)
-        self.test_container = kwargs.pop('test_container', None)
-        CommonTestCase.__init__(self, methodName, **kwargs)
+        Common2TestCase.__init__(self, methodName, **kwargs)
 
     @classmethod
-    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
+    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, testvars, **kwargs):
         # since we use imp.load_source to load test modules, if a module
         # is loaded with the same name as another one the module would just be
         # reloaded.
         #
         # We may end up by finding too many test in a module then since
         # reload() only update the module dict (so old keys are still there!)
         # see https://docs.python.org/2/library/functions.html#reload
         #
@@ -726,94 +428,54 @@ class MarionetteTestCase(CommonTestCase)
         test_mod = imp.load_source(mod_name, filepath)
 
         for name in dir(test_mod):
             obj = getattr(test_mod, name)
             if (isinstance(obj, (type, types.ClassType)) and
                 issubclass(obj, unittest.TestCase)):
                 testnames = testloader.getTestCaseNames(obj)
                 for testname in testnames:
-                    suite.addTest(obj(weakref.ref(marionette),
-                                  methodName=testname,
+                    suite.addTest(obj(methodName=testname,
                                   filepath=filepath,
                                   testvars=testvars,
                                   **kwargs))
 
     def setUp(self):
-        CommonTestCase.setUp(self)
-        self.marionette.test_name = self.test_name
-        self.marionette.execute_script("log('TEST-START: %s:%s')" %
-                                       (self.filepath.replace('\\', '\\\\'), self.methodName))
+        Common2TestCase.setUp(self)
 
     def tearDown(self):
-        if not self.marionette.check_for_crash():
-            try:
-                self.marionette.clear_imported_scripts()
-                self.marionette.execute_script("log('TEST-END: %s:%s')" %
-                                               (self.filepath.replace('\\', '\\\\'),
-                                                self.methodName))
-                self.marionette.test_name = None
-            except (MarionetteException, IOError):
-                # We have tried to log the test end when there is no listener
-                # object that we can access
-                pass
-
-        CommonTestCase.tearDown(self)
-
-    def get_new_emulator(self):
-        self.extra_emulator_index += 1
-        if len(self.marionette.extra_emulators) == self.extra_emulator_index:
-            qemu  = Marionette(emulator=self.marionette.emulator.arch,
-                               emulatorBinary=self.marionette.emulator.binary,
-                               homedir=self.marionette.homedir,
-                               baseurl=self.marionette.baseurl,
-                               noWindow=self.marionette.noWindow,
-                               gecko_path=self.marionette.gecko_path)
-            qemu.start_session()
-            self.marionette.extra_emulators.append(qemu)
-        else:
-            qemu = self.marionette.extra_emulators[self.extra_emulator_index]
-        return qemu
+        Common2TestCase.tearDown(self)
 
     def wait_for_condition(self, method, timeout=30):
         timeout = float(timeout) + time.time()
         while time.time() < timeout:
             value = method(self.marionette)
             if value:
                 return value
             time.sleep(0.5)
         else:
             raise TimeoutException("wait_for_condition timed out")
 
-class MarionetteJSTestCase(CommonTestCase):
+class Marionette2JSTestCase(Common2TestCase):
 
     match_re = re.compile(r"test_(.*)\.js$")
 
-    def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs):
+    def __init__(self, methodName='runTest', jsFile=None, **kwargs):
         assert(jsFile)
         self.jsFile = jsFile
-        self._marionette_weakref = marionette_weakref
         self.marionette = None
-        self.test_container = kwargs.pop('test_container', None)
-        CommonTestCase.__init__(self, methodName)
+        Common2TestCase.__init__(self, methodName)
 
     @classmethod
-    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
-        suite.addTest(cls(weakref.ref(marionette), jsFile=filepath, **kwargs))
+    def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, testvars, **kwargs):
+        suite.addTest(cls(jsFile=filepath, **kwargs))
 
     def runTest(self):
-        if self.marionette.session is None:
-            self.marionette.start_session()
-        self.marionette.execute_script("log('TEST-START: %s');" % self.jsFile.replace('\\', '\\\\'))
-
         self.run_js_test(self.jsFile)
 
-        self.marionette.execute_script("log('TEST-END: %s');" % self.jsFile.replace('\\', '\\\\'))
-        self.marionette.test_name = None
-
     def get_test_class_name(self):
         # returns a dot separated folders as class name
         dirname = os.path.dirname(self.jsFile).replace('\\', '/')
         if dirname.startswith('/'):
             dirname = dirname[1:]
         return '.'.join(dirname.split('/'))
 
     def get_test_method_name(self):
--- a/testing/marionette/harness/marionette/runner/__init__.py
+++ b/testing/marionette/harness/marionette/runner/__init__.py
@@ -10,16 +10,21 @@ from .base import (
     MarionetteTest,
     MarionetteTestResult,
     MarionetteTextTestRunner,
     TestManifest,
     TestResult,
     TestResultCollection,
 )
 
+from .base2 import (
+    BaseMarionette2Arguments,
+    BaseMarionette2TestRunner,
+)
+
 from .mixins import (
     B2GTestCaseMixin,
     B2GTestResultMixin,
     EnduranceArguments,
     EnduranceTestCaseMixin,
     HTMLReportingArguments,
     HTMLReportingTestResultMixin,
     HTMLReportingTestRunnerMixin,
--- a/testing/marionette/harness/marionette/runner/base2.py
+++ b/testing/marionette/harness/marionette/runner/base2.py
@@ -12,61 +12,51 @@ import random
 import socket
 import sys
 import time
 import traceback
 import unittest
 import warnings
 import mozprofile
 
-
 from manifestparser import TestManifest
 from manifestparser.filters import tags
 from marionette_driver.marionette import Marionette
-from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm
 from mozlog import get_default_logger
 from moztest.adapters.unit import StructuredTestRunner, StructuredTestResult
 from moztest.results import TestResultCollection, TestResult, relevant_line
 import mozversion
 
 import httpd
 
 
 here = os.path.abspath(os.path.dirname(__file__))
 
 
-class MarionetteTest(TestResult):
+class Marionette2Test(TestResult):
 
     @property
     def test_name(self):
         if self.test_class is not None:
             return '%s.py %s.%s' % (self.test_class.split('.')[0],
                                     self.test_class,
                                     self.name)
         else:
             return self.name
 
-class MarionetteTestResult(StructuredTestResult, TestResultCollection):
+class Marionette2TestResult(StructuredTestResult, TestResultCollection):
 
-    resultClass = MarionetteTest
+    resultClass = Marionette2Test
 
     def __init__(self, *args, **kwargs):
-        self.marionette = kwargs.pop('marionette')
-        TestResultCollection.__init__(self, 'MarionetteTest')
+        TestResultCollection.__init__(self, 'Marionette2Test')
         self.passed = 0
         self.testsRun = 0
         self.result_modifiers = [] # used by mixins to modify the result
-        pid = kwargs.pop('b2g_pid')
         logcat_stdout = kwargs.pop('logcat_stdout')
-        if pid:
-            if B2GTestResultMixin not in self.__class__.__bases__:
-                bases = [b for b in self.__class__.__bases__]
-                bases.append(B2GTestResultMixin)
-                self.__class__.__bases__ = tuple(bases)
-            B2GTestResultMixin.__init__(self, b2g_pid=pid, logcat_stdout=logcat_stdout)
         StructuredTestResult.__init__(self, *args, **kwargs)
 
     @property
     def skipped(self):
         return [t for t in self if t.result == 'SKIPPED']
 
     @skipped.setter
     def skipped(self, value):
@@ -135,41 +125,41 @@ class MarionetteTestResult(StructuredTes
         t.finish(result_actual,
                  time_end=time.time() if test.start_time else 0,
                  reason=relevant_line(output),
                  output=output)
         self.append(t)
 
     def addError(self, test, err):
         self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='ERROR')
-        super(MarionetteTestResult, self).addError(test, err)
+        super(Marionette2TestResult, self).addError(test, err)
 
     def addFailure(self, test, err):
         self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='UNEXPECTED-FAIL')
-        super(MarionetteTestResult, self).addFailure(test, err)
+        super(Marionette2TestResult, self).addFailure(test, err)
 
     def addSuccess(self, test):
         self.passed += 1
         self.add_test_result(test, result_actual='PASS')
-        super(MarionetteTestResult, self).addSuccess(test)
+        super(Marionette2TestResult, self).addSuccess(test)
 
     def addExpectedFailure(self, test, err):
         """Called when an expected failure/error occured."""
         self.add_test_result(test, output=self._exc_info_to_string(err, test),
                              result_actual='KNOWN-FAIL')
-        super(MarionetteTestResult, self).addExpectedFailure(test, err)
+        super(Marionette2TestResult, self).addExpectedFailure(test, err)
 
     def addUnexpectedSuccess(self, test):
         """Called when a test was expected to fail, but succeed."""
         self.add_test_result(test, result_actual='UNEXPECTED-PASS')
-        super(MarionetteTestResult, self).addUnexpectedSuccess(test)
+        super(Marionette2TestResult, self).addUnexpectedSuccess(test)
 
     def addSkip(self, test, reason):
         self.add_test_result(test, output=reason, result_actual='SKIPPED')
-        super(MarionetteTestResult, self).addSkip(test, reason)
+        super(Marionette2TestResult, self).addSkip(test, reason)
 
     def getInfo(self, test):
         return test.test_name
 
     def getDescription(self, test):
         doc_first_line = test.shortDescription()
         if self.descriptions and doc_first_line:
             return '\n'.join((str(test), doc_first_line))
@@ -194,63 +184,50 @@ class MarionetteTestResult(StructuredTes
                     return
                 self.logger.info('START LOG:')
                 for line in testcase.loglines:
                     self.logger.info(' '.join(line).encode('ascii', 'replace'))
                 self.logger.info('END LOG:')
 
     def stopTest(self, *args, **kwargs):
         unittest._TextTestResult.stopTest(self, *args, **kwargs)
-        if self.marionette.check_for_crash():
-            # this tells unittest.TestSuite not to continue running tests
-            self.shouldStop = True
+        self.shouldStop = True # not sure here
 
 
-class MarionetteTextTestRunner(StructuredTestRunner):
+class Marionette2TextTestRunner(StructuredTestRunner):
 
-    resultclass = MarionetteTestResult
+    resultclass = Marionette2TestResult
 
     def __init__(self, **kwargs):
-        self.marionette = kwargs.pop('marionette')
-        self.capabilities = kwargs.pop('capabilities')
         self.pre_run_functions = []
-        self.b2g_pid = None
         self.logcat_stdout = kwargs.pop('logcat_stdout')
-
-        if self.capabilities["device"] != "desktop" and self.capabilities["browserName"] == "B2G":
-            def b2g_pre_run():
-                dm_type = os.environ.get('DM_TRANS', 'adb')
-                if dm_type == 'adb':
-                    self.b2g_pid = get_b2g_pid(get_dm(self.marionette))
-            self.pre_run_functions.append(b2g_pre_run)
+        self.binary = kwargs.pop('binary')
 
         StructuredTestRunner.__init__(self, **kwargs)
 
 
     def _makeResult(self):
         return self.resultclass(self.stream,
                                 self.descriptions,
                                 self.verbosity,
-                                marionette=self.marionette,
-                                b2g_pid=self.b2g_pid,
                                 logger=self.logger,
                                 logcat_stdout=self.logcat_stdout,
                                 result_callbacks=self.result_callbacks)
 
     def run(self, test):
         "Run the given test case or test suite."
         for pre_run_func in self.pre_run_functions:
             pre_run_func()
 
-        result = super(MarionetteTextTestRunner, self).run(test)
+        result = super(Marionette2TextTestRunner, self).run(test)
         result.printLogs(test)
         return result
 
 
-class BaseMarionetteArguments(ArgumentParser):
+class BaseMarionette2Arguments(ArgumentParser):
     socket_timeout_default = 360.0
 
     def __init__(self, **kwargs):
         ArgumentParser.__init__(self, **kwargs)
 
         def dir_path(path):
             path = os.path.abspath(os.path.expanduser(path))
             if not os.access(path, os.F_OK):
@@ -261,67 +238,24 @@ class BaseMarionetteArguments(ArgumentPa
         self.add_argument('tests',
                           nargs='*',
                           default=[],
                           help='Tests to run.')
         self.add_argument('-v', '--verbose',
                         action='count',
                         help='Increase verbosity to include debug messages with -v, '
                             'and trace messages with -vv.')
-        self.add_argument('--emulator',
-                        choices=['x86', 'arm'],
-                        help='if no --address is given, then the harness will launch a B2G emulator on which to run '
-                             'emulator tests. if --address is given, then the harness assumes you are running an '
-                             'emulator already, and will run the emulator tests using that emulator. you need to '
-                             'specify which architecture to emulate for both cases')
-        self.add_argument('--emulator-binary',
-                        help='launch a specific emulator binary rather than launching from the B2G built emulator')
-        self.add_argument('--emulator-img',
-                        help='use a specific image file instead of a fresh one')
-        self.add_argument('--emulator-res',
-                        help='set a custom resolution for the emulator'
-                             'Example: "480x800"')
-        self.add_argument('--sdcard',
-                        help='size of sdcard to create for the emulator')
-        self.add_argument('--no-window',
-                        action='store_true',
-                        default=False,
-                        help='when Marionette launches an emulator, start it with the -no-window argument')
         self.add_argument('--logcat-dir',
                         dest='logdir',
                         help='directory to store logcat dump files',
                         type=dir_path)
         self.add_argument('--logcat-stdout',
                         action='store_true',
                         default=False,
                         help='dump adb logcat to stdout')
-        self.add_argument('--address',
-                        help='host:port of running Gecko instance to connect to')
-        self.add_argument('--device',
-                        dest='device_serial',
-                        help='serial ID of a device to use for adb / fastboot')
-        self.add_argument('--adb-host',
-                        help='host to use for adb connection')
-        self.add_argument('--adb-port',
-                        help='port to use for adb connection')
-        self.add_argument('--type',
-                        help="the type of test to run, can be a combination of values defined in the manifest file; "
-                             "individual values are combined with '+' or '-' characters. for example: 'browser+b2g' "
-                             "means the set of tests which are compatible with both browser and b2g; 'b2g-qemu' means "
-                             "the set of tests which are compatible with b2g but do not require an emulator. this "
-                             "argument is only used when loading tests from manifest files")
-        self.add_argument('--homedir',
-                        help='home directory of emulator files')
-        self.add_argument('--app',
-                        help='application to use')
-        self.add_argument('--app-arg',
-                        dest='app_args',
-                        action='append',
-                        default=[],
-                        help='specify a command line argument to be passed onto the application')
         self.add_argument('--binary',
                         help='gecko executable to launch before running the test')
         self.add_argument('--profile',
                         help='profile to use when launching the gecko process. if not passed, then a profile will be '
                              'constructed and used',
                         type=dir_path)
         self.add_argument('--pref',
                         action='append',
@@ -339,19 +273,16 @@ class BaseMarionetteArguments(ArgumentPa
                         help="addon to install; repeat for multiple addons.")
         self.add_argument('--repeat',
                         type=int,
                         default=0,
                         help='number of times to repeat the test(s)')
         self.add_argument('--testvars',
                         action='append',
                         help='path to a json file with any test data required')
-        self.add_argument('--tree',
-                        default='b2g',
-                        help='the tree that the revision parameter refers to')
         self.add_argument('--symbols-path',
                         help='absolute path to directory containing breakpad symbols, or the url of a zip file containing symbols')
         self.add_argument('--timeout',
                         type=int,
                         help='if a --timeout value is given, it will set the default page load timeout, search timeout and script timeout to the given value. If not passed in, it will use the default values of 30000ms for page load, 0ms for search timeout and 10000ms for script timeout')
         self.add_argument('--startup-timeout',
                         type=int,
                         default=60,
@@ -365,18 +296,16 @@ class BaseMarionetteArguments(ArgumentPa
                         default=random.randint(0, sys.maxint),
                         help='Use given seed to shuffle tests')
         self.add_argument('--total-chunks',
                         type=int,
                         help='how many chunks to split the tests up into')
         self.add_argument('--this-chunk',
                         type=int,
                         help='which chunk to run')
-        self.add_argument('--sources',
-                        help='path to sources.xml (Firefox OS only)')
         self.add_argument('--server-root',
                         help='url to a webserver or path to a document root from which content '
                         'resources are served (default: {}).'.format(os.path.join(
                             os.path.dirname(here), 'www')))
         self.add_argument('--gecko-log',
                         help="Define the path to store log file. If the path is"
                              " a directory, the real log file will be created"
                              " given the format gecko-(timestamp).log. If it is"
@@ -452,36 +381,20 @@ class BaseMarionetteArguments(ArgumentPa
 
         return dict(prefs())
 
     def verify_usage(self, args):
         if not args.tests:
             print 'must specify one or more test files, manifests, or directories'
             sys.exit(1)
 
-        if not args.emulator and not args.address and not args.binary:
-            print 'must specify --binary, --emulator or --address'
-            sys.exit(1)
-
-        if args.emulator and args.binary:
-            print 'can\'t specify both --emulator and --binary'
+        if not args.binary:
+            print 'must specify --binary'
             sys.exit(1)
 
-        # check for valid resolution string, strip whitespaces
-        try:
-            if args.emulator_res:
-                dims = args.emulator_res.split('x')
-                assert len(dims) == 2
-                width = str(int(dims[0]))
-                height = str(int(dims[1]))
-                args.emulator_res = 'x'.join([width, height])
-        except:
-            raise ValueError('Invalid emulator resolution format. '
-                             'Should be like "480x800".')
-
         if args.total_chunks is not None and args.this_chunk is None:
             self.error('You must specify which chunk to run.')
 
         if args.this_chunk is not None and args.total_chunks is None:
             self.error('You must specify how many chunks to split the tests into.')
 
         if args.total_chunks is not None:
             if not 1 <= args.total_chunks:
@@ -503,83 +416,67 @@ class BaseMarionetteArguments(ArgumentPa
 
         for container in self.argument_containers:
             if hasattr(container, 'verify_usage_handler'):
                 container.verify_usage_handler(args)
 
         return args
 
 
-class BaseMarionetteTestRunner(object):
+class BaseMarionette2TestRunner(object):
 
-    textrunnerclass = MarionetteTextTestRunner
+    textrunnerclass = Marionette2TextTestRunner
     driverclass = Marionette
 
-    def __init__(self, address=None, emulator=None, emulator_binary=None,
-                 emulator_img=None, emulator_res='480x800', homedir=None,
-                 app=None, app_args=None, binary=None, profile=None,
-                 logger=None, no_window=False, logdir=None, logcat_stdout=False,
-                 repeat=0, testvars=None, tree=None, type=None,
-                 device_serial=None, symbols_path=None, timeout=None,
+    def __init__(self, address=None,
+                 homedir=None,
+                 binary=None,
+                 logger=None, logdir=None, logcat_stdout=False,
+                 repeat=0, testvars=None, type=None,
+                 symbols_path=None, timeout=None,
                  shuffle=False, shuffle_seed=random.randint(0, sys.maxint),
-                 sdcard=None, this_chunk=1, total_chunks=1, sources=None,
+                 this_chunk=1, total_chunks=1, sources=None,
                  server_root=None, gecko_log=None, result_callbacks=None,
-                 adb_host=None, adb_port=None, prefs=None, test_tags=None,
-                 socket_timeout=BaseMarionetteArguments.socket_timeout_default,
+                 prefs=None, test_tags=None,
+                 socket_timeout=BaseMarionette2Arguments.socket_timeout_default,
                  startup_timeout=None, addons=None, workspace=None,
                  verbose=0, **kwargs):
         self.address = address
-        self.emulator = emulator
-        self.emulator_binary = emulator_binary
-        self.emulator_img = emulator_img
-        self.emulator_res = emulator_res
         self.homedir = homedir
-        self.app = app
-        self.app_args = app_args or []
         self.bin = binary
-        self.profile = profile
         self.addons = addons
         self.logger = logger
-        self.no_window = no_window
         self.httpd = None
-        self.marionette = None
         self.logdir = logdir
         self.logcat_stdout = logcat_stdout
         self.repeat = repeat
         self.test_kwargs = kwargs
-        self.tree = tree
         self.type = type
-        self.device_serial = device_serial
         self.symbols_path = symbols_path
         self.timeout = timeout
         self.socket_timeout = socket_timeout
-        self._device = None
-        self._capabilities = None
-        self._appName = None
         self.shuffle = shuffle
         self.shuffle_seed = shuffle_seed
-        self.sdcard = sdcard
         self.sources = sources
         self.server_root = server_root
         self.this_chunk = this_chunk
         self.total_chunks = total_chunks
         self.mixin_run_tests = []
         self.manifest_skipped_tests = []
         self.tests = []
         self.result_callbacks = result_callbacks if result_callbacks is not None else []
-        self._adb_host = adb_host
-        self._adb_port = adb_port
         self.prefs = prefs or {}
         self.test_tags = test_tags
         self.startup_timeout = startup_timeout
         self.workspace = workspace
         # If no workspace is set, default location for logcat and gecko.log is .
         # and default location for profile is TMP
         self.workspace_path = workspace or os.getcwd()
         self.verbose = verbose
+        self.base_url = None
 
         def gather_debug(test, status):
             rv = {}
             marionette = test._marionette_weakref()
 
             # In the event we're gathering debug without starting a session, skip marionette commands
             if marionette.session is not None:
                 try:
@@ -621,252 +518,75 @@ class BaseMarionetteTestRunner(object):
         # set up test handlers
         self.test_handlers = []
 
         self.reset_test_stats()
 
         self.logger.info('Using workspace for temporary data: '
                          '"{}"'.format(self.workspace_path))
 
-        if self.emulator and not self.logdir:
-            self.logdir = os.path.join(self.workspace_path or '', 'logcat')
         if self.logdir and not os.access(self.logdir, os.F_OK):
                 os.mkdir(self.logdir)
 
         if not gecko_log:
             self.gecko_log = os.path.join(self.workspace_path or '', 'gecko.log')
         else:
             self.gecko_log = gecko_log
 
         self.results = []
 
     @property
-    def capabilities(self):
-        if self._capabilities:
-            return self._capabilities
-
-        self.marionette.start_session()
-        self._capabilities = self.marionette.session_capabilities
-        self.marionette.delete_session()
-        return self._capabilities
-
-    @property
-    def device(self):
-        if self._device:
-            return self._device
-
-        self._device = self.capabilities.get('device')
-        return self._device
-
-    @property
-    def appName(self):
-        if self._appName:
-            return self._appName
-
-        self._appName = self.capabilities.get('browserName')
-        return self._appName
-
-    @property
     def bin(self):
         return self._bin
 
     @bin.setter
     def bin(self, path):
         """
         Set binary and reset parts of runner accordingly
 
         Intended use: to change binary between calls to run_tests
         """
         self._bin = path
         self.tests = []
-        if hasattr(self, 'marionette') and self.marionette:
-            self.marionette.cleanup()
-            if self.marionette.instance:
-                self.marionette.instance = None
-        self.marionette = None
 
     def reset_test_stats(self):
         self.passed = 0
         self.failed = 0
         self.unexpected_successes = 0
         self.todo = 0
         self.skipped = 0
         self.failures = []
 
-    def _build_kwargs(self):
-        kwargs = {
-            'device_serial': self.device_serial,
-            'symbols_path': self.symbols_path,
-            'timeout': self.timeout,
-            'socket_timeout': self.socket_timeout,
-            'adb_host': self._adb_host,
-            'adb_port': self._adb_port,
-            'prefs': self.prefs,
-            'startup_timeout': self.startup_timeout,
-            'verbose': self.verbose,
-        }
-        if self.bin:
-            kwargs.update({
-                'host': 'localhost',
-                'port': 2828,
-                'app': self.app,
-                'app_args': self.app_args,
-                'bin': self.bin,
-                'profile': self.profile,
-                'addons': self.addons,
-                'gecko_log': self.gecko_log,
-            })
-
-        if self.emulator:
-            kwargs.update({
-                'homedir': self.homedir,
-                'logdir': self.logdir,
-            })
-
-        if self.address:
-            host, port = self.address.split(':')
-            kwargs.update({
-                'host': host,
-                'port': int(port),
-            })
-            if self.emulator:
-                kwargs['connectToRunningEmulator'] = True
-
-            if not self.bin:
-                try:
-                    #establish a socket connection so we can vertify the data come back
-                    connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
-                    connection.connect((host,int(port)))
-                    connection.close()
-                except Exception, e:
-                    raise Exception("Connection attempt to %s:%s failed with error: %s" %(host,port,e))
-        elif self.emulator:
-            kwargs.update({
-                'emulator': self.emulator,
-                'emulator_binary': self.emulator_binary,
-                'emulator_img': self.emulator_img,
-                'emulator_res': self.emulator_res,
-                'no_window': self.no_window,
-                'sdcard': self.sdcard,
-            })
-        if self.workspace:
-            kwargs['workspace'] = self.workspace_path
-        return kwargs
-
-    def start_marionette(self):
-        self.marionette = self.driverclass(**self._build_kwargs())
-
-    def launch_test_container(self):
-        if self.marionette.session is None:
-            self.marionette.start_session()
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
-
-        result = self.marionette.execute_async_script("""
-if((navigator.mozSettings == undefined) || (navigator.mozSettings == null) || (navigator.mozApps == undefined) || (navigator.mozApps == null)) {
-    marionetteScriptFinished(false);
-    return;
-}
-let setReq = navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
-setReq.onsuccess = function() {
-    let appName = 'Test Container';
-    let activeApp = window.wrappedJSObject.Service.currentApp;
-
-    // if the Test Container is already open then do nothing
-    if(activeApp.name === appName){
-        marionetteScriptFinished(true);
-    }
-
-    let appsReq = navigator.mozApps.mgmt.getAll();
-    appsReq.onsuccess = function() {
-        let apps = appsReq.result;
-        for (let i = 0; i < apps.length; i++) {
-            let app = apps[i];
-            if (app.manifest.name === appName) {
-                app.launch();
-                window.addEventListener('appopen', function apploadtime(){
-                    window.removeEventListener('appopen', apploadtime);
-                    marionetteScriptFinished(true);
-                });
-                return;
-            }
-        }
-        marionetteScriptFinished(false);
-    }
-    appsReq.onerror = function() {
-        marionetteScriptFinished(false);
-    }
-}
-setReq.onerror = function() {
-    marionetteScriptFinished(false);
-}""", script_timeout=60000)
-
-        if not result:
-            raise Exception("Could not launch test container app")
-
     def run_tests(self, tests):
         self.reset_test_stats()
         self.start_time = time.time()
 
-        need_external_ip = True
-        if not self.marionette:
-            self.start_marionette()
-            # Retrieve capabilities for later use
-            if not self._capabilities:
-                self.capabilities
-            # if we're working against a desktop version, we usually don't need
-            # an external ip
-            if self._capabilities['device'] == "desktop":
-                need_external_ip = False
-        self.logger.info('Initial Profile Destination is '
-                         '"{}"'.format(self.marionette.profile_path))
-
-        # Gaia sets server_root and that means we shouldn't spin up our own httpd
         if not self.httpd:
             if self.server_root is None or os.path.isdir(self.server_root):
                 self.logger.info("starting httpd")
-                self.start_httpd(need_external_ip)
-                self.marionette.baseurl = self.httpd.get_url()
-                self.logger.info("running httpd on %s" % self.marionette.baseurl)
+                self.httpd = self.create_httpd(False) # we only support desktop for now
+                self.base_url = self.httpd.get_url()
+                self.logger.info("running httpd on %s" % self.base_url)
             else:
-                self.marionette.baseurl = self.server_root
-                self.logger.info("using remote content from %s" % self.marionette.baseurl)
-
-        device_info = None
-        if self.capabilities['device'] != 'desktop' and self.capabilities['browserName'] == 'B2G':
-            dm = get_dm(self.marionette)
-            device_info = dm.getInfo()
-            # Add Android version (SDK level) to mozinfo so that manifest entries
-            # can be conditional on android_version.
-            androidVersion = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
-            self.logger.info(
-                "Android sdk version '%s'; will use this to filter manifests" % androidVersion)
-            mozinfo.info['android_version'] = androidVersion
+                self.base_url = self.server_root
+                self.logger.info("using remote content from %s" % self.base_url)
 
         for test in tests:
             self.add_test(test)
 
         # ensure we have only tests files with names starting with 'test_'
         invalid_tests = \
             [t['filepath'] for t in self.tests
              if not os.path.basename(t['filepath']).startswith('test_')]
         if invalid_tests:
             raise Exception("Tests file names must starts with 'test_'."
                             " Invalid test names:\n  %s"
                             % '\n  '.join(invalid_tests))
 
-        version_info = mozversion.get_version(binary=self.bin,
-                                              sources=self.sources,
-                                              dm_type=os.environ.get('DM_TRANS', 'adb'),
-                                              device_serial=self.device_serial,
-                                              adb_host=self.marionette.adb_host,
-                                              adb_port=self.marionette.adb_port)
-
-        self.logger.suite_start(self.tests,
-                                version_info=version_info,
-                                device_info=device_info)
+        self.logger.suite_start(self.tests)
 
         for test in self.manifest_skipped_tests:
             name = os.path.basename(test['path'])
             self.logger.test_start(name)
             self.logger.test_end(name,
                                  'SKIP',
                                  message=test['disabled'])
             self.todo += 1
@@ -908,52 +628,36 @@ setReq.onerror = function() {
         else:
             self.logger.info('todo: %d (skipped: %d)' % (self.todo, self.skipped))
 
         if self.failed > 0:
             self.logger.info('\nFAILED TESTS\n-------')
             for failed_test in self.failures:
                 self.logger.info('%s' % failed_test[0])
 
-        try:
-            self.marionette.check_for_crash()
-        except:
-            traceback.print_exc()
-
         self.end_time = time.time()
         self.elapsedtime = self.end_time - self.start_time
 
-        if self.marionette.instance:
-            self.marionette.instance.close()
-            self.marionette.instance = None
-
-        self.marionette.cleanup()
-
         for run_tests in self.mixin_run_tests:
             run_tests(tests)
         if self.shuffle:
             self.logger.info("Using seed where seed is:%d" % self.shuffle_seed)
 
         self.logger.suite_end()
 
-    def start_httpd(self, need_external_ip):
-        warnings.warn("start_httpd has been deprecated in favour of create_httpd",
-            DeprecationWarning)
-        self.httpd = self.create_httpd(need_external_ip)
-
     def create_httpd(self, need_external_ip):
         host = "127.0.0.1"
         if need_external_ip:
             host = moznetwork.get_ip()
         root = self.server_root or os.path.join(os.path.dirname(here), "www")
         rv = httpd.FixtureServer(root, host=host)
         rv.start()
         return rv
 
-    def add_test(self, test, expected='pass', test_container=None):
+    def add_test(self, test, expected='pass'):
         filepath = os.path.abspath(test)
 
         if os.path.isdir(filepath):
             for root, dirs, files in os.walk(filepath):
                 for filename in files:
                     if (filename.startswith('test_') and
                         (filename.endswith('.py') or filename.endswith('.js'))):
                         filepath = os.path.join(root, filename)
@@ -966,32 +670,28 @@ setReq.onerror = function() {
             for atype in testtypes:
                 if atype.startswith('+'):
                     testargs.update({ atype[1:]: 'true' })
                 elif atype.startswith('-'):
                     testargs.update({ atype[1:]: 'false' })
                 else:
                     testargs.update({ atype: 'true' })
 
-        testarg_b2g = bool(testargs.get('b2g'))
-
         file_ext = os.path.splitext(os.path.split(filepath)[-1])[1]
 
         if file_ext == '.ini':
             manifest = TestManifest()
             manifest.read(filepath)
 
             filters = []
             if self.test_tags:
                 filters.append(tags(self.test_tags))
             manifest_tests = manifest.active_tests(exists=False,
                                                    disabled=True,
                                                    filters=filters,
-                                                   device=self.device,
-                                                   app=self.appName,
                                                    **mozinfo.info)
             if len(manifest_tests) == 0:
                 self.logger.error("no tests to run using specified "
                                   "combination of filters: {}".format(
                                        manifest.fmt_filters()))
 
             unfiltered_tests = []
             for test in manifest_tests:
@@ -1006,55 +706,44 @@ setReq.onerror = function() {
                     test.setdefault('disabled', 'filtered by type (%s)' % self.type)
                     self.manifest_skipped_tests.append(test)
 
             for i in target_tests:
                 if not os.path.exists(i["path"]):
                     raise IOError("test file: %s does not exist" % i["path"])
 
                 file_ext = os.path.splitext(os.path.split(i['path'])[-1])[-1]
-                test_container = None
-                if i.get('test_container') and testarg_b2g:
-                    if i.get('test_container') == "true":
-                        test_container = True
-                    elif i.get('test_container') == "false":
-                        test_container = False
-
-                self.add_test(i["path"], i["expected"], test_container)
+                self.add_test(i["path"], i["expected"])
             return
 
-        self.tests.append({'filepath': filepath, 'expected': expected, 'test_container': test_container})
+        self.tests.append({'filepath': filepath, 'expected': expected})
 
-    def run_test(self, filepath, expected, test_container):
+    def run_test(self, filepath, expected):
 
         testloader = unittest.TestLoader()
         suite = unittest.TestSuite()
+        self.test_kwargs['binary'] = self.bin
         self.test_kwargs['expected'] = expected
-        self.test_kwargs['test_container'] = test_container
+        self.test_kwargs['base_url'] = self.base_url
         mod_name = os.path.splitext(os.path.split(filepath)[-1])[0]
         for handler in self.test_handlers:
             if handler.match(os.path.basename(filepath)):
                 handler.add_tests_to_suite(mod_name,
                                            filepath,
                                            suite,
                                            testloader,
-                                           self.marionette,
                                            self.testvars,
                                            **self.test_kwargs)
                 break
 
         if suite.countTestCases():
             runner = self.textrunnerclass(logger=self.logger,
-                                          marionette=self.marionette,
-                                          capabilities=self.capabilities,
                                           logcat_stdout=self.logcat_stdout,
-                                          result_callbacks=self.result_callbacks)
-
-            if test_container:
-                self.launch_test_container()
+                                          result_callbacks=self.result_callbacks,
+                                          binary=self.bin)
 
             results = runner.run(suite)
             self.results.append(results)
 
             self.failed += len(results.failures) + len(results.errors)
             if hasattr(results, 'skipped'):
                 self.skipped += len(results.skipped)
                 self.todo += len(results.skipped)
@@ -1074,19 +763,17 @@ setReq.onerror = function() {
                 result.result_modifiers = []
 
     def run_test_set(self, tests):
         if self.shuffle:
             random.seed(self.shuffle_seed)
             random.shuffle(tests)
 
         for test in tests:
-            self.run_test(test['filepath'], test['expected'], test['test_container'])
-            if self.marionette.check_for_crash():
-                break
+            self.run_test(test['filepath'], test['expected'])
 
     def run_test_sets(self):
         if len(self.tests) < 1:
             raise Exception('There are no tests to run.')
         elif self.total_chunks > len(self.tests):
             raise ValueError('Total number of chunks must be between 1 and %d.' % len(self.tests))
         if self.total_chunks > 1:
             chunks = [[] for i in range(self.total_chunks)]
@@ -1101,12 +788,9 @@ setReq.onerror = function() {
             self.tests = chunks[self.this_chunk - 1]
 
         self.run_test_set(self.tests)
 
     def cleanup(self):
         if self.httpd:
             self.httpd.stop()
 
-        if self.marionette:
-            self.marionette.cleanup()
-
     __del__ = cleanup
--- a/testing/marionette/harness/marionette/runtests2.py
+++ b/testing/marionette/harness/marionette/runtests2.py
@@ -1,94 +1,94 @@
 # 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 sys
 
 from marionette import __version__
 from marionette_driver import __version__ as driver_version
-from marionette.marionette_test import MarionetteTestCase, MarionetteJSTestCase
+from marionette.marionette2_test import Marionette2TestCase, Marionette2JSTestCase
 from marionette.runner import (
-    BaseMarionetteTestRunner,
-    BaseMarionetteArguments,
-    BrowserMobProxyArguments,
+    BaseMarionette2TestRunner,
+    BaseMarionette2Arguments,
 )
 import mozlog
 
 
-class MarionetteTestRunner(BaseMarionetteTestRunner):
+class Marionette2TestRunner(BaseMarionette2TestRunner):
     def __init__(self, **kwargs):
-        BaseMarionetteTestRunner.__init__(self, **kwargs)
-        self.test_handlers = [MarionetteTestCase, MarionetteJSTestCase]
+        BaseMarionette2TestRunner.__init__(self, **kwargs)
+        self.test_handlers = [Marionette2TestCase, Marionette2JSTestCase]
 
 
-class MarionetteArguments(BaseMarionetteArguments):
+class Marionette2Arguments(BaseMarionette2Arguments):
     def __init__(self, **kwargs):
-        BaseMarionetteArguments.__init__(self, **kwargs)
-        self.register_argument_container(BrowserMobProxyArguments())
+        BaseMarionette2Arguments.__init__(self, **kwargs)
 
 
-class MarionetteHarness(object):
+class Marionette2Harness(object):
     def __init__(self,
-                 runner_class=MarionetteTestRunner,
-                 parser_class=MarionetteArguments,
+                 runner_class=Marionette2TestRunner,
+                 parser_class=Marionette2Arguments,
                  args=None):
         self._runner_class = runner_class
         self._parser_class = parser_class
         self.args = args or self.parse_args()
 
     def parse_args(self, logger_defaults=None):
         parser = self._parser_class(usage='%(prog)s [options] test_file_or_dir <test_file_or_dir> ...')
         parser.add_argument('--version', action='version',
             help="Show version information.",
             version="%(prog)s {version}"
-                    " (using marionette-driver: {driver_version}, ".format(
+                    " (using marionette-driver: {driver_version}, "
+                    "marionette-transport: {transport_version})".format(
                         version=__version__,
-                        driver_version=driver_version
+                        driver_version=driver_version,
+                        transport_version=transport_version
                     ))
         mozlog.commandline.add_logging_group(parser)
         args = parser.parse_args()
         parser.verify_usage(args)
 
         logger = mozlog.commandline.setup_logging(
             args.logger_name, args, logger_defaults or {"tbpl": sys.stdout})
 
         args.logger = logger
         return args
 
     def process_args(self):
         if self.args.pydebugger:
-            MarionetteTestCase.pydebugger = __import__(self.args.pydebugger)
+            Marionette2TestCase.pydebugger = __import__(self.args.pydebugger)
 
     def run(self):
         try:
             self.process_args()
             args_dict = vars(self.args)
             tests = args_dict.pop('tests')
             runner = self._runner_class(**args_dict)
             runner.run_tests(tests)
             return runner.failed
         except Exception:
             self.args.logger.error('Failure during test execution.',
                                    exc_info=True)
             raise
 
 
-def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
-        harness_class=MarionetteHarness, args=None):
+def cli(runner_class=Marionette2TestRunner, parser_class=Marionette2Arguments,
+        harness_class=Marionette2Harness, args=None):
     """
     Call the harness to parse args and run tests.
 
     The following exit codes are expected:
     - Test failures: 10
     - Harness/other failures: 1
     - Success: 0
     """
-    logger = mozlog.commandline.setup_logging('Marionette test runner', {})
+    logger = mozlog.commandline.setup_logging('Marionette2 test runner', {})
     try:
         failed = harness_class(runner_class, parser_class, args=args).run()
         if failed > 0:
             sys.exit(10)
     except Exception:
         logger.error('Failure during harness setup', exc_info=True)
         sys.exit(1)
     sys.exit(0)
--- a/testing/marionette/harness/marionette/tests2/test_marionette2.py
+++ b/testing/marionette/harness/marionette/tests2/test_marionette2.py
@@ -1,60 +1,23 @@
 # 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 itertools
 
 from marionette_driver import errors
-from marionette.marionette_test import MarionetteTestCase as TC
+from marionette.marionette2_test import Marionette2TestCase as TC
 
 
-class TestProtocol1Errors(TC):
+class TestHelloWorld(TC):
     def setUp(self):
         TC.setUp(self)
-        self.op = self.marionette.protocol
-        self.marionette.protocol = 1
 
     def tearDown(self):
-        self.marionette.protocol = self.op
-        TC.tearDown(self)
-
-    def test_malformed_packet(self):
-        for t in [{}, {"error": None}]:
-            with self.assertRaisesRegexp(errors.MarionetteException, "Malformed packet"):
-                self.marionette._handle_error(t)
-
-    def test_known_error_code(self):
-        with self.assertRaises(errors.NoSuchElementException):
-            self.marionette._handle_error(
-                {"error": {"status": errors.NoSuchElementException.code[0]}})
-
-    def test_known_error_status(self):
-        with self.assertRaises(errors.NoSuchElementException):
-            self.marionette._handle_error(
-                {"error": {"status": errors.NoSuchElementException.status}})
-
-    def test_unknown_error_code(self):
-        with self.assertRaises(errors.MarionetteException):
-            self.marionette._handle_error({"error": {"status": 123456}})
-
-    def test_unknown_error_status(self):
-        with self.assertRaises(errors.MarionetteException):
-            self.marionette._handle_error({"error": {"status": "barbera"}})
-
-
-class TestProtocol2Errors(TC):
-    def setUp(self):
-        TC.setUp(self)
-        self.op = self.marionette.protocol
-        self.marionette.protocol = 2
-
-    def tearDown(self):
-        self.marionette.protocol = self.op
         TC.tearDown(self)
 
     def test_malformed_packet(self):
         req = ["error", "message", "stacktrace"]
         ps = []
         for p in [p for i in range(0, len(req) + 1) for p in itertools.permutations(req, i)]:
             ps.append(dict((x, None) for x in p))
 
--- a/testing/marionette/harness/marionette/tests2/unit-tests.ini
+++ b/testing/marionette/harness/marionette/tests2/unit-tests.ini
@@ -1,164 +1,14 @@
 [DEFAULT]
 ; true if the test requires an emulator, otherwise false
 qemu = false
 
 ; true if the test is compatible with the browser, otherwise false
 browser = true
 
 ; true if the test is compatible with b2g, otherwise false
-b2g = true
+b2g = false
 
 ; true if the test should be skipped
 skip = false
 
-[test_marionette.py]
-[test_data_driven.py]
-[test_session.py]
-[test_capabilities.py]
-
-[test_accessibility.py]
-b2g = false
-
-[test_expectedfail.py]
-expected = fail
-[test_import_script.py]
-b2g = false
-[test_click.py]
-[test_click_chrome.py]
-b2g = false
-[test_selected.py]
-[test_selected_chrome.py]
-b2g = false
-[test_getattr.py]
-[test_getattr_chrome.py]
-b2g = false
-[test_elementsize.py]
-[test_position.py]
-[test_rendered_element.py]
-[test_chrome_element_css.py]
-b2g = false
-[test_elementState.py]
-[test_elementState_chrome.py]
-b2g = false
-[test_text.py]
-[test_text_chrome.py]
-disabled = "Bug 896046"
-
-[test_clearing.py]
-[test_typing.py]
-
-[test_log.py]
-[test_emulator.py]
-qemu = true
-
-[test_about_pages.py]
-b2g = false
-
-[test_execute_async_script.py]
-[test_execute_script.py]
-[test_simpletest_fail.js]
-[test_findelement.py]
-[test_findelement_chrome.py]
-b2g = false
-
-[test_navigation.py]
-
-[test_timeouts.py]
-
-[test_element_touch.py]
-b2g = true
-browser = false
-
-[test_gesture.py]
-disabled = "Bug 1060060"
-b2g = true
-browser = false
-
-[test_single_finger.py]
-disabled = "Bug 1060060"
-b2g = true
-browser = false
-[test_single_finger_desktop.py]
-b2g = false
-skip-if = os == "win" # Bug 1025040
-
-[test_multi_finger.py]
-disabled = "Bug 1060060"
-b2g = true
-browser = false
-
-[test_simpletest_pass.js]
-[test_simpletest_sanity.py]
-[test_simpletest_chrome.js]
-[test_simpletest_timeout.js]
-[test_anonymous_content.py]
-b2g = false
-[test_switch_frame.py]
-b2g = false
-skip-if = os == "win" # Bug 1078237
-[test_switch_frame_chrome.py]
-b2g = false
-[test_switch_remote_frame.py]
-b2g = false
-
-[test_pagesource.py]
-b2g = false
-
-[test_visibility.py]
-[test_window_switching.py]
-b2g = false
-[test_window_management.py]
-b2g = false
-[test_window_position.py]
-b2g = false
-[test_window_handles.py]
-b2g = false
-
-[test_screenshot.py]
-[test_cookies.py]
-b2g = false
-[test_window_title.py]
-[test_window_type.py]
-b2g = false
-[test_implicit_waits.py]
-[test_wait.py]
-[test_expected.py]
-[test_date_time_value.py]
-[test_getactiveframe_oop.py]
-disabled = "Bug 925688"
-b2g = false
-[test_chrome_async_finish.js]
-[test_screen_orientation.py]
-browser = false
-[test_errors.py]
-
-[test_execute_isolate.py]
-[test_click_scrolling.py]
-[test_profile_management.py]
-b2g = false
-[test_set_window_size.py]
-b2g = false
-skip-if = os == "linux" # Bug 1085717
-[test_with_using_context.py]
-
-[test_modal_dialogs.py]
-b2g = false
-[test_key_actions.py]
-[test_mouse_action.py]
-b2g = false
-[test_teardown_context_preserved.py]
-b2g = false
-[test_file_upload.py]
-b2g = false
-skip-if = os == "win" # http://bugs.python.org/issue14574
-
-[test_execute_sandboxes.py]
-[test_using_permissions.py]
-[test_using_prefs.py]
-
-[test_shadow_dom.py]
-
-[test_chrome.py]
-b2g = false
-
-[test_addons.py]
+[test_marionette2.py]
--- a/testing/marionette/mach_commands.py
+++ b/testing/marionette/mach_commands.py
@@ -118,8 +118,66 @@ class MachCommands(MachCommandBase):
         if 'test_objects' in kwargs:
             tests = []
             for obj in kwargs['test_objects']:
                 tests.append(obj['file_relpath'])
             del kwargs['test_objects']
 
         kwargs['binary'] = self.get_binary_path('app')
         return run_marionette(tests, topsrcdir=self.topsrcdir, **kwargs)
+
+def setup_argument_parser2():
+    from marionette.runner.base2 import BaseMarionette2Arguments
+    return BaseMarionette2Arguments()
+
+def run_marionette2(tests, testtype=None,
+    binary=None, topsrcdir=None, **kwargs):
+    from mozlog.structured import commandline
+
+    from marionette.runtests2 import (
+        Marionette2TestRunner,
+        BaseMarionette2Arguments,
+        Marionette2Harness
+    )
+
+    parser = BaseMarionette2Arguments()
+    commandline.add_logging_group(parser)
+    args = parser.parse_args()
+
+    if not tests:
+        tests = [os.path.join(topsrcdir,
+                 'testing/marionette/harness/marionette/tests2/unit-tests.ini')]
+    args.tests = tests
+
+    args.binary = binary
+    path, exe = os.path.split(args.binary)
+
+    for k, v in kwargs.iteritems():
+        setattr(args, k, v)
+
+    parser.verify_usage(args)
+
+    args.logger = commandline.setup_logging("Marionette Unit Tests",
+                                            args,
+                                            {"mach": sys.stdout})
+    failed = Marionette2Harness(Marionette2TestRunner, args=args).run()
+    if failed > 0:
+        return 1
+    else:
+        return 0
+
+@CommandProvider
+class MachCommands2(MachCommandBase):
+    @Command('marionette2-test', category='testing',
+        description='Run a Marionette2 test (Check UI or the internal JavaScript using marionette).',
+        conditions=[conditions.is_firefox],
+        parser=setup_argument_parser2,
+    )
+    def run_marionette2_test(self, tests, **kwargs):
+        if 'test_objects' in kwargs:
+            tests = []
+            for obj in kwargs['test_objects']:
+                tests.append(obj['file_relpath'])
+            del kwargs['test_objects']
+
+        from pudb import set_trace; set_trace() #AR TODO: remove this line
+        kwargs['binary'] = self.get_binary_path('app')
+        return run_marionette2(tests, topsrcdir=self.topsrcdir, **kwargs)