]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
pytest: Show a message when sandbox crashes
authorSimon Glass <sjg@chromium.org>
Fri, 8 Oct 2021 15:15:23 +0000 (09:15 -0600)
committerTom Rini <trini@konsulko.com>
Thu, 14 Oct 2021 23:45:07 +0000 (19:45 -0400)
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 <sjg@chromium.org>
doc/develop/py_testing.rst
test/py/u_boot_spawn.py

index 52238ca54d3c022a7ce1d9c73ac8f68b879d0dbe..06f919609b5785eeadf1d54c3ae5ae3b9b87f60a 100644 (file)
@@ -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
 ~~~~~~~~~~~~~~~~~~
 
index 6991b78cca89ea75c733d2ee8b537695fbd77c63..e34cb217e84a1995fcd30db2740e62ac3aa19448 100644 (file)
@@ -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