Beispiel #1
0
def runprofile(binary, fileobj):
    try:
        runner = FirefoxRunner(binary=binary, profile=fileobj.profile)
        runner.start()
        runner.wait()
    except KeyboardInterrupt:
        pass
Beispiel #2
0
    def run(self, test, phase='phase1', ignore_unused_engines=True):
        self.profile.set_preferences({
            'testing.tps.testFile': os.path.abspath(test),
            'testing.tps.testPhase': phase,
            'testing.tps.ignoreUnusedEngines': ignore_unused_engines,
        })
        args = ['-marionette']
        process_args = {'processOutputLine': [self._log]}
        self.logger.info('Running: {} {}'.format(self.firefox, ' '.join(args)))
        self.logger.info('Using profile at: {}'.format(self.profile.profile))
        runner = FirefoxRunner(
            binary=self.firefox,
            cmdargs=args,
            profile=self.profile,
            process_args=process_args)
        runner.start(timeout=TIMEOUT)
        runner.wait(timeout=TIMEOUT)
        self.firefox_log.close()

        with open(self.tps_log) as f:
            for line in f.readlines():
                if 'CROSSWEAVE ERROR: ' in line:
                    raise TPSError(line.partition('CROSSWEAVE ERROR: ')[-1])

        with open(self.tps_log) as f:
            assert 'test phase {}: PASS'.format(phase) in f.read()
Beispiel #3
0
    def run(self, test, phase='phase1', ignore_unused_engines=True):
        args = [
            '-tps={}'.format(os.path.abspath(test)),
            '-tpsphase={}'.format(phase),
            '-marionette']
        if ignore_unused_engines:
            args.append('--ignore-unused-engines')

        process_args = {'processOutputLine': [self._log]}
        self.logger.info('Running: {} {}'.format(self.firefox, ' '.join(args)))
        self.logger.info('Using profile at: {}'.format(self.profile.profile))
        runner = FirefoxRunner(
            binary=self.firefox,
            cmdargs=args,
            profile=self.profile,
            process_args=process_args)
        runner.start(timeout=TIMEOUT)
        runner.wait(timeout=TIMEOUT)
        self.firefox_log.close()

        with open(self.tps_log) as f:
            for line in f.readlines():
                if 'CROSSWEAVE ERROR: ' in line:
                    raise TPSError(line.partition('CROSSWEAVE ERROR: ')[-1])

        with open(self.tps_log) as f:
            assert 'test phase {}: PASS'.format(phase) in f.read()
