Add a bootstd test for the error path of the efi_mgr bootmeth: remove
the BootOrder variable so that the boot manager has nothing to load and
check that booting the bootflow returns -ENOENT rather than the generic
-EFAULT that bootflow_boot() reports when a boot() method returns zero.

Running the real boot manager initialises the EFI subsystem in the
sandbox process, which would leak into later tests, so restart U-Boot
after this test in test_ut.py as is already done for other
session-changing tests.

Signed-off-by: Aristo Chen <[email protected]>
---
Changes in v2:
- Remove BootOrder instead of pointing it at a non-existent load option,
  which relied on efidebug accepting invalid input (Heinrich)
- Check for -ENOENT accordingly and drop the CMD_EFIDEBUG dependency

 test/boot/bootflow.c     | 40 ++++++++++++++++++++++++++++++++++++++++
 test/py/tests/test_ut.py |  3 ++-
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 1cc137c9700..9d71fffba8e 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -14,6 +14,7 @@
 #include <dm.h>
 #include <efi.h>
 #include <efi_loader.h>
+#include <efi_variable.h>
 #include <env.h>
 #include <expo.h>
 #include <mapmem.h>
@@ -470,6 +471,45 @@ static int bootflow_system(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_system, UTF_DM | UTF_SCAN_PDATA | UTF_SCAN_FDT |
             UTF_CONSOLE);
+
+/* Check that a failed 'efi_mgr' boot reports the boot manager's error */
+static int bootflow_efi_mgr_err(struct unit_test_state *uts)
+{
+       struct udevice *bootstd, *dev;
+       struct bootflow *bflow;
+       efi_status_t status;
+       int ret;
+
+       if (!IS_ENABLED(CONFIG_EFI_BOOTMGR))
+               return -EAGAIN;
+       ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
+       ut_assertok(device_bind(bootstd, DM_DRIVER_GET(bootmeth_3efi_mgr),
+                               "efi_mgr", 0, ofnode_null(), &dev));
+       ut_assertok(device_probe(dev));
+       sandbox_set_fake_efi_mgr_dev(dev, true);
+
+       bootstd_clear_glob();
+       ut_assertok(run_command("bootflow scan -H", 0));
+
+       /* Remove any BootOrder so that the boot manager has nothing to load */
+       ut_asserteq(EFI_SUCCESS, efi_init_obj_list());
+       status = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+                                     0, 0, NULL, false);
+       ut_assert(status == EFI_SUCCESS || status == EFI_NOT_FOUND);
+
+       for (ret = bootflow_first_glob(&bflow); !ret;
+            ret = bootflow_next_glob(&bflow)) {
+               if (!strcmp("efi_mgr", bflow->method->name))
+                       break;
+       }
+       ut_assertok(ret);
+
+       /* The boot manager finds no boot option; its error must not be lost */
+       ut_asserteq(-ENOENT, bootflow_boot(bflow));
+
+       return 0;
+}
+BOOTSTD_TEST(bootflow_efi_mgr_err, UTF_DM | UTF_SCAN_PDATA | UTF_SCAN_FDT);
 #endif
 
 /* Check disabling a bootmethod if it requests it */
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index fa50c8008a5..787020e3e0c 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -643,7 +643,8 @@ def ut_ubman_fixture(ubman, ut_subtest):
 
     yield ubman
 
-    if ut_subtest in ("bootstd bootflow_cmd_boot", "bootstd 
bootflow_scan_boot"):
+    if ut_subtest in ("bootstd bootflow_cmd_boot", "bootstd 
bootflow_scan_boot",
+                      "bootstd bootflow_efi_mgr_err"):
         ubman.restart_uboot()
 
 
-- 
2.43.0

Reply via email to