예제 #1
0
파일: runjunit.py 프로젝트: hop11/gecko-dev
 def server_init(self):
     """
     Additional initialization required to satisfy MochitestDesktop.startServers
     """
     self._locations = None
     self.server = None
     self.wsserver = None
     self.websocketProcessBridge = None
     self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get("debug") else 90
     if self.options.remoteWebServer is None:
         if os.name != "nt":
             self.options.remoteWebServer = moznetwork.get_ip()
         else:
             raise UserError("--remote-webserver must be specified")
     self.options.webServer = self.options.remoteWebServer
     self.options.webSocketPort = "9988"
     self.options.httpdPath = None
     self.options.keep_open = False
     self.options.pidFile = ""
     self.options.subsuite = None
     self.options.xrePath = None
     if build_obj and "MOZ_HOST_BIN" in os.environ:
         self.options.xrePath = os.environ["MOZ_HOST_BIN"]
         if not self.options.utilityPath:
             self.options.utilityPath = self.options.xrePath
     if not self.options.xrePath:
         self.options.xrePath = self.options.utilityPath
     if build_obj:
         self.options.certPath = os.path.join(
             build_obj.topsrcdir, "build", "pgo", "certs"
         )
예제 #2
0
    def python(
        self,
        command_context,
        no_virtualenv,
        no_activate,
        exec_file,
        ipython,
        requirements,
        args,
    ):
        # Avoid logging the command
        self.log_manager.terminal_handler.setLevel(logging.CRITICAL)

        # Note: subprocess requires native strings in os.environ on Windows.
        append_env = {"PYTHONDONTWRITEBYTECODE": str("1")}

        if requirements and no_virtualenv:
            raise UserError(
                "Cannot pass both --requirements and --no-virtualenv.")

        if no_virtualenv:
            from mach_bootstrap import mach_sys_path

            python_path = sys.executable
            append_env["PYTHONPATH"] = os.pathsep.join(
                mach_sys_path(self.topsrcdir))
        else:
            self.virtualenv_manager.ensure()
            if not no_activate:
                self.virtualenv_manager.activate()
            python_path = self.virtualenv_manager.python_path
            if requirements:
                self.virtualenv_manager.install_pip_requirements(
                    requirements, require_hashes=False)

        if exec_file:
            exec(open(exec_file).read())
            return 0

        if ipython:
            bindir = os.path.dirname(python_path)
            python_path = which("ipython", path=bindir)
            if not python_path:
                if not no_virtualenv:
                    # Use `_run_pip` directly rather than `install_pip_package` to bypass
                    # `req.check_if_exists()` which may detect a system installed ipython.
                    self.virtualenv_manager._run_pip(["install", "ipython"])
                    python_path = which("ipython", path=bindir)

                if not python_path:
                    print("error: could not detect or install ipython")
                    return 1

        return self.run_process(
            [python_path] + args,
            pass_thru=True,  # Allow user to run Python interactively.
            ensure_exit_code=False,  # Don't throw on non-zero exit code.
            python_unbuffered=False,  # Leave input buffered.
            append_env=append_env,
        )
예제 #3
0
    def __init__(self, log, options):
        self.log = log
        verbose = False
        if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
            verbose = True
        self.device = ADBDeviceFactory(adb=options.adbPath or 'adb',
                                       device=options.deviceSerial,
                                       test_root=options.remoteTestRoot,
                                       verbose=verbose,
                                       run_as_package=options.app)
        self.options = options
        self.log.debug("options=%s" % vars(options))
        update_mozinfo()
        self.remote_profile = posixpath.join(self.device.test_root,
                                             'junit-profile')
        self.remote_filter_list = posixpath.join(self.device.test_root,
                                                 'junit-filters.list')

        if self.options.coverage and not self.options.coverage_output_dir:
            raise UserError(
                "--coverage-output-dir is required when using --enable-coverage"
            )
        if self.options.coverage:
            self.remote_coverage_output_file = posixpath.join(
                self.device.test_root, 'junit-coverage.ec')
            self.coverage_output_file = os.path.join(
                self.options.coverage_output_dir, 'junit-coverage.ec')

        self.server_init()

        self.cleanup()
        self.device.clear_logcat()
        self.build_profile()
        self.startServers(self.options, debuggerInfo=None, public=True)
        self.log.debug("Servers started")