Beispiel #4
0
    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(
            filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      proxy=True,
                                      preferences=preferences)
        self.profile.set_preferences({
            "marionette.defaultPrefs.enabled": True,
            "marionette.defaultPrefs.port": self.marionette_port,
            "dom.disable_open_during_load": False
        })

        self.runner = FirefoxRunner(
            profile=self.profile,
            binary=self.binary,
            cmdargs=[cmd_arg("marionette"), "about:blank"],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")
        self.runner.start(debug_args=self.debug_args,
                          interactive=self.interactive)
        self.logger.debug("Firefox Started")
Beispiel #5
0
class FFRunner():
    # Calls FirefoxRunner with the right parameters
    def __init__(self, name="firefox", installDir=os.path.join(os.path.expanduser("~"),"remotebisectorapp")):
        self.name = name
        platform=get_platform()
        if platform['name'] == "Windows":
            if platform['bits'] == '64':
                print "No builds available for 64 bit Windows"
                sys.exit()
            self.buildRegex = ".*win32.zip"
            self.processName = self.name + ".exe"
            self.binary = os.path.join(installDir, self.name, self.name + ".exe")
        elif platform['name'] == "Linux":
            self.processName = self.name + "-bin"
            self.binary = os.path.join(installDir, self.name, self.name)
            if platform['bits'] == '64':
                self.buildRegex = ".*linux-x86_64.tar.bz2"
            else:
                self.buildRegex = ".*linux-i686.tar.bz2"
        elif platform['name'] == "Mac":
            self.buildRegex = ".*mac.*\.dmg"
            self.processName = self.name + "-bin"
            self.binary = os.path.join(installDir, "Mozilla.app/Contents/MacOS", self.name + "-bin")

    def run(self):
        self.runner = FirefoxRunner(binary=self.binary)
        self.runner.start()
Beispiel #6
0
    def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
        """Runs the given FirefoxRunner with the given Profile, waits
           for completion, then returns the process exit code
        """
        if profile is None:
            profile = Profile()
        self.profile = profile

        if self.binary is None and self.url:
            self.binary = self.download_build()

        if self.runner is None:
            self.runner = FirefoxRunner(self.profile, binary=self.binary)

        self.runner.profile = self.profile

        if env is not None:
            self.runner.env.update(env)

        if args is not None:
            self.runner.cmdargs = copy.copy(args)

        self.runner.start()
        returncode = self.runner.wait(timeout)

        return returncode
Beispiel #7
0
    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)

        env = os.environ.copy()
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
                                      "marionette.defaultPrefs.port": self.marionette_port,
                                      "dom.disable_open_during_load": False,
                                      "network.dns.localDomains": ",".join(hostnames)})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(self.binary, [cmd_arg("marionette"), "about:blank"],
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)
        self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(
            filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({
            "marionette.enabled":
            True,
            "marionette.port":
            self.marionette_port,
            "dom.disable_open_during_load":
            False,
            "network.dns.localDomains":
            ",".join(hostnames),
            "network.proxy.type":
            0,
            "places.history.enabled":
            False
        })
        if self.e10s:
            self.profile.set_preferences(
                {"browser.tabs.remote.autostart": True})

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft")
                and '5.1' in platform.version()):
            self.profile.set_preferences(
                {"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(
            self.binary, [cmd_arg("marionette"), "about:blank"],
            self.debug_info)

        self.runner = FirefoxRunner(
            profile=self.profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args,
                          interactive=self.debug_info
                          and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
Beispiel #9
0
    def start(self):
        """Start an instance of Firefox, returning a BrowserInstance handle"""
        profile = self.base_profile.clone(self.base_profile.profile)

        marionette_port = get_free_port()
        profile.set_preferences({"marionette.port": marionette_port})

        env = test_environment(xrePath=os.path.dirname(self.binary),
                               debugger=self.debug_info is not None,
                               useLSan=True,
                               log=self.logger)

        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
        if self.headless:
            env["MOZ_HEADLESS"] = "1"
        if self.enable_webrender:
            env["MOZ_WEBRENDER"] = "1"
            env["MOZ_ACCELERATED"] = "1"
            # Set MOZ_X_SYNC and GDK_SYNCHRONIZE for investigation; bug 1625250.
            env["MOZ_X_SYNC"] = "1"
            env["GDK_SYNCHRONIZE"] = "1"
        else:
            env["MOZ_WEBRENDER"] = "0"

        args = self.binary_args[:] if self.binary_args else []
        args += [cmd_arg("marionette"), "about:blank"]

        debug_args, cmd = browser_command(self.binary, args, self.debug_info)

        if self.leak_check:
            leak_report_file = os.path.join(
                profile.profile, "runtests_leaks_%s.log" % os.getpid())
            if os.path.exists(leak_report_file):
                os.remove(leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = leak_report_file
        else:
            leak_report_file = None

        output_handler = OutputHandler(self.logger, self.stackfix_dir,
                                       self.symbols_path, self.asan)
        runner = FirefoxRunner(
            profile=profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=cast_env(env),
            process_class=ProcessHandler,
            process_args={"processOutputLine": [output_handler]})
        instance = BrowserInstance(self.logger, runner, marionette_port,
                                   output_handler, leak_report_file)

        self.logger.debug("Starting Firefox")
        runner.start(debug_args=debug_args,
                     interactive=self.debug_info
                     and self.debug_info.interactive)
        self.logger.debug("Firefox Started")

        return instance
Beispiel #10
0
    def run_tests(self, test_path, options):
        reftestlist = self.getManifestPath(test_path)
        if not reftestlist.startswith('file://'):
            reftestlist = 'file://%s' % reftestlist

        self.profile = self.create_profile(options,
                                           reftestlist,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = {
            'processOutputLine': [self._on_output],
            'onTimeout': [self._on_timeout],
            'kill_on_timeout': False
        }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(
            options.app,
            ignore_window_size=options.ignoreWindowSize,
            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d", os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s", self.last_test,
                     -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status
Beispiel #11
0
def launch_firefox(path, profile=None, url=None, args=None):
    """Launch the app with optional args for profile, windows, URI, etc.

    :param path: Firefox path.
    :param profile: Firefox profile.
    :param url: URL to be loaded.
    :param args: Optional list of arguments.
    :return: List of Firefox flags.
    """
    if args is None:
        args = []

    if profile is None:
        raise APIHelperError('No profile name present, aborting run.')

    profile = FirefoxProfile(profile=profile)

    args.append('-foreground')
    args.append('-no-remote')

    if url is not None:
        args.append('-new-tab')
        args.append(url)

    process_args = {'stream': None}
    logger.debug('Creating Firefox runner ...')
    try:
        runner = FirefoxRunner(binary=path, profile=profile, cmdargs=args, process_args=process_args)
        logger.debug('Firefox runner successfully created.')
        logger.debug('Running Firefox with command: "%s"' % ','.join(runner.command))
        return runner
    except errors.RunnerNotStartedError:
        raise APIHelperError('Error creating Firefox runner.')
    def launch(self, args=None):
        """Launch the app with optional args for profile, windows, URI, etc.

        :param url: URL to be loaded.
        :param args: Optional list of arguments.
        :return: List of Firefox flags.
        """
        if args is None:
            args = []

        args.append('-foreground')
        args.append('-no-remote')
        args.append('-new-tab')
        args.append(self.url)

        process_args = {'stream': None}
        logger.debug('Creating Firefox runner ...')
        try:
            runner = FirefoxRunner(binary=self.application.path,
                                   profile=self.profile,
                                   cmdargs=args,
                                   process_args=process_args)
            logger.debug('Firefox runner successfully created.')
            logger.debug('Running Firefox with command: "%s"' %
                         ','.join(runner.command))
        except run_errors.RunnerNotStartedError:
            raise APIHelperError('Error creating Firefox runner.')

        else:
            return runner
Beispiel #13
0
    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        ports = {"http": "8000",
                 "https": "8443",
                 "ws": "8888"}

        self.profile = FirefoxProfile(locations=locations,
                                      proxy=ports,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
                                      "marionette.defaultPrefs.port": self.marionette_port,
                                      "dom.disable_open_during_load": False})

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=self.binary,
                                    cmdargs=[cmd_arg("marionette"), "about:blank"],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")
        self.runner.start(debug_args=self.debug_args, interactive=self.interactive)
        self.logger.debug("Firefox Started")
 def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
     """Runs the given FirefoxRunner with the given Profile, waits
        for completion, then returns the process exit code
     """
     if profile is None:
         profile = Profile()
     self.profile = profile
 
     if self.binary is None and self.url:
         self.binary = self.download_build()
   
     if self.runner is None:
         self.runner = FirefoxRunner(self.profile, binary=self.binary)
   
     self.runner.profile = self.profile
 
     if env is not None:
         self.runner.env.update(env)
   
     if args is not None:
         self.runner.cmdargs = copy.copy(args)
   
     self.runner.start()
 
     status = self.runner.process_handler.waitForFinish(timeout=timeout)
 
     return status
Beispiel #15
0
    def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
        """Runs the given FirefoxRunner with the given Profile, waits
           for completion, then returns the process exit code
        """
        if profile is None:
            profile = Profile()
        self.profile = profile

        if self.binary is None and self.url:
            self.binary = self.download_build()

        runner = FirefoxRunner(profile=self.profile, binary=self.binary,
                               env=env, cmdargs=args)

        runner.start(timeout=timeout)
        return runner.wait()
    def start(self, **kwargs):
        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
        env["STYLO_THREADS"] = str(self.stylo_threads)

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.port": self.marionette_port,
                                      "dom.disable_open_during_load": False,
                                      "network.dns.localDomains": ",".join(hostnames),
                                      "network.proxy.type": 0,
                                      "places.history.enabled": False,
                                      "dom.send_after_paint_to_content": True})
        if self.e10s:
            self.profile.set_preferences({"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences({"layout.interruptible-reflow.enabled": False})

        if self.leak_check and kwargs.get("check_leaks", True):
            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks.log")
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft") and
            '5.1' in platform.version()):
            self.profile.set_preferences({"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(self.binary,
                                          self.binary_args if self.binary_args else [] +
                                          [cmd_arg("marionette"), "about:blank"],
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
 def run(self):
     #Run the built binary if it exists. ONLY WORKS IF BUILD WAS CALLED!
     if sys.platform == "darwin":
         runner = FirefoxRunner.create(binary=os.path.join(self.shellCacheDir,"mozbuild-trunk","obj-ff-dbg","dist","NightlyDebug.app","Contents","MacOS")+"/firefox-bin")
         runner.start()
         runner.wait()
     elif sys.platform == "linux2":
         runner = FirefoxRunner.create(binary=os.path.join(self.shellCacheDir,"mozbuild-trunk","obj-ff-dbg","dist","bin") + "/firefox")
         runner.start()
         runner.wait()
     elif sys.platform == "win32" or sys.platform == "cygwin":
         runner = FirefoxRunner.create(binary=os.path.join(self.shellCacheDir,"mozbuild-trunk","obj-ff-dbg","dist","bin") + "/firefox.exe")
         runner.start()
         runner.wait()
     else:
         print "Your platform is not currently supported."
         quit()
    def run_tests(self, tests, options):
        manifests = self.resolver.resolveManifests(options, tests)

        self.profile = self.create_profile(options, manifests,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)

        self._populate_logger(options)
        outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=options.symbolsPath)

        kp_kwargs = { 'processOutputLine': [outputHandler],
                      'onTimeout': [self._on_timeout],
                      'kill_on_timeout': False }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        self.log.info("%s | Running tests: start." % os.path.basename(__file__))
        cmd, args = self.build_command_line(options.app,
                            ignore_window_size=options.ignoreWindowSize,
                            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            self.log.info("%s | Application pid: %d" % (
                     os.path.basename(__file__),
                     self.runner.process_handler.pid))

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            self.log.testFail("%s | application terminated with exit code %s" % (
                         self.last_test, status))
        elif status < 0:
            self.log.info("%s | application killed with signal %s" % (
                         self.last_test, -status))

        self.log.info("%s | Running tests: end." % os.path.basename(__file__))
        return status
Beispiel #19
0
    def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
        """Runs the given FirefoxRunner with the given Profile, waits
        for completion, then returns the process exit code
        """
        if profile is None:
            profile = Profile()
        self.profile = profile

        if self.binary is None and self.url:
            self.binary = self.download_build()

        runner = FirefoxRunner(profile=self.profile,
                               binary=self.binary,
                               env=env,
                               cmdargs=args)

        runner.start(timeout=timeout)
        return runner.wait()
Beispiel #20
0
    def start(self):
        """Start an instance of Firefox, returning a BrowserInstance handle"""
        profile = self.base_profile.clone(self.base_profile.profile)

        marionette_port = get_free_port()
        profile.set_preferences({"marionette.port": marionette_port})

        env = get_environ(self.logger, self.binary, self.debug_info,
                          self.stylo_threads, self.headless,
                          self.enable_webrender, self.chaos_mode_flags)

        args = self.binary_args[:] if self.binary_args else []
        args += [cmd_arg("marionette"), "about:blank"]

        debug_args, cmd = browser_command(self.binary, args, self.debug_info)

        if self.leak_check:
            leak_report_file = os.path.join(
                profile.profile, "runtests_leaks_%s.log" % os.getpid())
            if os.path.exists(leak_report_file):
                os.remove(leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = leak_report_file
        else:
            leak_report_file = None

        output_handler = OutputHandler(self.logger, self.stackfix_dir,
                                       self.symbols_path, self.asan)
        runner = FirefoxRunner(
            profile=profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [output_handler]})
        instance = BrowserInstance(self.logger, runner, marionette_port,
                                   output_handler, leak_report_file)

        self.logger.debug("Starting Firefox")
        runner.start(debug_args=debug_args,
                     interactive=self.debug_info
                     and self.debug_info.interactive)
        self.logger.debug("Firefox Started")

        return instance
Beispiel #21
0
    def start_firefox(self):
        env = os.environ.copy()
        env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'

        profile = Profile()
        profile.set_preferences({"marionette.defaultPrefs.enabled": True,
                                 "marionette.defaultPrefs.port": self.marionette_port,
                                 "dom.disable_open_during_load": False,
                                 "dom.max_script_run_time": 0})

        self.firefox_runner = FirefoxRunner(profile,
                                            self.firefox_binary,
                                            cmdargs=["--marionette"],
                                            env=env,
                                            kp_kwargs = {"processOutputLine":[self.on_output]},
                                            process_class=self.process_cls)
        self.logger.debug("Starting Firefox")
        self.firefox_runner.start()
        self.logger.debug("Firefox Started")
Beispiel #22
0
    def start(self):
        """Start an instance of Firefox, returning a BrowserInstance handle"""
        profile = self.base_profile.clone(self.base_profile.profile)

        marionette_port = get_free_port()
        profile.set_preferences({"marionette.port": marionette_port})

        env = get_environ(self.logger, self.binary, self.debug_info,
                          self.stylo_threads, self.headless,
                          self.chaos_mode_flags)

        args = self.binary_args[:] if self.binary_args else []
        args += [cmd_arg("marionette"), "about:blank"]

        debug_args, cmd = browser_command(self.binary, args, self.debug_info)

        leak_report_file = setup_leak_report(self.leak_check, profile, env)
        output_handler = FirefoxOutputHandler(
            self.logger,
            cmd,
            stackfix_dir=self.stackfix_dir,
            symbols_path=self.symbols_path,
            asan=self.asan,
            leak_report_file=leak_report_file)
        runner = FirefoxRunner(
            profile=profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [output_handler]})
        instance = BrowserInstance(self.logger, runner, marionette_port,
                                   output_handler, leak_report_file)

        self.logger.debug("Starting Firefox")
        runner.start(debug_args=debug_args,
                     interactive=self.debug_info
                     and self.debug_info.interactive)
        output_handler.after_process_start(runner.process_handler.pid)
        self.logger.debug("Firefox Started")

        return instance
Beispiel #23
0
    def run_tests(self, test_path, options):
        reftestlist = self.getManifestPath(test_path)
        if not reftestlist.startswith('file://'):
            reftestlist = 'file://%s' % reftestlist

        self.profile = self.create_profile(options, reftestlist,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = { 'processOutputLine': [self._on_output],
                      'onTimeout': [self._on_timeout],
                      'kill_on_timeout': False }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(options.app,
                            ignore_window_size=options.ignoreWindowSize)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    symbols_path=options.symbolsPath,
                                    kp_kwargs=kp_kwargs)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d",
                     os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s",
                         self.last_test, -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status
Beispiel #24
0
    def run(self, test, phase='phase1', ignore_unused_engines=True):
        self.profile.set_preferences({
            'testing.tps.testFile':
            os.path.abspath(test),
            'testing.tps.testPhase':
            phase,
            'testing.tps.ignoreUnusedEngines':
            ignore_unused_engines,
        })
        args = ['-marionette']
        process_args = {'processOutputLine': [self._log]}
        self.logger.info('Running: {} {}'.format(self.firefox, ' '.join(args)))
        self.logger.info('Using profile at: {}'.format(self.profile.profile))
        runner = FirefoxRunner(binary=self.firefox,
                               cmdargs=args,
                               profile=self.profile,
                               process_args=process_args)
        runner.start(timeout=TIMEOUT)
        runner.wait(timeout=TIMEOUT)
        self.firefox_log.close()

        with open(self.tps_log) as f:
            for line in f.readlines():
                if 'CROSSWEAVE ERROR: ' in line:
                    raise TPSError(line.partition('CROSSWEAVE ERROR: ')[-1])

        with open(self.tps_log) as f:
            assert 'test phase {}: PASS'.format(phase) in f.read()
Beispiel #25
0
def launch_control_center():
    profile_path = os.path.join(get_core_args().workdir, 'cc_profile')
    fx_path = PathManager.get_local_firefox_path()
    if fx_path is None:
        logger.error(
            'Can\'t find local Firefox installation, aborting Iris run.')
        return False, None

    args = ['http://127.0.0.1:%s' % get_core_args().port]
    process_args = {'stream': None}
    profile = MozProfile(profile=profile_path,
                         preferences=Settings.default_fx_prefs)
    fx_runner = FirefoxRunner(binary=fx_path,
                              profile=profile,
                              cmdargs=args,
                              process_args=process_args)
    fx_runner.start()
    server = LocalWebServer(get_core_args().workdir, get_core_args().port)
    server.stop()
    time.sleep(Settings.DEFAULT_UI_DELAY)

    if OSHelper.is_mac():
        type(text='q', modifier=KeyModifier.CMD)
    elif OSHelper.is_windows():
        type(text='w', modifier=[KeyModifier.CTRL, KeyModifier.SHIFT])
    else:
        type(text='q', modifier=KeyModifier.CTRL)

    try:
        fx_runner.stop()
    except Exception as e:
        logger.debug('Error stopping fx_runner')
        logger.debug(e)

    return server.result
Beispiel #26
0
    def run(self, test, phase='phase1', ignore_unused_engines=True):
        args = [
            '-tps={}'.format(os.path.abspath(test)),
            '-tpsphase={}'.format(phase), '-marionette'
        ]
        if ignore_unused_engines:
            args.append('--ignore-unused-engines')

        process_args = {'processOutputLine': [self._log]}
        self.logger.info('Running: {} {}'.format(self.firefox, ' '.join(args)))
        self.logger.info('Using profile at: {}'.format(self.profile.profile))
        runner = FirefoxRunner(binary=self.firefox,
                               cmdargs=args,
                               profile=self.profile,
                               process_args=process_args)
        runner.start(timeout=TIMEOUT)
        runner.wait(timeout=TIMEOUT)
        self.firefox_log.close()

        with open(self.tps_log) as f:
            for line in f.readlines():
                if 'CROSSWEAVE ERROR: ' in line:
                    raise TPSError(line.partition('CROSSWEAVE ERROR: ')[-1])

        with open(self.tps_log) as f:
            assert 'test phase {}: PASS'.format(phase) in f.read()
Beispiel #27
0
def runprofile(binary, fileobj):
    try:
        runner = FirefoxRunner(binary=binary, profile=fileobj.profile)
        runner.start()
        runner.wait()
    except KeyboardInterrupt:
        pass
Beispiel #28
0
def launch_control_center():
    profile_path = os.path.join(PathManager.get_working_dir(), "cc_profile")
    fx_path = PathManager.get_local_firefox_path()
    if fx_path is None:
        logger.error("Can't find local Firefox installation, aborting Iris run.")
        return False, None

    args = ["http://127.0.0.1:%s" % get_core_args().port]
    process_args = {"stream": None}
    profile = MozProfile(profile=profile_path, preferences=get_fx_prefs())
    if OSHelper.is_windows():
        process = subprocess.Popen(
            [
                fx_path,
                "-no-remote",
                "-new-tab",
                args,
                "--wait-for-browser",
                "-foreground",
                "-profile",
                profile.profile,
            ],
            shell=False,
        )

    else:
        fx_runner = FirefoxRunner(
            binary=fx_path, profile=profile, cmdargs=args, process_args=process_args
        )
        fx_runner.start()
    logger.debug("Launching web server for directory %s" % PathManager.get_working_dir())
    server = LocalWebServer(PathManager.get_working_dir(), get_core_args().port)
    server.stop()
    time.sleep(Settings.DEFAULT_UI_DELAY)

    if OSHelper.is_mac():
        type(text="q", modifier=KeyModifier.CMD)
    elif OSHelper.is_windows():
        type(text="w", modifier=[KeyModifier.CTRL, KeyModifier.SHIFT])
    else:
        type(text="q", modifier=KeyModifier.CTRL)
    if OSHelper.is_windows():
        if process.pid is not None:
            try:
                logger.debug("Closing Firefox process ID: %s" % process.pid)
                process = psutil.Process(process.pid)
                for proc in process.children(recursive=True):
                    proc.kill()
                process.kill()
            except psutil.NoSuchProcess:
                pass
    else:
        try:
            fx_runner.stop()
        except Exception as e:
            logger.debug("Error stopping fx_runner")
            logger.debug(e)

    return server.result
Beispiel #29
0
 def run(self):
     #Run the built binary if it exists. ONLY WORKS IF BUILD WAS CALLED!
     if sys.platform == "darwin":
         runner = FirefoxRunner.create(binary=os.path.join(
             self.shellCacheDir, "mozbuild-trunk", "obj-ff-dbg", "dist",
             "NightlyDebug.app", "Contents", "MacOS") + "/firefox-bin")
         runner.start()
         runner.wait()
     elif sys.platform == "linux2":
         runner = FirefoxRunner.create(
             binary=os.path.join(self.shellCacheDir, "mozbuild-trunk",
                                 "obj-ff-dbg", "dist", "bin") + "/firefox")
         runner.start()
         runner.wait()
     elif sys.platform == "win32" or sys.platform == "cygwin":
         runner = FirefoxRunner.create(
             binary=os.path.join(self.shellCacheDir, "mozbuild-trunk",
                                 "obj-ff-dbg", "dist", "bin") +
             "/firefox.exe")
         runner.start()
         runner.wait()
     else:
         print "Your platform is not currently supported."
         quit()
Beispiel #30
0
def launch_control_center():
    profile_path = os.path.join(get_core_args().workdir, 'cc_profile')
    fx_path = PathManager.get_local_firefox_path()
    if fx_path is None:
        logger.error(
            'Can\'t find local Firefox installation, aborting Iris run.')
        return False, None

    args = ['http://127.0.0.1:%s' % get_core_args().port]
    process_args = {'stream': None}
    profile = MozProfile(profile=profile_path,
                         preferences=Settings.default_fx_prefs)
    if OSHelper.is_windows():
        process = subprocess.Popen([
            fx_path, '-no-remote', '-new-tab', args, '--wait-for-browser',
            '-foreground', '-profile', profile.profile
        ],
                                   shell=False)

    else:
        fx_runner = FirefoxRunner(binary=fx_path,
                                  profile=profile,
                                  cmdargs=args,
                                  process_args=process_args)
        fx_runner.start()

    server = LocalWebServer(get_core_args().workdir, get_core_args().port)
    server.stop()
    time.sleep(Settings.DEFAULT_UI_DELAY)

    if OSHelper.is_mac():
        type(text='q', modifier=KeyModifier.CMD)
    elif OSHelper.is_windows():
        type(text='w', modifier=[KeyModifier.CTRL, KeyModifier.SHIFT])
    else:
        type(text='q', modifier=KeyModifier.CTRL)
    if OSHelper.is_windows():
        if process.pid is not None:
            try:
                logger.debug('Closing Firefox process ID: %s' % process.pid)
                process = psutil.Process(process.pid)
                for proc in process.children(recursive=True):
                    proc.kill()
                process.kill()
            except psutil.NoSuchProcess:
                pass
    else:
        try:
            fx_runner.stop()
        except Exception as e:
            logger.debug('Error stopping fx_runner')
            logger.debug(e)

    return server.result
Beispiel #31
0
    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)
        self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.enabled": True,
                                      "marionette.port": self.marionette_port,
                                      "dom.disable_open_during_load": False,
                                      "network.dns.localDomains": ",".join(hostnames),
                                      "network.proxy.type": 0,
                                      "places.history.enabled": False})
        if self.e10s:
            self.profile.set_preferences({"browser.tabs.remote.autostart": True})

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft") and
            '5.1' in platform.version()):
            self.profile.set_preferences({"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(self.binary,
                                          self.binary_args if self.binary_args else [] +
                                          [cmd_arg("marionette"), "about:blank"],
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
Beispiel #32
0
    def run(self):
        '''
        Starts Firefox thread with Marionette turned on.
        '''
        
        self.profile = FirefoxProfile()
        self.profile.set_preferences({"marionette.defaultPrefs.enabled" : True,
                                      "marionette.defaultPrefs.port": 2828,
                                      "browser.startup.page": 0,
                                      "browser.startup.homepage": "about:blank",
                                      })
        self.runner = FirefoxRunner(profile = self.profile,
                                    binary = self.binary,
                                    kp_kwargs = {'processOutputLine' : [self.logger]})

        self.runner.start()
        self._firefoxRunningEvent.set()
        self.runner.wait()
Beispiel #33
0
        # For VC12+, make sure we can find the right bitness of pgort1x0.dll
        if not substs.get('HAVE_64BIT_BUILD'):
            for e in ('VS140COMNTOOLS', 'VS120COMNTOOLS'):
                if e not in env:
                    continue

                vcdir = os.path.abspath(os.path.join(env[e], '../../VC/bin'))
                if os.path.exists(vcdir):
                    env['PATH'] = '%s;%s' % (vcdir, env['PATH'])
                    break

        # Run Firefox a first time to initialize its profile
        runner = FirefoxRunner(profile=profile,
                               binary=build.get_binary_path(
                                   where="staged-package"),
                               cmdargs=['javascript:Quitter.quit()'],
                               env=env)
        runner.start()
        runner.wait()

        jarlog = os.getenv("JARLOG_FILE")
        if jarlog:
            env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
            print "jarlog: %s" % env["MOZ_JAR_LOG_FILE"]

        cmdargs = ["http://localhost:%d/index.html" % PORT]
        runner = FirefoxRunner(profile=profile,
                               binary=build.get_binary_path(
                                   where="staged-package"),
                               cmdargs=cmdargs,
    def valgrind_test(self, suppressions):

        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath
        from six import string_types
        from valgrind.output_handler import OutputHandler

        build_dir = os.path.join(self.topsrcdir, "build")

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, "pgo"))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            # TODO: refactor this into mozprofile
            profile_data_dir = os.path.join(self.topsrcdir, "testing",
                                            "profiles")
            with open(os.path.join(profile_data_dir, "profiles.json"),
                      "r") as fh:
                base_profiles = json.load(fh)["valgrind"]

            prefpaths = [
                os.path.join(profile_data_dir, profile, "user.js")
                for profile in base_profiles
            ]
            prefs = {}
            for path in prefpaths:
                prefs.update(Preferences.read_prefs(path))

            interpolation = {
                "server": "%s:%d" % httpd.httpd.server_address,
            }
            for k, v in prefs.items():
                if isinstance(v, string_types):
                    v = v.format(**interpolation)
                prefs[k] = Preferences.cast(v)

            quitter = os.path.join(self.topsrcdir, "tools", "quitter",
                                   "*****@*****.**")

            locations = ServerLocations()
            locations.add_host(host="127.0.0.1",
                               port=httpd.httpd.server_port,
                               options="primary")

            profile = FirefoxProfile(
                profile=profilePath,
                preferences=prefs,
                addons=[quitter],
                locations=locations,
            )

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env["G_SLICE"] = "always-malloc"
            env["MOZ_CC_RUN_DURING_SHUTDOWN"] = "1"
            env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
            env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
            env["XPCOM_DEBUG_BREAK"] = "warn"

            outputHandler = OutputHandler(self.log)
            kp_kwargs = {
                "processOutputLine": [outputHandler],
                "universal_newlines": True,
            }

            valgrind = "valgrind"
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                "--sym-offsets=yes",
                "--smc-check=all-non-file",
                "--vex-iropt-register-updates=allregs-at-mem-access",
                "--gen-suppressions=all",
                "--num-callers=36",
                "--leak-check=full",
                "--show-possibly-lost=no",
                "--track-origins=yes",
                "--trace-children=yes",
                "-v",  # Enable verbosity to get the list of used suppressions
                # Avoid excessive delays in the presence of spinlocks.
                # See bug 1309851.
                "--fair-sched=yes",
                # Keep debuginfo after library unmap.  See bug 1382280.
                "--keep-debuginfo=yes",
                # Reduce noise level on rustc and/or LLVM compiled code.
                # See bug 1365915
                "--expensive-definedness-checks=yes",
                # Compensate for the compiler inlining `new` but not `delete`
                # or vice versa.
                "--show-mismatched-frees=no",
            ]

            for s in suppressions:
                valgrind_args.append("--suppressions=" + s)

            supps_dir = os.path.join(build_dir, "valgrind")
            supps_file1 = os.path.join(supps_dir, "cross-architecture.sup")
            valgrind_args.append("--suppressions=" + supps_file1)

            if mozinfo.os == "linux":
                machtype = {
                    "x86_64": "x86_64-pc-linux-gnu",
                    "x86": "i386-pc-linux-gnu",
                }.get(mozinfo.processor)
                if machtype:
                    supps_file2 = os.path.join(supps_dir, machtype + ".sup")
                    if os.path.isfile(supps_file2):
                        valgrind_args.append("--suppressions=" + supps_file2)

            exitcode = None
            timeout = 1800
            binary_not_found_exception = None
            try:
                runner = FirefoxRunner(
                    profile=profile,
                    binary=self.get_binary_path(),
                    cmdargs=firefox_args,
                    env=env,
                    process_args=kp_kwargs,
                )
                runner.start(debug_args=valgrind_args)
                exitcode = runner.wait(timeout=timeout)
            except BinaryNotFoundException as e:
                binary_not_found_exception = e
            finally:
                errs = outputHandler.error_count
                supps = outputHandler.suppression_count
                if errs != supps:
                    status = 1  # turns the TBPL job orange
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-parsing",
                        {
                            "errs": errs,
                            "supps": supps
                        },
                        "TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {errs} errors "
                        "seen, but {supps} generated suppressions seen",
                    )

                elif errs == 0:
                    status = 0
                    self.log(
                        logging.INFO,
                        "valgrind-pass",
                        {},
                        "TEST-PASS | valgrind-test | valgrind found no errors",
                    )
                else:
                    status = 1  # turns the TBPL job orange
                    # We've already printed details of the errors.

                if binary_not_found_exception:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-errors",
                        {"error": str(binary_not_found_exception)},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | {error}",
                    )
                    self.log(
                        logging.INFO,
                        "valgrind-fail-errors",
                        {"help": binary_not_found_exception.help()},
                        "{help}",
                    )
                elif exitcode is None:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-timeout",
                        {"timeout": timeout},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out "
                        "(reached {timeout} second limit)",
                    )
                elif exitcode != 0:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-errors",
                        {"exitcode": exitcode},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code "
                        "from Valgrind: {exitcode}",
                    )

                httpd.stop()

            return status
                             preferences=prefs,
                             addons=[os.path.join(build.distdir, 'xpi-stage', 'quitter')],
                             locations=locations)

    env = os.environ.copy()
    env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
    env["XPCOM_DEBUG_BREAK"] = "warn"

    # For VC12, make sure we can find the right bitness of pgort120.dll
    if "VS120COMNTOOLS" in env and not substs["HAVE_64BIT_OS"]:
      vc12dir = os.path.abspath(os.path.join(env["VS120COMNTOOLS"],
                                             "../../VC/bin"))
      if os.path.exists(vc12dir):
        env["PATH"] = vc12dir + ";" + env["PATH"]

    jarlog = os.getenv("JARLOG_FILE")
    if jarlog:
      env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
      print "jarlog: %s" % env["MOZ_JAR_LOG_FILE"]

    cmdargs = ["http://localhost:%d/index.html" % PORT]
    runner = FirefoxRunner(profile=profile,
                           binary=build.get_binary_path(where="staged-package"),
                           cmdargs=cmdargs,
                           env=env)
    runner.start(debug_args=debug_args, interactive=interactive)
    runner.wait()
    httpd.stop()
  finally:
    shutil.rmtree(profilePath)
