def killNamedOrphans(self, pname): """ Kill orphan processes matching the given command name """ self.log.info("Checking for orphan %s processes..." % pname) def _psInfo(line): if pname in line: self.log.info(line) process = mozprocess.ProcessHandler(['ps', '-f'], processOutputLine=_psInfo) process.run() process.wait() def _psKill(line): parts = line.split() if len(parts) == 3 and parts[0].isdigit(): pid = int(parts[0]) if parts[2] == pname and parts[1] == '1': self.log.info("killing %s orphan with pid %d" % (pname, pid)) try: os.kill(pid, getattr(signal, "SIGKILL", signal.SIGTERM)) except Exception as e: self.log.info("Failed to kill process %d: %s" % (pid, str(e))) process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'], processOutputLine=_psKill) process.run() process.wait()
def run_one_test(self, prog, env, symbols_path=None, interactive=False, timeout_factor=1): """ Run a single C++ unit test program. Arguments: * prog: The path to the test program to run. * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. * timeout_factor: An optional test-specific timeout multiplier. Return True if the program exits with a zero status, False otherwise. """ basename = os.path.basename(prog) self.log.test_start(basename) with mozfile.TemporaryDirectory() as tempdir: if interactive: # For tests run locally, via mach, print output directly proc = mozprocess.ProcessHandler([prog], cwd=tempdir, env=env, storeOutput=False) else: proc = mozprocess.ProcessHandler([prog], cwd=tempdir, env=env, storeOutput=True, processOutputLine=lambda _: None) # TODO: After bug 811320 is fixed, don't let .run() kill the process, # instead use a timeout in .wait() and then kill to get a stack. test_timeout = CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor proc.run(timeout=test_timeout, outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT) proc.wait() if proc.output: if self.fix_stack: procOutput = [self.fix_stack(l) for l in proc.output] else: procOutput = proc.output output = "\n%s" % "\n".join(procOutput) self.log.process_output(proc.pid, output, command=[prog]) if proc.timedOut: message = "timed out after %d seconds" % CPPUnitTests.TEST_PROC_TIMEOUT self.log.test_end(basename, status='TIMEOUT', expected='PASS', message=message) return False if mozcrash.check_for_crashes(tempdir, symbols_path, test_name=basename): self.log.test_end(basename, status='CRASH', expected='PASS') return False result = proc.proc.returncode == 0 if not result: self.log.test_end(basename, status='FAIL', expected='PASS', message=("test failed with return code %d" % proc.proc.returncode)) else: self.log.test_end(basename, status='PASS', expected='PASS') return result
def _run(self, block): self._cmd = self.make_command() self._proc = mozprocess.ProcessHandler( self._cmd, processOutputLine=self.on_output, env=self.env, storeOutput=False) try: self._proc.run() except OSError as e: if e.errno == errno.ENOENT: raise IOError( "WebDriver HTTP server executable not found: %s" % self.binary) raise self.logger.debug("Waiting for server to become accessible: %s" % self.url) try: wait_for_service((self.host, self.port)) except: self.logger.error("WebDriver HTTP server was not accessible " "within the timeout:\n%s" % traceback.format_exc()) raise if block: self._proc.wait()
def run_one_test(self, prog, env, symbols_path=None): """ Run a single C++ unit test program. Arguments: * prog: The path to the test program to run. * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. Return True if the program exits with a zero status, False otherwise. """ basename = os.path.basename(prog) log.info("Running test %s", basename) with TemporaryDirectory() as tempdir: proc = mozprocess.ProcessHandler([prog], cwd=tempdir, env=env) #TODO: After bug 811320 is fixed, don't let .run() kill the process, # instead use a timeout in .wait() and then kill to get a stack. proc.run(timeout=CPPUnitTests.TEST_PROC_TIMEOUT, outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT) proc.wait() if proc.timedOut: log.testFail("%s | timed out after %d seconds", basename, CPPUnitTests.TEST_PROC_TIMEOUT) return False if mozcrash.check_for_crashes(tempdir, symbols_path, test_name=basename): log.testFail("%s | test crashed", basename) return False result = proc.proc.returncode == 0 if not result: log.testFail("%s | test failed with return code %d", basename, proc.proc.returncode) return result
def _run_server(self, group_metadata, **kwargs): cmd = self.make_command() self._output_handler = self.create_output_handler(cmd) self._proc = mozprocess.ProcessHandler( cmd, processOutputLine=self._output_handler, env=self.env, storeOutput=False) self.logger.debug("Starting WebDriver: %s" % ' '.join(cmd)) try: self._proc.run() except OSError as e: if e.errno == errno.ENOENT: raise IOError("WebDriver executable not found: %s" % self.webdriver_binary) raise self._output_handler.after_process_start(self._proc.pid) try: wait_for_service(self.logger, self.host, self.port) except Exception: self.logger.error("WebDriver was not accessible " f"within the timeout:\n{traceback.format_exc()}") raise self._output_handler.start(group_metadata=group_metadata, **kwargs) self.logger.debug("_run complete")
def run_test(self, suite, groups, temp_dir): logger.info('Running suite %s' % suite) try: cmd, output_files = self.build_command(suite, groups, temp_dir) logger.debug(cmd) logger.debug(output_files) env = dict(os.environ) env['PYTHONUNBUFFERED'] = '1' proc = mozprocess.ProcessHandler(cmd, env=env) logger.debug("Process '%s' is running" % " ".join(cmd)) #TODO: move timeout handling to here instead of each test? proc.run() proc.wait() logger.debug("Process finished") except Exception: logger.critical("Error running suite %s:\n%s" % (suite, traceback.format_exc())) raise finally: try: proc.kill() except: pass return output_files
def run_gtest(self, prog, xre_path, cwd, symbols_path=None, utility_path=None, enable_webrender=False): """ Run a single C++ unit test program. Arguments: * prog: The path to the test program to run. * env: The environment to use for running the program. * cwd: The directory to run tests from (support files will be found in this direcotry). * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. * utility_path: A path to a directory containing utility programs. currently used to locate a stack fixer to provide symbols symbols for assertion stacks. Return True if the program exits with a zero status, False otherwise. """ self.xre_path = xre_path env = self.build_environment(enable_webrender) log.info("Running gtest") if cwd and not os.path.isdir(cwd): os.makedirs(cwd) stream_output = mozprocess.StreamOutput(sys.stdout) process_output = stream_output if utility_path: stack_fixer = get_stack_fixer_function(utility_path, symbols_path) if stack_fixer: def f(line): return stream_output(stack_fixer(line)) process_output = f proc = mozprocess.ProcessHandler([prog, "-unittest", "--gtest_death_test_style=threadsafe"], cwd=cwd, env=env, processOutputLine=process_output) # TODO: After bug 811320 is fixed, don't let .run() kill the process, # instead use a timeout in .wait() and then kill to get a stack. proc.run(timeout=GTests.TEST_PROC_TIMEOUT, outputTimeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT) proc.wait() log.info("gtest | process wait complete, returncode=%s" % proc.proc.returncode) if proc.timedOut: if proc.outputTimedOut: log.testFail("gtest | timed out after %d seconds without output", GTests.TEST_PROC_NO_OUTPUT_TIMEOUT) else: log.testFail("gtest | timed out after %d seconds", GTests.TEST_PROC_TIMEOUT) return False if mozcrash.check_for_crashes(cwd, symbols_path, test_name="gtest"): # mozcrash will output the log failure line for us. return False result = proc.proc.returncode == 0 if not result: log.testFail("gtest | test failed with return code %d", proc.proc.returncode) return result
def start(self): self.cmd = [ self.binary, cmd_arg("port", str(self.webdriver_port)), cmd_arg("url-base", "wd/url") ] self.proc = mozprocess.ProcessHandler(self.cmd, processOutputLine=self.on_output) self.logger.debug("Starting chromedriver") self.proc.run()
def _run(self): try: # TODO: adb logcat -c fail randomly with message # "failed to clear the 'main' log" self.browser.clear_log() except subprocess.CalledProcessError: self.logger.error("Failed to clear logcat buffer") self._cmd = self.browser.logcat_cmd() self._proc = mozprocess.ProcessHandler( self._cmd, processOutputLine=self.on_output, storeOutput=False) self._proc.run()
def run_test(self, suite, groups, temp_dir): logger.info('Running suite %s' % suite) def on_output(line): written = False if line.startswith("{"): try: data = json.loads(line.strip()) if "action" in data: sub_logger.log_raw(data) written = True except ValueError: pass if not written: logger.process_output(proc.pid, line.decode("utf8", "replace"), command=" ".join(cmd)) try: cmd, output_files, structured_path = self.build_command( suite, groups, temp_dir) logger.debug(cmd) logger.debug(output_files) env = dict(os.environ) env['PYTHONUNBUFFERED'] = '1' proc = mozprocess.ProcessHandler(cmd, env=env, processOutputLine=on_output) logger.debug("Process '%s' is running" % " ".join(cmd)) #TODO: move timeout handling to here instead of each test? with open(structured_path, "w") as structured_log: sub_logger = structuredlog.StructuredLogger(suite) sub_logger.add_handler(stdio_handler) sub_logger.add_handler( handlers.StreamHandler(structured_log, formatters.JSONFormatter())) proc.run() proc.wait() logger.debug("Process finished") except Exception: logger.error("Error running suite %s:\n%s" % (suite, traceback.format_exc())) raise finally: try: proc.kill() except: pass return output_files, structured_path
def run_gtest(self, prog, xre_path, symbols_path=None, cwd=None): """ Run a single C++ unit test program. Arguments: * prog: The path to the test program to run. * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. Return True if the program exits with a zero status, False otherwise. """ self.xre_path = xre_path env = self.build_environment() log.info("Running gtest") if cwd and not os.path.isdir(cwd): os.makedirs(cwd) proc = mozprocess.ProcessHandler([prog, "-unittest"], cwd=cwd, env=env) #TODO: After bug 811320 is fixed, don't let .run() kill the process, # instead use a timeout in .wait() and then kill to get a stack. proc.run(timeout=GTests.TEST_PROC_TIMEOUT, outputTimeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT) proc.wait() if proc.timedOut: log.testFail("gtest | timed out after %d seconds", GTests.TEST_PROC_TIMEOUT) return False if mozcrash.check_for_crashes(os.getcwd(), symbols_path, test_name="gtest"): # mozcrash will output the log failure line for us. return False result = proc.proc.returncode == 0 if not result: log.testFail("gtest | test failed with return code %d", proc.proc.returncode) return result
def start(self): self.proc = mozprocess.ProcessHandler(self.cmd, processOutputLine=self.on_output) try: self.proc.run() except OSError as e: if e.errno == errno.ENOENT: raise IOError("chromedriver executable not found: %s" % self.binary) raise self.logger.debug("Waiting for server to become accessible: %s" % self.url) surl = urlparse.urlparse(self.url) addr = (surl.hostname, surl.port) try: wait_service(addr) except: self.logger.error( "Server was not accessible within the timeout:\n%s" % traceback.format_exc()) raise else: self.logger.info("Server listening on port %i" % self.port)
def _run(self, block, output_handler_kwargs, output_handler_start_kwargs): if output_handler_kwargs is None: output_handler_kwargs = {} if output_handler_start_kwargs is None: output_handler_start_kwargs = {} self._cmd = self.make_command() self._output_handler = self.output_handler_cls(self.logger, self._cmd, **output_handler_kwargs) self._proc = mozprocess.ProcessHandler( self._cmd, processOutputLine=self._output_handler, env=self.env, storeOutput=False) self.logger.debug("Starting WebDriver: %s" % ' '.join(self._cmd)) try: self._proc.run() except OSError as e: if e.errno == errno.ENOENT: raise IOError("WebDriver executable not found: %s" % self.binary) raise self._output_handler.after_process_start(self._proc.pid) self.logger.debug("Waiting for WebDriver to become accessible: %s" % self.url) try: wait_for_service((self.host, self.port)) except Exception: self.logger.error("WebDriver was not accessible " "within the timeout:\n%s" % traceback.format_exc()) raise self._output_handler.start(**output_handler_start_kwargs) if block: self._proc.wait()
def run_one_test(prog, env, symbols_path=None): """ Run a single C++ unit test program. Arguments: * prog: The path to the test program to run. * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. Return True if the program exits with a zero status, False otherwise. """ basename = os.path.basename(prog) log.info("Running test %s", basename) with TemporaryDirectory() as tempdir: proc = mozprocess.ProcessHandler([prog], cwd=tempdir, env=env) proc.run() timeout = 300 proc.processOutput(timeout=timeout) if proc.timedOut: log.testFail("%s | timed out after %d seconds", basename, timeout) return False proc.waitForFinish(timeout=timeout) if proc.timedOut: log.testFail("%s | timed out after %d seconds", basename, timeout) return False if mozcrash.check_for_crashes(tempdir, symbols_path, test_name=basename): log.testFail("%s | test crashed", basename) return False result = proc.proc.returncode == 0 if not result: log.testFail("%s | test failed with return code %d", basename, proc.proc.returncode) return result
def get_browser_meta(self): """Returns the browser name and version in a tuple (name, version). On desktop, we use mozversion but a fallback method also exists for non-firefox browsers, where mozversion is known to fail. The methods are OS-specific, with windows being the outlier. """ browser_name = None browser_version = None try: meta = mozversion.get_version(binary=self.config["binary"]) browser_name = meta.get("application_name") browser_version = meta.get("application_version") except Exception as e: LOG.warning( "Failed to get browser meta data through mozversion: %s-%s" % (e.__class__.__name__, e)) LOG.info("Attempting to get version through fallback method...") # Fall-back method to get browser version on desktop try: if ("linux" in self.config["platform"] or "mac" in self.config["platform"]): command = [self.config["binary"], "--version"] proc = mozprocess.ProcessHandler(command) proc.run(timeout=10, outputTimeout=10) proc.wait() bmeta = proc.output meta_re = re.compile(r"([A-z\s]+)\s+([\w.]*)") if len(bmeta) != 0: match = meta_re.match(bmeta[0].decode("utf-8")) if match: browser_name = self.config["app"] browser_version = match.group(2) else: LOG.info("Couldn't get browser version and name") else: # On windows we need to use wimc to get the version command = r'wmic datafile where name="{0}"'.format( self.config["binary"].replace("\\", r"\\")) bmeta = subprocess.check_output(command) meta_re = re.compile(r"\s+([\d.a-z]+)\s+") match = meta_re.findall(bmeta.decode("utf-8")) if len(match) > 0: browser_name = self.config["app"] browser_version = match[-1] else: LOG.info("Couldn't get browser version and name") except Exception as e: LOG.warning( "Failed to get browser meta data through fallback method: %s-%s" % (e.__class__.__name__, e)) if not browser_name: LOG.warning("Could not find a browser name") else: LOG.info("Browser name: %s" % browser_name) if not browser_version: LOG.warning("Could not find a browser version") else: LOG.info("Browser version: %s" % browser_version) return (browser_name, browser_version)