예제 #4
0
def current_firefox_checkout(env, hg=None):
    """Determine whether we're in a Firefox checkout.

    Returns one of None, ``git``, or ``hg``.
    """
    HG_ROOT_REVISIONS = set(
        [
            # From mozilla-unified.
            "8ba995b74e18334ab3707f27e9eb8f4e37ba3d29",
        ]
    )

    path = os.getcwd()
    while path:
        hg_dir = os.path.join(path, ".hg")
        git_dir = os.path.join(path, ".git")
        if hg and os.path.exists(hg_dir):
            # Verify the hg repo is a Firefox repo by looking at rev 0.
            try:
                node = subprocess.check_output(
                    [hg, "log", "-r", "0", "--template", "{node}"],
                    cwd=path,
                    env=env,
                    universal_newlines=True,
                )
                if node in HG_ROOT_REVISIONS:
                    _warn_if_risky_revision(path)
                    return ("hg", path)
                # Else the root revision is different. There could be nested
                # repos. So keep traversing the parents.
            except subprocess.CalledProcessError:
                pass

        # Just check for known-good files in the checkout, to prevent attempted
        # foot-shootings.  Determining a canonical git checkout of mozilla-unified
        # is...complicated
        elif os.path.exists(git_dir):
            moz_configure = os.path.join(path, "moz.configure")
            if os.path.exists(moz_configure):
                _warn_if_risky_revision(path)
                return ("git", path)

        path, child = os.path.split(path)
        if child == "":
            break

    raise UserError(
        "Could not identify the root directory of your checkout! "
        "Are you running `mach bootstrap` in an hg or git clone?"
    )
예제 #5
0
    def create_state_dir(self):
        state_dir = get_state_dir()

        if not os.path.exists(state_dir):
            should_create_state_dir = True
            if not self.instance.no_interactive:
                should_create_state_dir = self.instance.prompt_yesno(
                    prompt=STATE_DIR_INFO.format(statedir=state_dir))

            # This directory is by default in $HOME, or overridden via an env
            # var, so we probably shouldn't gate it on --no-system-changes.
            if should_create_state_dir:
                print("Creating global state directory: %s" % state_dir)
                os.makedirs(state_dir, mode=0o770)
            else:
                raise UserError("Need permission to create global state "
                                "directory at %s" % state_dir)

        return state_dir
예제 #6
0
def generate_test_certs(command_context, specifications):
    """Generate test certificates and keys from specifications."""

    command_context.activate_virtualenv()
    import pycert
    import pykey

    if not specifications:
        specifications = find_all_specifications(command_context)

    for specification in specifications:
        if is_certspec_file(specification):
            module = pycert
        elif is_keyspec_file(specification):
            module = pykey
        else:
            raise UserError("'{}' is not a .certspec or .keyspec file".format(
                specification))
        run_module_main_on(module, os.path.abspath(specification))
    return 0