Beispiel #36
0
class B2GDesktopReftest(RefTest):
    marionette = None

    def __init__(self, marionette_args):
        RefTest.__init__(self)
        self.last_test = os.path.basename(__file__)
        self.marionette_args = marionette_args
        self.profile = None
        self.runner = None
        self.test_script = os.path.join(here, 'b2g_start_script.js')
        self.timeout = None

    def run_marionette_script(self):
        self.marionette = Marionette(**self.marionette_args)
        assert (self.marionette.wait_for_port())
        self.marionette.start_session()
        self.marionette.set_context(self.marionette.CONTEXT_CHROME)

        if os.path.isfile(self.test_script):
            f = open(self.test_script, 'r')
            self.test_script = f.read()
            f.close()
        self.marionette.execute_script(self.test_script)

    def run_tests(self, test_path, options):
        reftestlist = self.getManifestPath(test_path)
        if not reftestlist.startswith('file://'):
            reftestlist = 'file://%s' % reftestlist

        self.profile = self.create_profile(options,
                                           reftestlist,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = {
            'processOutputLine': [self._on_output],
            'onTimeout': [self._on_timeout],
            'kill_on_timeout': False
        }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(
            options.app,
            ignore_window_size=options.ignoreWindowSize,
            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d", os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s", self.last_test,
                     -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status

    def create_profile(self, options, reftestlist, profile_to_clone=None):
        profile = RefTest.createReftestProfile(
            self, options, reftestlist, profile_to_clone=profile_to_clone)

        prefs = {}
        # Turn off the locale picker screen
        prefs["browser.firstrun.show.localepicker"] = False
        prefs[
            "b2g.system_startup_url"] = "app://test-container.gaiamobile.org/index.html"
        prefs[
            "b2g.system_manifest_url"] = "app://test-container.gaiamobile.org/manifest.webapp"
        prefs["browser.tabs.remote"] = False
        prefs["dom.ipc.tabs.disabled"] = False
        prefs["dom.mozBrowserFramesEnabled"] = True
        prefs["font.size.inflation.emPerLine"] = 0
        prefs["font.size.inflation.minTwips"] = 0
        prefs[
            "network.dns.localDomains"] = "app://test-container.gaiamobile.org"
        prefs["reftest.browser.iframe.enabled"] = False
        prefs["reftest.remote"] = False
        prefs["reftest.uri"] = "%s" % reftestlist
        # Set a future policy version to avoid the telemetry prompt.
        prefs["toolkit.telemetry.prompted"] = 999
        prefs["toolkit.telemetry.notifiedOptOut"] = 999

        # Set the extra prefs.
        profile.set_preferences(prefs)
        return profile

    def build_command_line(self,
                           app,
                           ignore_window_size=False,
                           browser_arg=None):
        cmd = os.path.abspath(app)
        args = ['-marionette']

        if browser_arg:
            args += [browser_arg]

        if not ignore_window_size:
            args.extend(['--screen', '800x1000'])
        return cmd, args

    def _on_output(self, line):
        print(line)
        # TODO use structured logging
        if "TEST-START" in line and "|" in line:
            self.last_test = line.split("|")[1].strip()

    def _on_timeout(self):
        msg = "%s | application timed out after %s seconds with no output"
        log.testFail(msg % (self.last_test, self.timeout))

        # kill process to get a stack
        self.runner.stop(sig=signal.SIGABRT)
Beispiel #37
0
class FirefoxBrowser(Browser):
    used_ports = set()
    init_timeout = 60
    shutdown_timeout = 60

    def __init__(self,
                 logger,
                 binary,
                 prefs_root,
                 test_type,
                 extra_prefs=None,
                 debug_info=None,
                 symbols_path=None,
                 stackwalk_binary=None,
                 certutil_binary=None,
                 ca_certificate_path=None,
                 e10s=False,
                 stackfix_dir=None,
                 binary_args=None,
                 timeout_multiplier=None,
                 leak_check=False,
                 stylo_threads=1,
                 chaos_mode_flags=None):
        Browser.__init__(self, logger)
        self.binary = binary
        self.prefs_root = prefs_root
        self.test_type = test_type
        self.extra_prefs = extra_prefs
        self.marionette_port = None
        self.runner = None
        self.debug_info = debug_info
        self.profile = None
        self.symbols_path = symbols_path
        self.stackwalk_binary = stackwalk_binary
        self.ca_certificate_path = ca_certificate_path
        self.certutil_binary = certutil_binary
        self.e10s = e10s
        self.binary_args = binary_args
        if stackfix_dir:
            self.stack_fixer = get_stack_fixer_function(
                stackfix_dir, self.symbols_path)
        else:
            self.stack_fixer = None

        if timeout_multiplier:
            self.init_timeout = self.init_timeout * timeout_multiplier

        self.leak_report_file = None
        self.leak_check = leak_check
        self.stylo_threads = stylo_threads
        self.chaos_mode_flags = chaos_mode_flags

    def settings(self, test):
        return {"check_leaks": self.leak_check and not test.leaks}

    def start(self, **kwargs):
        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)

        locations = ServerLocations(
            filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({
            "marionette.port":
            self.marionette_port,
            "dom.disable_open_during_load":
            False,
            "network.dns.localDomains":
            ",".join(hostnames),
            "network.proxy.type":
            0,
            "places.history.enabled":
            False,
            "dom.send_after_paint_to_content":
            True,
            "network.preload":
            True
        })
        if self.e10s:
            self.profile.set_preferences(
                {"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences(
                {"layout.interruptible-reflow.enabled": False})

        if self.leak_check and kwargs.get("check_leaks", True):
            self.leak_report_file = os.path.join(self.profile.profile,
                                                 "runtests_leaks.log")
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft")
                and '5.1' in platform.version()):
            self.profile.set_preferences(
                {"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(
            self.binary, self.binary_args if self.binary_args else [] +
            [cmd_arg("marionette"), "about:blank"], self.debug_info)

        self.runner = FirefoxRunner(
            profile=self.profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args,
                          interactive=self.debug_info
                          and self.debug_info.interactive)
        self.logger.debug("Firefox Started")

    def load_prefs(self):
        prefs = Preferences()

        prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
        if os.path.exists(prefs_path):
            prefs.add(Preferences.read_prefs(prefs_path))
        else:
            self.logger.warning("Failed to find base prefs file in %s" %
                                prefs_path)

        # Add any custom preferences
        prefs.add(self.extra_prefs, cast=True)

        return prefs()

    def stop(self, force=False):
        if self.runner is not None and self.runner.is_running():
            try:
                # For Firefox we assume that stopping the runner prompts the
                # browser to shut down. This allows the leak log to be written
                for clean, stop_f in [
                    (True, lambda: self.runner.wait(self.shutdown_timeout)),
                    (False, lambda: self.runner.stop(signal.SIGTERM)),
                    (False, lambda: self.runner.stop(signal.SIGKILL))
                ]:
                    if not force or not clean:
                        retcode = stop_f()
                        if retcode is not None:
                            self.logger.info(
                                "Browser exited with return code %s" % retcode)
                            break
            except OSError:
                # This can happen on Windows if the process is already dead
                pass
        self.logger.debug("stopped")

    def process_leaks(self):
        self.logger.debug("PROCESS LEAKS %s" % self.leak_report_file)
        if self.leak_report_file is None:
            return
        mozleak.process_leak_log(
            self.leak_report_file,
            leak_thresholds={
                "default": 0,
                "tab": 10000,  # See dependencies of bug 1051230.
                # GMP rarely gets a log, but when it does, it leaks a little.
                "geckomediaplugin": 20000,
            },
            ignore_missing_leaks=["geckomediaplugin"],
            log=self.logger,
            stack_fixer=self.stack_fixer)

    def pid(self):
        if self.runner.process_handler is None:
            return None

        try:
            return self.runner.process_handler.pid
        except AttributeError:
            return None

    def on_output(self, line):
        """Write a line of output from the firefox process to the log"""
        data = line.decode("utf8", "replace")
        if self.stack_fixer:
            data = self.stack_fixer(data)
        self.logger.process_output(self.pid(),
                                   data,
                                   command=" ".join(self.runner.command))

    def is_alive(self):
        if self.runner:
            return self.runner.is_running()
        return False

    def cleanup(self):
        self.stop()
        self.process_leaks()

    def executor_browser(self):
        assert self.marionette_port is not None
        return ExecutorBrowser, {"marionette_port": self.marionette_port}

    def check_for_crashes(self):
        dump_dir = os.path.join(self.profile.profile, "minidumps")

        return bool(
            mozcrash.check_for_crashes(dump_dir,
                                       symbols_path=self.symbols_path,
                                       stackwalk_binary=self.stackwalk_binary,
                                       quiet=True))

    def log_crash(self, process, test):
        dump_dir = os.path.join(self.profile.profile, "minidumps")

        mozcrash.log_crashes(self.logger,
                             dump_dir,
                             symbols_path=self.symbols_path,
                             stackwalk_binary=self.stackwalk_binary,
                             process=process,
                             test=test)

    def setup_ssl(self):
        """Create a certificate database to use in the test profile. This is configured
        to trust the CA Certificate that has signed the web-platform.test server
        certificate."""
        if self.certutil_binary is None:
            self.logger.info(
                "--certutil-binary not supplied; Firefox will not check certificates"
            )
            return

        self.logger.info("Setting up ssl")

        # Make sure the certutil libraries from the source tree are loaded when using a
        # local copy of certutil
        # TODO: Maybe only set this if certutil won't launch?
        env = os.environ.copy()
        certutil_dir = os.path.dirname(self.binary)
        if mozinfo.isMac:
            env_var = "DYLD_LIBRARY_PATH"
        elif mozinfo.isUnix:
            env_var = "LD_LIBRARY_PATH"
        else:
            env_var = "PATH"

        env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]])
                        if env_var in env else certutil_dir).encode(
                            sys.getfilesystemencoding() or 'utf-8', 'replace')

        def certutil(*args):
            cmd = [self.certutil_binary] + list(args)
            self.logger.process_output(
                "certutil",
                subprocess.check_output(cmd, env=env,
                                        stderr=subprocess.STDOUT),
                " ".join(cmd))

        pw_path = os.path.join(self.profile.profile, ".crtdbpw")
        with open(pw_path, "w") as f:
            # Use empty password for certificate db
            f.write("\n")

        cert_db_path = self.profile.profile

        # Create a new certificate db
        certutil("-N", "-d", cert_db_path, "-f", pw_path)

        # Add the CA certificate to the database and mark as trusted to issue server certs
        certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,", "-n",
                 "web-platform-tests", "-i", self.ca_certificate_path)

        # List all certs in the database
        certutil("-L", "-d", cert_db_path)
        env["XPCOM_DEBUG_BREAK"] = "warn"

        # For VC12+, make sure we can find the right bitness of pgort1x0.dll
        if not substs.get('HAVE_64BIT_BUILD'):
            for e in ('VS140COMNTOOLS', 'VS120COMNTOOLS'):
                if e not in env:
                    continue

                vcdir = os.path.abspath(os.path.join(env[e], '../../VC/bin'))
                if os.path.exists(vcdir):
                    env['PATH'] = '%s;%s' % (vcdir, env['PATH'])
                    break

        # Run Firefox a first time to initialize its profile
        runner = FirefoxRunner(profile=profile,
                               binary=binary,
                               cmdargs=['data:text/html,<script>Quitter.quit()</script>'],
                               env=env)
        runner.start()
        ret = runner.wait()
        if ret:
            print("Firefox exited with code %d during profile initialization"
                  % ret)
            httpd.stop()
            sys.exit(ret)

        jarlog = os.getenv("JARLOG_FILE")
        if jarlog:
            env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
            print("jarlog: %s" % env["MOZ_JAR_LOG_FILE"])

        cmdargs = ["http://localhost:%d/index.html" % PORT]
