X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/a604ba860f2989b7703e79518b1ebec6d36364c8..2e2c91eaa94e8fa79a41bbcdd443f55ad2a37f19:/tools/tesh/tesh.py diff --git a/tools/tesh/tesh.py b/tools/tesh/tesh.py index 8821279506..a1375b9aa4 100755 --- a/tools/tesh/tesh.py +++ b/tools/tesh/tesh.py @@ -5,7 +5,7 @@ tesh -- testing shell ======================== -Copyright (c) 2012-2022. The SimGrid Team. All rights reserved. +Copyright (c) 2012-2023. The SimGrid Team. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU LGPL) which comes with this package. @@ -46,10 +46,6 @@ else: # # -def is_windows(): - """ Check if running on Windows """ - return sys.platform.startswith('win') - # Singleton metaclass that works in Python 2 & 3 # http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python @@ -120,7 +116,7 @@ def process_is_dead(pid): def kill_process_group(pid): """ This function send TERM signal + KILL signal after 0.2s to the group of the specified process """ if pid is None: - # Nobody to kill. We don't know who to kill on windows, or we don't have anyone to kill on signal handler + # Nobody to kill. We don't have anyone to kill on signal handler return try: @@ -200,6 +196,7 @@ class TeshState(Singleton): self.args_suffix = "" self.ignore_regexps_common = [] self.jenkins = False # not a Jenkins run by default + self.auto_valgrind = True self.timeout = 10 # default value: 10 sec self.wrapper = None self.keep = False @@ -241,6 +238,7 @@ class Cmd: self.output_display = False self.sort = -1 + self.rerun_with_valgrind = False self.ignore_regexps = TeshState().ignore_regexps_common @@ -306,6 +304,14 @@ class Cmd: _thread.start_new_thread(Cmd._run, (self, lock)) else: self._run() + if self.rerun_with_valgrind and TeshState().auto_valgrind: + print('\n\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') + print( 'XXXXXXXXX Rerunning this test with valgrind to help debugging it XXXXXXXXX') + print( 'XXXXXXXX (this will fail if valgrind is not installed, of course) XXXXXXXX') + print( 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n\n') + + self.args = "valgrind " + self.args + self._run() return True def _run(self, lock=None): @@ -348,17 +354,18 @@ class Cmd: self.args += TeshState().args_suffix logs = list() - logs.append("[{file}:{number}] {args}".format(file=FileReader().filename, - number=self.linenumber, args=self.args)) + msg = "[{file}:{number}] {args}".format(file=FileReader().filename, number=self.linenumber, args=self.args) + if self.background: + logs.append(msg) + else: + print(msg, flush=True) args = shlex.split(self.args) local_pid = None try: - preexec_function = None - if not is_windows(): - preexec_function = lambda: os.setpgid(0, 0) + preexec_function = lambda: os.setpgid(0, 0) proc = subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn args, bufsize=1, @@ -367,9 +374,8 @@ class Cmd: stderr=subprocess.STDOUT, universal_newlines=True, preexec_fn=preexec_function) - if not is_windows(): - local_pid = proc.pid - TeshState().running_pids.append(local_pid) + local_pid = proc.pid + TeshState().running_pids.append(local_pid) except PermissionError: logs.append("[{file}:{number}] Cannot start '{cmd}': The binary is not executable.".format( file=FileReader().filename, number=self.linenumber, cmd=args[0])) @@ -418,20 +424,24 @@ class Cmd: print('\n'.join(logs)) return - if self.output_display: - logs.append(str(stdout_data)) - # remove text colors ansi_escape = re.compile(r'\x1b[^m]*m') stdout_data = ansi_escape.sub('', stdout_data) + if self.output_display: + logs.append(str(stdout_data)) + + if self.rerun_with_valgrind: + print(str(stdout_data), file=sys.stderr) + return + if self.ignore_output: logs.append("(ignoring the output of <{cmd}> as requested)".format(cmd=cmd_name)) else: stdouta = stdout_data.split("\n") + stdouta = self.remove_ignored_lines(stdouta) while stdouta and stdouta[-1] == "": del stdouta[-1] - stdouta = self.remove_ignored_lines(stdouta) stdcpy = stdouta[:] # Mimic the "sort" bash command, which is case unsensitive. @@ -468,6 +478,18 @@ class Cmd: logs.append("Test suite `{file}': NOK (<{cmd}> output mismatch)".format( file=FileReader().filename, cmd=cmd_name)) + + # Also report any failed return code and/or signal we got in case of output mismatch + if not proc.returncode in self.expect_return: + if proc.returncode >= 0: + logs.append("In addition, <{cmd}> returned code {code}.".format( + cmd=cmd_name, code=proc.returncode)) + else: + logs.append("In addition, <{cmd}> got signal {sig}.".format(cmd=cmd_name, + sig=SIGNALS_TO_NAMES_DICT[-proc.returncode])) + if proc.returncode == -signal.SIGSEGV: + self.rerun_with_valgrind = True + if lock is not None: lock.release() if TeshState().keep: @@ -502,6 +524,10 @@ class Cmd: logs.append("Test suite `{file}': NOK (<{cmd}> got signal {sig})".format( file=FileReader().filename, cmd=cmd_name, sig=SIGNALS_TO_NAMES_DICT[-proc.returncode])) + + if proc.returncode == -signal.SIGSEGV: + self.rerun_with_valgrind = True + if lock is not None: lock.release() TeshState().set_return_code(max(-proc.returncode, 1)) @@ -542,6 +568,10 @@ def main(): '--ignore-jenkins', action='store_true', help='ignore all cruft generated on SimGrid continuous integration servers') + group1.add_argument( + '--no-auto-valgrind', + action='store_true', + help='do not automaticall launch segfaulting commands in valgrind') group1.add_argument('--wrapper', metavar='arg', help='Run each command in the provided wrapper (eg valgrind)') group1.add_argument( '--keep', @@ -561,14 +591,13 @@ def main(): re.compile(r"profiling:"), re.compile(r"Unable to clean temporary file C:"), re.compile(r".*Configuration change: Set 'contexts/"), - re.compile(r"Picked up JAVA_TOOL_OPTIONS: "), - re.compile(r"Picked up _JAVA_OPTIONS: "), re.compile(r"==[0-9]+== ?WARNING: ASan doesn't fully support"), re.compile(r"==[0-9]+== ?WARNING: ASan is ignoring requested __asan_handle_no_return: stack "), re.compile(r"False positive error reports may follow"), re.compile(r"For details see http://code\.google\.com/p/address-sanitizer/issues/detail\?id=189"), re.compile(r"For details see https://github\.com/google/sanitizers/issues/189"), re.compile(r"Python runtime initialized with LC_CTYPE=C .*"), + re.compile(r"sthread is intercepting the execution of \.*"), # Seen on CircleCI re.compile(r"cmake: /usr/local/lib/libcurl\.so\.4: no version information available \(required by cmake\)"), re.compile( @@ -577,6 +606,9 @@ def main(): ] TeshState().jenkins = True # This is a Jenkins build + if options.no_auto_valgrind: + TeshState().auto_valgrind = False + if options.teshfile is None: file = FileReader(None) print("Test suite from stdin") @@ -681,7 +713,16 @@ def main(): cmd.add_ignore(line[len("! ignore "):]) else: - fatal_error("UNRECOGNIZED OPTION") + fatal_error(f"UNRECOGNIZED OPTION LINE: {line}\n" + "Valid requests:\n" + " ! output ignore\n" + " ! output sort\n" + " ! output display\n" + " ! setenv XX=YY\n" + " ! ignore XYZ\n" + " ! expect return NN\n" + " ! expect signal NN\n" + " ! timeout NN\n") line = file.readfullline()