From 3f2faf7327ae7cf1a78097a8089f91e3f2aa8652 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 22 Jan 2016 12:30:11 -0700 Subject: test/py: optionally ignore errors from shell commands Sometimes it's useful to run shell commands and ignore any errors. One example might be cleanup logic; if a test-case experiences an error, the cleanup logic might experience an error too, and we don't want that error to mask the original error, so we want to ignore the subsequent error. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- test/py/multiplexed_log.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/py/multiplexed_log.py') diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index 48f2b51de15..5059bbfb99c 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -106,13 +106,17 @@ class RunAndLog(object): '''Clean up any resources managed by this object.''' pass - def run(self, cmd, cwd=None): + def run(self, cmd, cwd=None, ignore_errors=False): '''Run a command as a sub-process, and log the results. Args: cmd: The command to execute. cwd: The directory to run the command in. Can be None to use the current directory. + ignore_errors: Indicate whether to ignore errors. If True, the + function will simply return if the command cannot be executed + or exits with an error code, otherwise an exception will be + raised if such problems occur. Returns: Nothing. @@ -148,7 +152,7 @@ class RunAndLog(object): exception = e if output and not output.endswith('\n'): output += '\n' - if exit_status and not exception: + if exit_status and not exception and not ignore_errors: exception = Exception('Exit code: ' + str(exit_status)) if exception: output += str(exception) + '\n' -- cgit v1.2.3 From e8debf394fbba594fcfc267c61f8c6bbca395b06 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Jan 2016 13:41:30 -0700 Subject: test/py: use " for docstrings Python's coding style docs indicate to use " not ' for docstrings. test/py has other violations of the coding style docs, since the docs specify a stranger style than I would expect, but nobody has complained about those yet:-) Signed-off-by: Stephen Warren Reviewed-by: Simon Glass --- test/py/multiplexed_log.py | 122 ++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'test/py/multiplexed_log.py') diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index 5059bbfb99c..c2a3b895364 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -14,12 +14,12 @@ import subprocess mod_dir = os.path.dirname(os.path.abspath(__file__)) class LogfileStream(object): - '''A file-like object used to write a single logical stream of data into + """A file-like object used to write a single logical stream of data into a multiplexed log file. Objects of this type should be created by factory - functions in the Logfile class rather than directly.''' + functions in the Logfile class rather than directly.""" def __init__(self, logfile, name, chained_file): - '''Initialize a new object. + """Initialize a new object. Args: logfile: The Logfile object to log to. @@ -29,26 +29,26 @@ class LogfileStream(object): Returns: Nothing. - ''' + """ self.logfile = logfile self.name = name self.chained_file = chained_file def close(self): - '''Dummy function so that this class is "file-like". + """Dummy function so that this class is "file-like". Args: None. Returns: Nothing. - ''' + """ pass def write(self, data, implicit=False): - '''Write data to the log stream. + """Write data to the log stream. Args: data: The data to write tot he file. @@ -60,33 +60,33 @@ class LogfileStream(object): Returns: Nothing. - ''' + """ self.logfile.write(self, data, implicit) if self.chained_file: self.chained_file.write(data) def flush(self): - '''Flush the log stream, to ensure correct log interleaving. + """Flush the log stream, to ensure correct log interleaving. Args: None. Returns: Nothing. - ''' + """ self.logfile.flush() if self.chained_file: self.chained_file.flush() class RunAndLog(object): - '''A utility object used to execute sub-processes and log their output to + """A utility object used to execute sub-processes and log their output to a multiplexed log file. Objects of this type should be created by factory - functions in the Logfile class rather than directly.''' + functions in the Logfile class rather than directly.""" def __init__(self, logfile, name, chained_file): - '''Initialize a new object. + """Initialize a new object. Args: logfile: The Logfile object to log to. @@ -96,18 +96,18 @@ class RunAndLog(object): Returns: Nothing. - ''' + """ self.logfile = logfile self.name = name self.chained_file = chained_file def close(self): - '''Clean up any resources managed by this object.''' + """Clean up any resources managed by this object.""" pass def run(self, cmd, cwd=None, ignore_errors=False): - '''Run a command as a sub-process, and log the results. + """Run a command as a sub-process, and log the results. Args: cmd: The command to execute. @@ -120,7 +120,7 @@ class RunAndLog(object): Returns: Nothing. - ''' + """ msg = "+" + " ".join(cmd) + "\n" if self.chained_file: @@ -163,13 +163,13 @@ class RunAndLog(object): raise exception class SectionCtxMgr(object): - '''A context manager for Python's "with" statement, which allows a certain + """A context manager for Python's "with" statement, which allows a certain portion of test code to be logged to a separate section of the log file. Objects of this type should be created by factory functions in the Logfile - class rather than directly.''' + class rather than directly.""" def __init__(self, log, marker): - '''Initialize a new object. + """Initialize a new object. Args: log: The Logfile object to log to. @@ -177,7 +177,7 @@ class SectionCtxMgr(object): Returns: Nothing. - ''' + """ self.log = log self.marker = marker @@ -189,18 +189,18 @@ class SectionCtxMgr(object): self.log.end_section(self.marker) class Logfile(object): - '''Generates an HTML-formatted log file containing multiple streams of - data, each represented in a well-delineated/-structured fashion.''' + """Generates an HTML-formatted log file containing multiple streams of + data, each represented in a well-delineated/-structured fashion.""" def __init__(self, fn): - '''Initialize a new object. + """Initialize a new object. Args: fn: The filename to write to. Returns: Nothing. - ''' + """ self.f = open(fn, "wt") self.last_stream = None @@ -217,7 +217,7 @@ class Logfile(object): """) def close(self): - '''Close the log file. + """Close the log file. After calling this function, no more data may be written to the log. @@ -226,7 +226,7 @@ class Logfile(object): Returns: Nothing. - ''' + """ self.f.write("""\ @@ -241,7 +241,7 @@ class Logfile(object): "".join(chr(c) for c in range(127, 256))) def _escape(self, data): - '''Render data format suitable for inclusion in an HTML document. + """Render data format suitable for inclusion in an HTML document. This includes HTML-escaping certain characters, and translating control characters to a hexadecimal representation. @@ -251,7 +251,7 @@ class Logfile(object): Returns: An escaped version of the data. - ''' + """ data = data.replace(chr(13), "") data = "".join((c in self._nonprint) and ("%%%02x" % ord(c)) or @@ -260,14 +260,14 @@ class Logfile(object): return data def _terminate_stream(self): - '''Write HTML to the log file to terminate the current stream's data. + """Write HTML to the log file to terminate the current stream's data. Args: None. Returns: Nothing. - ''' + """ self.cur_evt += 1 if not self.last_stream: @@ -280,7 +280,7 @@ class Logfile(object): self.last_stream = None def _note(self, note_type, msg): - '''Write a note or one-off message to the log file. + """Write a note or one-off message to the log file. Args: note_type: The type of note. This must be a value supported by the @@ -289,7 +289,7 @@ class Logfile(object): Returns: Nothing. - ''' + """ self._terminate_stream() self.f.write("
\n
")
@@ -297,14 +297,14 @@ class Logfile(object):
         self.f.write("\n
\n") def start_section(self, marker): - '''Begin a new nested section in the log file. + """Begin a new nested section in the log file. Args: marker: The name of the section that is starting. Returns: Nothing. - ''' + """ self._terminate_stream() self.blocks.append(marker) @@ -314,7 +314,7 @@ class Logfile(object): "\">Section: " + blk_path + "\n") def end_section(self, marker): - '''Terminate the current nested section in the log file. + """Terminate the current nested section in the log file. This function validates proper nesting of start_section() and end_section() calls. If a mismatch is found, an exception is raised. @@ -324,7 +324,7 @@ class Logfile(object): Returns: Nothing. - ''' + """ if (not self.blocks) or (marker != self.blocks[-1]): raise Exception("Block nesting mismatch: \"%s\" \"%s\"" % @@ -337,7 +337,7 @@ class Logfile(object): self.blocks.pop() def section(self, marker): - '''Create a temporary section in the log file. + """Create a temporary section in the log file. This function creates a context manager for Python's "with" statement, which allows a certain portion of test code to be logged to a separate @@ -352,96 +352,96 @@ class Logfile(object): Returns: A context manager object. - ''' + """ return SectionCtxMgr(self, marker) def error(self, msg): - '''Write an error note to the log file. + """Write an error note to the log file. Args: msg: A message describing the error. Returns: Nothing. - ''' + """ self._note("error", msg) def warning(self, msg): - '''Write an warning note to the log file. + """Write an warning note to the log file. Args: msg: A message describing the warning. Returns: Nothing. - ''' + """ self._note("warning", msg) def info(self, msg): - '''Write an informational note to the log file. + """Write an informational note to the log file. Args: msg: An informational message. Returns: Nothing. - ''' + """ self._note("info", msg) def action(self, msg): - '''Write an action note to the log file. + """Write an action note to the log file. Args: msg: A message describing the action that is being logged. Returns: Nothing. - ''' + """ self._note("action", msg) def status_pass(self, msg): - '''Write a note to the log file describing test(s) which passed. + """Write a note to the log file describing test(s) which passed. Args: msg: A message describing passed test(s). Returns: Nothing. - ''' + """ self._note("status-pass", msg) def status_skipped(self, msg): - '''Write a note to the log file describing skipped test(s). + """Write a note to the log file describing skipped test(s). Args: msg: A message describing passed test(s). Returns: Nothing. - ''' + """ self._note("status-skipped", msg) def status_fail(self, msg): - '''Write a note to the log file describing failed test(s). + """Write a note to the log file describing failed test(s). Args: msg: A message describing passed test(s). Returns: Nothing. - ''' + """ self._note("status-fail", msg) def get_stream(self, name, chained_file=None): - '''Create an object to log a single stream's data into the log file. + """Create an object to log a single stream's data into the log file. This creates a "file-like" object that can be written to in order to write a single stream's data to the log file. The implementation will @@ -456,12 +456,12 @@ class Logfile(object): Returns: A file-like object. - ''' + """ return LogfileStream(self, name, chained_file) def get_runner(self, name, chained_file=None): - '''Create an object that executes processes and logs their output. + """Create an object that executes processes and logs their output. Args: name: The name of this sub-process. @@ -470,12 +470,12 @@ class Logfile(object): Returns: A RunAndLog object. - ''' + """ return RunAndLog(self, name, chained_file) def write(self, stream, data, implicit=False): - '''Write stream data into the log file. + """Write stream data into the log file. This function should only be used by instances of LogfileStream or RunAndLog. @@ -491,7 +491,7 @@ class Logfile(object): Returns: Nothing. - ''' + """ if stream != self.last_stream: self._terminate_stream() @@ -507,13 +507,13 @@ class Logfile(object): self.last_stream = stream def flush(self): - '''Flush the log stream, to ensure correct log interleaving. + """Flush the log stream, to ensure correct log interleaving. Args: None. Returns: Nothing. - ''' + """ self.f.flush() -- cgit v1.2.3 From a2ec560647e90250183e379799db957970cb260e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Jan 2016 13:41:31 -0700 Subject: test/py: Quote consistency When converting test/py from " to ', I missed a few places (or added a few inconsistencies later). Fix these. Note that only quotes in code are converted; double-quotes in comments and HTML are left as-is, since English and HTML use " not '. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass --- test/py/multiplexed_log.py | 68 +++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'test/py/multiplexed_log.py') diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index c2a3b895364..fd3a9231a81 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -122,7 +122,7 @@ class RunAndLog(object): Nothing. """ - msg = "+" + " ".join(cmd) + "\n" + msg = '+' + ' '.join(cmd) + '\n' if self.chained_file: self.chained_file.write(msg) self.logfile.write(self, msg) @@ -202,19 +202,19 @@ class Logfile(object): Nothing. """ - self.f = open(fn, "wt") + self.f = open(fn, 'wt') self.last_stream = None self.blocks = [] self.cur_evt = 1 - shutil.copy(mod_dir + "/multiplexed_log.css", os.path.dirname(fn)) - self.f.write("""\ + shutil.copy(mod_dir + '/multiplexed_log.css', os.path.dirname(fn)) + self.f.write('''\ -""") +''') def close(self): """Close the log file. @@ -228,17 +228,17 @@ class Logfile(object): Nothing. """ - self.f.write("""\ + self.f.write('''\ -""") +''') self.f.close() # The set of characters that should be represented as hexadecimal codes in # the log file. - _nonprint = ("%" + "".join(chr(c) for c in range(0, 32) if c not in (9, 10)) + - "".join(chr(c) for c in range(127, 256))) + _nonprint = ('%' + ''.join(chr(c) for c in range(0, 32) if c not in (9, 10)) + + ''.join(chr(c) for c in range(127, 256))) def _escape(self, data): """Render data format suitable for inclusion in an HTML document. @@ -253,8 +253,8 @@ class Logfile(object): An escaped version of the data. """ - data = data.replace(chr(13), "") - data = "".join((c in self._nonprint) and ("%%%02x" % ord(c)) or + data = data.replace(chr(13), '') + data = ''.join((c in self._nonprint) and ('%%%02x' % ord(c)) or c for c in data) data = cgi.escape(data) return data @@ -272,11 +272,11 @@ class Logfile(object): self.cur_evt += 1 if not self.last_stream: return - self.f.write("\n") - self.f.write("
End stream: " + - self.last_stream.name + "
\n") - self.f.write("\n") + self.f.write('\n') + self.f.write('
End stream: ' + + self.last_stream.name + '
\n') + self.f.write('\n') self.last_stream = None def _note(self, note_type, msg): @@ -292,9 +292,9 @@ class Logfile(object): """ self._terminate_stream() - self.f.write("
\n
")
+        self.f.write('
\n
')
         self.f.write(self._escape(msg))
-        self.f.write("\n
\n") + self.f.write('\n
\n') def start_section(self, marker): """Begin a new nested section in the log file. @@ -308,10 +308,10 @@ class Logfile(object): self._terminate_stream() self.blocks.append(marker) - blk_path = "/".join(self.blocks) - self.f.write("
\n") - self.f.write("
Section: " + blk_path + "
\n") + blk_path = '/'.join(self.blocks) + self.f.write('
\n') + self.f.write('
Section: ' + blk_path + '
\n') def end_section(self, marker): """Terminate the current nested section in the log file. @@ -327,13 +327,13 @@ class Logfile(object): """ if (not self.blocks) or (marker != self.blocks[-1]): - raise Exception("Block nesting mismatch: \"%s\" \"%s\"" % - (marker, "/".join(self.blocks))) + raise Exception('Block nesting mismatch: "%s" "%s"' % + (marker, '/'.join(self.blocks))) self._terminate_stream() - blk_path = "/".join(self.blocks) - self.f.write("
End section: " + blk_path + "
\n") - self.f.write("
\n") + blk_path = '/'.join(self.blocks) + self.f.write('
End section: ' + blk_path + '
\n') + self.f.write('
\n') self.blocks.pop() def section(self, marker): @@ -495,15 +495,15 @@ class Logfile(object): if stream != self.last_stream: self._terminate_stream() - self.f.write("
\n" % stream.name) - self.f.write("
Stream: " + stream.name + "
\n") - self.f.write("
")
+            self.f.write('
\n' % stream.name) + self.f.write('
Stream: ' + stream.name + '
\n') + self.f.write('
')
         if implicit:
-            self.f.write("")
+            self.f.write('')
         self.f.write(self._escape(data))
         if implicit:
-            self.f.write("")
+            self.f.write('')
         self.last_stream = stream
 
     def flush(self):
-- 
cgit v1.2.3


From 78b39cc3e19e698c04c2417ed5f79e324c90595e Mon Sep 17 00:00:00 2001
From: Stephen Warren 
Date: Wed, 27 Jan 2016 23:57:51 -0700
Subject: test/py: correctly log xfail/xpass tests

Tests can complete in passed, skipped, xpass, xfailed, or failed, states.
Currently the U-Boot log generation code doesn't handle the xfailed or
xpass states since they aren't used. Add support for the remaining states.
Without this, tests that xfail end up being reported as skipped.

Signed-off-by: Stephen Warren 
Acked-by: Simon Glass 
---
 test/py/multiplexed_log.py | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

(limited to 'test/py/multiplexed_log.py')

diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
index fd3a9231a81..69a577e5772 100644
--- a/test/py/multiplexed_log.py
+++ b/test/py/multiplexed_log.py
@@ -408,7 +408,7 @@ class Logfile(object):
         """Write a note to the log file describing test(s) which passed.
 
         Args:
-            msg: A message describing passed test(s).
+            msg: A message describing the passed test(s).
 
         Returns:
             Nothing.
@@ -420,7 +420,7 @@ class Logfile(object):
         """Write a note to the log file describing skipped test(s).
 
         Args:
-            msg: A message describing passed test(s).
+            msg: A message describing the skipped test(s).
 
         Returns:
             Nothing.
@@ -428,11 +428,35 @@ class Logfile(object):
 
         self._note("status-skipped", msg)
 
+    def status_xfail(self, msg):
+        """Write a note to the log file describing xfailed test(s).
+
+        Args:
+            msg: A message describing the xfailed test(s).
+
+        Returns:
+            Nothing.
+        """
+
+        self._note("status-xfail", msg)
+
+    def status_xpass(self, msg):
+        """Write a note to the log file describing xpassed test(s).
+
+        Args:
+            msg: A message describing the xpassed test(s).
+
+        Returns:
+            Nothing.
+        """
+
+        self._note("status-xpass", msg)
+
     def status_fail(self, msg):
         """Write a note to the log file describing failed test(s).
 
         Args:
-            msg: A message describing passed test(s).
+            msg: A message describing the failed test(s).
 
         Returns:
             Nothing.
-- 
cgit v1.2.3