Beispiel #39
0
    def bisectRecurse(self, testcondition=None, args_for_condition=[]):
        #Recursively build, run, and prompt
        verdict = ""
        current_revision = captureStdout(self.hgPrefix + ["id", "-i"])

        if self.remote:
            print "on current revision " + current_revision
            print "This would ask for a remote changeset, but it's not implemented yet."
            #TODO:
            #Remote bisection!
            #Step 1. Check if revision is in the archive
            #Step 2. If revision is not in the archive, set remote=False and continue (it will build and bisect that revision)
            #if not check_archived:
            #    set remote false and continue
            #else:
            #Step 3. If the revision is in the archive, download it and its corresponding tests
            #STEP3
            #1. Extract tests into some directory
            #2. Extract Nightly.app into "tests"
            #MozInstaller(src=, dest="", dest_app="Nightly.app")
            #3. run the following:
            #test_command = ['python', 'mochitest/runtests.py', '--appname=./Nightly.app/Contents/MacOS/firefox-bin', '--utility-path=bin', '--extra-profile-file=bin/plugins', '--certificate-path=certs', '--autorun', '--close-when-done', '--console-level=INFO', '--test-path=test_name']
            #output = captureStdout(test_command, ignoreStderr=True)
            #set verdict based on output
            #python mochitest/runtests.py --appname=./Nightly.app/Contents/MacOS/firefox-bin --utility-path=bin --extra-profile-file=bin/plugins --certificate-path=certs --autorun --close-when-done --console-level=INFO --test-path=test_name

            #example test name: Harness_sanity/test_sanityException.html
            #Step 4. Run and run test to get verdict
            #Step 5. Set verdict

        elif self.tryPusher:
            try:
                caller = BuildCaller(host=self.tryhost,
                                     port=int(self.tryport),
                                     data=current_revision)
                print "Getting revision " + current_revision + "..."
            except:
                print "Failed to connect to trypusher. Make sure your settings are correct and that the trypusher server was started."
                exit()
            response = caller.getChangeset()
            print "Waiting on Mozilla Pulse for revision " + response + "..."
            url = caller.getURLResponse(response)
            print "the base is " + url_base(url)
            #Download it here
            #1. Download from url, extract to same place as tests
            #2. Run test or start browser.
            binary_path = os.path.join(self.binaryDir, url_base(url))
            downloaded_binary = download_url(url, dest=str(binary_path))
            MozInstaller(src=str(binary_path),
                         dest=str(self.testDir),
                         dest_app="Nightly.app")
            #now nightly is installed in
            if sys.platform == "darwin":
                binary_path = os.path.join(self.testDir, "Nightly.app")
                runner = FirefoxRunner.create(
                    binary=os.path.join(binary_path, "Contents", "MacOS") +
                    "/firefox-bin")
            elif sys.platform == "linux2":
                binary_path = os.path.join(self.testDir, "firefox")
                runner = FirefoxRunner.create(binary=binary_path)
            elif sys.platform == "win32" or sys.platform == "cygwin":
                binary_path = os.path.join(self.testDir, "firefox.exe")
                runner = FirefoxRunner.create(binary=binary_path)
            else:
                print "Your platform is not currently supported."
                quit()

            dest = runner.start()
            if not dest:
                print "Failed to start the downloaded binary"
                verdict == "skip"
            runner.wait()
            if verdict == "skip":
                pass
            elif testcondition != None:
                #Support condition scripts where arg0 is the directory with the binary and tests
                args_to_pass = [self.testDir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass, tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"
        else:
            try:
                self.build()
            except Exception:
                print "This build failed!"
                verdict = "skip"

            if verdict == "skip":
                pass
            elif testcondition == None:
                #Not using a test, interactive bisect begin!
                self.run()
            else:
                #Using Jesse's idea: import any testing script and run it as the truth condition
                args_to_pass = [self.objdir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass, tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"

        while verdict not in ["good", "bad", "skip"]:
            verdict = raw_input(
                "Was this commit good or bad? (type 'good', 'bad', or 'skip'): "
            )
            if verdict == 'g':
                verdict = "good"
            if verdict == 'b':
                verdict = "bad"
            if verdict == 's':
                verdict = "skip"

        # do hg bisect --good, --bad, or --skip
        verdictCommand = self.hgPrefix + ["bisect", "--" + verdict]
        print " ".join(verdictCommand)
        retval = captureStdout(verdictCommand)

        string_to_parse = str(retval)
        print string_to_parse

        self.check_done(string_to_parse)

        if retval.startswith("Testing changeset"):
            print "\n"

        self.bisectRecurse(testcondition=testcondition,
                           args_for_condition=args_for_condition)
Beispiel #40
0
    def valgrind_test(self, suppressions):
        import json
        import re
        import sys
        import tempfile

        from mozbuild.base import MozbuildObject
        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath

        build_dir = os.path.join(self.topsrcdir, "build")

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, "pgo"))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            # TODO: refactor this into mozprofile
            prefpath = os.path.join(self.topsrcdir, "testing", "profiles", "prefs_general.js")
            prefs = {}
            prefs.update(Preferences.read_prefs(prefpath))
            interpolation = {"server": "%s:%d" % httpd.httpd.server_address, "OOP": "false"}
            prefs = json.loads(json.dumps(prefs) % interpolation)
            for pref in prefs:
                prefs[pref] = Preferences.cast(prefs[pref])

            quitter = os.path.join(self.distdir, "xpi-stage", "quitter")

            locations = ServerLocations()
            locations.add_host(host="127.0.0.1", port=httpd.httpd.server_port, options="primary")

            profile = FirefoxProfile(profile=profilePath, preferences=prefs, addons=[quitter], locations=locations)

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env["G_SLICE"] = "always-malloc"
            env["XPCOM_CC_RUN_DURING_SHUTDOWN"] = "1"
            env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
            env["XPCOM_DEBUG_BREAK"] = "warn"

            class OutputHandler(object):
                def __init__(self):
                    self.found_errors = False

                def __call__(self, line):
                    print(line)
                    m = re.match(r".*ERROR SUMMARY: [1-9]\d* errors from \d+ contexts", line)
                    if m:
                        self.found_errors = True

            outputHandler = OutputHandler()
            kp_kwargs = {"processOutputLine": [outputHandler]}

            valgrind = "valgrind"
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                "--smc-check=all-non-file",
                "--vex-iropt-register-updates=allregs-at-mem-access",
                "--gen-suppressions=all",
                "--num-callers=20",
                "--leak-check=full",
                "--show-possibly-lost=no",
                "--track-origins=yes",
            ]

            for s in suppressions:
                valgrind_args.append("--suppressions=" + s)

            supps_dir = os.path.join(build_dir, "valgrind")
            supps_file1 = os.path.join(supps_dir, "cross-architecture.sup")
            valgrind_args.append("--suppressions=" + supps_file1)

            # MACHTYPE is an odd bash-only environment variable that doesn't
            # show up in os.environ, so we have to get it another way.
            machtype = subprocess.check_output(["bash", "-c", "echo $MACHTYPE"]).rstrip()
            supps_file2 = os.path.join(supps_dir, machtype + ".sup")
            if os.path.isfile(supps_file2):
                valgrind_args.append("--suppressions=" + supps_file2)

            exitcode = None
            try:
                runner = FirefoxRunner(
                    profile=profile, binary=self.get_binary_path(), cmdargs=firefox_args, env=env, kp_kwargs=kp_kwargs
                )
                runner.start(debug_args=valgrind_args)
                exitcode = runner.wait()

            finally:
                if not outputHandler.found_errors:
                    status = 0
                    print("TEST-PASS | valgrind-test | valgrind found no errors")
                else:
                    status = 1  # turns the TBPL job orange
                    print("TEST-UNEXPECTED-FAIL | valgrind-test | valgrind found errors")

                if exitcode != 0:
                    status = 2  # turns the TBPL job red
                    print("TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code from Valgrind")

                httpd.stop()

            return status
