Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not overwrite LibCI log files if test runs multiple times #8615

Merged
merged 7 commits into from
Mar 18, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 58 additions & 29 deletions unit-tests/run-unit-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,16 @@ def usage():
if pyrs:
os.environ["PYTHONPATH"] += os.pathsep + pyrs_path

def subprocess_run(cmd, stdout = None, timeout = 200):
def subprocess_run(cmd, stdout = None, timeout = 200, append = False):
"""
Wrapper function for subprocess.run.
If the child process times out or ends with a non-zero exit status an exception is raised!

:param cmd: the command and argument for the child process, as a list
:param stdout: path of file to direct the output of the process to (None to disable)
:param timeout: number of seconds to give the process before forcefully ending it (None to disable)
:param append: if True and stdout is not None, the log of the test will be appended to the file instead of
overwriting it
:return: the output written by the child, if stdout is None -- otherwise N/A
"""
log.d( 'running:', cmd )
Expand All @@ -137,7 +139,12 @@ def subprocess_run(cmd, stdout = None, timeout = 200):
try:
log.debug_indent()
if stdout and stdout != subprocess.PIPE:
handle = open( stdout, "w" )
if append:
handle = open(stdout, "a" )
handle.write("\n---------------------------------------------------------------------------------\n\n")
handle.flush()
else:
handle = open( stdout, "w" )
stdout = handle
rv = subprocess.run( cmd,
stdout = stdout,
Expand Down Expand Up @@ -172,32 +179,43 @@ def check_log_for_fails( path_to_log, testname, configuration = None ):
# Tests that have failures, however, will show:
# "test cases: 1 | 1 failed
# assertions: 9 | 6 passed | 3 failed"
# We make sure we look at the log written by the last run of the test by ignoring anything before the last
# line with "----...---" that separate between 2 separate runs of he test
if path_to_log is None:
return False
for ctx in file.grep( r'^test cases:\s*(\d+) \|\s*(\d+) (passed|failed)', path_to_log ):
results = None
for ctx in file.grep( r'^test cases:\s*(\d+) \|\s*(\d+) (passed|failed)|^-+$', path_to_log ):
m = ctx['match']
total = int(m.group(1))
passed = int(m.group(2))
if m.group(3) == 'failed':
# "test cases: 1 | 1 failed"
passed = total - passed
if passed < total:
if total == 1 or passed == 0:
desc = 'failed'
else:
desc = str(total - passed) + ' of ' + str(total) + ' failed'

if log.is_verbose_on():
log.e( log.red + testname + log.reset + ': ' + configuration_str( configuration, suffix = ' ' ) + desc )
log.i( 'Log: >>>' )
log.out()
file.cat( path_to_log )
log.out( '<<<' )
else:
log.e( log.red + testname + log.reset + ': ' + configuration_str( configuration, suffix = ' ' ) + desc + '; see ' + path_to_log )
return True
if m.string == "---------------------------------------------------------------------------------":
results = None
else:
results = m

if not results:
return False

total = int(results.group(1))
passed = int(results.group(2))
if results.group(3) == 'failed':
# "test cases: 1 | 1 failed"
passed = total - passed
if passed < total:
if total == 1 or passed == 0:
desc = 'failed'
else:
desc = str(total - passed) + ' of ' + str(total) + ' failed'

if log.is_verbose_on():
log.e( log.red + testname + log.reset + ': ' + configuration_str( configuration, suffix = ' ' ) + desc )
log.i( 'Log: >>>' )
log.out()
file.cat( path_to_log )
log.out( '<<<' )
else:
log.e( log.red + testname + log.reset + ': ' + configuration_str( configuration, suffix = ' ' ) + desc + '; see ' + path_to_log )
return True
return False


class TestConfig(ABC): # Abstract Base Class
"""
Expand Down Expand Up @@ -279,23 +297,28 @@ def __init__(self, testname):
#log.d( 'found', testname )
self._name = testname
self._config = None
self._ran = False

@abstractmethod
def run_test( self, configuration = None, log_path = None ):
pass

def debug_dump(self):
def debug_dump( self ):
if self._config:
self._config.debug_dump()

@property
def config(self):
def config( self ):
return self._config

@property
def name(self):
def name( self ):
return self._name

@property
def ran( self ):
return self._ran

def get_log( self ):
global to_stdout
if to_stdout:
Expand All @@ -304,7 +327,7 @@ def get_log( self ):
path = logdir + os.sep + self.name + ".log"
return path

def is_live(self):
def is_live( self ):
"""
Returns True if the test configurations specify devices (test has a 'device' directive)
"""
Expand Down Expand Up @@ -347,7 +370,10 @@ def command(self):
return cmd

def run_test( self, configuration = None, log_path = None ):
subprocess_run( self.command, stdout=log_path )
try:
subprocess_run( self.command, stdout=log_path, append=self.ran )
finally:
self._ran = True


class ExeTest(Test):
Expand Down Expand Up @@ -398,7 +424,10 @@ def command(self):
return [self.exe]

def run_test( self, configuration = None, log_path = None ):
subprocess_run( self.command, stdout=log_path )
try:
subprocess_run( self.command, stdout=log_path, append=self.ran )
finally:
self._ran = True


def get_tests():
Expand Down