[PATCH v2] pytest: Show a message when sandbox crashes

2021-10-08 Thread Simon Glass
When a test hands on a real board there is no way on the console to obtain
any information about why it hung.

With sandbox we can actually find out that it died and get a signal or
exit code. Add this to make it easier to figure out what happened.

So instead of:

test/py/u_boot_spawn.py:171: in expect
c = os.read(self.fd, 1024).decode(errors='replace')
E   OSError: [Errno 5] Input/output error

We get:

test/py/u_boot_spawn.py:171: in expect
c = os.read(self.fd, 1024).decode(errors='replace')
E   ValueError: U-Boot exited with signal 11 (Signals.SIGSEGV)

Signed-off-by: Simon Glass 
---

Changes in v2:
- Fix a few test failure it causes

 doc/develop/py_testing.rst |  8 ++
 test/py/u_boot_spawn.py| 56 ++
 2 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/doc/develop/py_testing.rst b/doc/develop/py_testing.rst
index 52238ca54d3..06f919609b5 100644
--- a/doc/develop/py_testing.rst
+++ b/doc/develop/py_testing.rst
@@ -103,6 +103,14 @@ will be written to `${build_dir}/test-log.html`. This is 
best viewed in a web
 browser, but may be read directly as plain text, perhaps with the aid of the
 `html2text` utility.
 
+If sandbox crashes (e.g. with a segfault) you will see message like this::
+
+
+test/py/u_boot_spawn.py:171: in expect
+c = os.read(self.fd, 1024).decode(errors='replace')
+E   ValueError: U-Boot exited with signal 11 (Signals.SIGSEGV)
+
+
 Controlling output
 ~~
 
diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py
index 6991b78cca8..e34cb217e84 100644
--- a/test/py/u_boot_spawn.py
+++ b/test/py/u_boot_spawn.py
@@ -35,6 +35,8 @@ class Spawn(object):
 """
 
 self.waited = False
+self.exit_code = 0
+self.exit_info = ''
 self.buf = ''
 self.output = ''
 self.logfile_read = None
@@ -80,25 +82,44 @@ class Spawn(object):
 
 os.kill(self.pid, sig)
 
-def isalive(self):
+def checkalive(self):
 """Determine whether the child process is still running.
 
-Args:
-None.
-
 Returns:
-Boolean indicating whether process is alive.
+tuple:
+True if process is alive, else False
+0 if process is alive, else exit code of process
+string describing what happened ('' or 'status/signal n')
 """
 
 if self.waited:
-return False
+return False, self.exit_code, self.exit_info
 
 w = os.waitpid(self.pid, os.WNOHANG)
 if w[0] == 0:
-return True
-
+return True, 0, 'running'
+status = w[1]
+
+if os.WIFEXITED(status):
+self.exit_code = os.WEXITSTATUS(status)
+self.exit_info = 'status %d' % self.exit_code
+elif os.WIFSIGNALED(status):
+signum = os.WTERMSIG(status)
+self.exit_code = -signum
+self.exit_info = 'signal %d (%s)' % (signum, 
signal.Signals(signum))
 self.waited = True
-return False
+return False, self.exit_code, self.exit_info
+
+def isalive(self):
+"""Determine whether the child process is still running.
+
+Args:
+None.
+
+Returns:
+Boolean indicating whether process is alive.
+"""
+return self.checkalive()[0]
 
 def send(self, data):
 """Send data to the sub-process's stdin.
@@ -168,9 +189,20 @@ class Spawn(object):
 events = self.poll.poll(poll_maxwait)
 if not events:
 raise Timeout()
-c = os.read(self.fd, 1024).decode(errors='replace')
-if not c:
-raise EOFError()
+try:
+c = os.read(self.fd, 1024).decode(errors='replace')
+except OSError as err:
+# With sandbox, try to detect when U-Boot exits when it
+# shouldn't and explain why. This is much more friendly 
than
+# just dying with an I/O error
+if err.errno == 5:  # Input/output error
+alive, exit_code, info = self.checkalive()
+if alive:
+raise
+else:
+raise ValueError('U-Boot exited with %s' % info)
+else:
+raise
 if self.logfile_read:
 self.logfile_read.write(c)
 self.buf += c
-- 
2.33.0.882.g93a45727a2-goog



Re: [PATCH v2] pytest: Show a message when sandbox crashes

2021-10-15 Thread Tom Rini
On Fri, Oct 08, 2021 at 09:15:23AM -0600, Simon Glass wrote:

> When a test hands on a real board there is no way on the console to obtain
> any information about why it hung.
> 
> With sandbox we can actually find out that it died and get a signal or
> exit code. Add this to make it easier to figure out what happened.
> 
> So instead of:
> 
> test/py/u_boot_spawn.py:171: in expect
> c = os.read(self.fd, 1024).decode(errors='replace')
> E   OSError: [Errno 5] Input/output error
> 
> We get:
> 
> test/py/u_boot_spawn.py:171: in expect
> c = os.read(self.fd, 1024).decode(errors='replace')
> E   ValueError: U-Boot exited with signal 11 (Signals.SIGSEGV)
> 
> Signed-off-by: Simon Glass 

Applied to u-boot/master, thanks!

-- 
Tom


signature.asc
Description: PGP signature