Beispiel #41
0
    def start(self, group_metadata=None, **kwargs):
        if group_metadata is None:
            group_metadata = {}

        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        if self.asan:
            print "Setting up LSAN"
            self.lsan_handler = mozleak.LSANLeaks(
                self.logger,
                scope=group_metadata.get("scope", "/"),
                allowed=self.lsan_allowed,
                maxNumRecordedFrames=self.lsan_max_stack_depth)

        env = test_environment(xrePath=os.path.dirname(self.binary),
                               debugger=self.debug_info is not None,
                               log=self.logger,
                               lsanPath=self.prefs_root)

        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
        if self.headless:
            env["MOZ_HEADLESS"] = "1"

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(preferences=preferences)
        self.profile.set_preferences({
            "marionette.port":
            self.marionette_port,
            "network.dns.localDomains":
            ",".join(self.config.domains_set),
            "dom.file.createInChild":
            True,
            # TODO: Remove preferences once Firefox 64 is stable (Bug 905404)
            "network.proxy.type":
            0,
            "places.history.enabled":
            False,
            "network.preload":
            True,
        })
        if self.e10s:
            self.profile.set_preferences(
                {"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences(
                {"layout.interruptible-reflow.enabled": False})

        if self.leak_check:
            self.leak_report_file = os.path.join(
                self.profile.profile, "runtests_leaks_%s.log" % os.getpid())
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft")
                and '5.1' in platform.version()):
            self.profile.set_preferences(
                {"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        args = self.binary_args[:] if self.binary_args else []
        args += [cmd_arg("marionette"), "about:blank"]

        debug_args, cmd = browser_command(self.binary, args, self.debug_info)

        self.runner = FirefoxRunner(
            profile=self.profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args,
                          interactive=self.debug_info
                          and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
Beispiel #42
0
class FirefoxBrowser(Browser):
    used_ports = set()

    def __init__(self, logger, binary, prefs_root, debug_args=None, interactive=None,
                 symbols_path=None, stackwalk_binary=None):
        Browser.__init__(self, logger)
        self.binary = binary
        self.prefs_root = prefs_root
        self.marionette_port = None
        self.used_ports.add(self.marionette_port)
        self.runner = None
        self.debug_args = debug_args
        self.interactive = interactive
        self.profile = None
        self.symbols_path = symbols_path
        self.stackwalk_binary = stackwalk_binary

    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        ports = {"http": "8000",
                 "https": "8443",
                 "ws": "8888"}

        self.profile = FirefoxProfile(locations=locations,
                                      proxy=ports,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
                                      "marionette.defaultPrefs.port": self.marionette_port,
                                      "dom.disable_open_during_load": False})

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=self.binary,
                                    cmdargs=[cmd_arg("marionette"), "about:blank"],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")
        self.runner.start(debug_args=self.debug_args, interactive=self.interactive)
        self.logger.debug("Firefox Started")

    def load_prefs(self):
        prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
        if os.path.exists(prefs_path):
            preferences = Preferences.read_prefs(prefs_path)
        else:
            self.logger.warning("Failed to find base prefs file in %s" % prefs_path)
            preferences = []

        return preferences

    def stop(self):
        self.logger.debug("Stopping browser")
        if self.runner is not None:
            try:
                self.runner.stop()
            except OSError:
                # This can happen on Windows if the process is already dead
                pass

    def pid(self):
        if self.runner.process_handler is None:
            return None

        try:
            return self.runner.process_handler.pid
        except AttributeError:
            return None

    def on_output(self, line):
        """Write a line of output from the firefox process to the log"""
        self.logger.process_output(self.pid(),
                                   line.decode("utf8", "replace"),
                                   command=" ".join(self.runner.command))

    def is_alive(self):
        if self.runner:
            return self.runner.is_running()
        return False

    def cleanup(self):
        self.stop()

    def executor_browser(self):
        assert self.marionette_port is not None
        return ExecutorBrowser, {"marionette_port": self.marionette_port}

    def log_crash(self, process, test):
        dump_dir = os.path.join(self.profile.profile, "minidumps")
        mozcrash.log_crashes(self.logger, dump_dir, symbols_path=self.symbols_path,
                             stackwalk_binary=self.stackwalk_binary,
                             process=process, test=test)
Beispiel #43
0
    def start(self, group_metadata=None, **kwargs):
        if group_metadata is None:
            group_metadata = {}

        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        if self.asan:
            print "Setting up LSAN"
            self.lsan_handler = mozleak.LSANLeaks(self.logger,
                                                  scope=group_metadata.get("scope", "/"),
                                                  allowed=self.lsan_allowed,
                                                  maxNumRecordedFrames=self.lsan_max_stack_depth)

        env = test_environment(xrePath=os.path.dirname(self.binary),
                               debugger=self.debug_info is not None,
                               log=self.logger,
                               lsanPath=self.prefs_root)

        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
        if self.headless:
            env["MOZ_HEADLESS"] = "1"

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(preferences=preferences)
        self.profile.set_preferences({
            "marionette.port": self.marionette_port,
            "network.dns.localDomains": ",".join(self.config.domains_set),
            "dom.file.createInChild": True,
            # TODO: Remove preferences once Firefox 64 is stable (Bug 905404)
            "network.proxy.type": 0,
            "places.history.enabled": False,
            "network.preload": True,
        })
        if self.e10s:
            self.profile.set_preferences({"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences({"layout.interruptible-reflow.enabled": False})

        if self.leak_check:
            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks_%s.log" % os.getpid())
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft") and
            '5.1' in platform.version()):
            self.profile.set_preferences({"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        args = self.binary_args[:] if self.binary_args else []
        args += [cmd_arg("marionette"), "about:blank"]

        debug_args, cmd = browser_command(self.binary,
                                          args,
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
class TPSFirefoxRunner(object):

  PROCESS_TIMEOUT = 240

  def __init__(self, binary):
    if binary is not None and ('http://' in binary or 'ftp://' in binary):
      self.url = binary
      self.binary = None
    else:
      self.url = None
      self.binary = binary
    self.runner = None
    self.installdir = None

  def __del__(self):
    if self.installdir:
      shutil.rmtree(self.installdir, True)

  def download_build(self, installdir='downloadedbuild',
                     appname='firefox', macAppName='Minefield.app'):
    self.installdir = os.path.abspath(installdir)
    buildName = os.path.basename(self.url)
    pathToBuild = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                               buildName)

    # delete the build if it already exists
    if os.access(pathToBuild, os.F_OK):
      os.remove(pathToBuild)

    # download the build
    print "downloading build"
    download_url(self.url, pathToBuild)

    # install the build
    print "installing %s" % pathToBuild
    shutil.rmtree(self.installdir, True)
    MozInstaller(src=pathToBuild, dest=self.installdir, dest_app=macAppName)

    # remove the downloaded archive
    os.remove(pathToBuild)

    # calculate path to binary
    platform = get_platform()
    if platform['name'] == 'Mac':
      binary = '%s/%s/Contents/MacOS/%s-bin' % (installdir,
                                                macAppName,
                                                appname)
    else:
      binary = '%s/%s/%s%s' % (installdir,
                               appname,
                               appname,
                               '.exe' if platform['name'] == 'Windows' else '')

    return binary

  def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
    """Runs the given FirefoxRunner with the given Profile, waits
       for completion, then returns the process exit code
    """
    if profile is None:
      profile = Profile()
    self.profile = profile

    if self.binary is None and self.url:
      self.binary = self.download_build()

    if self.runner is None:
      self.runner = FirefoxRunner(self.profile, binary=self.binary)

    self.runner.profile = self.profile

    if env is not None:
      self.runner.env.update(env)

    if args is not None:
      self.runner.cmdargs = copy.copy(args)

    self.runner.start()

    status = self.runner.process_handler.waitForFinish(timeout=timeout)

    return status
Beispiel #45
0
class B2GDesktopReftest(RefTest):
    build_type = "desktop"
    marionette = None

    def __init__(self, marionette_args):
        RefTest.__init__(self)
        self.last_test = os.path.basename(__file__)
        self.marionette_args = marionette_args
        self.profile = None
        self.runner = None
        self.test_script = os.path.join(here, 'b2g_start_script.js')
        self.timeout = None

    def run_marionette_script(self):
        self.marionette = Marionette(**self.marionette_args)
        assert(self.marionette.wait_for_port())
        self.marionette.start_session()
        if self.build_type == "mulet":
            self._wait_for_homescreen(timeout=300)
            self._unlockScreen()
        self.marionette.set_context(self.marionette.CONTEXT_CHROME)

        if os.path.isfile(self.test_script):
            f = open(self.test_script, 'r')
            self.test_script = f.read()
            f.close()
        self.marionette.execute_script(self.test_script)

    def run_tests(self, tests, options):
        manifests = self.resolver.resolveManifests(options, tests)

        self.profile = self.create_profile(options, manifests,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = { 'processOutputLine': [self._on_output],
                      'onTimeout': [self._on_timeout],
                      'kill_on_timeout': False }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(options.app,
                            ignore_window_size=options.ignoreWindowSize,
                            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d",
                     os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s",
                         self.last_test, -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status

    def create_profile(self, options, manifests, profile_to_clone=None):
        profile = RefTest.createReftestProfile(self, options, manifests,
                                               profile_to_clone=profile_to_clone)

        prefs = {}
        # Turn off the locale picker screen
        prefs["browser.firstrun.show.localepicker"] = False
        if not self.build_type == "mulet":
            # FIXME: With Mulet we can't set this values since Gaia won't launch
            prefs["b2g.system_startup_url"] = \
                    "app://test-container.gaiamobile.org/index.html"
            prefs["b2g.system_manifest_url"] = \
                    "app://test-container.gaiamobile.org/manifest.webapp"
        # Make sure we disable system updates
        prefs["app.update.enabled"] = False
        prefs["app.update.url"] = ""
        prefs["app.update.url.override"] = ""
        # Disable webapp updates
        prefs["webapps.update.enabled"] = False
        # Disable tiles also
        prefs["browser.newtabpage.directory.source"] = ""
        prefs["browser.newtabpage.directory.ping"] = ""
        prefs["dom.ipc.tabs.disabled"] = False
        prefs["dom.mozBrowserFramesEnabled"] = True
        prefs["font.size.inflation.emPerLine"] = 0
        prefs["font.size.inflation.minTwips"] = 0
        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
        prefs["reftest.browser.iframe.enabled"] = False
        prefs["reftest.remote"] = False
        # Set a future policy version to avoid the telemetry prompt.
        prefs["toolkit.telemetry.prompted"] = 999
        prefs["toolkit.telemetry.notifiedOptOut"] = 999
        # Disable periodic updates of service workers
        prefs["dom.serviceWorkers.periodic-updates.enabled"] = False

        # Set the extra prefs.
        profile.set_preferences(prefs)
        return profile

    def build_command_line(self, app, ignore_window_size=False,
                           browser_arg=None):
        cmd = os.path.abspath(app)
        args = ['-marionette']

        if browser_arg:
            args += [browser_arg]

        if not ignore_window_size:
            args.extend(['--screen', '800x1000'])

        if self.build_type == "mulet":
            args += ['-chrome', 'chrome://b2g/content/shell.html']
        return cmd, args

    def _on_output(self, line):
        sys.stdout.write("%s\n" % line)
        sys.stdout.flush()

        # TODO use structured logging
        if "TEST-START" in line and "|" in line:
            self.last_test = line.split("|")[1].strip()

    def _on_timeout(self):
        msg = "%s | application timed out after %s seconds with no output"
        log.testFail(msg % (self.last_test, self.timeout))

        # kill process to get a stack
        self.runner.stop(sig=signal.SIGABRT)
class MuletReftest(RefTest):
    build_type = "mulet"
    marionette = None

    def __init__(self, marionette_args):
        RefTest.__init__(self)
        self.last_test = os.path.basename(__file__)
        self.marionette_args = marionette_args
        self.profile = None
        self.runner = None
        self.test_script = os.path.join(here, 'b2g_start_script.js')
        self.timeout = None

    def run_marionette_script(self):
        self.marionette = Marionette(**self.marionette_args)
        assert (self.marionette.wait_for_port())
        self.marionette.start_session()
        if self.build_type == "mulet":
            self._wait_for_homescreen(timeout=300)
            self._unlockScreen()
        self.marionette.set_context(self.marionette.CONTEXT_CHROME)

        if os.path.isfile(self.test_script):
            f = open(self.test_script, 'r')
            self.test_script = f.read()
            f.close()
        self.marionette.execute_script(self.test_script)

    def run_tests(self, tests, options):
        manifests = self.resolver.resolveManifests(options, tests)

        self.profile = self.create_profile(options,
                                           manifests,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = {
            'processOutputLine': [self._on_output],
            'onTimeout': [self._on_timeout],
            'kill_on_timeout': False
        }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(
            options.app,
            ignore_window_size=options.ignoreWindowSize,
            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d", os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s", self.last_test,
                     -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status

    def create_profile(self, options, manifests, profile_to_clone=None):
        profile = RefTest.createReftestProfile(
            self, options, manifests, profile_to_clone=profile_to_clone)

        prefs = {}
        # Turn off the locale picker screen
        prefs["browser.firstrun.show.localepicker"] = False
        if not self.build_type == "mulet":
            # FIXME: With Mulet we can't set this values since Gaia won't launch
            prefs["b2g.system_startup_url"] = \
                    "app://test-container.gaiamobile.org/index.html"
            prefs["b2g.system_manifest_url"] = \
                    "app://test-container.gaiamobile.org/manifest.webapp"
        # Make sure we disable system updates
        prefs["app.update.enabled"] = False
        prefs["app.update.url"] = ""
        prefs["app.update.url.override"] = ""
        # Disable webapp updates
        prefs["webapps.update.enabled"] = False
        # Disable tiles also
        prefs["browser.newtabpage.directory.source"] = ""
        prefs["browser.newtabpage.directory.ping"] = ""
        prefs["dom.ipc.tabs.disabled"] = False
        prefs["dom.mozBrowserFramesEnabled"] = True
        prefs["font.size.inflation.emPerLine"] = 0
        prefs["font.size.inflation.minTwips"] = 0
        prefs[
            "network.dns.localDomains"] = "app://test-container.gaiamobile.org"
        prefs["reftest.browser.iframe.enabled"] = False
        prefs["reftest.remote"] = False
        # Set a future policy version to avoid the telemetry prompt.
        prefs["toolkit.telemetry.prompted"] = 999
        prefs["toolkit.telemetry.notifiedOptOut"] = 999

        # Set the extra prefs.
        profile.set_preferences(prefs)
        return profile

    def build_command_line(self,
                           app,
                           ignore_window_size=False,
                           browser_arg=None):
        cmd = os.path.abspath(app)
        args = ['-marionette']

        if browser_arg:
            args += [browser_arg]

        if not ignore_window_size:
            args.extend(['--screen', '800x1000'])

        if self.build_type == "mulet":
            args += ['-chrome', 'chrome://b2g/content/shell.html']
        return cmd, args

    def _on_output(self, line):
        sys.stdout.write("%s\n" % line)
        sys.stdout.flush()

        # TODO use structured logging
        if "TEST-START" in line and "|" in line:
            self.last_test = line.split("|")[1].strip()

    def _on_timeout(self):
        msg = "%s | application timed out after %s seconds with no output"
        log.testFail(msg % (self.last_test, self.timeout))

        # kill process to get a stack
        self.runner.stop(sig=signal.SIGABRT)

    def _unlockScreen(self):
        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
        self.marionette.import_script(
            os.path.abspath(
                os.path.join(__file__, os.path.pardir, "gaia_lock_screen.js")))
        self.marionette.switch_to_frame()
        self.marionette.execute_async_script('GaiaLockScreen.unlock()')

    def _wait_for_homescreen(self, timeout):
        log.info("Waiting for home screen to load")
        Wait(self.marionette, timeout).until(
            expected.element_present(By.CSS_SELECTOR,
                                     '#homescreen[loading-state=false]'))
Beispiel #47
0
class B2GDesktopReftest(RefTest):
    def __init__(self, marionette):
        RefTest.__init__(self)
        self.last_test = os.path.basename(__file__)
        self.marionette = marionette
        self.profile = None
        self.runner = None
        self.test_script = os.path.join(here, 'b2g_start_script.js')
        self.timeout = None

    def run_marionette_script(self):
        assert(self.marionette.wait_for_port())
        self.marionette.start_session()
        self.marionette.set_context(self.marionette.CONTEXT_CHROME)

        if os.path.isfile(self.test_script):
            f = open(self.test_script, 'r')
            self.test_script = f.read()
            f.close()
        self.marionette.execute_script(self.test_script)

    def run_tests(self, test_path, options):
        reftestlist = self.getManifestPath(test_path)
        if not reftestlist.startswith('file://'):
            reftestlist = 'file://%s' % reftestlist

        self.profile = self.create_profile(options, reftestlist,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)
        kp_kwargs = { 'processOutputLine': [self._on_output],
                      'onTimeout': [self._on_timeout],
                      'kill_on_timeout': False }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        log.info("%s | Running tests: start.", os.path.basename(__file__))
        cmd, args = self.build_command_line(options.app,
                            ignore_window_size=options.ignoreWindowSize)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    symbols_path=options.symbolsPath,
                                    kp_kwargs=kp_kwargs)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            log.info("%s | Application pid: %d",
                     os.path.basename(__file__),
                     self.runner.process_handler.pid)

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            log.testFail("%s | application terminated with exit code %s",
                         self.last_test, status)
        elif status < 0:
            log.info("%s | application killed with signal %s",
                         self.last_test, -status)

        log.info("%s | Running tests: end.", os.path.basename(__file__))
        return status

    def create_profile(self, options, reftestlist, profile_to_clone=None):
        profile = RefTest.createReftestProfile(self, options, reftestlist,
                                               profile_to_clone=profile_to_clone)

        prefs = {}
        # Turn off the locale picker screen
        prefs["browser.firstrun.show.localepicker"] = False
        prefs["browser.homescreenURL"] = "app://test-container.gaiamobile.org/index.html"
        prefs["browser.manifestURL"] = "app://test-container.gaiamobile.org/manifest.webapp"
        prefs["browser.tabs.remote"] = False
        prefs["dom.ipc.tabs.disabled"] = False
        prefs["dom.mozBrowserFramesEnabled"] = True
        prefs["font.size.inflation.emPerLine"] = 0
        prefs["font.size.inflation.minTwips"] = 0
        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
        prefs["reftest.browser.iframe.enabled"] = False
        prefs["reftest.remote"] = False
        prefs["reftest.uri"] = "%s" % reftestlist
        # Set a future policy version to avoid the telemetry prompt.
        prefs["toolkit.telemetry.prompted"] = 999
        prefs["toolkit.telemetry.notifiedOptOut"] = 999

        # Set the extra prefs.
        profile.set_preferences(prefs)
        return profile

    def build_command_line(self, app, ignore_window_size=False):
        cmd = os.path.abspath(app)
        args = ['-marionette']

        if not ignore_window_size:
            args.extend(['--screen', '800x1000'])
        return cmd, args

    def _on_output(self, line):
        print(line)
        # TODO use structured logging
        if "TEST-START" in line and "|" in line:
            self.last_test = line.split("|")[1].strip()

    def _on_timeout(self):
        msg = "%s | application timed out after %s seconds with no output"
        log.testFail(msg % (self.last_test, self.timeout))

        # kill process to get a stack
        self.runner.stop(sig=signal.SIGABRT)
class TPSFirefoxRunner(object):

    PROCESS_TIMEOUT = 240
  
    def __init__(self, binary):
        if binary is not None and ('http://' in binary or 'ftp://' in binary):
            self.url = binary
            self.binary = None
        else:
            self.url = None
            self.binary = binary
        self.runner = None
        self.installdir = None
    
    def __del__(self):
        if self.installdir:
            shutil.rmtree(self.installdir, True)
      
    def download_url(self, url, dest=None):
        h = httplib2.Http()
        resp, content = h.request(url, "GET")
        if dest == None:
            dest = os.path.basename(url)
    
        local = open(dest, 'wb')
        local.write(content)
        local.close()
        return dest
    
    def download_build(self, installdir='downloadedbuild', appname='firefox'):
        self.installdir = os.path.abspath(installdir)
        buildName = os.path.basename(self.url)
        pathToBuild = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                   buildName)
    
        # delete the build if it already exists
        if os.access(pathToBuild, os.F_OK):
            os.remove(pathToBuild)
      
        # download the build
        print "downloading build"
        self.download_url(self.url, pathToBuild)
    
        # install the build
        print "installing %s" % pathToBuild
        shutil.rmtree(self.installdir, True)
        binary = mozinstall.install(src=pathToBuild, dest=self.installdir)
    
        # remove the downloaded archive
        os.remove(pathToBuild)
    
        return binary
    
    def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None):
        """Runs the given FirefoxRunner with the given Profile, waits
           for completion, then returns the process exit code
        """
        if profile is None:
            profile = Profile()
        self.profile = profile
    
        if self.binary is None and self.url:
            self.binary = self.download_build()
      
        if self.runner is None:
            self.runner = FirefoxRunner(self.profile, binary=self.binary)
      
        self.runner.profile = self.profile
    
        if env is not None:
            self.runner.env.update(env)
      
        if args is not None:
            self.runner.cmdargs = copy.copy(args)
      
        self.runner.start()
    
        status = self.runner.process_handler.waitForFinish(timeout=timeout)
    
        return status
Beispiel #49
0
class FirefoxBrowser(Browser):
    used_ports = set()
    init_timeout = 60

    def __init__(self, logger, binary, prefs_root, debug_info=None,
                 symbols_path=None, stackwalk_binary=None, certutil_binary=None,
                 ca_certificate_path=None, e10s=False):
        Browser.__init__(self, logger)
        self.binary = binary
        self.prefs_root = prefs_root
        self.marionette_port = None
        self.runner = None
        self.debug_info = debug_info
        self.profile = None
        self.symbols_path = symbols_path
        self.stackwalk_binary = stackwalk_binary
        self.ca_certificate_path = ca_certificate_path
        self.certutil_binary = certutil_binary
        self.e10s = e10s

    def start(self):
        self.marionette_port = get_free_port(2828, exclude=self.used_ports)
        self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"

        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
                                      "marionette.defaultPrefs.port": self.marionette_port,
                                      "dom.disable_open_during_load": False,
                                      "network.dns.localDomains": ",".join(hostnames),
                                      "network.proxy.type": 0,
                                      "places.history.enabled": False})
        if self.e10s:
            self.profile.set_preferences({"browser.tabs.remote.autostart": True})

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft") and
            '5.1' in platform.version()):
            self.profile.set_preferences({"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(self.binary, [cmd_arg("marionette"), "about:blank"],
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")

    def load_prefs(self):
        prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
        if os.path.exists(prefs_path):
            preferences = Preferences.read_prefs(prefs_path)
        else:
            self.logger.warning("Failed to find base prefs file in %s" % prefs_path)
            preferences = []

        return preferences

    def stop(self):
        self.logger.debug("Stopping browser")
        if self.runner is not None:
            try:
                self.runner.stop()
            except OSError:
                # This can happen on Windows if the process is already dead
                pass

    def pid(self):
        if self.runner.process_handler is None:
            return None

        try:
            return self.runner.process_handler.pid
        except AttributeError:
            return None

    def on_output(self, line):
        """Write a line of output from the firefox process to the log"""
        self.logger.process_output(self.pid(),
                                   line.decode("utf8", "replace"),
                                   command=" ".join(self.runner.command))

    def is_alive(self):
        if self.runner:
            return self.runner.is_running()
        return False

    def cleanup(self):
        self.stop()

    def executor_browser(self):
        assert self.marionette_port is not None
        return ExecutorBrowser, {"marionette_port": self.marionette_port}

    def log_crash(self, process, test):
        dump_dir = os.path.join(self.profile.profile, "minidumps")

        mozcrash.log_crashes(self.logger,
                             dump_dir,
                             symbols_path=self.symbols_path,
                             stackwalk_binary=self.stackwalk_binary,
                             process=process,
                             test=test)

    def setup_ssl(self):
        """Create a certificate database to use in the test profile. This is configured
        to trust the CA Certificate that has signed the web-platform.test server
        certificate."""

        self.logger.info("Setting up ssl")

        # Make sure the certutil libraries from the source tree are loaded when using a
        # local copy of certutil
        # TODO: Maybe only set this if certutil won't launch?
        env = os.environ.copy()
        certutil_dir = os.path.dirname(self.binary)
        if mozinfo.isMac:
            env_var = "DYLD_LIBRARY_PATH"
        elif mozinfo.isUnix:
            env_var = "LD_LIBRARY_PATH"
        else:
            env_var = "PATH"


        env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]])
                        if env_var in env else certutil_dir).encode(
                                sys.getfilesystemencoding() or 'utf-8', 'replace')

        def certutil(*args):
            cmd = [self.certutil_binary] + list(args)
            self.logger.process_output("certutil",
                                       subprocess.check_output(cmd,
                                                               env=env,
                                                               stderr=subprocess.STDOUT),
                                       " ".join(cmd))

        pw_path = os.path.join(self.profile.profile, ".crtdbpw")
        with open(pw_path, "w") as f:
            # Use empty password for certificate db
            f.write("\n")

        cert_db_path = self.profile.profile

        # Create a new certificate db
        certutil("-N", "-d", cert_db_path, "-f", pw_path)

        # Add the CA certificate to the database and mark as trusted to issue server certs
        certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,",
                 "-n", "web-platform-tests", "-i", self.ca_certificate_path)

        # List all certs in the database
        certutil("-L", "-d", cert_db_path)
