# 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 __future__ import absolute_import, print_function, unicode_literals import argparse import os import re import subprocess import sys import mozinfo from six.moves.urllib.parse import urljoin from six.moves.urllib.request import pathname2url from mach.decorators import ( CommandArgument, CommandProvider, Command, ) from mozbuild.base import MachCommandBase, MozbuildObject from mozbuild.base import MachCommandConditions as conditions from argparse import ArgumentParser def get_parser(): parser = argparse.ArgumentParser() parser.add_argument( "suite_name", nargs=1, type=str, action="store", help="Suite to run in mozharness", ) parser.add_argument( "mozharness_args", nargs=argparse.REMAINDER, help="Extra arguments to pass to mozharness", ) return parser class MozharnessRunner(MozbuildObject): def __init__(self, *args, **kwargs): MozbuildObject.__init__(self, *args, **kwargs) self.test_packages_url = self._test_packages_url() self.installer_url = self._installer_url() desktop_unittest_config = [ "--config-file", lambda: self.config_path( "unittests", "%s_unittest.py" % mozinfo.info["os"] ), "--config-file", lambda: self.config_path("developer_config.py"), ] self.config = { "__defaults__": { "config": [ "--download-symbols", "ondemand", "--installer-url", self.installer_url, "--test-packages-url", self.test_packages_url, ] }, "mochitest-valgrind": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "valgrind-plain"], }, "mochitest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "plain"], }, "mochitest-chrome": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "chrome"], }, "mochitest-browser-chrome": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "browser-chrome"], }, "mochitest-devtools-chrome": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "mochitest-devtools-chrome"], }, "mochitest-remote": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--mochitest-suite", "mochitest-remote"], }, "crashtest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--reftest-suite", "crashtest"], }, "jsreftest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--reftest-suite", "jsreftest"], }, "reftest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--reftest-suite", "reftest"], }, "reftest-no-accel": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--reftest-suite", "reftest-no-accel"], }, "cppunittest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--cppunittest-suite", "cppunittest"], }, "xpcshell": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--xpcshell-suite", "xpcshell"], }, "xpcshell-addons": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--xpcshell-suite", "xpcshell-addons"], }, "jittest": { "script": "desktop_unittest.py", "config": desktop_unittest_config + ["--jittest-suite", "jittest"], }, "marionette": { "script": "marionette.py", "config": [ "--config-file", self.config_path("marionette", "test_config.py"), ], }, "web-platform-tests": { "script": "web_platform_tests.py", "config": [ "--config-file", self.config_path("web_platform_tests", self.wpt_config), ], }, } def path_to_url(self, path): return urljoin("file:", pathname2url(path)) def _installer_url(self): package_re = { "linux": re.compile("^firefox-\d+\..+\.tar\.bz2$"), "win": re.compile("^firefox-\d+\..+\.installer\.exe$"), "mac": re.compile("^firefox-\d+\..+\.mac(?:64)?\.dmg$"), }[mozinfo.info["os"]] dist_path = os.path.join(self.topobjdir, "dist") filenames = [item for item in os.listdir(dist_path) if package_re.match(item)] assert len(filenames) == 1 return self.path_to_url(os.path.join(dist_path, filenames[0])) def _test_packages_url(self): dist_path = os.path.join(self.topobjdir, "dist") filenames = [ item for item in os.listdir(dist_path) if item.endswith("test_packages.json") ] assert len(filenames) == 1 return self.path_to_url(os.path.join(dist_path, filenames[0])) def config_path(self, *parts): return self.path_to_url( os.path.join(self.topsrcdir, "testing", "mozharness", "configs", *parts) ) @property def wpt_config(self): return ( "test_config.py" if mozinfo.info["os"] != "win" else "test_config_windows.py" ) def run_suite(self, suite, **kwargs): default_config = self.config.get("__defaults__") suite_config = self.config.get(suite) if suite_config is None: print("Unknown suite %s" % suite) return 1 script = os.path.join( self.topsrcdir, "testing", "mozharness", "scripts", suite_config["script"] ) options = [ item() if callable(item) else item for item in default_config["config"] + suite_config["config"] ] cmd = [script] + options rv = subprocess.call(cmd, cwd=os.path.dirname(script)) return rv @CommandProvider class MozharnessCommands(MachCommandBase): @Command( "mozharness", category="testing", description="Run tests using mozharness.", conditions=[conditions.is_firefox_or_android], parser=get_parser, ) def mozharness(self, **kwargs): runner = self._spawn(MozharnessRunner) return runner.run_suite(kwargs.pop("suite_name")[0], **kwargs)