예제 #7
0
    def run_tests(self, test_filters_file=None, test_filters=None):
        """
        Run the tests.
        """
        if not self.device.is_app_installed(self.options.app):
            raise UserError("%s is not installed" % self.options.app)
        if self.device.process_exist(self.options.app):
            raise UserError(
                "%s already running before starting tests" % self.options.app
            )
        # test_filters_file and test_filters must be mutually-exclusive
        if test_filters_file and test_filters:
            raise UserError(
                "Test filters may not be specified when test-filters-file is provided"
            )

        self.test_started = False
        self.pass_count = 0
        self.fail_count = 0
        self.todo_count = 0
        self.total_count = 0
        self.runs = 0
        self.seen_last_test = False

        def callback(line):
            # Output callback: Parse the raw junit log messages, translating into
            # treeherder-friendly test start/pass/fail messages.

            line = six.ensure_str(line)
            self.log.process_output(self.options.app, str(line))
            # Expect per-test info like: "INSTRUMENTATION_STATUS: class=something"
            match = re.match(r"INSTRUMENTATION_STATUS:\s*class=(.*)", line)
            if match:
                self.class_name = match.group(1)
            # Expect per-test info like: "INSTRUMENTATION_STATUS: test=something"
            match = re.match(r"INSTRUMENTATION_STATUS:\s*test=(.*)", line)
            if match:
                self.test_name = match.group(1)
            match = re.match(r"INSTRUMENTATION_STATUS:\s*numtests=(.*)", line)
            if match:
                self.total_count = int(match.group(1))
            match = re.match(r"INSTRUMENTATION_STATUS:\s*current=(.*)", line)
            if match:
                self.current_test_id = int(match.group(1))
            match = re.match(r"INSTRUMENTATION_STATUS:\s*stack=(.*)", line)
            if match:
                self.exception_message = match.group(1)
            if (
                "org.mozilla.geckoview.test.rule.TestHarnessException"
                in self.exception_message
            ):
                # This is actually a problem in the test harness itself
                raise JavaTestHarnessException(self.exception_message)

            # Expect per-test info like: "INSTRUMENTATION_STATUS_CODE: 0|1|..."
            match = re.match(r"INSTRUMENTATION_STATUS_CODE:\s*([+-]?\d+)", line)
            if match:
                status = match.group(1)
                full_name = "%s#%s" % (self.class_name, self.test_name)
                if full_name == self.current_full_name:
                    # A crash in the test harness might cause us to ignore tests,
                    # so we double check that we've actually ran all the tests
                    if self.total_count == self.current_test_id:
                        self.seen_last_test = True

                    if status == "0":
                        message = ""
                        status = "PASS"
                        expected = "PASS"
                        self.pass_count += 1
                        if self.verbose:
                            self.log.info("Printing logcat for test:")
                            print(self.collectLogcatForCurrentTest())
                    elif status == "-3":  # ignored (skipped)
                        message = ""
                        status = "SKIP"
                        expected = "SKIP"
                        self.todo_count += 1
                    elif status == "-4":  # known fail
                        message = ""
                        status = "FAIL"
                        expected = "FAIL"
                        self.todo_count += 1
                    else:
                        if self.exception_message:
                            message = self.exception_message
                        else:
                            message = "status %s" % status
                        status = "FAIL"
                        expected = "PASS"
                        self.fail_count += 1
                        self.log.info("Printing logcat for test:")
                        print(self.collectLogcatForCurrentTest())
                    self.log.test_end(full_name, status, expected, message)
                    self.test_started = False
                else:
                    if self.test_started:
                        # next test started without reporting previous status
                        self.fail_count += 1
                        status = "FAIL"
                        expected = "PASS"
                        self.log.test_end(
                            self.current_full_name,
                            status,
                            expected,
                            "missing test completion status",
                        )
                    self.log.test_start(full_name)
                    self.test_started = True
                    self.current_full_name = full_name

        # Ideally all test names should be reported to suite_start, but these test
        # names are not known in advance.
        self.log.suite_start(["geckoview-junit"])
        try:
            self.device.grant_runtime_permissions(self.options.app)
            cmd = self.build_command_line(
                test_filters_file=test_filters_file, test_filters=test_filters
            )
            while self.need_more_runs():
                self.class_name = ""
                self.exception_message = ""
                self.test_name = ""
                self.current_full_name = ""
                self.current_test_id = 0
                self.runs += 1
                self.log.info("launching %s" % cmd)
                p = self.device.shell(
                    cmd, timeout=self.options.max_time, stdout_callback=callback
                )
                if p.timedout:
                    self.log.error(
                        "TEST-UNEXPECTED-TIMEOUT | runjunit.py | "
                        "Timed out after %d seconds" % self.options.max_time
                    )
            self.log.info("Passed: %d" % self.pass_count)
            self.log.info("Failed: %d" % self.fail_count)
            self.log.info("Todo: %d" % self.todo_count)
            if not self.seen_last_test:
                self.log.error(
                    "TEST-UNEXPECTED-FAIL | runjunit.py | "
                    "Some tests did not run (probably due to a crash in the harness)"
                )
        finally:
            self.log.suite_end()

        if self.check_for_crashes():
            self.fail_count = 1

        if self.options.coverage:
            try:
                self.device.pull(
                    self.remote_coverage_output_file, self.coverage_output_file
                )
            except ADBError:
                # Avoid a task retry in case the code coverage file is not found.
                self.log.error(
                    "No code coverage file (%s) found on remote device"
                    % self.remote_coverage_output_file
                )
                return -1

        return 1 if self.fail_count else 0