class MuletReftest(RefTest):
    build_type = "mulet"
    marionette = None

    def __init__(self, marionette_args):
        RefTest.__init__(self)
        self.last_test = os.path.basename(__file__)
        self.marionette_args = marionette_args
        self.profile = None
        self.runner = None
        self.test_script = os.path.join(here, 'b2g_start_script.js')
        self.timeout = None

    def run_marionette_script(self):
        self.marionette = Marionette(**self.marionette_args)
        assert(self.marionette.wait_for_port())
        self.marionette.start_session()
        if self.build_type == "mulet":
            self._wait_for_homescreen(timeout=300)
            self._unlockScreen()
        self.marionette.set_context(self.marionette.CONTEXT_CHROME)

        if os.path.isfile(self.test_script):
            f = open(self.test_script, 'r')
            self.test_script = f.read()
            f.close()
        self.marionette.execute_script(self.test_script)

    def run_tests(self, tests, options):
        manifests = self.resolver.resolveManifests(options, tests)

        self.profile = self.create_profile(options, manifests,
                                           profile_to_clone=options.profile)
        env = self.buildBrowserEnv(options, self.profile.profile)

        self._populate_logger(options)
        outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=options.symbolsPath)

        kp_kwargs = { 'processOutputLine': [outputHandler],
                      'onTimeout': [self._on_timeout],
                      'kill_on_timeout': False }

        if not options.debugger:
            if not options.timeout:
                if mozinfo.info['debug']:
                    options.timeout = 420
                else:
                    options.timeout = 300
            self.timeout = options.timeout + 30.0

        self.log.info("%s | Running tests: start." % os.path.basename(__file__))
        cmd, args = self.build_command_line(options.app,
                            ignore_window_size=options.ignoreWindowSize,
                            browser_arg=options.browser_arg)
        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd,
                                    cmdargs=args,
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args=kp_kwargs,
                                    symbols_path=options.symbolsPath)

        status = 0
        try:
            self.runner.start(outputTimeout=self.timeout)
            self.log.info("%s | Application pid: %d" % (
                     os.path.basename(__file__),
                     self.runner.process_handler.pid))

            # kick starts the reftest harness
            self.run_marionette_script()
            status = self.runner.wait()
        finally:
            self.runner.check_for_crashes(test_name=self.last_test)
            self.runner.cleanup()

        if status > 0:
            self.log.testFail("%s | application terminated with exit code %s" % (
                         self.last_test, status))
        elif status < 0:
            self.log.info("%s | application killed with signal %s" % (
                         self.last_test, -status))

        self.log.info("%s | Running tests: end." % os.path.basename(__file__))
        return status

    def create_profile(self, options, manifests, profile_to_clone=None):
        profile = RefTest.createReftestProfile(self, options, manifests,
                                               profile_to_clone=profile_to_clone)

        prefs = {}
        # Turn off the locale picker screen
        prefs["browser.firstrun.show.localepicker"] = False
        if not self.build_type == "mulet":
            # FIXME: With Mulet we can't set this values since Gaia won't launch
            prefs["b2g.system_startup_url"] = \
                    "app://test-container.gaiamobile.org/index.html"
            prefs["b2g.system_manifest_url"] = \
                    "app://test-container.gaiamobile.org/manifest.webapp"
        # Make sure we disable system updates
        prefs["app.update.enabled"] = False
        prefs["app.update.url"] = ""
        # Disable webapp updates
        prefs["webapps.update.enabled"] = False
        # Disable tiles also
        prefs["browser.newtabpage.directory.source"] = ""
        prefs["browser.newtabpage.directory.ping"] = ""
        prefs["dom.ipc.tabs.disabled"] = False
        prefs["dom.mozBrowserFramesEnabled"] = True
        prefs["font.size.inflation.emPerLine"] = 0
        prefs["font.size.inflation.minTwips"] = 0
        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
        prefs["reftest.browser.iframe.enabled"] = False
        prefs["reftest.remote"] = False

        # Set the extra prefs.
        profile.set_preferences(prefs)
        return profile

    def build_command_line(self, app, ignore_window_size=False,
                           browser_arg=None):
        cmd = os.path.abspath(app)
        args = ['-marionette']

        if browser_arg:
            args += [browser_arg]

        if not ignore_window_size:
            args.extend(['--screen', '800x1000'])

        if self.build_type == "mulet":
            args += ['-chrome', 'chrome://b2g/content/shell.html']
        return cmd, args

    def _on_timeout(self):
        msg = "%s | application timed out after %s seconds with no output"
        self.log.testFail(msg % (self.last_test, self.timeout))
        self.log.error("Force-terminating active process(es).");

        # kill process to get a stack
        self.runner.stop(sig=signal.SIGABRT)

    def _unlockScreen(self):
        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
        self.marionette.import_script(os.path.abspath(
            os.path.join(__file__, os.path.pardir, "gaia_lock_screen.js")))
        self.marionette.switch_to_frame()
        self.marionette.execute_async_script('GaiaLockScreen.unlock()')

    def _wait_for_homescreen(self, timeout):
        self.log.info("Waiting for home screen to load")
        Wait(self.marionette, timeout).until(expected.element_present(
            By.CSS_SELECTOR, '#homescreen[loading-state=false]'))
