def kill_and_get_minidump(context, minidump_dir): proc = context.process if context.is_launcher: kids = context.process.children() if len(kids) == 1: LOG.debug(("Launcher process {} detected. Killing parent" " process {} instead.").format(proc, kids[0])) proc = kids[0] LOG.debug("Killing %s and writing a minidump file" % proc) mozcrash.kill_and_get_minidump(proc.pid, minidump_dir)
def run_browser(command, timeout=None, on_started=None, **kwargs): """ Run the browser using the given `command`. After the browser prints __endTimestamp, we give it 5 seconds to quit and kill it if it's still alive at that point. Note that this method ensure that the process is killed at the end. If this is not possible, an exception will be raised. :param command: the commad (as a string list) to run the browser :param timeout: if specified, timeout to wait for the browser before we raise a :class:`TalosError` :param on_started: a callback that can be used to do things just after the browser has been started :param kwargs: additional keyword arguments for the :class:`ProcessHandler` instance Returns a ProcessContext instance, with available output and pid used. """ context = ProcessContext() first_time = int(time.time()) * 1000 wait_for_quit_timeout = 5 event = Event() reader = Reader(event) kwargs['storeOutput'] = False kwargs['processOutputLine'] = reader kwargs['onFinish'] = event.set proc = ProcessHandler(command, **kwargs) proc.run() try: context.process = psutil.Process(proc.pid) if on_started: on_started() # wait until we saw __endTimestamp in the proc output, # or the browser just terminated - or we have a timeout if not event.wait(timeout): # try to extract the minidump stack if the browser hangs mozcrash.kill_and_get_minidump(proc.pid) raise TalosError("timeout") if reader.got_end_timestamp: for i in range(1, wait_for_quit_timeout): if proc.wait(1) is not None: break if proc.poll() is None: logging.info( "Browser shutdown timed out after {0} seconds, terminating" " process.".format(wait_for_quit_timeout) ) finally: # this also handle KeyboardInterrupt # ensure early the process is really terminated context.kill_process() reader.output.append( "__startBeforeLaunchTimestamp%d__endBeforeLaunchTimestamp" % first_time) reader.output.append( "__startAfterTerminationTimestamp%d__endAfterTerminationTimestamp" % (int(time.time()) * 1000)) logging.info("Browser exited with error code: {0}".format(proc.returncode)) context.output = reader.output return context
def run_browser(command, minidump_dir, timeout=None, on_started=None, **kwargs): """ Run the browser using the given `command`. After the browser prints __endTimestamp, we give it 5 seconds to quit and kill it if it's still alive at that point. Note that this method ensure that the process is killed at the end. If this is not possible, an exception will be raised. :param command: the commad (as a string list) to run the browser :param minidump_dir: a path where to extract minidumps in case the browser hang. This have to be the same value used in `mozcrash.check_for_crashes`. :param timeout: if specified, timeout to wait for the browser before we raise a :class:`TalosError` :param on_started: a callback that can be used to do things just after the browser has been started. The callback must takes an argument, which is the psutil.Process instance :param kwargs: additional keyword arguments for the :class:`ProcessHandler` instance Returns a ProcessContext instance, with available output and pid used. """ context = ProcessContext() first_time = int(time.time()) * 1000 wait_for_quit_timeout = 5 event = Event() reader = Reader(event) kwargs['storeOutput'] = False kwargs['processOutputLine'] = reader kwargs['onFinish'] = event.set proc = ProcessHandler(command, **kwargs) proc.run() try: context.process = psutil.Process(proc.pid) if on_started: on_started(context.process) # wait until we saw __endTimestamp in the proc output, # or the browser just terminated - or we have a timeout if not event.wait(timeout): # try to extract the minidump stack if the browser hangs mozcrash.kill_and_get_minidump(proc.pid, minidump_dir) raise TalosError("timeout") if reader.got_end_timestamp: for i in range(1, wait_for_quit_timeout): if proc.wait(1) is not None: break if proc.poll() is None: logging.info( "Browser shutdown timed out after {0} seconds, terminating" " process.".format(wait_for_quit_timeout)) elif reader.got_timeout: raise TalosError('TIMEOUT: %s' % reader.timeout_message) finally: # this also handle KeyboardInterrupt # ensure early the process is really terminated context.kill_process() return_code = proc.wait(1) reader.output.append( "__startBeforeLaunchTimestamp%d__endBeforeLaunchTimestamp" % first_time) reader.output.append( "__startAfterTerminationTimestamp%d__endAfterTerminationTimestamp" % (int(time.time()) * 1000)) logging.info("Browser exited with error code: {0}".format(return_code)) context.output = reader.output return context
def run_browser(command, minidump_dir, timeout=None, on_started=None, debug=None, debugger=None, debugger_args=None, **kwargs): """ Run the browser using the given `command`. After the browser prints __endTimestamp, we give it 5 seconds to quit and kill it if it's still alive at that point. Note that this method ensure that the process is killed at the end. If this is not possible, an exception will be raised. :param command: the commad (as a string list) to run the browser :param minidump_dir: a path where to extract minidumps in case the browser hang. This have to be the same value used in `mozcrash.check_for_crashes`. :param timeout: if specified, timeout to wait for the browser before we raise a :class:`TalosError` :param on_started: a callback that can be used to do things just after the browser has been started. The callback must takes an argument, which is the psutil.Process instance :param kwargs: additional keyword arguments for the :class:`ProcessHandler` instance Returns a ProcessContext instance, with available output and pid used. """ debugger_info = find_debugger_info(debug, debugger, debugger_args) if debugger_info is not None: return run_in_debug_mode(command, debugger_info, on_started=on_started, env=kwargs.get('env')) context = ProcessContext() first_time = int(time.time()) * 1000 wait_for_quit_timeout = 5 event = Event() reader = Reader(event) LOG.info("Using env: %s" % pprint.pformat(kwargs['env'])) kwargs['storeOutput'] = False kwargs['processOutputLine'] = reader kwargs['onFinish'] = event.set proc = ProcessHandler(command, **kwargs) reader.proc = proc proc.run() LOG.process_start(proc.pid, ' '.join(command)) try: context.process = psutil.Process(proc.pid) if on_started: on_started(context.process) # wait until we saw __endTimestamp in the proc output, # or the browser just terminated - or we have a timeout if not event.wait(timeout): LOG.info("Timeout waiting for test completion; killing browser...") # try to extract the minidump stack if the browser hangs mozcrash.kill_and_get_minidump(proc.pid, minidump_dir) raise TalosError("timeout") if reader.got_end_timestamp: for i in range(1, wait_for_quit_timeout): if proc.wait(1) is not None: break if proc.poll() is None: LOG.info( "Browser shutdown timed out after {0} seconds, terminating" " process.".format(wait_for_quit_timeout)) elif reader.got_timeout: raise TalosError('TIMEOUT: %s' % reader.timeout_message) finally: # this also handle KeyboardInterrupt # ensure early the process is really terminated return_code = None try: return_code = context.kill_process() if return_code is None: return_code = proc.wait(1) except Exception: # Maybe killed by kill_and_get_minidump(), maybe ended? LOG.info("Unable to kill process") LOG.info(traceback.format_exc()) reader.output.append( "__startBeforeLaunchTimestamp%d__endBeforeLaunchTimestamp" % first_time) reader.output.append( "__startAfterTerminationTimestamp%d__endAfterTerminationTimestamp" % (int(time.time()) * 1000)) if return_code is not None: LOG.process_exit(proc.pid, return_code) else: LOG.debug("Unable to detect exit code of the process %s." % proc.pid) context.output = reader.output return context
def run_browser(command, minidump_dir, timeout=None, on_started=None, **kwargs): """ Run the browser using the given `command`. After the browser prints __endTimestamp, we give it 5 seconds to quit and kill it if it's still alive at that point. Note that this method ensure that the process is killed at the end. If this is not possible, an exception will be raised. :param command: the commad (as a string list) to run the browser :param minidump_dir: a path where to extract minidumps in case the browser hang. This have to be the same value used in `mozcrash.check_for_crashes`. :param timeout: if specified, timeout to wait for the browser before we raise a :class:`TalosError` :param on_started: a callback that can be used to do things just after the browser has been started. The callback must takes an argument, which is the psutil.Process instance :param kwargs: additional keyword arguments for the :class:`ProcessHandler` instance Returns a ProcessContext instance, with available output and pid used. """ context = ProcessContext() first_time = int(time.time()) * 1000 wait_for_quit_timeout = 5 event = Event() reader = Reader(event) kwargs['storeOutput'] = False kwargs['processOutputLine'] = reader kwargs['onFinish'] = event.set proc = ProcessHandler(command, **kwargs) reader.proc = proc proc.run() LOG.process_start(proc.pid, ' '.join(command)) try: context.process = psutil.Process(proc.pid) if on_started: on_started(context.process) # wait until we saw __endTimestamp in the proc output, # or the browser just terminated - or we have a timeout if not event.wait(timeout): # try to extract the minidump stack if the browser hangs mozcrash.kill_and_get_minidump(proc.pid, minidump_dir) raise TalosError("timeout") if reader.got_end_timestamp: for i in range(1, wait_for_quit_timeout): if proc.wait(1) is not None: break if proc.poll() is None: LOG.info( "Browser shutdown timed out after {0} seconds, terminating" " process.".format(wait_for_quit_timeout) ) elif reader.got_timeout: raise TalosError('TIMEOUT: %s' % reader.timeout_message) finally: # this also handle KeyboardInterrupt # ensure early the process is really terminated return_code = context.kill_process() if return_code is None: return_code = proc.wait(1) reader.output.append( "__startBeforeLaunchTimestamp%d__endBeforeLaunchTimestamp" % first_time) reader.output.append( "__startAfterTerminationTimestamp%d__endAfterTerminationTimestamp" % (int(time.time()) * 1000)) if return_code is not None: LOG.process_exit(proc.pid, return_code) else: LOG.debug("Unable to detect exit code of the process %s." % proc.pid) context.output = reader.output return context