Bug 1147031 - Write mach command for luciddream. r=jgriffin, a=test-only
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 09 Apr 2015 11:46:00 -0400
changeset 267824 2e94e80384c126003b0ad31e3b0a49dc651c34f4
parent 267823 2f0587d64897e59ce45c125bc9478bf5f3916b11
child 267825 55049b5a6763cf4a6df102b0fee97aebda8c9e09
push id853
push userryanvm@gmail.com
push dateWed, 08 Jul 2015 22:27:16 +0000
treeherdermozilla-release@ac2cb134e758 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgriffin, test-only
bugs1147031
milestone39.0.1
Bug 1147031 - Write mach command for luciddream. r=jgriffin, a=test-only
build/mach_bootstrap.py
testing/luciddream/luciddream/__init__.py
testing/luciddream/luciddream/runluciddream.py
testing/luciddream/mach_commands.py
testing/mach_commands.py
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -47,16 +47,17 @@ SEARCH_PATHS = [
     'testing',
     'testing/taskcluster',
     'testing/xpcshell',
     'testing/web-platform',
     'testing/web-platform/harness',
     'testing/marionette/client',
     'testing/marionette/transport',
     'testing/marionette/driver',
+    'testing/luciddream',
     'testing/mozbase/mozcrash',
     'testing/mozbase/mozdebug',
     'testing/mozbase/mozdevice',
     'testing/mozbase/mozfile',
     'testing/mozbase/mozhttpd',
     'testing/mozbase/mozlog',
     'testing/mozbase/moznetwork',
     'testing/mozbase/mozprocess',
@@ -79,16 +80,17 @@ MACH_MODULES = [
     'python/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/compare-locales/mach_commands.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/backend/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'services/common/tests/mach_commands.py',
+    'testing/luciddream/mach_commands.py',
     'testing/mach_commands.py',
     'testing/taskcluster/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'testing/talos/mach_commands.py',
     'testing/web-platform/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
--- a/testing/luciddream/luciddream/__init__.py
+++ b/testing/luciddream/luciddream/__init__.py
@@ -5,18 +5,19 @@
 #
 
 import os
 import sys
 from marionette.marionette_test import MarionetteTestCase, MarionetteJSTestCase
 from marionette_driver.errors import ScriptTimeoutException
 
 class LucidDreamTestCase(MarionetteTestCase):
-    def __init__(self, marionette_weakref, browser=None, **kwargs):
+    def __init__(self, marionette_weakref, browser=None, logger=None, **kwargs):
         self.browser = browser
+        self.logger = logger
         MarionetteTestCase.__init__(self, marionette_weakref, **kwargs)
 
     def run_js_test(self, filename, marionette):
         '''
         Run a JavaScript test file and collect its set of assertions
         into the current test's results.
 
         :param filename: The path to the JavaScript test file to execute.
--- a/testing/luciddream/luciddream/runluciddream.py
+++ b/testing/luciddream/luciddream/runluciddream.py
@@ -17,48 +17,48 @@ import marionette
 from mozlog import structured
 
 
 class CommandLineError(Exception):
     pass
 
 
 def validate_options(options):
-    if not (options.b2gPath or options.b2gDesktopPath):
-        raise CommandLineError('You must specify --b2gpath or ' +
+    if not (options.emulator_path or options.b2g_desktop_path):
+        raise CommandLineError('You must specify --emulator-path or ' +
                                '--b2g-desktop-path')
-    if options.b2gPath and options.b2gDesktopPath:
-        raise CommandLineError('You may only use one of --b2gpath or ' +
+    if options.emulator_path and options.b2g_desktop_path:
+        raise CommandLineError('You may only use one of --emulator-path or ' +
                                '--b2g-desktop-path')
-    if options.gaiaProfile and options.b2gPath:
+    if options.gaia_profile and options.emulator_path:
         raise CommandLineError('You may not use --gaia-profile with ' +
-                               '--b2gpath')
-    if not options.browserPath:
+                               '--emulator-path')
+    if not options.browser_path:
         raise CommandLineError('You must specify --browser-path')
     if not os.path.isfile(options.manifest):
         raise CommandLineError('The manifest at "%s" does not exist!'
                                % options.manifest)
 
 
 # BaseMarionetteOptions has a lot of stuff we don't care about, and
 # it seems hard to apply directly to this problem. We can revisit this
 # decision later if necessary.
 def parse_args(in_args):
     parser = argparse.ArgumentParser(description='Run Luciddream tests.')
-    parser.add_argument('--emulator', dest='emulator', action='store',
+    parser.add_argument('--emulator-arch', dest='emulator_arch', action='store',
                         default='arm',
                         help='Architecture of emulator to use: x86 or arm')
-    parser.add_argument('--b2gpath', dest='b2gPath', action='store',
+    parser.add_argument('--emulator-path', dest='emulator_path', action='store',
                         help='path to B2G repo or qemu dir')
-    parser.add_argument('--b2g-desktop-path', dest='b2gDesktopPath',
+    parser.add_argument('--b2g-desktop-path', dest='b2g_desktop_path',
                         action='store',
                         help='path to B2G desktop binary')
-    parser.add_argument('--browser-path', dest='browserPath', action='store',
+    parser.add_argument('--browser-path', dest='browser_path', action='store',
                         help='path to Firefox binary')
-    parser.add_argument('--gaia-profile', dest='gaiaProfile', action='store',
+    parser.add_argument('--gaia-profile', dest='gaia_profile', action='store',
                         help='path to Gaia profile')
     parser.add_argument('manifest', metavar='MANIFEST', action='store',
                         help='path to manifest of tests to run')
     structured.commandline.add_logging_group(parser)
 
     args = parser.parse_args(in_args)
     try:
         validate_options(args)
@@ -71,81 +71,81 @@ def parse_args(in_args):
 
 class LucidDreamTestRunner(BaseMarionetteTestRunner):
     def __init__(self, **kwargs):
         BaseMarionetteTestRunner.__init__(self, **kwargs)
         #TODO: handle something like MarionetteJSTestCase
         self.test_handlers = [LucidDreamTestCase]
 
 
-def start_browser(browserPath):
+def start_browser(browser_path, app_args):
     '''
     Start a Firefox browser and return a Marionette instance that
     can talk to it.
     '''
     marionette = Marionette(
-        bin=browserPath,
+        bin=browser_path,
         # Need to avoid the browser and emulator's ports stepping
         # on each others' toes.
         port=2929,
+        app_args=app_args,
+        gecko_log="firefox.log"
     )
     runner = marionette.runner
     if runner:
         runner.start()
     marionette.wait_for_port()
     marionette.start_session()
     marionette.set_context(marionette.CONTEXT_CHROME)
     return marionette
 
 
 #TODO: make marionette/client/marionette/runtests.py importable so we can
 # just use cli from there. A lot of this is copy/paste from that function.
-def main():
-    try:
-        args = parse_args(sys.argv[1:])
-    except CommandLineError as e:
-        return 1
-
-    logger = structured.commandline.setup_logging(
-        'luciddream', args, {"tbpl": sys.stdout})
-
+def run(browser_path=None, b2g_desktop_path=None, emulator_path=None, emulator_arch=None, gaia_profile=None, manifest=None, browser_args=None, **kwargs):
     # It's sort of debatable here whether the marionette instance managed
     # by the test runner should be the browser or the emulator. Right now
     # it's the emulator because it feels like there's more fiddly setup around
     # that, but longer-term if we want to run tests against different
     # (non-B2G) targets this won't match up very well, so maybe it ought to
     # be the browser?
-    browser = start_browser(args.browserPath)
-    kwargs = {
-        'browser': browser,
-        'logger': logger,
-    }
-    if args.b2gPath:
-        kwargs['homedir'] = args.b2gPath
-        kwargs['emulator'] = args.emulator
-    elif args.b2gDesktopPath:
+    browser = start_browser(browser_path, browser_args)
+
+    kwargs["browser"] = browser
+    if not "logger" in kwargs:
+        logger = structured.commandline.setup_logging(
+            "luciddream", kwargs, {"tbpl": sys.stdout})
+        kwargs["logger"] = logger
+
+    if emulator_path:
+        kwargs['homedir'] = emulator_path
+        kwargs['emulator'] = emulator_arch
+    elif b2g_desktop_path:
         # Work around bug 859952
-        if '-bin' not in args.b2gDesktopPath:
-            if args.b2gDesktopPath.endswith('.exe'):
-                newpath = args.b2gDesktopPath[:-4] + '-bin.exe'
+        if '-bin' not in b2g_desktop_path:
+            if b2g_desktop_path.endswith('.exe'):
+                newpath = b2g_desktop_path[:-4] + '-bin.exe'
             else:
-                newpath = args.b2gDesktopPath + '-bin'
+                newpath = b2g_desktop_path + '-bin'
             if os.path.exists(newpath):
-                args.b2gDesktopPath = newpath
-        kwargs['binary'] = args.b2gDesktopPath
+                b2g_desktop_path = newpath
+        kwargs['binary'] = b2g_desktop_path
         kwargs['app'] = 'b2gdesktop'
-        if args.gaiaProfile:
-            kwargs['profile'] = args.gaiaProfile
+        if gaia_profile:
+            kwargs['profile'] = gaia_profile
         else:
             kwargs['profile'] = os.path.join(
-                os.path.dirname(args.b2gDesktopPath),
+                os.path.dirname(b2g_desktop_path),
                 'gaia',
                 'profile'
             )
     runner = LucidDreamTestRunner(**kwargs)
-    runner.run_tests([args.manifest])
+    runner.run_tests([manifest])
     if runner.failed > 0:
         sys.exit(10)
     sys.exit(0)
 
+def main():
+    args = parse_args(sys.argv[1:])
+    run(**vars(args))
 
 if __name__ == '__main__':
     main()
new file mode 100644
--- /dev/null
+++ b/testing/luciddream/mach_commands.py
@@ -0,0 +1,99 @@
+# 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/.
+
+# Integrates luciddream test runner with mach.
+
+import os
+import re
+import sys
+
+import mozpack.path as mozpath
+
+from mozbuild.base import (
+    MachCommandBase,
+    MachCommandConditions as conditions,
+    MozbuildObject,
+)
+
+from mach.decorators import (
+    CommandArgument,
+    CommandProvider,
+    Command,
+)
+
+class LucidDreamRunner(MozbuildObject):
+    """Run luciddream tests."""
+    def run_tests(self, **kwargs):
+        self._run_make(target='jetpack-tests')
+
+@CommandProvider
+class MachCommands(MachCommandBase):
+    @Command('luciddream', category='testing',
+        description='Runs the luciddream test suite.')
+    @CommandArgument("--consoles", action="store_true",
+                     help="Open jsconsole in both runtimes.")
+    @CommandArgument('--b2g-desktop', dest="b2g_desktop_path", type=str, default=None,
+                     help='Path to b2g desktop binary.')
+    @CommandArgument('--browser', dest="browser_path", type=str, default=None,
+                     help='Path to firefox binary.')
+    @CommandArgument('--gaia-profile', type=str, default=None,
+                     help='Path to gaia profile, optional, if not bundled with b2g desktop.')
+    @CommandArgument('--emulator', dest="emulator_path", type=str, default=None,
+                     help='Path to android emulator.')
+    @CommandArgument('--emulator-arch', type=str, default="arm",
+                     help='Emulator arch: x86 or arm.')
+    @CommandArgument('test_paths', default=None, nargs='*', metavar='TEST',
+                     help='Test to run. Can be specified as a single file, a '
+                          'directory, or omitted. If omitted, the entire test suite is '
+                          'executed.')
+    def run_luciddream_test(self, browser_path, b2g_desktop_path, test_paths, consoles, **params):
+        # import luciddream lazily as its marionette dependency make ./mach clobber fails
+        # early on TBPL
+        import luciddream.runluciddream
+
+        # get_binary_path is going to throw if we haven't built any product
+        # but luciddream can still be run if we provide both binaries...
+        binary_path=False
+        try:
+            binary_path = self.get_binary_path()
+        except Exception:
+            pass
+
+        # otherwise, if we have a build, automatically fetch the binary
+        if conditions.is_b2g(self):
+            if not b2g_desktop_path and binary_path:
+                b2g_desktop_path = binary_path
+        else:
+            if not browser_path and binary_path:
+                browser_path = binary_path
+
+        if not browser_path:
+            print "Need firefox binary path via --browser_path argument"
+            return 1
+        elif not os.path.exists(browser_path):
+            print "Firefox binary doesn't exists: " + browser_path
+            return 1
+
+        if not b2g_desktop_path:
+            print "Need b2g desktop binary path via --b2g-desktop argument"
+            return 1
+        elif not os.path.exists(b2g_desktop_path):
+            print "B2G desktop binary doesn't exists: " + b2g_desktop_path
+            return 1
+
+        if not test_paths or len(test_paths) == 0:
+            print "Please specify a test manifest to run"
+            return 1
+
+        browser_args = None
+        if consoles:
+            browser_args = ["-jsconsole"]
+            if "app_args" in params and isinstance(params["app_args"], list):
+                params["app_args"].append("-jsconsole")
+            else:
+                params["app_args"] = ["-jsconsole"]
+
+        for test in test_paths:
+          luciddream.runluciddream.run(browser_path=browser_path, b2g_desktop_path=b2g_desktop_path,
+            manifest=test, browser_args=browser_args, **params)
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -82,16 +82,20 @@ TEST_SUITES = {
     },
     'mochitest-ipcplugins': {
         'make_target': 'mochitest-ipcplugins',
     },
     'mochitest-plain': {
         'mach_command': 'mochitest',
         'kwargs': {'flavor': 'mochitest', 'test_paths': None},
     },
+    'luciddream': {
+        'mach_command': 'luciddream',
+        'kwargs': {'test_paths': None},
+    },
     'reftest': {
         'aliases': ('RR', 'rr', 'Rr'),
         'mach_command': 'reftest',
         'kwargs': {'test_file': None},
     },
     'reftest-ipc': {
         'aliases': ('Ripc',),
         'mach_command': 'reftest-ipc',