Beispiel #51
0
    def bisectRecurse(self, testcondition=None, args_for_condition=[]):
        #Recursively build, run, and prompt
        verdict = ""
        current_revision = captureStdout(self.hgPrefix+["id","-i"])

        if self.remote:
            print "on current revision "+current_revision
            print "This would ask for a remote changeset, but it's not implemented yet."
            #TODO:
            #Remote bisection!
            #Step 1. Check if revision is in the archive
            #Step 2. If revision is not in the archive, set remote=False and continue (it will build and bisect that revision)
            #if not check_archived:
            #    set remote false and continue
            #else:
            #Step 3. If the revision is in the archive, download it and its corresponding tests
                #STEP3
                #1. Extract tests into some directory
                #2. Extract Nightly.app into "tests"
                #MozInstaller(src=, dest="", dest_app="Nightly.app")
                #3. run the following:
                #test_command = ['python', 'mochitest/runtests.py', '--appname=./Nightly.app/Contents/MacOS/firefox-bin', '--utility-path=bin', '--extra-profile-file=bin/plugins', '--certificate-path=certs', '--autorun', '--close-when-done', '--console-level=INFO', '--test-path=test_name']
                #output = captureStdout(test_command, ignoreStderr=True)
                #set verdict based on output
                #python mochitest/runtests.py --appname=./Nightly.app/Contents/MacOS/firefox-bin --utility-path=bin --extra-profile-file=bin/plugins --certificate-path=certs --autorun --close-when-done --console-level=INFO --test-path=test_name

                #example test name: Harness_sanity/test_sanityException.html
                #Step 4. Run and run test to get verdict
                #Step 5. Set verdict

        elif self.tryPusher:
            try:
                caller = BuildCaller(host=self.tryhost, port=int(self.tryport), data=current_revision)
                print "Getting revision "+current_revision+"..."
            except:
                print "Failed to connect to trypusher. Make sure your settings are correct and that the trypusher server was started."
                exit()
            response = caller.getChangeset()
            print "Waiting on Mozilla Pulse for revision " + response + "..."
            url = caller.getURLResponse(response)
            print "the base is " +url_base(url)
            #Download it here
            #1. Download from url, extract to same place as tests
            #2. Run test or start browser.
            binary_path =  os.path.join(self.binaryDir,url_base(url))
            downloaded_binary = download_url(url, dest=str(binary_path))
            MozInstaller(src=str(binary_path), dest=str(self.testDir), dest_app="Nightly.app")
            #now nightly is installed in
            if sys.platform == "darwin":
                binary_path = os.path.join(self.testDir,"Nightly.app")
                runner = FirefoxRunner(binary=os.path.join(binary_path,"Contents","MacOS")+"/firefox-bin")
            elif sys.platform == "linux2":
                binary_path = os.path.join(self.testDir,"firefox")
                runner = FirefoxRunner(binary=binary_path)
            elif sys.platform == "win32" or sys.platform == "cygwin":
                binary_path = os.path.join(self.testDir,"firefox.exe")
                runner = FirefoxRunner(binary=binary_path)
            else:
                print "Your platform is not currently supported."
                quit()

            dest = runner.start()
            if not dest:
                print "Failed to start the downloaded binary"
                verdict == "skip"
            runner.wait()
            if verdict == "skip":
                pass
            elif testcondition!=None:
                #Support condition scripts where arg0 is the directory with the binary and tests
                args_to_pass = [self.testDir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass,tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"
        else:
            try:
                self.build()
            except Exception:
                print "This build failed!"
                verdict = "skip"

            if verdict == "skip":
                pass
            elif testcondition==None:
                #Not using a test, interactive bisect begin!
                self.run()
            else:
                #Using Jesse's idea: import any testing script and run it as the truth condition
                args_to_pass = [self.objdir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass,tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"

        while verdict not in ["good", "bad", "skip"]:
            verdict = raw_input("Was this commit good or bad? (type 'good', 'bad', or 'skip'): ")
            if verdict == 'g':
                verdict = "good"
            if verdict == 'b':
                verdict = "bad"
            if verdict == 's':
                verdict = "skip"

        # do hg bisect --good, --bad, or --skip
        verdictCommand = self.hgPrefix+["bisect","--"+verdict]
        print " ".join(verdictCommand)
        retval = captureStdout(verdictCommand)

        string_to_parse = str(retval)
        print string_to_parse

        self.check_done(string_to_parse)

        if retval.startswith("Testing changeset"):
            print "\n"

        self.bisectRecurse(testcondition=testcondition, args_for_condition=args_for_condition)
Beispiel #52
0
    def start(self, **kwargs):
        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)

        locations = ServerLocations(
            filename=os.path.join(here, "server-locations.txt"))

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(locations=locations,
                                      preferences=preferences)
        self.profile.set_preferences({
            "marionette.port":
            self.marionette_port,
            "dom.disable_open_during_load":
            False,
            "network.dns.localDomains":
            ",".join(hostnames),
            "network.proxy.type":
            0,
            "places.history.enabled":
            False,
            "dom.send_after_paint_to_content":
            True,
            "network.preload":
            True
        })
        if self.e10s:
            self.profile.set_preferences(
                {"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences(
                {"layout.interruptible-reflow.enabled": False})

        if self.leak_check and kwargs.get("check_leaks", True):
            self.leak_report_file = os.path.join(self.profile.profile,
                                                 "runtests_leaks.log")
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft")
                and '5.1' in platform.version()):
            self.profile.set_preferences(
                {"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(
            self.binary, self.binary_args if self.binary_args else [] +
            [cmd_arg("marionette"), "about:blank"], self.debug_info)

        self.runner = FirefoxRunner(
            profile=self.profile,
            binary=cmd[0],
            cmdargs=cmd[1:],
            env=env,
            process_class=ProcessHandler,
            process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args,
                          interactive=self.debug_info
                          and self.debug_info.interactive)
        self.logger.debug("Firefox Started")
class FirefoxBrowser(Browser):
    used_ports = set()
    init_timeout = 60
    shutdown_timeout = 60

    def __init__(self, logger, binary, prefs_root, test_type, extra_prefs=None, debug_info=None,
                 symbols_path=None, stackwalk_binary=None, certutil_binary=None,
                 ca_certificate_path=None, e10s=False, stackfix_dir=None,
                 binary_args=None, timeout_multiplier=None, leak_check=False, stylo_threads=1,
                 chaos_mode_flags=None, config=None):
        Browser.__init__(self, logger)
        self.binary = binary
        self.prefs_root = prefs_root
        self.test_type = test_type
        self.extra_prefs = extra_prefs
        self.marionette_port = None
        self.runner = None
        self.debug_info = debug_info
        self.profile = None
        self.symbols_path = symbols_path
        self.stackwalk_binary = stackwalk_binary
        self.ca_certificate_path = ca_certificate_path
        self.certutil_binary = certutil_binary
        self.e10s = e10s
        self.binary_args = binary_args
        self.config = config
        if stackfix_dir:
            self.stack_fixer = get_stack_fixer_function(stackfix_dir,
                                                        self.symbols_path)
        else:
            self.stack_fixer = None

        if timeout_multiplier:
            self.init_timeout = self.init_timeout * timeout_multiplier

        self.leak_report_file = None
        self.leak_check = leak_check
        self.stylo_threads = stylo_threads
        self.chaos_mode_flags = chaos_mode_flags

    def settings(self, test):
        return {"check_leaks": self.leak_check and not test.leaks}

    def start(self, **kwargs):
        if self.marionette_port is None:
            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
            self.used_ports.add(self.marionette_port)

        env = os.environ.copy()
        env["MOZ_CRASHREPORTER"] = "1"
        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
        env["STYLO_THREADS"] = str(self.stylo_threads)
        if self.chaos_mode_flags is not None:
            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)

        preferences = self.load_prefs()

        self.profile = FirefoxProfile(preferences=preferences)
        self.profile.set_preferences({"marionette.port": self.marionette_port,
                                      "dom.disable_open_during_load": False,
                                      "network.dns.localDomains": ",".join(self.config.domains_set),
                                      "network.proxy.type": 0,
                                      "places.history.enabled": False,
                                      "dom.send_after_paint_to_content": True,
                                      "network.preload": True})
        if self.e10s:
            self.profile.set_preferences({"browser.tabs.remote.autostart": True})

        if self.test_type == "reftest":
            self.profile.set_preferences({"layout.interruptible-reflow.enabled": False})

        if self.leak_check and kwargs.get("check_leaks", True):
            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks.log")
            if os.path.exists(self.leak_report_file):
                os.remove(self.leak_report_file)
            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
        else:
            self.leak_report_file = None

        # Bug 1262954: winxp + e10s, disable hwaccel
        if (self.e10s and platform.system() in ("Windows", "Microsoft") and
            '5.1' in platform.version()):
            self.profile.set_preferences({"layers.acceleration.disabled": True})

        if self.ca_certificate_path is not None:
            self.setup_ssl()

        debug_args, cmd = browser_command(self.binary,
                                          self.binary_args if self.binary_args else [] +
                                          [cmd_arg("marionette"), "about:blank"],
                                          self.debug_info)

        self.runner = FirefoxRunner(profile=self.profile,
                                    binary=cmd[0],
                                    cmdargs=cmd[1:],
                                    env=env,
                                    process_class=ProcessHandler,
                                    process_args={"processOutputLine": [self.on_output]})

        self.logger.debug("Starting Firefox")

        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
        self.logger.debug("Firefox Started")

    def load_prefs(self):
        prefs = Preferences()

        pref_paths = []
        prefs_general = os.path.join(self.prefs_root, 'prefs_general.js')
        if os.path.isfile(prefs_general):
            # Old preference file used in Firefox 60 and earlier (remove when no longer supported)
            pref_paths.append(prefs_general)

        profiles = os.path.join(self.prefs_root, 'profiles.json')
        if os.path.isfile(profiles):
            with open(profiles, 'r') as fh:
                for name in json.load(fh)['web-platform-tests']:
                    pref_paths.append(os.path.join(self.prefs_root, name, 'user.js'))

        for path in pref_paths:
            if os.path.exists(path):
                prefs.add(Preferences.read_prefs(path))
            else:
                self.logger.warning("Failed to find base prefs file in %s" % path)

        # Add any custom preferences
        prefs.add(self.extra_prefs, cast=True)

        return prefs()

    def stop(self, force=False):
        if self.runner is not None and self.runner.is_running():
            try:
                # For Firefox we assume that stopping the runner prompts the
                # browser to shut down. This allows the leak log to be written
                for clean, stop_f in [(True, lambda: self.runner.wait(self.shutdown_timeout)),
                                      (False, lambda: self.runner.stop(signal.SIGTERM)),
                                      (False, lambda: self.runner.stop(signal.SIGKILL))]:
                    if not force or not clean:
                        retcode = stop_f()
                        if retcode is not None:
                            self.logger.info("Browser exited with return code %s" % retcode)
                            break
            except OSError:
                # This can happen on Windows if the process is already dead
                pass
        self.logger.debug("stopped")

    def process_leaks(self):
        self.logger.debug("PROCESS LEAKS %s" % self.leak_report_file)
        if self.leak_report_file is None:
            return
        mozleak.process_leak_log(
            self.leak_report_file,
            leak_thresholds={
                "default": 0,
                "tab": 10000,  # See dependencies of bug 1051230.
                # GMP rarely gets a log, but when it does, it leaks a little.
                "geckomediaplugin": 20000,
            },
            ignore_missing_leaks=["geckomediaplugin"],
            log=self.logger,
            stack_fixer=self.stack_fixer
        )

    def pid(self):
        if self.runner.process_handler is None:
            return None

        try:
            return self.runner.process_handler.pid
        except AttributeError:
            return None

    def on_output(self, line):
        """Write a line of output from the firefox process to the log"""
        if "GLib-GObject-CRITICAL" in line:
            return
        if line:
            data = line.decode("utf8", "replace")
            if self.stack_fixer:
                data = self.stack_fixer(data)
            self.logger.process_output(self.pid(),
                                      data,
                                      command=" ".join(self.runner.command))

    def is_alive(self):
        if self.runner:
            return self.runner.is_running()
        return False

    def cleanup(self):
        self.stop()
        self.process_leaks()

    def executor_browser(self):
        assert self.marionette_port is not None
        return ExecutorBrowser, {"marionette_port": self.marionette_port}

    def check_for_crashes(self):
        dump_dir = os.path.join(self.profile.profile, "minidumps")

        return bool(mozcrash.check_for_crashes(dump_dir,
                                               symbols_path=self.symbols_path,
                                               stackwalk_binary=self.stackwalk_binary,
                                               quiet=True))

    def log_crash(self, process, test):
        dump_dir = os.path.join(self.profile.profile, "minidumps")

        mozcrash.log_crashes(self.logger,
                             dump_dir,
                             symbols_path=self.symbols_path,
                             stackwalk_binary=self.stackwalk_binary,
                             process=process,
                             test=test)

    def setup_ssl(self):
        """Create a certificate database to use in the test profile. This is configured
        to trust the CA Certificate that has signed the web-platform.test server
        certificate."""
        if self.certutil_binary is None:
            self.logger.info("--certutil-binary not supplied; Firefox will not check certificates")
            return

        self.logger.info("Setting up ssl")

        # Make sure the certutil libraries from the source tree are loaded when using a
        # local copy of certutil
        # TODO: Maybe only set this if certutil won't launch?
        env = os.environ.copy()
        certutil_dir = os.path.dirname(self.binary)
        if mozinfo.isMac:
            env_var = "DYLD_LIBRARY_PATH"
        elif mozinfo.isUnix:
            env_var = "LD_LIBRARY_PATH"
        else:
            env_var = "PATH"


        env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]])
                        if env_var in env else certutil_dir).encode(
                            sys.getfilesystemencoding() or 'utf-8', 'replace')

        def certutil(*args):
            cmd = [self.certutil_binary] + list(args)
            self.logger.process_output("certutil",
                                       subprocess.check_output(cmd,
                                                               env=env,
                                                               stderr=subprocess.STDOUT),
                                       " ".join(cmd))

        pw_path = os.path.join(self.profile.profile, ".crtdbpw")
        with open(pw_path, "w") as f:
            # Use empty password for certificate db
            f.write("\n")

        cert_db_path = self.profile.profile

        # Create a new certificate db
        certutil("-N", "-d", cert_db_path, "-f", pw_path)

        # Add the CA certificate to the database and mark as trusted to issue server certs
        certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,",
                 "-n", "web-platform-tests", "-i", self.ca_certificate_path)

        # List all certs in the database
        certutil("-L", "-d", cert_db_path)
Beispiel #54
0
    def valgrind_test(self, suppressions):
        import json
        import sys
        import tempfile

        from mozbuild.base import MozbuildObject
        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath
        from valgrind.output_handler import OutputHandler

        build_dir = os.path.join(self.topsrcdir, "build")

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, "pgo"))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            # TODO: refactor this into mozprofile
            prefpath = os.path.join(self.topsrcdir, "testing", "profiles", "prefs_general.js")
            prefs = {}
            prefs.update(Preferences.read_prefs(prefpath))
            interpolation = {"server": "%s:%d" % httpd.httpd.server_address, "OOP": "false"}
            prefs = json.loads(json.dumps(prefs) % interpolation)
            for pref in prefs:
                prefs[pref] = Preferences.cast(prefs[pref])

            quitter = os.path.join(self.topsrcdir, "tools", "quitter", "*****@*****.**")

            locations = ServerLocations()
            locations.add_host(host="127.0.0.1", port=httpd.httpd.server_port, options="primary")

            profile = FirefoxProfile(profile=profilePath, preferences=prefs, addons=[quitter], locations=locations)

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env["G_SLICE"] = "always-malloc"
            env["MOZ_CC_RUN_DURING_SHUTDOWN"] = "1"
            env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
            env["XPCOM_DEBUG_BREAK"] = "warn"

            env.update(self.extra_environment_variables)

            outputHandler = OutputHandler(self.log)
            kp_kwargs = {"processOutputLine": [outputHandler]}

            valgrind = "valgrind"
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                "--smc-check=all-non-file",
                "--vex-iropt-register-updates=allregs-at-mem-access",
                "--gen-suppressions=all",
                "--num-callers=36",
                "--leak-check=full",
                "--show-possibly-lost=no",
                "--track-origins=yes",
                "--trace-children=yes",
                "-v",  # Enable verbosity to get the list of used suppressions
            ]

            for s in suppressions:
                valgrind_args.append("--suppressions=" + s)

            supps_dir = os.path.join(build_dir, "valgrind")
            supps_file1 = os.path.join(supps_dir, "cross-architecture.sup")
            valgrind_args.append("--suppressions=" + supps_file1)

            # MACHTYPE is an odd bash-only environment variable that doesn't
            # show up in os.environ, so we have to get it another way.
            machtype = subprocess.check_output(["bash", "-c", "echo $MACHTYPE"]).rstrip()
            supps_file2 = os.path.join(supps_dir, machtype + ".sup")
            if os.path.isfile(supps_file2):
                valgrind_args.append("--suppressions=" + supps_file2)

            exitcode = None
            timeout = 1800
            try:
                runner = FirefoxRunner(
                    profile=profile,
                    binary=self.get_binary_path(),
                    cmdargs=firefox_args,
                    env=env,
                    process_args=kp_kwargs,
                )
                runner.start(debug_args=valgrind_args)
                exitcode = runner.wait(timeout=timeout)

            finally:
                errs = outputHandler.error_count
                supps = outputHandler.suppression_count
                if errs != supps:
                    status = 1  # turns the TBPL job orange
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-parsing",
                        {"errs": errs, "supps": supps},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {errs} errors seen, but {supps} generated suppressions seen",
                    )

                elif errs == 0:
                    status = 0
                    self.log(logging.INFO, "valgrind-pass", {}, "TEST-PASS | valgrind-test | valgrind found no errors")
                else:
                    status = 1  # turns the TBPL job orange
                    # We've already printed details of the errors.

                if exitcode == None:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-timeout",
                        {"timeout": timeout},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out (reached {timeout} second limit)",
                    )
                elif exitcode != 0:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR,
                        "valgrind-fail-errors",
                        {},
                        "TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code from Valgrind",
                    )

                httpd.stop()

            return status
