[U-Boot] [PATCH 1/1] test/py: catch errors occurring when reading the console
Heinrich Schuchardt
xypron.glpk at gmx.de
Wed Sep 19 00:43:50 UTC 2018
On 09/18/2018 07:23 PM, Stephen Warren wrote:
> On 09/18/2018 11:21 AM, Heinrich Schuchardt wrote:
>> Spawn.exept has a try block without 'except'.
>>
>> If no output is available an OSError may arise. Catch this exception and
>> continue testing.
>>
>> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
>> Reviewed-by: Simon Glass <sjg at chromium.org>
>> ---
>> I suggest that Alex takes the patch because we need it when working on
>> the
>> efi-next branch.
>>
>> v2
>> replace TAB by spaces
>> fix typo in subject
>
> I'll point out that I still object to this.
>
On 09/18/2018 07:06 PM, Stephen Warren wrote:
> This doesn't make sense at all. It catches all errors and ignores them.
> It'll turn any error condition into a timeout (presumably, the expected
> data being waited for will never appear) rather than dealing with it
> immediately (due to the thrown exception). Why is this needed?
>
When the py test is running it is connected via pipes to the U-Boot
process. If the U-Boot process ends due to a segmentation fault the
pipes are broken. Trying to read from a broken pipe results in an OSError.
Before this patch this leads to an uncaught error in the Python script.
The output that has occured up to this point is lost and not displayed.
All further tests for the configuration are not run.
An example can be seen at the end of
https://api.travis-ci.org/v3/job/429566431/log.txt .
I have copied the relevant part of the output below.
Please, observe that the output that has occurred until the segmentation
fault is not displayed. Instead we see lines with "INTERNAL ERROR>".
The same can be observed when executing
make mrproper && make tests
Further below I have copied the output with the patch. Here the OSError
is caught and the py tests continue as expected.
Best regards
Heinrich
=== Output without the patch ===
test/py/tests/test_efi_selftest.py F
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/_pytest/main.py", line 178,
in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/_pytest/main.py", line 215,
in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/hooks.py", line 258,
in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers +
self._wrappers, kwargs)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/manager.py", line
67, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/manager.py", line
61, in <lambda>
INTERNALERROR> firstresult=hook.spec_opts.get('firstresult'),
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
201, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
77, in get_result
INTERNALERROR> _reraise(*ex) # noqa
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
180, in _multicall
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/_pytest/main.py", line 236,
in pytest_runtestloop
INTERNALERROR> item.config.hook.pytest_runtest_protocol(item=item,
nextitem=nextitem)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/hooks.py", line 258,
in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers +
self._wrappers, kwargs)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/manager.py", line
67, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/manager.py", line
61, in <lambda>
INTERNALERROR> firstresult=hook.spec_opts.get('firstresult'),
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
201, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
77, in get_result
INTERNALERROR> _reraise(*ex) # noqa
INTERNALERROR> File
"/tmp/venv/local/lib/python2.7/site-packages/pluggy/callers.py", line
180, in _multicall
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File
"/home/travis/build/agraf/u-boot/test/py/conftest.py", line 577, in
pytest_runtest_protocol
INTERNALERROR> console.drain_console()
INTERNALERROR> File
"/home/travis/build/agraf/u-boot/test/py/u_boot_console_base.py", line
306, in drain_console
INTERNALERROR> self.p.expect(['This should never match U-Boot output'])
INTERNALERROR> File
"/home/travis/build/agraf/u-boot/test/py/u_boot_spawn.py", line 174, in
expect
INTERNALERROR> c = os.read(self.fd, 1024)
INTERNALERROR> OSError: [Errno 5] Input/output error
=== Output with the patch ===
$ make tests
./test/run
+make O=/home/user/workspace/u-boot-build/denx/build-sandbox -s
sandbox_defconfig
+make O=/home/user/workspace/u-boot-build/denx/build-sandbox -s -j8
===========================================================================
test session starts
============================================================================
platform linux2 -- Python 2.7.15+, pytest-3.6.4, py-1.6.0, pluggy-0.6.0
rootdir: /home/user/workspace/u-boot-build/denx/test/py, inifile: pytest.ini
collected 411 items
test/py/tests/test_000_version.py .
[ 0%]
test/py/tests/test_avb.py sssss
[ 0%]
test/py/tests/test_bind.py ..
[ 0%]
test/py/tests/test_dfu.py s
[ 0%]
test/py/tests/test_efi_loader.py .sssss
[ 0%]
test/py/tests/test_efi_selftest.py FFFFF
[ 0%]
test/py/tests/test_env.py ............
[ 0%]
test/py/tests/test_fit.py F
[ 0%]
test/py/tests/test_fpga.py sssssssssssssssssssssssssss
[ 0%]
test/py/tests/test_gpt.py sssssss
[ 0%]
test/py/tests/test_help.py .
[ 0%]
test/py/tests/test_hush_if_test.py
.......................................................
[ 0%]
test/py/tests/test_log.py ..
[ 0%]
test/py/tests/test_md.py ..
[ 0%]
test/py/tests/test_mmc_rd.py s
[ 0%]
test/py/tests/test_net.py .sssss
[ 0%]
test/py/tests/test_ofplatdata.py s
[ 0%]
test/py/tests/test_sandbox_exit.py ..
[ 0%]
test/py/tests/test_sf.py ssss
[ 0%]
test/py/tests/test_shell_basics.py ....
[ 0%]
test/py/tests/test_sleep.py .
[ 0%]
test/py/tests/test_tpm2.py ...........
[ 0%]
test/py/tests/test_ums.py s
[ 0%]
test/py/tests/test_unknown_cmd.py .
[ 0%]
test/py/tests/test_ut.py
........................................................................................................................................................................
[ 0%]
test/py/tests/test_vboot.py F[sudo] password for user:
[ 0%]
test/py/tests/test_fs/test_basic.py
sssssssssssssssssssssssssssssssssssssss
[ 0%]
test/py/tests/test_fs/test_ext.py ssssssssssssssssss
[ 0%]
test/py/tests/test_fs/test_mkdir.py ssssssssssss
[ 0%]
test/py/tests/test_fs/test_unlink.py ssssssssssssss
=================================================================================
FAILURES
=================================================================================
____________________________________________________________________________
test_efi_selftest
_____________________________________________________________________________
u_boot_console = <u_boot_console_sandbox.ConsoleSandbox object at
0x7fb32ef7cfd0>
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest(u_boot_console):
"""
Run bootefi selftest
"""
u_boot_console.run_command(cmd='setenv efi_selftest')
u_boot_console.run_command(cmd='bootefi selftest',
wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any
key'])
if m != 0:
> raise Exception('Failures occurred during the EFI selftest')
E Exception: Failures occurred during the EFI selftest
test/py/tests/test_efi_selftest.py:19: Exception
---------------------------------------------------------------------------
Captured stdout call
---------------------------------------------------------------------------
=> setenv efi_selftest
=> => bootefi selftest
Scanning disk mmc2.blk...
^[[44;172R______________________________________________________________________
test_efi_selftest_device_tree
_______________________________________________________________________
u_boot_console = <u_boot_console_sandbox.ConsoleSandbox object at
0x7fb32ef7cfd0>
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
@pytest.mark.buildconfigspec('of_control')
def test_efi_selftest_device_tree(u_boot_console):
u_boot_console.run_command(cmd='setenv efi_selftest list')
> output = u_boot_console.run_command('bootefi selftest')
test/py/tests/test_efi_selftest.py:30:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <u_boot_console_sandbox.ConsoleSandbox object at 0x7fb32ef7cfd0>,
cmd = '', wait_for_echo = True, send_nl = True, wait_for_prompt = True
def run_command(self, cmd, wait_for_echo=True, send_nl=True,
wait_for_prompt=True):
"""Execute a command via the U-Boot console.
The command is always sent to U-Boot.
U-Boot echoes any command back to its output, and this function
typically waits for that to occur. The wait can be disabled
by setting
wait_for_echo=False, which is useful e.g. when sending CTRL-C to
interrupt a long-running command such as "ums".
Command execution is typically triggered by sending a newline
character. This can be disabled by setting send_nl=False,
which is
also useful when sending CTRL-C.
This function typically waits for the command to finish
executing, and
returns the console output that it generated. This can be
disabled by
setting wait_for_prompt=False, which is useful when invoking
a long-
running command such as "ums".
Args:
cmd: The command to send.
wait_for_echo: Boolean indicating whether to wait for
U-Boot to
echo the command text back to its output.
send_nl: Boolean indicating whether to send a newline
character
after the command string.
wait_for_prompt: Boolean indicating whether to wait for the
command prompt to be sent by U-Boot. This typically
occurs
immediately after the command has been executed.
Returns:
If wait_for_prompt == False:
Nothing.
Else:
The output from U-Boot during command execution. In
other
words, the text U-Boot emitted between the point it
echod the
command string and emitted the subsequent command
prompts.
"""
if self.at_prompt and \
self.at_prompt_logevt != self.logstream.logfile.cur_evt:
self.logstream.write(self.prompt, implicit=True)
try:
self.at_prompt = False
if send_nl:
cmd += '\n'
while cmd:
# Limit max outstanding data, so UART FIFOs don't overflow
chunk = cmd[:self.max_fifo_fill]
cmd = cmd[self.max_fifo_fill:]
self.p.send(chunk)
if not wait_for_echo:
continue
chunk = re.escape(chunk)
chunk = chunk.replace('\\\n', '[\r\n]')
m = self.p.expect([chunk] + self.bad_patterns)
if m != 0:
self.at_prompt = False
raise Exception('Bad pattern found on console: ' +
self.bad_pattern_ids[m - 1])
if not wait_for_prompt:
return
m = self.p.expect([self.prompt_compiled] + self.bad_patterns)
if m != 0:
self.at_prompt = False
raise Exception('Bad pattern found on console: ' +
> self.bad_pattern_ids[m - 1])
E TypeError: unsupported operand type(s)
for -: 'NoneType' and 'int'
test/py/u_boot_console_base.py:207: TypeError
--------------------------------------------------------------------------
Captured stdout setup
---------------------------------------------------------------------------
/u-boot
More information about the U-Boot
mailing list