diff options
Diffstat (limited to 'test/py')
-rw-r--r-- | test/py/requirements.txt | 2 | ||||
-rw-r--r-- | test/py/tests/test_dm.py | 5 | ||||
-rw-r--r-- | test/py/tests/test_efi_secboot/conftest.py | 10 | ||||
-rw-r--r-- | test/py/tests/test_efi_secboot/test_authvar.py | 4 | ||||
-rw-r--r-- | test/py/tests/test_efi_secboot/test_signed.py | 10 | ||||
-rw-r--r-- | test/py/tests/test_help.py | 6 | ||||
-rw-r--r-- | test/py/tests/test_log.py | 11 | ||||
-rw-r--r-- | test/py/tests/test_net.py | 5 | ||||
-rw-r--r-- | test/py/tests/test_net_boot.py | 400 | ||||
-rw-r--r-- | test/py/tests/test_tpm2.py | 2 | ||||
-rw-r--r-- | test/py/tests/test_trace.py | 6 | ||||
-rw-r--r-- | test/py/tests/test_ut.py | 1 | ||||
-rw-r--r-- | test/py/u_boot_console_base.py | 44 | ||||
-rw-r--r-- | test/py/u_boot_console_sandbox.py | 2 | ||||
-rw-r--r-- | test/py/u_boot_spawn.py | 10 |
15 files changed, 492 insertions, 26 deletions
diff --git a/test/py/requirements.txt b/test/py/requirements.txt index 0f67c3c6194..c1dd636931f 100644 --- a/test/py/requirements.txt +++ b/test/py/requirements.txt @@ -20,7 +20,7 @@ pytest==6.2.5 pytest-xdist==2.5.0 python-mimeparse==1.6.0 python-subunit==1.3.0 -requests==2.31.0 +requests==2.32.2 setuptools==65.5.1 six==1.16.0 testtools==2.3.0 diff --git a/test/py/tests/test_dm.py b/test/py/tests/test_dm.py index 68d4ea12235..be94971e455 100644 --- a/test/py/tests/test_dm.py +++ b/test/py/tests/test_dm.py @@ -13,8 +13,11 @@ def test_dm_compat(u_boot_console): for line in response[:-1].split('\n')[2:]) response = u_boot_console.run_command('dm compat') + bad_drivers = set() for driver in drivers: - assert driver in response + if not driver in response: + bad_drivers.add(driver) + assert not bad_drivers # check sorting - output looks something like this: # testacpi 0 [ ] testacpi_drv |-- acpi-test diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index ff7ac7c8101..0fa0747fc76 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -64,6 +64,12 @@ def efi_boot_env(request, u_boot_config): check_call('cd %s; %scert-to-efi-sig-list -g %s db1.crt db1.esl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key db db1.esl db1.auth' % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), shell=True) + # db2 (APPEND_WRITE) + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db2/ -keyout db2.key -out db2.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s db2.crt db2.esl; %ssign-efi-sig-list -a -c KEK.crt -k KEK.key db db2.esl db2.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) # dbx (TEST_dbx certificate) check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_dbx/ -keyout dbx.key -out dbx.crt -nodes -days 365' % mnt_point, shell=True) @@ -84,6 +90,10 @@ def efi_boot_env(request, u_boot_config): check_call('cd %s; %scert-to-efi-hash-list -g %s -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-06" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth' % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), shell=True) + # dbx_hash2 (digest of TEST_db2 certificate, with APPEND_WRITE) + check_call('cd %s; %scert-to-efi-hash-list -g %s -s 256 db2.crt dbx_hash2.crl; %ssign-efi-sig-list -a -c KEK.crt -k KEK.key dbx dbx_hash2.crl dbx_hash2.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) # dbx_db (with TEST_db certificate) check_call('cd %s; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx db.esl dbx_db.auth' % (mnt_point, EFITOOLS_PATH), diff --git a/test/py/tests/test_efi_secboot/test_authvar.py b/test/py/tests/test_efi_secboot/test_authvar.py index f99b8270a64..d5aeb650480 100644 --- a/test/py/tests/test_efi_secboot/test_authvar.py +++ b/test/py/tests/test_efi_secboot/test_authvar.py @@ -183,7 +183,7 @@ class TestEfiAuthVar(object): assert 'db:' in ''.join(output) output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -a -i 4000000:$filesize db']) assert 'Failed to set EFI variable' in ''.join(output) @@ -197,7 +197,7 @@ class TestEfiAuthVar(object): with u_boot_console.log.section('Test Case 3c'): # Test Case 3c, update with correct signature output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py index 5000a4ab7b6..f604138a356 100644 --- a/test/py/tests/test_efi_secboot/test_signed.py +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -177,7 +177,7 @@ class TestEfiSignedImage(object): with u_boot_console.log.section('Test Case 5b'): # Test Case 5b, authenticated if both signatures are verified output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ @@ -201,7 +201,7 @@ class TestEfiSignedImage(object): with u_boot_console.log.section('Test Case 5d'): # Test Case 5d, rejected if both of signatures are revoked output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 dbx_hash1.auth', + 'fatload host 0:1 4000000 dbx_hash2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ @@ -223,7 +223,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 'fatload host 0:1 4000000 dbx_hash1.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) @@ -300,7 +300,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 'fatload host 0:1 4000000 dbx_hash384.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) @@ -323,7 +323,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'fatload host 0:1 4000000 db1.auth', + 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 'fatload host 0:1 4000000 dbx_hash512.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) diff --git a/test/py/tests/test_help.py b/test/py/tests/test_help.py index 153133cf28f..2325ff69229 100644 --- a/test/py/tests/test_help.py +++ b/test/py/tests/test_help.py @@ -7,7 +7,11 @@ import pytest def test_help(u_boot_console): """Test that the "help" command can be executed.""" - u_boot_console.run_command('help') + lines = u_boot_console.run_command('help') + if u_boot_console.config.buildconfig.get('config_cmd_2048', 'n') == 'y': + assert lines.splitlines()[0] == "2048 - The 2048 game" + else: + assert lines.splitlines()[0] == "? - alias for 'help'" @pytest.mark.boardspec('sandbox') def test_help_no_devicetree(u_boot_console): diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py index 140dcb9aa2b..79808674bbe 100644 --- a/test/py/tests/test_log.py +++ b/test/py/tests/test_log.py @@ -27,13 +27,16 @@ def test_log_format(u_boot_console): cons = u_boot_console with cons.log.section('format'): - run_with_format('all', 'NOTICE.arch,file.c:123-func() msg') + pad = int(u_boot_console.config.buildconfig.get('config_logf_func_pad')) + padding = ' ' * (pad - len('func')) + + run_with_format('all', f'NOTICE.arch,file.c:123-{padding}func() msg') output = cons.run_command('log format') assert output == 'Log format: clFLfm' - run_with_format('fm', 'func() msg') - run_with_format('clfm', 'NOTICE.arch,func() msg') - run_with_format('FLfm', 'file.c:123-func() msg') + run_with_format('fm', f'{padding}func() msg') + run_with_format('clfm', f'NOTICE.arch,{padding}func() msg') + run_with_format('FLfm', f'file.c:123-{padding}func() msg') run_with_format('lm', 'NOTICE. msg') run_with_format('m', 'msg') diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py index 038a473b239..ad143c19b0d 100644 --- a/test/py/tests/test_net.py +++ b/test/py/tests/test_net.py @@ -254,7 +254,7 @@ def test_net_network_discovery(u_boot_console): assert 'Set gatewayip6:' in output assert '0000:0000:0000:0000:0000:0000:0000:0000' not in output -@pytest.mark.buildconfigspec('cmd_net') +@pytest.mark.buildconfigspec('cmd_tftpboot') def test_net_tftpboot(u_boot_console): """Test the tftpboot command. @@ -335,7 +335,6 @@ def test_net_nfs(u_boot_console): output = u_boot_console.run_command('crc32 %x $filesize' % addr) assert expected_crc in output -@pytest.mark.buildconfigspec("cmd_net") @pytest.mark.buildconfigspec("cmd_pxe") def test_net_pxe_get(u_boot_console): """Test the pxe get command. @@ -391,7 +390,7 @@ def test_net_pxe_get(u_boot_console): assert "Config file 'default.boot' found" in output @pytest.mark.buildconfigspec("cmd_crc32") -@pytest.mark.buildconfigspec("cmd_net") +@pytest.mark.buildconfigspec("cmd_tftpboot") @pytest.mark.buildconfigspec("cmd_tftpput") def test_net_tftpput(u_boot_console): """Test the tftpput command. diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py new file mode 100644 index 00000000000..63309fe82e1 --- /dev/null +++ b/test/py/tests/test_net_boot.py @@ -0,0 +1,400 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2023, Advanced Micro Devices, Inc. + +import pytest +import u_boot_utils +import test_net +import re + +""" +Note: This test relies on boardenv_* containing configuration values to define +which the network environment available for testing. Without this, this test +will be automatically skipped. + +For example: + +# Details regarding a boot image file that may be read from a TFTP server. This +# variable may be omitted or set to None if TFTP boot testing is not possible +# or desired. +env__net_tftp_bootable_file = { + 'fn': 'image.ub', + 'addr': 0x10000000, + 'size': 5058624, + 'crc32': 'c2244b26', + 'pattern': 'Linux', + 'config': 'config@2', + 'timeout': 50000, + 'check_type': 'boot_error', + 'check_pattern': 'ERROR', +} + +# False or omitted if a TFTP boot test should be tested. +# If TFTP boot testing is not possible or desired, set this variable to True. +# For example: If FIT image is not proper to boot +env__tftp_boot_test_skip = False + +# Here is the example of FIT image configurations: +configurations { + default = "config@1"; + config@1 { + description = "Boot Linux kernel with config@1"; + kernel = "kernel@0"; + fdt = "fdt@0"; + ramdisk = "ramdisk@0"; + hash@1 { + algo = "sha1"; + }; + }; + config@2 { + description = "Boot Linux kernel with config@2"; + kernel = "kernel@1"; + fdt = "fdt@1"; + ramdisk = "ramdisk@1"; + hash@1 { + algo = "sha1"; + }; + }; +}; + +# Details regarding a file that may be read from a TFTP server. This variable +# may be omitted or set to None if PXE testing is not possible or desired. +env__net_pxe_bootable_file = { + 'fn': 'default', + 'addr': 0x10000000, + 'size': 74, + 'timeout': 50000, + 'pattern': 'Linux', + 'valid_label': '1', + 'invalid_label': '2', + 'exp_str_invalid': 'Skipping install for failure retrieving', + 'local_label': '3', + 'exp_str_local': 'missing environment variable: localcmd', + 'empty_label': '4', + 'exp_str_empty': 'No kernel given, skipping boot', + 'check_type': 'boot_error', + 'check_pattern': 'ERROR', +} + +# False or omitted if a PXE boot test should be tested. +# If PXE boot testing is not possible or desired, set this variable to True. +# For example: If pxe configuration file is not proper to boot +env__pxe_boot_test_skip = False + +# Here is the example of pxe configuration file ordered based on the execution +# flow: +1) /tftpboot/pxelinux.cfg/default-arm-zynqmp + + menu include pxelinux.cfg/default-arm + timeout 50 + + default Linux + +2) /tftpboot/pxelinux.cfg/default-arm + + menu title Linux boot selections + menu include pxelinux.cfg/default + + label install + menu label Invalid boot + kernel kernels/install.bin + append console=ttyAMA0,38400 debug earlyprintk + initrd initrds/uzInitrdDebInstall + + label local + menu label Local boot + append root=/dev/sdb1 + localboot 1 + + label boot + menu label Empty boot + +3) /tftpboot/pxelinux.cfg/default + + label Linux + menu label Boot kernel + kernel Image + fdt system.dtb + initrd rootfs.cpio.gz.u-boot +""" + +def setup_networking(u_boot_console): + test_net.test_net_dhcp(u_boot_console) + if not test_net.net_set_up: + test_net.test_net_setup_static(u_boot_console) + +def setup_tftpboot_boot(u_boot_console): + f = u_boot_console.config.env.get('env__net_tftp_bootable_file', None) + if not f: + pytest.skip('No TFTP bootable file to read') + + setup_networking(u_boot_console) + addr = f.get('addr', None) + if not addr: + addr = u_boot_utils.find_ram_base(u_boot_console) + + fn = f['fn'] + timeout = f.get('timeout', 50000) + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn)) + + expected_text = 'Bytes transferred = ' + sz = f.get('size', None) + if sz: + expected_text += '%d' % sz + assert expected_text in output + + expected_crc = f.get('crc32', None) + output = u_boot_console.run_command('crc32 %x $filesize' % addr) + if expected_crc: + assert expected_crc in output + + pattern = f.get('pattern') + chk_type = f.get('check_type', 'boot_error') + chk_pattern = re.compile(f.get('check_pattern', 'ERROR')) + config = f.get('config', None) + + return addr, timeout, pattern, chk_type, chk_pattern, config + +@pytest.mark.buildconfigspec('cmd_tftpboot') +def test_net_tftpboot_boot(u_boot_console): + """Boot the loaded image + + A boot file (fit image) is downloaded from the TFTP server and booted using + bootm command with the default fit configuration, its boot log pattern are + validated. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + if u_boot_console.config.env.get('env__tftp_boot_test_skip', True): + pytest.skip('TFTP boot test is not enabled!') + + addr, timeout, pattern, chk_type, chk_pattern, imcfg = setup_tftpboot_boot( + u_boot_console + ) + + if imcfg: + bootcmd = 'bootm %x#%s' % (addr, imcfg) + else: + bootcmd = 'bootm %x' % addr + + with u_boot_console.enable_check( + chk_type, chk_pattern + ), u_boot_console.temporary_timeout(timeout): + try: + # wait_for_prompt=False makes the core code not wait for the U-Boot + # prompt code to be seen, since it won't be on a successful kernel + # boot + u_boot_console.run_command(bootcmd, wait_for_prompt=False) + + # Wait for boot log pattern + u_boot_console.wait_for(pattern) + finally: + # This forces the console object to be shutdown, so any subsequent + # test will reset the board back into U-Boot. We want to force this + # no matter whether the kernel boot passed or failed. + u_boot_console.drain_console() + u_boot_console.cleanup_spawn() + +def setup_pxe_boot(u_boot_console): + f = u_boot_console.config.env.get('env__net_pxe_bootable_file', None) + if not f: + pytest.skip('No PXE bootable file to read') + + setup_networking(u_boot_console) + bootfile = u_boot_console.run_command('echo $bootfile') + if not bootfile: + bootfile = '<NULL>' + + return f, bootfile + +@pytest.mark.buildconfigspec('cmd_pxe') +def test_net_pxe_boot(u_boot_console): + """Test the pxe boot command. + + A pxe configuration file is downloaded from the TFTP server and interpreted + to boot the images mentioned in pxe configuration file. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + if u_boot_console.config.env.get('env__pxe_boot_test_skip', True): + pytest.skip('PXE boot test is not enabled!') + + f, bootfile = setup_pxe_boot(u_boot_console) + addr = f.get('addr', None) + timeout = f.get('timeout', u_boot_console.p.timeout) + fn = f['fn'] + + if addr: + u_boot_console.run_command('setenv pxefile_addr_r %x' % addr) + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command('pxe get') + + expected_text = 'Bytes transferred = ' + sz = f.get('size', None) + if sz: + expected_text += '%d' % sz + assert 'TIMEOUT' not in output + assert expected_text in output + assert f"Config file '{bootfile}' found" in output + + pattern = f.get('pattern') + chk_type = f.get('check_type', 'boot_error') + chk_pattern = re.compile(f.get('check_pattern', 'ERROR')) + + if not addr: + pxe_boot_cmd = 'pxe boot' + else: + pxe_boot_cmd = 'pxe boot %x' % addr + + with u_boot_console.enable_check( + chk_type, chk_pattern + ), u_boot_console.temporary_timeout(timeout): + try: + u_boot_console.run_command(pxe_boot_cmd, wait_for_prompt=False) + u_boot_console.wait_for(pattern) + finally: + u_boot_console.drain_console() + u_boot_console.cleanup_spawn() + +@pytest.mark.buildconfigspec('cmd_pxe') +def test_net_pxe_boot_config(u_boot_console): + """Test the pxe boot command by selecting different combination of labels + + A pxe configuration file is downloaded from the TFTP server and interpreted + to boot the images mentioned in pxe configuration file. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + if u_boot_console.config.env.get('env__pxe_boot_test_skip', True): + pytest.skip('PXE boot test is not enabled!') + + f, bootfile = setup_pxe_boot(u_boot_console) + addr = f.get('addr', None) + timeout = f.get('timeout', u_boot_console.p.timeout) + fn = f['fn'] + local_label = f['local_label'] + empty_label = f['empty_label'] + exp_str_local = f['exp_str_local'] + exp_str_empty = f['exp_str_empty'] + + if addr: + u_boot_console.run_command('setenv pxefile_addr_r %x' % addr) + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command('pxe get') + + expected_text = 'Bytes transferred = ' + sz = f.get('size', None) + if sz: + expected_text += '%d' % sz + assert 'TIMEOUT' not in output + assert expected_text in output + assert f"Config file '{bootfile}' found" in output + + pattern = f.get('pattern') + chk_type = f.get('check_type', 'boot_error') + chk_pattern = re.compile(f.get('check_pattern', 'ERROR')) + + if not addr: + pxe_boot_cmd = 'pxe boot' + else: + pxe_boot_cmd = 'pxe boot %x' % addr + + with u_boot_console.enable_check( + chk_type, chk_pattern + ), u_boot_console.temporary_timeout(timeout): + try: + u_boot_console.run_command(pxe_boot_cmd, wait_for_prompt=False) + + # pxe config is loaded where multiple labels are there and need to + # select particular label to boot and check for expected string + # In this case, local label is selected and it should look for + # localcmd env variable and if that variable is not defined it + # should not boot it and come out to u-boot prompt + u_boot_console.wait_for('Enter choice:') + u_boot_console.run_command(local_label, wait_for_prompt=False) + expected_str = u_boot_console.p.expect([exp_str_local]) + assert ( + expected_str == 0 + ), f'Expected string: {exp_str_local} did not match!' + + # In this case, empty label is selected and it should look for + # kernel image path and if it is not set it should fail it and load + # default label to boot + u_boot_console.run_command(pxe_boot_cmd, wait_for_prompt=False) + u_boot_console.wait_for('Enter choice:') + u_boot_console.run_command(empty_label, wait_for_prompt=False) + expected_str = u_boot_console.p.expect([exp_str_empty]) + assert ( + expected_str == 0 + ), f'Expected string: {exp_str_empty} did not match!' + + u_boot_console.wait_for(pattern) + finally: + u_boot_console.drain_console() + u_boot_console.cleanup_spawn() + +@pytest.mark.buildconfigspec('cmd_pxe') +def test_net_pxe_boot_config_invalid(u_boot_console): + """Test the pxe boot command by selecting invalid label + + A pxe configuration file is downloaded from the TFTP server and interpreted + to boot the images mentioned in pxe configuration file. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + if u_boot_console.config.env.get('env__pxe_boot_test_skip', True): + pytest.skip('PXE boot test is not enabled!') + + f, bootfile = setup_pxe_boot(u_boot_console) + addr = f.get('addr', None) + timeout = f.get('timeout', u_boot_console.p.timeout) + fn = f['fn'] + invalid_label = f['invalid_label'] + exp_str_invalid = f['exp_str_invalid'] + + if addr: + u_boot_console.run_command('setenv pxefile_addr_r %x' % addr) + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command('pxe get') + + expected_text = 'Bytes transferred = ' + sz = f.get('size', None) + if sz: + expected_text += '%d' % sz + assert 'TIMEOUT' not in output + assert expected_text in output + assert f"Config file '{bootfile}' found" in output + + pattern = f.get('pattern') + if not addr: + pxe_boot_cmd = 'pxe boot' + else: + pxe_boot_cmd = 'pxe boot %x' % addr + + with u_boot_console.temporary_timeout(timeout): + try: + u_boot_console.run_command(pxe_boot_cmd, wait_for_prompt=False) + + # pxe config is loaded where multiple labels are there and need to + # select particular label to boot and check for expected string + # In this case invalid label is selected, it should load invalid + # label and if it fails it should load the default label to boot + u_boot_console.wait_for('Enter choice:') + u_boot_console.run_command(invalid_label, wait_for_prompt=False) + expected_str = u_boot_console.p.expect([exp_str_invalid]) + assert ( + expected_str == 0 + ), f'Expected string: {exp_str_invalid} did not match!' + + u_boot_console.wait_for(pattern) + finally: + u_boot_console.drain_console() + u_boot_console.cleanup_spawn() diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py index 1d654cd4a23..75f5d31fc67 100644 --- a/test/py/tests/test_tpm2.py +++ b/test/py/tests/test_tpm2.py @@ -257,7 +257,7 @@ def test_tpm2_pcr_read(u_boot_console): updates = int(re.findall(r'\d+', str)[0]) # Check the output value - assert 'PCR #10 content' in read_pcr + assert 'PCR #10 sha256 32 byte content' in read_pcr assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr @pytest.mark.buildconfigspec('cmd_tpm_v2') diff --git a/test/py/tests/test_trace.py b/test/py/tests/test_trace.py index 7c5696ce747..ec1e624722c 100644 --- a/test/py/tests/test_trace.py +++ b/test/py/tests/test_trace.py @@ -12,7 +12,7 @@ import u_boot_utils as util TMPDIR = '/tmp/test_trace' # Decode a function-graph line -RE_LINE = re.compile(r'.*0\.\.\.\.\. \s*([0-9.]*): func.*[|](\s*)(\S.*)?([{};])$') +RE_LINE = re.compile(r'.*0\.\.\.\.\.? \s*([0-9.]*): func.*[|](\s*)(\S.*)?([{};])$') def collect_trace(cons): @@ -175,7 +175,7 @@ def check_funcgraph(cons, fname, proftool, map_fname, trace_dat): # Then look for this: # u-boot-1 0..... 282.101375: funcgraph_exit: 0.006 us | } # Then check for this: - # u-boot-1 0..... 282.101375: funcgraph_entry: 0.000 us | initcall_is_event(); + # u-boot-1 0..... 282.101375: funcgraph_entry: 0.000 us | calc_reloc_ofs(); expected_indent = None found_start = False @@ -199,7 +199,7 @@ def check_funcgraph(cons, fname, proftool, map_fname, trace_dat): # The next function after initf_bootstage() exits should be # initcall_is_event() - assert upto == 'initcall_is_event()' + assert upto == 'calc_reloc_ofs()' # Now look for initf_dm() and dm_timer_init() so we can check the bootstage # time diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index c169c835e38..58205066ec8 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -470,6 +470,7 @@ def test_ut_dm_init(u_boot_console): fh.write(data) @pytest.mark.buildconfigspec('cmd_bootflow') +@pytest.mark.buildconfigspec('sandbox') def test_ut_dm_init_bootstd(u_boot_console): """Initialise data for bootflow tests""" diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 3e01be11029..76a550d45a1 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -55,6 +55,32 @@ class ConsoleDisableCheck(object): self.console.disable_check_count[self.check_type] -= 1 self.console.eval_bad_patterns() +class ConsoleEnableCheck(object): + """Context manager (for Python's with statement) that temporarily enables + the specified console output error check. This is useful when executing a + command that might raise an extra bad pattern, beyond the default bad + patterns, in order to validate that the extra bad pattern is actually + detected. This class is used internally by ConsoleBase::enable_check(); it + is not intended for direct usage.""" + + def __init__(self, console, check_type, check_pattern): + self.console = console + self.check_type = check_type + self.check_pattern = check_pattern + + def __enter__(self): + global bad_pattern_defs + self.default_bad_patterns = bad_pattern_defs + bad_pattern_defs += ((self.check_type, self.check_pattern),) + self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs} + self.console.eval_bad_patterns() + + def __exit__(self, extype, value, traceback): + global bad_pattern_defs + bad_pattern_defs = self.default_bad_patterns + self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs} + self.console.eval_bad_patterns() + class ConsoleSetupTimeout(object): """Context manager (for Python's with statement) that temporarily sets up timeout for specific command. This is useful when execution time is greater @@ -492,6 +518,24 @@ class ConsoleBase(object): return ConsoleDisableCheck(self, check_type) + def enable_check(self, check_type, check_pattern): + """Temporarily enable an error check of U-Boot's output. + + Create a new context manager (for use with the "with" statement) which + temporarily enables a particular console output error check. The + arguments form a new element of bad_pattern_defs defined above. + + Args: + check_type: The type of error-check or bad pattern to enable. + check_pattern: The regexes for text error pattern or bad pattern + to be checked. + + Returns: + A context manager object. + """ + + return ConsoleEnableCheck(self, check_type, check_pattern) + def temporary_timeout(self, timeout): """Temporarily set up different timeout for commands. diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py index 27c6db8d719..7bc44c78b8b 100644 --- a/test/py/u_boot_console_sandbox.py +++ b/test/py/u_boot_console_sandbox.py @@ -58,7 +58,7 @@ class ConsoleSandbox(ConsoleBase): if self.use_dtb: cmd += ['-d', self.config.dtb] cmd += self.sandbox_flags - return Spawn(cmd, cwd=self.config.source_dir) + return Spawn(cmd, cwd=self.config.source_dir, decode_signal=True) def restart_uboot_with_flags(self, flags, expect_reset=False, use_dtb=True): """Run U-Boot with the given command-line flags diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index 7c48d96210e..97e95e07c80 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -24,18 +24,20 @@ class Spawn: output: accumulated output from expect() """ - def __init__(self, args, cwd=None): + def __init__(self, args, cwd=None, decode_signal=False): """Spawn (fork/exec) the sub-process. Args: args: array of processs arguments. argv[0] is the command to execute. cwd: the directory to run the process in, or None for no change. + decode_signal (bool): True to indicate the exception number when + something goes wrong Returns: Nothing. """ - + self.decode_signal = decode_signal self.waited = False self.exit_code = 0 self.exit_info = '' @@ -197,12 +199,12 @@ class Spawn: # 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 + if self.decode_signal and err.errno == 5: # I/O error alive, _, info = self.checkalive() if alive: raise err raise ValueError('U-Boot exited with %s' % info) - raise err + raise if self.logfile_read: self.logfile_read.write(c) self.buf += c |