Beispiel #55
0
    def valgrind_test(self, suppressions):

        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath
        from six import string_types
        from valgrind.output_handler import OutputHandler

        build_dir = os.path.join(self.topsrcdir, 'build')

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, 'pgo'))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            # TODO: refactor this into mozprofile
            profile_data_dir = os.path.join(
                self.topsrcdir, 'testing', 'profiles')
            with open(os.path.join(profile_data_dir, 'profiles.json'), 'r') as fh:
                base_profiles = json.load(fh)['valgrind']

            prefpaths = [os.path.join(profile_data_dir, profile, 'user.js')
                         for profile in base_profiles]
            prefs = {}
            for path in prefpaths:
                prefs.update(Preferences.read_prefs(path))

            interpolation = {
                'server': '%s:%d' % httpd.httpd.server_address,
            }
            for k, v in prefs.items():
                if isinstance(v, string_types):
                    v = v.format(**interpolation)
                prefs[k] = Preferences.cast(v)

            quitter = os.path.join(
                self.topsrcdir, 'tools', 'quitter', '*****@*****.**')

            locations = ServerLocations()
            locations.add_host(host='127.0.0.1',
                               port=httpd.httpd.server_port,
                               options='primary')

            profile = FirefoxProfile(profile=profilePath,
                                     preferences=prefs,
                                     addons=[quitter],
                                     locations=locations)

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env['G_SLICE'] = 'always-malloc'
            env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
            env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
            env['XPCOM_DEBUG_BREAK'] = 'warn'

            env.update(self.extra_environment_variables)

            outputHandler = OutputHandler(self.log)
            kp_kwargs = {'processOutputLine': [outputHandler]}

            valgrind = 'valgrind'
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                '--smc-check=all-non-file',
                '--vex-iropt-register-updates=allregs-at-mem-access',
                '--gen-suppressions=all',
                '--num-callers=36',
                '--leak-check=full',
                '--show-possibly-lost=no',
                '--track-origins=yes',
                '--trace-children=yes',
                '-v',  # Enable verbosity to get the list of used suppressions
                # Avoid excessive delays in the presence of spinlocks.
                # See bug 1309851.
                '--fair-sched=yes',
                # Keep debuginfo after library unmap.  See bug 1382280.
                '--keep-debuginfo=yes',
                # Reduce noise level on rustc and/or LLVM compiled code.
                # See bug 1365915
                '--expensive-definedness-checks=yes',
            ]

            for s in suppressions:
                valgrind_args.append('--suppressions=' + s)

            supps_dir = os.path.join(build_dir, 'valgrind')
            supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
            valgrind_args.append('--suppressions=' + supps_file1)

            if mozinfo.os == 'linux':
                machtype = {
                    'x86_64': 'x86_64-pc-linux-gnu',
                    'x86': 'i386-pc-linux-gnu',
                }.get(mozinfo.processor)
                if machtype:
                    supps_file2 = os.path.join(supps_dir, machtype + '.sup')
                    if os.path.isfile(supps_file2):
                        valgrind_args.append('--suppressions=' + supps_file2)

            exitcode = None
            timeout = 1800
            try:
                runner = FirefoxRunner(profile=profile,
                                       binary=self.get_binary_path(),
                                       cmdargs=firefox_args,
                                       env=env,
                                       process_args=kp_kwargs)
                runner.start(debug_args=valgrind_args)
                exitcode = runner.wait(timeout=timeout)

            finally:
                errs = outputHandler.error_count
                supps = outputHandler.suppression_count
                if errs != supps:
                    status = 1  # turns the TBPL job orange
                    self.log(logging.ERROR, 'valgrind-fail-parsing',
                             {'errs': errs, 'supps': supps},
                             'TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {errs} errors '
                             'seen, but {supps} generated suppressions seen')

                elif errs == 0:
                    status = 0
                    self.log(logging.INFO, 'valgrind-pass', {},
                             'TEST-PASS | valgrind-test | valgrind found no errors')
                else:
                    status = 1  # turns the TBPL job orange
                    # We've already printed details of the errors.

                if exitcode is None:
                    status = 2  # turns the TBPL job red
                    self.log(logging.ERROR, 'valgrind-fail-timeout',
                             {'timeout': timeout},
                             'TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out '
                             '(reached {timeout} second limit)')
                elif exitcode != 0:
                    status = 2  # turns the TBPL job red
                    self.log(logging.ERROR, 'valgrind-fail-errors', {},
                             'TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code'
                             'from Valgrind')

                httpd.stop()

            return status
Beispiel #56
0
    def valgrind_test(self, suppressions):
        import json
        import sys
        import tempfile

        from mozbuild.base import MozbuildObject
        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath
        from valgrind.output_handler import OutputHandler

        build_dir = os.path.join(self.topsrcdir, 'build')

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, 'pgo'))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            #TODO: refactor this into mozprofile
            prefpath = os.path.join(self.topsrcdir, 'testing', 'profiles', 'prefs_general.js')
            prefs = {}
            prefs.update(Preferences.read_prefs(prefpath))
            interpolation = { 'server': '%s:%d' % httpd.httpd.server_address,
                              'OOP': 'false'}
            prefs = json.loads(json.dumps(prefs) % interpolation)
            for pref in prefs:
                prefs[pref] = Preferences.cast(prefs[pref])

            quitter = os.path.join(self.distdir, 'xpi-stage', 'quitter')

            locations = ServerLocations()
            locations.add_host(host='127.0.0.1',
                               port=httpd.httpd.server_port,
                               options='primary')

            profile = FirefoxProfile(profile=profilePath,
                                     preferences=prefs,
                                     addons=[quitter],
                                     locations=locations)

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env['G_SLICE'] = 'always-malloc'
            env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
            env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
            env['XPCOM_DEBUG_BREAK'] = 'warn'

            env.update(self.extra_environment_variables)

            outputHandler = OutputHandler()
            kp_kwargs = {'processOutputLine': [outputHandler]}

            valgrind = 'valgrind'
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                '--smc-check=all-non-file',
                '--vex-iropt-register-updates=allregs-at-mem-access',
                '--gen-suppressions=all',
                '--num-callers=36',
                '--leak-check=full',
                '--show-possibly-lost=no',
                '--track-origins=yes',
                '--trace-children=yes',
                # The gstreamer plugin scanner can run as part of executing
                # firefox, but is an external program. In some weird cases,
                # valgrind finds errors while executing __libc_freeres when
                # it runs, but those are not relevant, as it's related to
                # executing third party code. So don't trace
                # gst-plugin-scanner.
                '--trace-children-skip=*/gst-plugin-scanner',
                '-v',  # Enable verbosity to get the list of used suppressions
            ]

            for s in suppressions:
                valgrind_args.append('--suppressions=' + s)

            supps_dir = os.path.join(build_dir, 'valgrind')
            supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
            valgrind_args.append('--suppressions=' + supps_file1)

            # MACHTYPE is an odd bash-only environment variable that doesn't
            # show up in os.environ, so we have to get it another way.
            machtype = subprocess.check_output(['bash', '-c', 'echo $MACHTYPE']).rstrip()
            supps_file2 = os.path.join(supps_dir, machtype + '.sup')
            if os.path.isfile(supps_file2):
                valgrind_args.append('--suppressions=' + supps_file2)

            exitcode = None
            timeout = 1100
            try:
                runner = FirefoxRunner(profile=profile,
                                       binary=self.get_binary_path(),
                                       cmdargs=firefox_args,
                                       env=env,
                                       process_args=kp_kwargs)
                runner.start(debug_args=valgrind_args)
                # This timeout is slightly less than the no-output timeout on
                # TBPL, so we'll timeout here first and give an informative
                # message.
                exitcode = runner.wait(timeout=timeout)

            finally:
                errs = outputHandler.error_count
                supps = outputHandler.suppression_count
                if errs != supps:
                    status = 1  # turns the TBPL job orange
                    print('TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {} errors seen, but {} generated suppressions seen'.format(errs, supps))

                elif errs == 0:
                    status = 0
                    print('TEST-PASS | valgrind-test | valgrind found no errors')
                else:
                    status = 1  # turns the TBPL job orange
                    # We've already printed details of the errors.

                if exitcode == None:
                    status = 2  # turns the TBPL job red
                    print('TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out (reached {} second limit)'.format(timeout))
                elif exitcode != 0:
                    status = 2  # turns the TBPL job red
                    print('TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code from Valgrind')

                httpd.stop()

            return status
Beispiel #57
0
    def valgrind_test(self, suppressions):

        from mozfile import TemporaryDirectory
        from mozhttpd import MozHttpd
        from mozprofile import FirefoxProfile, Preferences
        from mozprofile.permissions import ServerLocations
        from mozrunner import FirefoxRunner
        from mozrunner.utils import findInPath
        from six import string_types
        from valgrind.output_handler import OutputHandler

        build_dir = os.path.join(self.topsrcdir, 'build')

        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
        # change in the future.
        httpd = MozHttpd(docroot=os.path.join(build_dir, 'pgo'))
        httpd.start(block=False)

        with TemporaryDirectory() as profilePath:
            # TODO: refactor this into mozprofile
            profile_data_dir = os.path.join(self.topsrcdir, 'testing',
                                            'profiles')
            with open(os.path.join(profile_data_dir, 'profiles.json'),
                      'r') as fh:
                base_profiles = json.load(fh)['valgrind']

            prefpaths = [
                os.path.join(profile_data_dir, profile, 'user.js')
                for profile in base_profiles
            ]
            prefs = {}
            for path in prefpaths:
                prefs.update(Preferences.read_prefs(path))

            interpolation = {
                'server': '%s:%d' % httpd.httpd.server_address,
            }
            for k, v in prefs.items():
                if isinstance(v, string_types):
                    v = v.format(**interpolation)
                prefs[k] = Preferences.cast(v)

            quitter = os.path.join(self.topsrcdir, 'tools', 'quitter',
                                   '*****@*****.**')

            locations = ServerLocations()
            locations.add_host(host='127.0.0.1',
                               port=httpd.httpd.server_port,
                               options='primary')

            profile = FirefoxProfile(profile=profilePath,
                                     preferences=prefs,
                                     addons=[quitter],
                                     locations=locations)

            firefox_args = [httpd.get_url()]

            env = os.environ.copy()
            env['G_SLICE'] = 'always-malloc'
            env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
            env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
            env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
            env['XPCOM_DEBUG_BREAK'] = 'warn'

            env.update(self.extra_environment_variables)

            outputHandler = OutputHandler(self.log)
            kp_kwargs = {'processOutputLine': [outputHandler]}

            valgrind = 'valgrind'
            if not os.path.exists(valgrind):
                valgrind = findInPath(valgrind)

            valgrind_args = [
                valgrind,
                '--sym-offsets=yes',
                '--smc-check=all-non-file',
                '--vex-iropt-register-updates=allregs-at-mem-access',
                '--gen-suppressions=all',
                '--num-callers=36',
                '--leak-check=full',
                '--show-possibly-lost=no',
                '--track-origins=yes',
                '--trace-children=yes',
                '-v',  # Enable verbosity to get the list of used suppressions
                # Avoid excessive delays in the presence of spinlocks.
                # See bug 1309851.
                '--fair-sched=yes',
                # Keep debuginfo after library unmap.  See bug 1382280.
                '--keep-debuginfo=yes',
                # Reduce noise level on rustc and/or LLVM compiled code.
                # See bug 1365915
                '--expensive-definedness-checks=yes',
            ]

            for s in suppressions:
                valgrind_args.append('--suppressions=' + s)

            supps_dir = os.path.join(build_dir, 'valgrind')
            supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
            valgrind_args.append('--suppressions=' + supps_file1)

            if mozinfo.os == 'linux':
                machtype = {
                    'x86_64': 'x86_64-pc-linux-gnu',
                    'x86': 'i386-pc-linux-gnu',
                }.get(mozinfo.processor)
                if machtype:
                    supps_file2 = os.path.join(supps_dir, machtype + '.sup')
                    if os.path.isfile(supps_file2):
                        valgrind_args.append('--suppressions=' + supps_file2)

            exitcode = None
            timeout = 1800
            try:
                runner = FirefoxRunner(profile=profile,
                                       binary=self.get_binary_path(),
                                       cmdargs=firefox_args,
                                       env=env,
                                       process_args=kp_kwargs)
                runner.start(debug_args=valgrind_args)
                exitcode = runner.wait(timeout=timeout)

            finally:
                errs = outputHandler.error_count
                supps = outputHandler.suppression_count
                if errs != supps:
                    status = 1  # turns the TBPL job orange
                    self.log(
                        logging.ERROR, 'valgrind-fail-parsing', {
                            'errs': errs,
                            'supps': supps
                        },
                        'TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {errs} errors '
                        'seen, but {supps} generated suppressions seen')

                elif errs == 0:
                    status = 0
                    self.log(
                        logging.INFO, 'valgrind-pass', {},
                        'TEST-PASS | valgrind-test | valgrind found no errors')
                else:
                    status = 1  # turns the TBPL job orange
                    # We've already printed details of the errors.

                if exitcode is None:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR, 'valgrind-fail-timeout',
                        {'timeout': timeout},
                        'TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out '
                        '(reached {timeout} second limit)')
                elif exitcode != 0:
                    status = 2  # turns the TBPL job red
                    self.log(
                        logging.ERROR, 'valgrind-fail-errors',
                        {'exitcode': exitcode},
                        'TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code '
                        'from Valgrind: {exitcode}')

                httpd.stop()

            return status