diff options
Diffstat (limited to 'test')
37 files changed, 1879 insertions, 488 deletions
diff --git a/test/Kconfig b/test/Kconfig index 28704a25b61..2646e7d825a 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -6,6 +6,16 @@ menuconfig UNIT_TEST This does not require sandbox to be included, but it is most often used there. +config SPL_UNIT_TEST + bool "Unit tests in SPL" + # We need to be able to unbind devices for tests to work + select SPL_DM_DEVICE_REMOVE + help + Select this to enable unit tests in SPL. Most test are designed for + running in U-Boot proper, but some are intended for SPL, such as + of-platdata and SPL handover. To run these tests with the sandbox_spl + board, use the -u (unit test) option. + config UT_LIB bool "Unit tests for library functions" depends on UNIT_TEST diff --git a/test/Makefile b/test/Makefile index 7c4039964e1..1c930b31485 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,15 +2,19 @@ # # (C) Copyright 2012 The Chromium Authors -obj-$(CONFIG_SANDBOX) += bloblist.o -obj-$(CONFIG_CMDLINE) += cmd/ -obj-$(CONFIG_UNIT_TEST) += cmd_ut.o -obj-$(CONFIG_UNIT_TEST) += ut.o -obj-$(CONFIG_SANDBOX) += command_ut.o -obj-$(CONFIG_SANDBOX) += compression.o -obj-$(CONFIG_SANDBOX) += print_ut.o -obj-$(CONFIG_SANDBOX) += str_ut.o +obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o +obj-$(CONFIG_$(SPL_)CMDLINE) += cmd/ +obj-$(CONFIG_$(SPL_)CMDLINE) += cmd_ut.o +obj-$(CONFIG_$(SPL_)CMDLINE) += command_ut.o +obj-$(CONFIG_$(SPL_)CMDLINE) += compression.o +obj-y += dm/ +obj-$(CONFIG_$(SPL_)CMDLINE) += print_ut.o +obj-$(CONFIG_$(SPL_)CMDLINE) += str_ut.o obj-$(CONFIG_UT_TIME) += time_ut.o -obj-$(CONFIG_UT_UNICODE) += unicode_ut.o -obj-y += log/ +obj-y += ut.o + +ifeq ($(CONFIG_SPL_BUILD),) obj-$(CONFIG_UNIT_TEST) += lib/ +obj-y += log/ +obj-$(CONFIG_$(SPL_)UT_UNICODE) += unicode_ut.o +endif diff --git a/test/dm/Makefile b/test/dm/Makefile index 70ba1b66953..57e13ad5338 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -2,15 +2,18 @@ # # Copyright (c) 2013 Google, Inc +obj-$(CONFIG_UT_DM) += test-main.o + +# Tests for particular subsystems - when enabling driver model for a new +# subsystem you must add sandbox tests here. +ifeq ($(CONFIG_SPL_BUILD),y) +obj-$(CONFIG_SPL_OF_PLATDATA) += of_platdata.o +else obj-$(CONFIG_UT_DM) += bus.o -obj-$(CONFIG_UT_DM) += nop.o obj-$(CONFIG_UT_DM) += test-driver.o obj-$(CONFIG_UT_DM) += test-fdt.o -obj-$(CONFIG_UT_DM) += test-main.o obj-$(CONFIG_UT_DM) += test-uclass.o -# Tests for particular subsystems - when enabling driver model for a new -# subsystem you must add sandbox tests here. obj-$(CONFIG_UT_DM) += core.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_ACPIGEN) += acpi.o @@ -34,7 +37,9 @@ obj-y += irq.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o +obj-$(CONFIG_CMD_MUX) += mux-cmd.o obj-y += fdtdec.o +obj-$(CONFIG_UT_DM) += nop.o obj-y += ofnode.o obj-y += ofread.o obj-$(CONFIG_OSD) += osd.o @@ -57,6 +62,8 @@ obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_SMEM) += smem.o obj-$(CONFIG_DM_SPI) += spi.o obj-y += syscon.o +obj-$(CONFIG_MUX_MMIO) += mux-mmio.o +obj-$(CONFIG_MULTIPLEXER) += mux-emul.o obj-$(CONFIG_DM_USB) += usb.o obj-$(CONFIG_DM_PMIC) += pmic.o obj-$(CONFIG_DM_REGULATOR) += regulator.o @@ -81,4 +88,8 @@ obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o +ifneq ($(CONFIG_PINMUX),) +obj-$(CONFIG_PINCONF) += pinmux.o +endif endif +endif # !SPL diff --git a/test/dm/button.c b/test/dm/button.c index 91178017365..ecaa47cf5f3 100644 --- a/test/dm/button.c +++ b/test/dm/button.c @@ -57,17 +57,17 @@ static int dm_test_button_label(struct unit_test_state *uts) { struct udevice *dev, *cmp; - ut_assertok(button_get_by_label("summer", &dev)); + ut_assertok(button_get_by_label("button1", &dev)); ut_asserteq(1, device_active(dev)); ut_assertok(uclass_get_device(UCLASS_BUTTON, 1, &cmp)); ut_asserteq_ptr(dev, cmp); - ut_assertok(button_get_by_label("christmas", &dev)); + ut_assertok(button_get_by_label("button2", &dev)); ut_asserteq(1, device_active(dev)); ut_assertok(uclass_get_device(UCLASS_BUTTON, 2, &cmp)); ut_asserteq_ptr(dev, cmp); - ut_asserteq(-ENODEV, button_get_by_label("spring", &dev)); + ut_asserteq(-ENODEV, button_get_by_label("nobutton", &dev)); return 0; } diff --git a/test/dm/led.c b/test/dm/led.c index 8b587d0a22a..ac6ee363940 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -40,7 +40,8 @@ static int dm_test_led_default_state(struct unit_test_state *uts) ut_assertok(led_get_by_label("sandbox:default_on", &dev)); ut_asserteq(LEDST_ON, led_get_state(dev)); - ut_assertok(led_get_by_label("sandbox:default_off", &dev)); + /* Also tests default label behaviour */ + ut_assertok(led_get_by_label("default_off", &dev)); ut_asserteq(LEDST_OFF, led_get_state(dev)); return 0; diff --git a/test/dm/mux-cmd.c b/test/dm/mux-cmd.c new file mode 100644 index 00000000000..11c237b5da9 --- /dev/null +++ b/test/dm/mux-cmd.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Texas Instruments Inc. + * Pratyush Yadav <p.yadav@ti.com> + */ +#include <common.h> +#include <dm.h> +#include <mux.h> +#include <mux-internal.h> +#include <dt-bindings/mux/mux.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/ut.h> +#include <console.h> +#include <rand.h> + +#define BUF_SIZE 256 + +/* Test 'mux list' */ +static int dm_test_cmd_mux_list(struct unit_test_state *uts) +{ + char str[BUF_SIZE], *tok; + struct udevice *dev; + struct mux_chip *chip; + struct mux_control *mux; + int i; + unsigned long val; + + sandbox_set_enable_memio(true); + + ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller", + &dev)); + chip = dev_get_uclass_priv(dev); + ut_assertnonnull(chip); + + run_command("mux list", 0); + ut_assert_nextline("a-mux-controller:"); + + /* + * Check the table header to make sure we are not out of sync with the + * code in the command. If we are, catch it early. + */ + console_record_readline(str, BUF_SIZE); + tok = strtok(str, " "); + ut_asserteq_str("ID", tok); + + tok = strtok(NULL, " "); + ut_asserteq_str("Selected", tok); + + tok = strtok(NULL, " "); + ut_asserteq_str("Current", tok); + tok = strtok(NULL, " "); + ut_asserteq_str("State", tok); + + tok = strtok(NULL, " "); + ut_asserteq_str("Idle", tok); + tok = strtok(NULL, " "); + ut_asserteq_str("State", tok); + + tok = strtok(NULL, " "); + ut_asserteq_str("Num", tok); + tok = strtok(NULL, " "); + ut_asserteq_str("States", tok); + + for (i = 0; i < chip->controllers; i++) { + mux = &chip->mux[i]; + + console_record_readline(str, BUF_SIZE); + + /* + * Check if the ID printed matches with the ID of the chip we + * have. + */ + tok = strtok(str, " "); + ut_assertok(strict_strtoul(tok, 10, &val)); + ut_asserteq(i, val); + + /* Check if mux selection state matches. */ + tok = strtok(NULL, " "); + if (mux->in_use) { + ut_asserteq_str("yes", tok); + } else { + ut_asserteq_str("no", tok); + } + + /* Check if the current state matches. */ + tok = strtok(NULL, " "); + if (mux->cached_state == MUX_IDLE_AS_IS) { + ut_asserteq_str("unknown", tok); + } else { + ut_assertok(strict_strtoul(tok, 16, &val)); + ut_asserteq(mux->cached_state, val); + } + + /* Check if the idle state matches */ + tok = strtok(NULL, " "); + if (mux->idle_state == MUX_IDLE_AS_IS) { + ut_asserteq_str("as-is", tok); + } else { + ut_assertok(strict_strtoul(tok, 16, &val)); + ut_asserteq(mux->idle_state, val); + } + + /* Check if the number of states matches */ + tok = strtok(NULL, " "); + ut_assertok(strict_strtoul(tok, 16, &val)); + ut_asserteq(mux->states, val); + } + + return 0; +} +DM_TEST(dm_test_cmd_mux_list, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_cmd_mux_select(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mux_chip *chip; + struct mux_control *mux; + char cmd[BUF_SIZE]; + unsigned int i, state; + + sandbox_set_enable_memio(true); + + ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller", + &dev)); + chip = dev_get_uclass_priv(dev); + ut_assertnonnull(chip); + + srand(get_ticks() + rand()); + for (i = 0; i < chip->controllers; i++) { + mux = &chip->mux[i]; + + state = rand() % mux->states; + + snprintf(cmd, BUF_SIZE, "mux select a-mux-controller %x %x", i, + state); + run_command(cmd, 0); + ut_asserteq(!!mux->in_use, true); + ut_asserteq(state, mux->cached_state); + + ut_assertok(mux_control_deselect(mux)); + } + + return 0; +} +DM_TEST(dm_test_cmd_mux_select, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_cmd_mux_deselect(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mux_chip *chip; + struct mux_control *mux; + char cmd[BUF_SIZE]; + unsigned int i, state; + + sandbox_set_enable_memio(true); + + ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller", + &dev)); + chip = dev_get_uclass_priv(dev); + ut_assertnonnull(chip); + + srand(get_ticks() + rand()); + for (i = 0; i < chip->controllers; i++) { + mux = &chip->mux[i]; + + state = rand() % mux->states; + ut_assertok(mux_control_select(mux, state)); + + snprintf(cmd, BUF_SIZE, "mux deselect a-mux-controller %d", i); + run_command(cmd, 0); + ut_asserteq(!!mux->in_use, false); + } + + return 0; +} +DM_TEST(dm_test_cmd_mux_deselect, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); diff --git a/test/dm/mux-emul.c b/test/dm/mux-emul.c new file mode 100644 index 00000000000..141fd4d9083 --- /dev/null +++ b/test/dm/mux-emul.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * Pratyush Yadav <p.yadav@ti.com> + */ +#include <common.h> +#include <dm.h> +#include <mux.h> +#include <mux-internal.h> +#include <dm/test.h> +#include <test/ut.h> + +struct mux_emul_priv { + u32 state; +}; + +static int mux_emul_set(struct mux_control *mux, int state) +{ + struct mux_emul_priv *priv = dev_get_priv(mux->dev); + + priv->state = state; + return 0; +} + +static int mux_emul_probe(struct udevice *dev) +{ + struct mux_chip *mux_chip = dev_get_uclass_priv(dev); + struct mux_control *mux; + u32 idle_state; + int ret; + + ret = mux_alloc_controllers(dev, 1); + if (ret < 0) + return ret; + + mux = &mux_chip->mux[0]; + + ret = dev_read_u32(dev, "idle-state", &idle_state); + if (ret) + return ret; + + mux->idle_state = idle_state; + mux->states = 0x100000; + + return 0; +} + +static const struct mux_control_ops mux_emul_ops = { + .set = mux_emul_set, +}; + +static const struct udevice_id mux_emul_of_match[] = { + { .compatible = "mux-emul" }, + { /* sentinel */ }, +}; + +U_BOOT_DRIVER(emul_mux) = { + .name = "mux-emul", + .id = UCLASS_MUX, + .of_match = mux_emul_of_match, + .ops = &mux_emul_ops, + .probe = mux_emul_probe, + .priv_auto_alloc_size = sizeof(struct mux_emul_priv), +}; + +static int dm_test_mux_emul_default_state(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mux_control *mux; + struct mux_emul_priv *priv; + + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", + &dev)); + ut_assertok(mux_control_get(dev, "mux4", &mux)); + + priv = dev_get_priv(mux->dev); + + ut_asserteq(0xabcd, priv->state); + + return 0; +} +DM_TEST(dm_test_mux_emul_default_state, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_mux_emul_select_deselect(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mux_control *mux; + struct mux_emul_priv *priv; + + gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", + &dev)); + ut_assertok(mux_control_get(dev, "mux4", &mux)); + + priv = dev_get_priv(mux->dev); + + ut_assertok(mux_control_select(mux, 0x1234)); + ut_asserteq(priv->state, 0x1234); + + ut_assertok(mux_control_deselect(mux)); + ut_asserteq(priv->state, 0xabcd); + + return 0; +} +DM_TEST(dm_test_mux_emul_select_deselect, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); diff --git a/test/dm/mux-mmio.c b/test/dm/mux-mmio.c new file mode 100644 index 00000000000..fd353d8b155 --- /dev/null +++ b/test/dm/mux-mmio.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ + * Jean-Jacques Hiblot <jjhiblot@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <mux.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/test.h> +#include <dm/test.h> +#include <dm/device-internal.h> +#include <test/ut.h> + +static int dm_test_mux_mmio_select(struct unit_test_state *uts) +{ + struct udevice *dev, *dev_b; + struct regmap *map; + struct mux_control *ctl0_a, *ctl0_b; + struct mux_control *ctl1; + struct mux_control *ctl_err; + u32 val; + int i; + + sandbox_set_enable_memio(true); + + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", + &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "b-test", + &dev_b)); + map = syscon_regmap_lookup_by_phandle(dev, "mux-syscon"); + ut_assertok_ptr(map); + ut_assert(map); + + ut_assertok(mux_control_get(dev, "mux0", &ctl0_a)); + ut_assertok(mux_control_get(dev, "mux1", &ctl1)); + ut_asserteq(-ERANGE, mux_control_get(dev, "mux3", &ctl_err)); + ut_asserteq(-ENODATA, mux_control_get(dev, "dummy", &ctl_err)); + ut_assertok(mux_control_get(dev_b, "mux0", &ctl0_b)); + + for (i = 0; i < mux_control_states(ctl0_a); i++) { + /* Select a new state and verify the value in the regmap. */ + ut_assertok(mux_control_select(ctl0_a, i)); + ut_assertok(regmap_read(map, 0, &val)); + ut_asserteq(i, (val & 0x30) >> 4); + /* + * Deselect the mux and verify that the value in the regmap + * reflects the idle state (fixed to MUX_IDLE_AS_IS). + */ + ut_assertok(mux_control_deselect(ctl0_a)); + ut_assertok(regmap_read(map, 0, &val)); + ut_asserteq(i, (val & 0x30) >> 4); + } + + for (i = 0; i < mux_control_states(ctl1); i++) { + /* Select a new state and verify the value in the regmap. */ + ut_assertok(mux_control_select(ctl1, i)); + ut_assertok(regmap_read(map, 0xc, &val)); + ut_asserteq(i, (val & 0x1E) >> 1); + /* + * Deselect the mux and verify that the value in the regmap + * reflects the idle state (fixed to 2). + */ + ut_assertok(mux_control_deselect(ctl1)); + ut_assertok(regmap_read(map, 0xc, &val)); + ut_asserteq(2, (val & 0x1E) >> 1); + } + + /* Try unbalanced selection/deselection. */ + ut_assertok(mux_control_select(ctl0_a, 0)); + ut_asserteq(-EBUSY, mux_control_select(ctl0_a, 1)); + ut_asserteq(-EBUSY, mux_control_select(ctl0_a, 0)); + ut_assertok(mux_control_deselect(ctl0_a)); + + /* Try concurrent selection. */ + ut_assertok(mux_control_select(ctl0_a, 0)); + ut_assert(mux_control_select(ctl0_b, 0)); + ut_assertok(mux_control_deselect(ctl0_a)); + ut_assertok(mux_control_select(ctl0_b, 0)); + ut_assert(mux_control_select(ctl0_a, 0)); + ut_assertok(mux_control_deselect(ctl0_b)); + ut_assertok(mux_control_select(ctl0_a, 0)); + ut_assertok(mux_control_deselect(ctl0_a)); + + return 0; +} +DM_TEST(dm_test_mux_mmio_select, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Test that managed API for mux work correctly */ +static int dm_test_devm_mux_mmio(struct unit_test_state *uts) +{ + struct udevice *dev, *dev_b; + struct mux_control *ctl0_a, *ctl0_b; + struct mux_control *ctl1; + struct mux_control *ctl_err; + + sandbox_set_enable_memio(true); + + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", + &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "b-test", + &dev_b)); + + ctl0_a = devm_mux_control_get(dev, "mux0"); + ut_assertok_ptr(ctl0_a); + ut_assert(ctl0_a); + ctl1 = devm_mux_control_get(dev, "mux1"); + ut_assertok_ptr(ctl1); + ut_assert(ctl1); + ctl_err = devm_mux_control_get(dev, "mux3"); + ut_asserteq(-ERANGE, PTR_ERR(ctl_err)); + ctl_err = devm_mux_control_get(dev, "dummy"); + ut_asserteq(-ENODATA, PTR_ERR(ctl_err)); + + ctl0_b = devm_mux_control_get(dev_b, "mux0"); + ut_assertok_ptr(ctl0_b); + ut_assert(ctl0_b); + + /* Try concurrent selection. */ + ut_assertok(mux_control_select(ctl0_a, 0)); + ut_assert(mux_control_select(ctl0_b, 0)); + ut_assertok(mux_control_deselect(ctl0_a)); + ut_assertok(mux_control_select(ctl0_b, 0)); + ut_assert(mux_control_select(ctl0_a, 0)); + ut_assertok(mux_control_deselect(ctl0_b)); + + /* Remove one device and check that the mux is released. */ + ut_assertok(mux_control_select(ctl0_a, 0)); + ut_assert(mux_control_select(ctl0_b, 0)); + device_remove(dev, DM_REMOVE_NORMAL); + ut_assertok(mux_control_select(ctl0_b, 0)); + + device_remove(dev_b, DM_REMOVE_NORMAL); + return 0; +} +DM_TEST(dm_test_devm_mux_mmio, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c new file mode 100644 index 00000000000..4f3cc159d03 --- /dev/null +++ b/test/dm/of_platdata.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +/* Test that we can find a device using of-platdata */ +static int dm_test_of_platdata_base(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_SERIAL, &dev)); + ut_asserteq_str("sandbox_serial", dev->name); + + return 0; +} +DM_TEST(dm_test_of_platdata_base, UT_TESTF_SCAN_PDATA); + +/* Test that we can read properties from a device */ +static int dm_test_of_platdata_props(struct unit_test_state *uts) +{ + struct dtd_sandbox_spl_test *plat; + struct udevice *dev; + int i; + + /* Skip the clock */ + ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev)); + ut_asserteq_str("sandbox_clk_test", dev->name); + + ut_assertok(uclass_next_device_err(&dev)); + plat = dev_get_platdata(dev); + ut_assert(plat->boolval); + ut_asserteq(1, plat->intval); + ut_asserteq(4, ARRAY_SIZE(plat->intarray)); + ut_asserteq(2, plat->intarray[0]); + ut_asserteq(3, plat->intarray[1]); + ut_asserteq(4, plat->intarray[2]); + ut_asserteq(0, plat->intarray[3]); + ut_asserteq(5, plat->byteval); + ut_asserteq(3, ARRAY_SIZE(plat->bytearray)); + ut_asserteq(6, plat->bytearray[0]); + ut_asserteq(0, plat->bytearray[1]); + ut_asserteq(0, plat->bytearray[2]); + ut_asserteq(9, ARRAY_SIZE(plat->longbytearray)); + for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++) + ut_asserteq(9 + i, plat->longbytearray[i]); + ut_asserteq_str("message", plat->stringval); + ut_asserteq(3, ARRAY_SIZE(plat->stringarray)); + ut_asserteq_str("multi-word", plat->stringarray[0]); + ut_asserteq_str("message", plat->stringarray[1]); + ut_asserteq_str("", plat->stringarray[2]); + + ut_assertok(uclass_next_device_err(&dev)); + plat = dev_get_platdata(dev); + ut_assert(!plat->boolval); + ut_asserteq(3, plat->intval); + ut_asserteq(5, plat->intarray[0]); + ut_asserteq(0, plat->intarray[1]); + ut_asserteq(0, plat->intarray[2]); + ut_asserteq(0, plat->intarray[3]); + ut_asserteq(8, plat->byteval); + ut_asserteq(3, ARRAY_SIZE(plat->bytearray)); + ut_asserteq(1, plat->bytearray[0]); + ut_asserteq(0x23, plat->bytearray[1]); + ut_asserteq(0x34, plat->bytearray[2]); + for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++) + ut_asserteq(i < 4 ? 9 + i : 0, plat->longbytearray[i]); + ut_asserteq_str("message2", plat->stringval); + ut_asserteq_str("another", plat->stringarray[0]); + ut_asserteq_str("multi-word", plat->stringarray[1]); + ut_asserteq_str("message", plat->stringarray[2]); + + ut_assertok(uclass_next_device_err(&dev)); + plat = dev_get_platdata(dev); + ut_assert(!plat->boolval); + ut_asserteq_str("one", plat->stringarray[0]); + ut_asserteq_str("", plat->stringarray[1]); + ut_asserteq_str("", plat->stringarray[2]); + + ut_assertok(uclass_next_device_err(&dev)); + plat = dev_get_platdata(dev); + ut_assert(!plat->boolval); + ut_asserteq_str("spl", plat->stringarray[0]); + + ut_asserteq(-ENODEV, uclass_next_device_err(&dev)); + + return 0; +} +DM_TEST(dm_test_of_platdata_props, UT_TESTF_SCAN_PDATA); + +/* + * find_driver_info - recursively find the driver_info for a device + * + * This sets found[idx] to true when it finds the driver_info record for a + * device, where idx is the index in the driver_info linker list. + * + * @uts: Test state + * @parent: Parent to search + * @found: bool array to update + * @return 0 if OK, non-zero on error + */ +static int find_driver_info(struct unit_test_state *uts, struct udevice *parent, + bool found[]) +{ + struct udevice *dev; + + /* If not the root device, find the entry that caused it to be bound */ + if (parent->parent) { + const int n_ents = + ll_entry_count(struct driver_info, driver_info); + int idx = -1; + int i; + + for (i = 0; i < n_ents; i++) { + const struct driver_rt *drt = gd_dm_driver_rt() + i; + + if (drt->dev == parent) { + idx = i; + found[idx] = true; + break; + } + } + + ut_assert(idx != -1); + } + + device_foreach_child(dev, parent) { + int ret; + + ret = find_driver_info(uts, dev, found); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Check that every device is recorded in its driver_info struct */ +static int dm_test_of_platdata_dev(struct unit_test_state *uts) +{ + const struct driver_info *info = + ll_entry_start(struct driver_info, driver_info); + const int n_ents = ll_entry_count(struct driver_info, driver_info); + bool found[n_ents]; + uint i; + + /* Record the indexes that are found */ + memset(found, '\0', sizeof(found)); + ut_assertok(find_driver_info(uts, gd->dm_root, found)); + + /* Make sure that the driver entries without devices have no ->dev */ + for (i = 0; i < n_ents; i++) { + const struct driver_rt *drt = gd_dm_driver_rt() + i; + const struct driver_info *entry = info + i; + struct udevice *dev; + + if (found[i]) { + /* Make sure we can find it */ + ut_assertnonnull(drt->dev); + ut_assertok(device_get_by_driver_info(entry, &dev)); + ut_asserteq_ptr(dev, drt->dev); + } else { + ut_assertnull(drt->dev); + ut_asserteq(-ENOENT, + device_get_by_driver_info(entry, &dev)); + } + } + + return 0; +} +DM_TEST(dm_test_of_platdata_dev, UT_TESTF_SCAN_PDATA); + +/* Test handling of phandles that point to other devices */ +static int dm_test_of_platdata_phandle(struct unit_test_state *uts) +{ + struct dtd_sandbox_clk_test *plat; + struct udevice *dev, *clk; + + ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev)); + ut_asserteq_str("sandbox_clk_test", dev->name); + plat = dev_get_platdata(dev); + + ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk)); + ut_asserteq_str("fixed_clock", clk->name); + + ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk)); + ut_asserteq_str("sandbox_clk", clk->name); + ut_asserteq(1, plat->clocks[1].arg[0]); + + ut_assertok(device_get_by_driver_info_idx(plat->clocks[2].idx, &clk)); + ut_asserteq_str("sandbox_clk", clk->name); + ut_asserteq(0, plat->clocks[2].arg[0]); + + ut_assertok(device_get_by_driver_info_idx(plat->clocks[3].idx, &clk)); + ut_asserteq_str("sandbox_clk", clk->name); + ut_asserteq(3, plat->clocks[3].arg[0]); + + ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk)); + ut_asserteq_str("sandbox_clk", clk->name); + ut_asserteq(2, plat->clocks[4].arg[0]); + + return 0; +} +DM_TEST(dm_test_of_platdata_phandle, UT_TESTF_SCAN_PDATA); + +#if CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) +/* Test that device parents are correctly set up */ +static int dm_test_of_platdata_parent(struct unit_test_state *uts) +{ + struct udevice *rtc, *i2c; + + ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc)); + ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c)); + ut_asserteq_ptr(i2c, dev_get_parent(rtc)); + + return 0; +} +DM_TEST(dm_test_of_platdata_parent, UT_TESTF_SCAN_PDATA); +#endif diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 01ac3c2094c..fb1ceb13180 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -207,6 +207,28 @@ static int dm_test_ofnode_read_chosen(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_read_chosen, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_read_aliases(struct unit_test_state *uts) +{ + const void *val; + ofnode node; + int size; + + node = ofnode_get_aliases_node("eth3"); + ut_assert(ofnode_valid(node)); + ut_asserteq_str("sbe5", ofnode_get_name(node)); + + node = ofnode_get_aliases_node("unknown"); + ut_assert(!ofnode_valid(node)); + + val = ofnode_read_aliases_prop("spi0", &size); + ut_assertnonnull(val); + ut_asserteq(7, size); + ut_asserteq_str("/spi@0", (const char *)val); + + return 0; +} +DM_TEST(dm_test_ofnode_read_aliases, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + static int dm_test_ofnode_get_child_count(struct unit_test_state *uts) { ofnode node, child_node; diff --git a/test/dm/panel.c b/test/dm/panel.c index a840fb4951d..49f5ac7169d 100644 --- a/test/dm/panel.c +++ b/test/dm/panel.c @@ -40,7 +40,7 @@ static int dm_test_panel(struct unit_test_state *uts) ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); ut_asserteq(1000, period_ns); - ut_asserteq(170 * 1000 / 256, duty_ns); + ut_asserteq(170 * 1000 / 255, duty_ns); ut_asserteq(true, enable); ut_asserteq(false, polarity); ut_asserteq(1, sandbox_gpio_get_value(gpio, 1)); @@ -49,29 +49,29 @@ static int dm_test_panel(struct unit_test_state *uts) ut_assertok(panel_set_backlight(dev, 40)); ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); - ut_asserteq(64 * 1000 / 256, duty_ns); + ut_asserteq(64 * 1000 / 255, duty_ns); ut_assertok(panel_set_backlight(dev, BACKLIGHT_MAX)); ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); - ut_asserteq(255 * 1000 / 256, duty_ns); + ut_asserteq(255 * 1000 / 255, duty_ns); ut_assertok(panel_set_backlight(dev, BACKLIGHT_MIN)); ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); - ut_asserteq(0 * 1000 / 256, duty_ns); + ut_asserteq(0 * 1000 / 255, duty_ns); ut_asserteq(1, sandbox_gpio_get_value(gpio, 1)); ut_assertok(panel_set_backlight(dev, BACKLIGHT_DEFAULT)); ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); ut_asserteq(true, enable); - ut_asserteq(170 * 1000 / 256, duty_ns); + ut_asserteq(170 * 1000 / 255, duty_ns); ut_assertok(panel_set_backlight(dev, BACKLIGHT_OFF)); ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, &enable, &polarity)); - ut_asserteq(0 * 1000 / 256, duty_ns); + ut_asserteq(0 * 1000 / 255, duty_ns); ut_asserteq(0, sandbox_gpio_get_value(gpio, 1)); ut_asserteq(false, regulator_get_enable(reg)); diff --git a/test/dm/pinmux.c b/test/dm/pinmux.c new file mode 100644 index 00000000000..047184d4bcb --- /dev/null +++ b/test/dm/pinmux.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <dm/test.h> +#include <test/ut.h> + +static int dm_test_pinmux(struct unit_test_state *uts) +{ + char buf[64]; + struct udevice *dev; + +#define test_muxing(selector, expected) do { \ + ut_assertok(pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf))); \ + ut_asserteq_str(expected, (char *)&buf); \ +} while (0) + + ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, "pinctrl", &dev)); + test_muxing(0, "UART TX."); + test_muxing(1, "UART RX."); + test_muxing(2, "I2S SCK."); + test_muxing(3, "I2S SD."); + test_muxing(4, "I2S WS."); + test_muxing(5, "GPIO0 bias-pull-up input-disable."); + test_muxing(6, "GPIO1 drive-open-drain."); + test_muxing(7, "GPIO2 bias-pull-down input-enable."); + test_muxing(8, "GPIO3 bias-disable."); + + ut_assertok(pinctrl_select_state(dev, "alternate")); + test_muxing(0, "I2C SCL drive-open-drain."); + test_muxing(1, "I2C SDA drive-open-drain."); + test_muxing(2, "SPI SCLK."); + test_muxing(3, "SPI MOSI."); + test_muxing(4, "SPI MISO."); + test_muxing(5, "SPI CS0."); + test_muxing(6, "SPI CS1."); + test_muxing(7, "GPIO2 bias-pull-down input-enable."); + test_muxing(8, "GPIO3 bias-disable."); + + ut_assertok(pinctrl_select_state(dev, "0")); + test_muxing(0, "I2C SCL drive-open-drain."); + test_muxing(1, "I2C SDA drive-open-drain."); + test_muxing(2, "I2S SCK."); + test_muxing(3, "I2S SD."); + test_muxing(4, "I2S WS."); + test_muxing(5, "GPIO0 bias-pull-up input-disable."); + test_muxing(6, "GPIO1 drive-open-drain."); + test_muxing(7, "GPIO2 bias-pull-down input-enable."); + test_muxing(8, "GPIO3 bias-disable."); + + return 0; +} +DM_TEST(dm_test_pinmux, UT_TESTF_SCAN_FDT); diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 38b7b1481a7..fd24635006c 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -30,13 +30,12 @@ static int dm_test_init(struct unit_test_state *uts, bool of_live) memset(dms, '\0', sizeof(*dms)); gd->dm_root = NULL; - memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); state_reset_for_test(state_get_current()); -#ifdef CONFIG_OF_LIVE /* Determine whether to make the live tree available */ - gd->of_root = of_live ? uts->of_root : NULL; -#endif + gd_set_of_root(of_live ? uts->of_root : NULL); ut_assertok(dm_init(of_live)); dms->root = dm_root(); @@ -93,7 +92,8 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, ut_assertok(dm_scan_platdata(false)); if (test->flags & UT_TESTF_PROBE_TEST) ut_assertok(do_autoprobe(uts)); - if (test->flags & UT_TESTF_SCAN_FDT) + if (!CONFIG_IS_ENABLED(OF_PLATDATA) && + (test->flags & UT_TESTF_SCAN_FDT)) ut_assertok(dm_extended_scan_fdt(gd->fdt_blob, false)); /* @@ -127,7 +127,25 @@ static bool dm_test_run_on_flattree(struct unit_test *test) return !strstr(fname, "video") || strstr(test->name, "video_base"); } -static int dm_test_main(const char *test_name) +static bool test_matches(const char *test_name, const char *find_name) +{ + if (!find_name) + return true; + + if (!strcmp(test_name, find_name)) + return true; + + /* All tests have this prefix */ + if (!strncmp(test_name, "dm_test_", 8)) + test_name += 8; + + if (!strcmp(test_name, find_name)) + return true; + + return false; +} + +int dm_test_main(const char *test_name) { struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); const int n_ents = ll_entry_count(struct unit_test, dm_test); @@ -138,36 +156,34 @@ static int dm_test_main(const char *test_name) uts->priv = &_global_priv_dm_test_state; uts->fail_count = 0; - /* - * If we have no device tree, or it only has a root node, then these - * tests clearly aren't going to work... - */ - if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) { - puts("Please run with test device tree:\n" - " ./u-boot -d arch/sandbox/dts/test.dtb\n"); - ut_assert(gd->fdt_blob); + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { + /* + * If we have no device tree, or it only has a root node, then + * these * tests clearly aren't going to work... + */ + if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) { + puts("Please run with test device tree:\n" + " ./u-boot -d arch/sandbox/dts/test.dtb\n"); + ut_assert(gd->fdt_blob); + } } if (!test_name) printf("Running %d driver model tests\n", n_ents); + else found = 0; -#ifdef CONFIG_OF_LIVE - uts->of_root = gd->of_root; -#endif + uts->of_root = gd_of_root(); for (test = tests; test < tests + n_ents; test++) { const char *name = test->name; int runs; - /* All tests have this prefix */ - if (!strncmp(name, "dm_test_", 8)) - name += 8; - if (test_name && strcmp(test_name, name)) + if (!test_matches(name, test_name)) continue; /* Run with the live tree if possible */ runs = 0; - if (IS_ENABLED(CONFIG_OF_LIVE)) { + if (CONFIG_IS_ENABLED(OF_LIVE)) { if (!(test->flags & UT_TESTF_FLAT_TREE)) { ut_assertok(dm_do_test(uts, test, true)); runs++; @@ -192,13 +208,12 @@ static int dm_test_main(const char *test_name) printf("Failures: %d\n", uts->fail_count); /* Put everything back to normal so that sandbox works as expected */ -#ifdef CONFIG_OF_LIVE - gd->of_root = uts->of_root; -#endif + gd_set_of_root(uts->of_root); gd->dm_root = NULL; - ut_assertok(dm_init(IS_ENABLED(CONFIG_OF_LIVE))); + ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE))); dm_scan_platdata(false); - dm_scan_fdt(gd->fdt_blob, false); + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + dm_scan_fdt(gd->fdt_blob, false); return uts->fail_count ? CMD_RET_FAILURE : 0; } diff --git a/test/dm/usb.c b/test/dm/usb.c index db4b8ba0f7a..5d6ceefce0b 100644 --- a/test/dm/usb.c +++ b/test/dm/usb.c @@ -427,7 +427,7 @@ static int dm_test_usb_keyb(struct unit_test_state *uts) for (c = pos->result; *c; ++c) { ut_asserteq(1, tstc()); - ut_asserteq(*c, getc()); + ut_asserteq(*c, getchar()); } ut_asserteq(0, tstc()); } diff --git a/test/lib/Makefile b/test/lib/Makefile index 22236f85875..98a9abf40e2 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -7,9 +7,11 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o obj-y += hexdump.o obj-y += lmb.o +obj-y += test_print.o obj-$(CONFIG_SSCANF) += sscanf.o obj-y += string.o obj-$(CONFIG_ERRNO_STR) += test_errno_str.o obj-$(CONFIG_UT_LIB_ASN1) += asn1.o obj-$(CONFIG_UT_LIB_RSA) += rsa.o obj-$(CONFIG_AES) += test_aes.o +obj-$(CONFIG_GETOPT) += getopt.o diff --git a/test/lib/getopt.c b/test/lib/getopt.c new file mode 100644 index 00000000000..3c68b93c8a5 --- /dev/null +++ b/test/lib/getopt.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + * + * Portions of these tests were inspired by glibc's posix/bug-getopt1.c and + * posix/tst-getopt-cancel.c + */ + +#include <common.h> +#include <getopt.h> +#include <test/lib.h> +#include <test/test.h> +#include <test/ut.h> + +static int do_test_getopt(struct unit_test_state *uts, int line, + struct getopt_state *gs, const char *optstring, + int args, char *argv[], int expected_count, + int expected[]) +{ + int opt; + + getopt_init_state(gs); + for (int i = 0; i < expected_count; i++) { + opt = getopt_silent(gs, args, argv, optstring); + if (expected[i] != opt) { + /* + * Fudge the line number so we can tell which test + * failed + */ + ut_failf(uts, __FILE__, line, __func__, + "expected[i] == getopt()", + "Expected '%c' (%d) with i=%d, got '%c' (%d)", + expected[i], expected[i], i, opt, opt); + return CMD_RET_FAILURE; + } + } + + opt = getopt_silent(gs, args, argv, optstring); + if (opt != -1) { + ut_failf(uts, __FILE__, line, __func__, + "getopt() != -1", + "Expected -1, got '%c' (%d)", opt, opt); + return CMD_RET_FAILURE; + } + + return 0; +} + +#define test_getopt(optstring, argv, expected) do { \ + int ret = do_test_getopt(uts, __LINE__, &gs, optstring, \ + ARRAY_SIZE(argv) - 1, argv, \ + ARRAY_SIZE(expected), expected); \ + if (ret) \ + return ret; \ +} while (0) + +static int lib_test_getopt(struct unit_test_state *uts) +{ + struct getopt_state gs; + + /* Happy path */ + test_getopt("ab:c", + ((char *[]){ "program", "-cb", "x", "-a", "foo", 0 }), + ((int []){ 'c', 'b', 'a' })); + ut_asserteq(4, gs.index); + + /* Make sure we pick up the optional argument */ + test_getopt("a::b:c", + ((char *[]){ "program", "-cbx", "-a", "foo", 0 }), + ((int []){ 'c', 'b', 'a' })); + ut_asserteq(4, gs.index); + + /* Test required arguments */ + test_getopt("a:b", ((char *[]){ "program", "-a", 0 }), + ((int []){ ':' })); + ut_asserteq('a', gs.opt); + test_getopt("a:b", ((char *[]){ "program", "-b", "-a", 0 }), + ((int []){ 'b', ':' })); + ut_asserteq('a', gs.opt); + + /* Test invalid arguments */ + test_getopt("ab:c", ((char *[]){ "program", "-d", 0 }), + ((int []){ '?' })); + ut_asserteq('d', gs.opt); + + /* Test arg */ + test_getopt("a::b:c", + ((char *[]){ "program", "-a", 0 }), + ((int []){ 'a' })); + ut_asserteq(2, gs.index); + ut_assertnull(gs.arg); + + test_getopt("a::b:c", + ((char *[]){ "program", "-afoo", 0 }), + ((int []){ 'a' })); + ut_asserteq(2, gs.index); + ut_assertnonnull(gs.arg); + ut_asserteq_str("foo", gs.arg); + + test_getopt("a::b:c", + ((char *[]){ "program", "-a", "foo", 0 }), + ((int []){ 'a' })); + ut_asserteq(3, gs.index); + ut_assertnonnull(gs.arg); + ut_asserteq_str("foo", gs.arg); + + test_getopt("a::b:c", + ((char *[]){ "program", "-bfoo", 0 }), + ((int []){ 'b' })); + ut_asserteq(2, gs.index); + ut_assertnonnull(gs.arg); + ut_asserteq_str("foo", gs.arg); + + test_getopt("a::b:c", + ((char *[]){ "program", "-b", "foo", 0 }), + ((int []){ 'b' })); + ut_asserteq(3, gs.index); + ut_assertnonnull(gs.arg); + ut_asserteq_str("foo", gs.arg); + + return 0; +} +LIB_TEST(lib_test_getopt, 0); diff --git a/test/lib/test_print.c b/test/lib/test_print.c new file mode 100644 index 00000000000..1d497d00413 --- /dev/null +++ b/test/lib/test_print.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for print functions + * + * Copyright 2020, Heinrich Schuchadt <xypron.glpk@gmx.de> + */ + +#include <common.h> +#include <command.h> +#include <display_options.h> +#include <test/lib.h> +#include <test/test.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int test_print_freq(struct unit_test_state *uts, + uint64_t freq, char *expected) +{ + console_record_reset_enable(); + print_freq(freq, ";\n"); + gd->flags &= ~GD_FLG_RECORD; + console_record_readline(uts->actual_str, sizeof(uts->actual_str)); + ut_asserteq_str(expected, uts->actual_str); + ut_assertok(ut_check_console_end(uts)); + return 0; +} + +static int lib_test_print_freq(struct unit_test_state *uts) +{ + ut_assertok(test_print_freq(uts, 321, "321 Hz;")); + ut_assertok(test_print_freq(uts, 4321, "4.32 kHz;")); + ut_assertok(test_print_freq(uts, 54321, "54.32 kHz;")); + ut_assertok(test_print_freq(uts, 654321, "654.32 kHz;")); + ut_assertok(test_print_freq(uts, 7654321, "7.66 MHz;")); + ut_assertok(test_print_freq(uts, 87654321, "87.66 MHz;")); + ut_assertok(test_print_freq(uts, 987654321, "987.66 MHz;")); + ut_assertok(test_print_freq(uts, 1987654321, "1.99 GHz;")); + ut_assertok(test_print_freq(uts, 54321987654321, "54321.99 GHz;")); + return 0; +} + +LIB_TEST(lib_test_print_freq, 0); + +static int test_print_size(struct unit_test_state *uts, + uint64_t freq, char *expected) +{ + console_record_reset_enable(); + print_size(freq, ";\n"); + gd->flags &= ~GD_FLG_RECORD; + console_record_readline(uts->actual_str, sizeof(uts->actual_str)); + ut_asserteq_str(expected, uts->actual_str); + ut_assertok(ut_check_console_end(uts)); + return 0; +} + +static int lib_test_print_size(struct unit_test_state *uts) +{ + ut_assertok(test_print_size(uts, 321, "321 Bytes;")); + ut_assertok(test_print_size(uts, 4321, "4.2 KiB;")); + ut_assertok(test_print_size(uts, 54321, "53 KiB;")); + ut_assertok(test_print_size(uts, 654321, "639 KiB;")); + ut_assertok(test_print_size(uts, 7654321, "7.3 MiB;")); + ut_assertok(test_print_size(uts, 87654321, "83.6 MiB;")); + ut_assertok(test_print_size(uts, 987654321, "941.9 MiB;")); + ut_assertok(test_print_size(uts, 1987654321, "1.9 GiB;")); + ut_assertok(test_print_size(uts, 54321987654321, "49.4 TiB;")); + return 0; +} + +LIB_TEST(lib_test_print_size, 0); diff --git a/test/log/Makefile b/test/log/Makefile index 4c92550f6e3..88bc573e9fb 100644 --- a/test/log/Makefile +++ b/test/log/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2017 Google, Inc obj-$(CONFIG_LOG_TEST) += log_test.o +obj-$(CONFIG_CMD_LOG) += log_filter.o ifdef CONFIG_UT_LOG @@ -10,9 +11,12 @@ obj-y += test-main.o ifdef CONFIG_SANDBOX obj-$(CONFIG_LOG_SYSLOG) += syslog_test.o +obj-$(CONFIG_LOG_SYSLOG) += syslog_test_ndebug.o endif -ifndef CONFIG_LOG +ifdef CONFIG_LOG +obj-$(CONFIG_CONSOLE_RECORD) += cont_test.o +else obj-$(CONFIG_CONSOLE_RECORD) += nolog_test.o endif diff --git a/test/log/cont_test.c b/test/log/cont_test.c new file mode 100644 index 00000000000..68ca1d262c4 --- /dev/null +++ b/test/log/cont_test.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test continuation of log messages. + */ + +#include <common.h> +#include <console.h> +#include <test/log.h> +#include <test/test.h> +#include <test/suites.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BUFFSIZE 64 + +static int log_test_cont(struct unit_test_state *uts) +{ + int log_fmt; + int log_level; + + log_fmt = gd->log_fmt; + log_level = gd->default_log_level; + + /* Write two messages, the second continuing the first */ + gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG); + gd->default_log_level = LOGL_INFO; + console_record_reset_enable(); + log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1); + log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2); + gd->default_log_level = log_level; + gd->log_fmt = log_fmt; + gd->flags &= ~GD_FLG_RECORD; + ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 ERR.arch, cc2")); + ut_assertok(ut_check_console_end(uts)); + + /* Write a third message which is not a continuation */ + gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG); + gd->default_log_level = LOGL_INFO; + console_record_reset_enable(); + log(LOGC_EFI, LOGL_INFO, "ie%d\n", 3); + gd->default_log_level = log_level; + gd->log_fmt = log_fmt; + gd->flags &= ~GD_FLG_RECORD; + ut_assertok(ut_check_console_line(uts, "INFO.efi, ie3")); + ut_assertok(ut_check_console_end(uts)); + + return 0; +} +LOG_TEST(log_test_cont); diff --git a/test/log/log_filter.c b/test/log/log_filter.c new file mode 100644 index 00000000000..e8a6e01a5cc --- /dev/null +++ b/test/log/log_filter.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <console.h> +#include <log.h> +#include <test/log.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Test invalid options */ +static int log_test_filter_invalid(struct unit_test_state *uts) +{ + ut_asserteq(1, run_command("log filter-add -AD", 0)); + ut_asserteq(1, run_command("log filter-add -l1 -L1", 0)); + ut_asserteq(1, run_command("log filter-add -l1 -L1", 0)); + ut_asserteq(1, run_command("log filter-add -lfoo", 0)); + ut_asserteq(1, run_command("log filter-add -cfoo", 0)); + ut_asserteq(1, run_command("log filter-add -ccore -ccore -ccore -ccore " + "-ccore -ccore", 0)); + + return 0; +} +LOG_TEST_FLAGS(log_test_filter_invalid, UT_TESTF_CONSOLE_REC); + +/* Test adding and removing filters */ +static int log_test_filter(struct unit_test_state *uts) +{ + bool any_found = false; + bool filt1_found = false; + bool filt2_found = false; + char cmd[32]; + struct log_filter *filt; + struct log_device *ldev; + ulong filt1, filt2; + +#define create_filter(args, filter_num) do {\ + ut_assertok(console_record_reset_enable()); \ + ut_assertok(run_command("log filter-add -p " args, 0)); \ + ut_assert_skipline(); \ + ut_assertok(strict_strtoul(uts->actual_str, 10, &(filter_num))); \ + ut_assert_console_end(); \ +} while (0) + + create_filter("", filt1); + create_filter("-DL warning -cmmc -cspi -ffile", filt2); + + ldev = log_device_find_by_name("console"); + ut_assertnonnull(ldev); + list_for_each_entry(filt, &ldev->filter_head, sibling_node) { + if (filt->filter_num == filt1) { + filt1_found = true; + ut_asserteq(0, filt->flags); + ut_asserteq(LOGL_MAX, filt->level); + ut_assertnull(filt->file_list); + } else if (filt->filter_num == filt2) { + filt2_found = true; + ut_asserteq(LOGFF_HAS_CAT | LOGFF_DENY | + LOGFF_LEVEL_MIN, filt->flags); + ut_asserteq(true, log_has_cat(filt->cat_list, + log_uc_cat(UCLASS_MMC))); + ut_asserteq(true, log_has_cat(filt->cat_list, + log_uc_cat(UCLASS_SPI))); + ut_asserteq(LOGL_WARNING, filt->level); + ut_asserteq_str("file", filt->file_list); + } + } + ut_asserteq(true, filt1_found); + ut_asserteq(true, filt2_found); + +#define remove_filter(filter_num) do { \ + ut_assertok(console_record_reset_enable()); \ + snprintf(cmd, sizeof(cmd), "log filter-remove %lu", filter_num); \ + ut_assertok(run_command(cmd, 0)); \ + ut_assert_console_end(); \ +} while (0) + + remove_filter(filt1); + remove_filter(filt2); + + filt1_found = false; + filt2_found = false; + list_for_each_entry(filt, &ldev->filter_head, sibling_node) { + if (filt->filter_num == filt1) + filt1_found = true; + else if (filt->filter_num == filt2) + filt2_found = true; + } + ut_asserteq(false, filt1_found); + ut_asserteq(false, filt2_found); + + create_filter("", filt1); + create_filter("", filt2); + + ut_assertok(console_record_reset_enable()); + ut_assertok(run_command("log filter-remove -a", 0)); + ut_assert_console_end(); + + list_for_each_entry(filt, &ldev->filter_head, sibling_node) + any_found = true; + ut_asserteq(false, any_found); + + return 0; +} +LOG_TEST_FLAGS(log_test_filter, UT_TESTF_CONSOLE_REC); diff --git a/test/log/log_test.c b/test/log/log_test.c index 4245372d65f..ea4fc6bc30b 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -9,12 +9,17 @@ #include <common.h> #include <command.h> #include <log.h> +#include <test/log.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; /* emit some sample log records in different ways, for testing */ -static int log_run(enum uclass_id cat, const char *file) +static int do_log_run(int cat, const char *file) { int i; + gd->log_fmt = LOGF_TEST; debug("debug\n"); for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { log(cat, i, "log %d\n", i); @@ -22,198 +27,358 @@ static int log_run(enum uclass_id cat, const char *file) i); } + gd->log_fmt = log_get_default_format(); return 0; } -static int log_test(int testnum) +#define log_run_cat(cat) do_log_run(cat, "file") +#define log_run_file(file) do_log_run(UCLASS_SPI, file) +#define log_run() do_log_run(UCLASS_SPI, "file") + +#define EXPECT_LOG BIT(0) +#define EXPECT_DIRECT BIT(1) +#define EXPECT_EXTRA BIT(2) + +static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, + int max) { - int ret; + int i; - printf("test %d\n", testnum); - switch (testnum) { - case 0: { - /* Check a category filter using the first category */ - enum log_category_t cat_list[] = { - log_uc_cat(UCLASS_MMC), log_uc_cat(UCLASS_SPI), - LOGC_NONE, LOGC_END - }; - - ret = log_add_filter("console", cat_list, LOGL_MAX, NULL); - if (ret < 0) - return ret; - log_run(UCLASS_MMC, "file"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 1: { - /* Check a category filter using the second category */ - enum log_category_t cat_list[] = { - log_uc_cat(UCLASS_MMC), log_uc_cat(UCLASS_SPI), LOGC_END - }; - - ret = log_add_filter("console", cat_list, LOGL_MAX, NULL); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 2: { - /* Check a category filter that should block log entries */ - enum log_category_t cat_list[] = { - log_uc_cat(UCLASS_MMC), LOGC_NONE, LOGC_END - }; - - ret = log_add_filter("console", cat_list, LOGL_MAX, NULL); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 3: { - /* Check a passing file filter */ - ret = log_add_filter("console", NULL, LOGL_MAX, "file"); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 4: { - /* Check a failing file filter */ - ret = log_add_filter("console", NULL, LOGL_MAX, "file"); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file2"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 5: { - /* Check a passing file filter (second in list) */ - ret = log_add_filter("console", NULL, LOGL_MAX, "file,file2"); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file2"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 6: { - /* Check a passing file filter */ - ret = log_add_filter("console", NULL, LOGL_MAX, - "file,file2,log/log_test.c"); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file2"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 7: { - /* Check a log level filter */ - ret = log_add_filter("console", NULL, LOGL_WARNING, NULL); - if (ret < 0) - return ret; - log_run(UCLASS_SPI, "file"); - ret = log_remove_filter("console", ret); - if (ret < 0) - return ret; - break; - } - case 8: { - /* Check two filters, one of which passes everything */ - int filt1, filt2; - - ret = log_add_filter("console", NULL, LOGL_WARNING, NULL); - if (ret < 0) - return ret; - filt1 = ret; - ret = log_add_filter("console", NULL, LOGL_MAX, NULL); - if (ret < 0) - return ret; - filt2 = ret; - log_run(UCLASS_SPI, "file"); - ret = log_remove_filter("console", filt1); - if (ret < 0) - return ret; - ret = log_remove_filter("console", filt2); - if (ret < 0) - return ret; - break; - } - case 9: { - /* Check three filters, which together pass everything */ - int filt1, filt2, filt3; - - ret = log_add_filter("console", NULL, LOGL_MAX, "file)"); - if (ret < 0) - return ret; - filt1 = ret; - ret = log_add_filter("console", NULL, LOGL_MAX, "file2"); - if (ret < 0) - return ret; - filt2 = ret; - ret = log_add_filter("console", NULL, LOGL_MAX, - "log/log_test.c"); - if (ret < 0) - return ret; - filt3 = ret; - log_run(UCLASS_SPI, "file2"); - ret = log_remove_filter("console", filt1); - if (ret < 0) - return ret; - ret = log_remove_filter("console", filt2); - if (ret < 0) - return ret; - ret = log_remove_filter("console", filt3); - if (ret < 0) - return ret; - break; - } - case 10: { - log_err("level %d\n", LOGL_EMERG); - log_err("level %d\n", LOGL_ALERT); - log_err("level %d\n", LOGL_CRIT); - log_err("level %d\n", LOGL_ERR); - log_warning("level %d\n", LOGL_WARNING); - log_notice("level %d\n", LOGL_NOTICE); - log_info("level %d\n", LOGL_INFO); - log_debug("level %d\n", LOGL_DEBUG); - log_content("level %d\n", LOGL_DEBUG_CONTENT); - log_io("level %d\n", LOGL_DEBUG_IO); - break; - } + for (i = min; i <= max; i++) { + if (flags & EXPECT_LOG) + ut_assert_nextline("do_log_run() log %d", i); + if (flags & EXPECT_DIRECT) + ut_assert_nextline("func() _log %d", i); } + if (flags & EXPECT_EXTRA) + for (; i <= LOGL_MAX ; i++) + ut_assert_nextline("func() _log %d", i); + + ut_assert_console_end(); + return 0; +} + +#define check_log_entries_flags_levels(flags, min, max) do {\ + int ret = do_check_log_entries(uts, flags, min, max); \ + if (ret) \ + return ret; \ +} while (0) + +#define check_log_entries_flags(flags) \ + check_log_entries_flags_levels(flags, LOGL_FIRST, _LOG_MAX_LEVEL) +#define check_log_entries() check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT) +#define check_log_entries_extra() \ + check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT | EXPECT_EXTRA) +#define check_log_entries_none() check_log_entries_flags(0) + +/* Check a category filter using the first category */ +int log_test_cat_allow(struct unit_test_state *uts) +{ + enum log_category_t cat_list[] = { + log_uc_cat(UCLASS_MMC), log_uc_cat(UCLASS_SPI), + LOGC_NONE, LOGC_END + }; + int filt; + + filt = log_add_filter("console", cat_list, LOGL_MAX, NULL); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_cat(UCLASS_MMC); + check_log_entries_extra(); + + ut_assertok(console_record_reset_enable()); + log_run_cat(UCLASS_SPI); + check_log_entries_extra(); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_cat_allow, UT_TESTF_CONSOLE_REC); + +/* Check a category filter that should block log entries */ +int log_test_cat_deny_implicit(struct unit_test_state *uts) +{ + enum log_category_t cat_list[] = { + log_uc_cat(UCLASS_MMC), LOGC_NONE, LOGC_END + }; + int filt; + + filt = log_add_filter("console", cat_list, LOGL_MAX, NULL); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_cat(UCLASS_SPI); + check_log_entries_none(); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_cat_deny_implicit, UT_TESTF_CONSOLE_REC); + +/* Check passing and failing file filters */ +int log_test_file(struct unit_test_state *uts) +{ + int filt; + + filt = log_add_filter("console", NULL, LOGL_MAX, "file"); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_file("file"); + check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA); + + ut_assertok(console_record_reset_enable()); + log_run_file("file2"); + check_log_entries_none(); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_file, UT_TESTF_CONSOLE_REC); + +/* Check a passing file filter (second in list) */ +int log_test_file_second(struct unit_test_state *uts) +{ + int filt; + + filt = log_add_filter("console", NULL, LOGL_MAX, "file,file2"); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_file("file2"); + check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_file_second, UT_TESTF_CONSOLE_REC); + +/* Check a passing file filter (middle of list) */ +int log_test_file_mid(struct unit_test_state *uts) +{ + int filt; + + filt = log_add_filter("console", NULL, LOGL_MAX, + "file,file2,log/log_test.c"); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_file("file2"); + check_log_entries_extra(); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_file_mid, UT_TESTF_CONSOLE_REC); + +/* Check a log level filter */ +int log_test_level(struct unit_test_state *uts) +{ + int filt; + filt = log_add_filter("console", NULL, LOGL_WARNING, NULL); + ut_assert(filt >= 0); + + ut_assertok(console_record_reset_enable()); + log_run(); + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, LOGL_FIRST, + LOGL_WARNING); + + ut_assertok(log_remove_filter("console", filt)); + return 0; +} +LOG_TEST_FLAGS(log_test_level, UT_TESTF_CONSOLE_REC); + +/* Check two filters, one of which passes everything */ +int log_test_double(struct unit_test_state *uts) +{ + int filt1, filt2; + + filt1 = log_add_filter("console", NULL, LOGL_WARNING, NULL); + ut_assert(filt1 >= 0); + filt2 = log_add_filter("console", NULL, LOGL_MAX, NULL); + ut_assert(filt2 >= 0); + + ut_assertok(console_record_reset_enable()); + log_run(); + check_log_entries_extra(); + + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + return 0; +} +LOG_TEST_FLAGS(log_test_double, UT_TESTF_CONSOLE_REC); + +/* Check three filters, which together pass everything */ +int log_test_triple(struct unit_test_state *uts) +{ + int filt1, filt2, filt3; + + filt1 = log_add_filter("console", NULL, LOGL_MAX, "file)"); + ut_assert(filt1 >= 0); + filt2 = log_add_filter("console", NULL, LOGL_MAX, "file2"); + ut_assert(filt2 >= 0); + filt3 = log_add_filter("console", NULL, LOGL_MAX, "log/log_test.c"); + ut_assert(filt3 >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_file("file2"); + check_log_entries_extra(); + + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + ut_assertok(log_remove_filter("console", filt3)); + return 0; +} +LOG_TEST_FLAGS(log_test_triple, UT_TESTF_CONSOLE_REC); + +int do_log_test_helpers(struct unit_test_state *uts) +{ + int i; + + ut_assertok(console_record_reset_enable()); + log_err("level %d\n", LOGL_EMERG); + log_err("level %d\n", LOGL_ALERT); + log_err("level %d\n", LOGL_CRIT); + log_err("level %d\n", LOGL_ERR); + log_warning("level %d\n", LOGL_WARNING); + log_notice("level %d\n", LOGL_NOTICE); + log_info("level %d\n", LOGL_INFO); + log_debug("level %d\n", LOGL_DEBUG); + log_content("level %d\n", LOGL_DEBUG_CONTENT); + log_io("level %d\n", LOGL_DEBUG_IO); + + for (i = LOGL_EMERG; i <= _LOG_MAX_LEVEL; i++) + ut_assert_nextline("%s() level %d", __func__, i); + ut_assert_console_end(); + return 0; +} + +int log_test_helpers(struct unit_test_state *uts) +{ + int ret; + + gd->log_fmt = LOGF_TEST; + ret = do_log_test_helpers(uts); + gd->log_fmt = log_get_default_format(); + return ret; +} +LOG_TEST_FLAGS(log_test_helpers, UT_TESTF_CONSOLE_REC); + +int do_log_test_disable(struct unit_test_state *uts) +{ + ut_assertok(console_record_reset_enable()); + log_err("default\n"); + ut_assert_nextline("%s() default", __func__); + + ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), false)); + log_err("disabled\n"); + + ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), true)); + log_err("enabled\n"); + ut_assert_nextline("%s() enabled", __func__); + ut_assert_console_end(); return 0; } -#ifdef CONFIG_LOG_TEST -int do_log_test(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +int log_test_disable(struct unit_test_state *uts) { - int testnum = 0; int ret; - if (argc > 1) - testnum = simple_strtoul(argv[1], NULL, 10); + gd->log_fmt = LOGF_TEST; + ret = do_log_test_disable(uts); + gd->log_fmt = log_get_default_format(); + return ret; +} +LOG_TEST_FLAGS(log_test_disable, UT_TESTF_CONSOLE_REC); + +/* Check denying based on category */ +int log_test_cat_deny(struct unit_test_state *uts) +{ + int filt1, filt2; + enum log_category_t cat_list[] = { + log_uc_cat(UCLASS_SPI), LOGC_END + }; + + filt1 = log_add_filter("console", cat_list, LOGL_MAX, NULL); + ut_assert(filt1 >= 0); + filt2 = log_add_filter_flags("console", cat_list, LOGL_MAX, NULL, + LOGFF_DENY); + ut_assert(filt2 >= 0); + + ut_assertok(console_record_reset_enable()); + log_run_cat(UCLASS_SPI); + check_log_entries_none(); + + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + return 0; +} +LOG_TEST_FLAGS(log_test_cat_deny, UT_TESTF_CONSOLE_REC); + +/* Check denying based on file */ +int log_test_file_deny(struct unit_test_state *uts) +{ + int filt1, filt2; + + filt1 = log_add_filter("console", NULL, LOGL_MAX, "file"); + ut_assert(filt1 >= 0); + filt2 = log_add_filter_flags("console", NULL, LOGL_MAX, "file", + LOGFF_DENY); + ut_assert(filt2 >= 0); - ret = log_test(testnum); - if (ret) - printf("Test failure (err=%d)\n", ret); + ut_assertok(console_record_reset_enable()); + log_run_file("file"); + check_log_entries_none(); - return ret ? CMD_RET_FAILURE : 0; + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + return 0; +} +LOG_TEST_FLAGS(log_test_file_deny, UT_TESTF_CONSOLE_REC); + +/* Check denying based on level */ +int log_test_level_deny(struct unit_test_state *uts) +{ + int filt1, filt2; + + filt1 = log_add_filter("console", NULL, LOGL_INFO, NULL); + ut_assert(filt1 >= 0); + filt2 = log_add_filter_flags("console", NULL, LOGL_WARNING, NULL, + LOGFF_DENY); + ut_assert(filt2 >= 0); + + ut_assertok(console_record_reset_enable()); + log_run(); + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, + LOGL_WARNING + 1, _LOG_MAX_LEVEL); + + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + return 0; +} +LOG_TEST_FLAGS(log_test_level_deny, UT_TESTF_CONSOLE_REC); + +/* Check matching based on minimum level */ +int log_test_min(struct unit_test_state *uts) +{ + int filt1, filt2; + + filt1 = log_add_filter_flags("console", NULL, LOGL_WARNING, NULL, + LOGFF_LEVEL_MIN); + ut_assert(filt1 >= 0); + filt2 = log_add_filter_flags("console", NULL, LOGL_INFO, NULL, + LOGFF_DENY | LOGFF_LEVEL_MIN); + ut_assert(filt2 >= 0); + + ut_assertok(console_record_reset_enable()); + log_run(); + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, + LOGL_WARNING, LOGL_INFO - 1); + + ut_assertok(log_remove_filter("console", filt1)); + ut_assertok(log_remove_filter("console", filt2)); + return 0; } -#endif +LOG_TEST_FLAGS(log_test_min, UT_TESTF_CONSOLE_REC); diff --git a/test/log/syslog_test.c b/test/log/syslog_test.c index 120a8b2537b..a058d8f5695 100644 --- a/test/log/syslog_test.c +++ b/test/log/syslog_test.c @@ -18,48 +18,11 @@ #include <test/suites.h> #include <test/ut.h> #include <asm/eth.h> +#include "syslog_test.h" DECLARE_GLOBAL_DATA_PTR; -#define LOGF_TEST (BIT(LOGF_FUNC) | BIT(LOGF_MSG)) - -/** - * struct sb_log_env - private data for sandbox ethernet driver - * - * This structure is used for the private data of the sandbox ethernet - * driver. - * - * @expected: string expected to be written by the syslog driver - * @uts: unit test state - */ -struct sb_log_env { - const char *expected; - struct unit_test_state *uts; -}; - -/** - * sb_log_tx_handler() - transmit callback function - * - * This callback function is invoked when a network package is sent using the - * sandbox Ethernet driver. The private data of the driver holds a sb_log_env - * structure with the unit test state and the expected UDP payload. - * - * The following checks are executed: - * - * * the Ethernet packet indicates a IP broadcast message - * * the IP header is for a local UDP broadcast message to port 514 - * * the UDP payload matches the expected string - * - * After testing the pointer to the expected string is set to NULL to signal - * that the callback function has been called. - * - * @dev: sandbox ethernet device - * @packet: Ethernet packet - * @len: length of Ethernet packet - * Return: 0 = success - */ -static int sb_log_tx_handler(struct udevice *dev, void *packet, - unsigned int len) +int sb_log_tx_handler(struct udevice *dev, void *packet, unsigned int len) { struct eth_sandbox_priv *priv = dev_get_priv(dev); struct sb_log_env *env = priv->priv; @@ -93,6 +56,20 @@ static int sb_log_tx_handler(struct udevice *dev, void *packet, return 0; } +int syslog_test_setup(struct unit_test_state *uts) +{ + ut_assertok(log_device_set_enable(LOG_GET_DRIVER(syslog), true)); + + return 0; +} + +int syslog_test_finish(struct unit_test_state *uts) +{ + ut_assertok(log_device_set_enable(LOG_GET_DRIVER(syslog), false)); + + return 0; +} + /** * log_test_syslog_err() - test log_err() function * @@ -104,6 +81,7 @@ static int log_test_syslog_err(struct unit_test_state *uts) int old_log_level = gd->default_log_level; struct sb_log_env env; + ut_assertok(syslog_test_setup(uts)); gd->log_fmt = LOGF_TEST; gd->default_log_level = LOGL_INFO; env_set("ethact", "eth@10002000"); @@ -119,6 +97,7 @@ static int log_test_syslog_err(struct unit_test_state *uts) sandbox_eth_set_tx_handler(0, NULL); gd->default_log_level = old_log_level; gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); return 0; } @@ -135,6 +114,7 @@ static int log_test_syslog_warning(struct unit_test_state *uts) int old_log_level = gd->default_log_level; struct sb_log_env env; + ut_assertok(syslog_test_setup(uts)); gd->log_fmt = LOGF_TEST; gd->default_log_level = LOGL_INFO; env_set("ethact", "eth@10002000"); @@ -151,6 +131,7 @@ static int log_test_syslog_warning(struct unit_test_state *uts) ut_assertnull(env.expected); gd->default_log_level = old_log_level; gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); return 0; } @@ -167,6 +148,7 @@ static int log_test_syslog_notice(struct unit_test_state *uts) int old_log_level = gd->default_log_level; struct sb_log_env env; + ut_assertok(syslog_test_setup(uts)); gd->log_fmt = LOGF_TEST; gd->default_log_level = LOGL_INFO; env_set("ethact", "eth@10002000"); @@ -183,6 +165,7 @@ static int log_test_syslog_notice(struct unit_test_state *uts) ut_assertnull(env.expected); gd->default_log_level = old_log_level; gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); return 0; } @@ -199,6 +182,7 @@ static int log_test_syslog_info(struct unit_test_state *uts) int old_log_level = gd->default_log_level; struct sb_log_env env; + ut_assertok(syslog_test_setup(uts)); gd->log_fmt = LOGF_TEST; gd->default_log_level = LOGL_INFO; env_set("ethact", "eth@10002000"); @@ -215,6 +199,7 @@ static int log_test_syslog_info(struct unit_test_state *uts) ut_assertnull(env.expected); gd->default_log_level = old_log_level; gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); return 0; } @@ -231,6 +216,7 @@ static int log_test_syslog_debug(struct unit_test_state *uts) int old_log_level = gd->default_log_level; struct sb_log_env env; + ut_assertok(syslog_test_setup(uts)); gd->log_fmt = LOGF_TEST; gd->default_log_level = LOGL_DEBUG; env_set("ethact", "eth@10002000"); @@ -247,42 +233,8 @@ static int log_test_syslog_debug(struct unit_test_state *uts) ut_assertnull(env.expected); gd->default_log_level = old_log_level; gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); return 0; } LOG_TEST(log_test_syslog_debug); - -/** - * log_test_syslog_nodebug() - test logging level filter - * - * Verify that log_debug() does not lead to a log message if the logging level - * is set to LOGL_INFO. - * - * @uts: unit test state - * Return: 0 = success - */ -static int log_test_syslog_nodebug(struct unit_test_state *uts) -{ - int old_log_level = gd->default_log_level; - struct sb_log_env env; - - gd->log_fmt = LOGF_TEST; - gd->default_log_level = LOGL_INFO; - env_set("ethact", "eth@10002000"); - env_set("log_hostname", "sandbox"); - env.expected = "<7>sandbox uboot: log_test_syslog_nodebug() " - "testing log_debug\n"; - env.uts = uts; - sandbox_eth_set_tx_handler(0, sb_log_tx_handler); - /* Used by ut_assert macros in the tx_handler */ - sandbox_eth_set_priv(0, &env); - log_debug("testing %s\n", "log_debug"); - sandbox_eth_set_tx_handler(0, NULL); - /* Check that the callback function was not called */ - ut_assertnonnull(env.expected); - gd->default_log_level = old_log_level; - gd->log_fmt = log_get_default_format(); - - return 0; -} -LOG_TEST(log_test_syslog_nodebug); diff --git a/test/log/syslog_test.h b/test/log/syslog_test.h new file mode 100644 index 00000000000..bfaa6daef81 --- /dev/null +++ b/test/log/syslog_test.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Header file for logging tests + */ + +#ifndef __SYSLOG_TEST_H +#define __SYSLOG_TEST_H + +/** + * struct sb_log_env - private data for sandbox ethernet driver + * + * This structure is used for the private data of the sandbox ethernet + * driver. + * + * @expected: string expected to be written by the syslog driver + * @uts: unit test state + */ +struct sb_log_env { + const char *expected; + struct unit_test_state *uts; +}; + +/** + * sb_log_tx_handler() - transmit callback function + * + * This callback function is invoked when a network package is sent using the + * sandbox Ethernet driver. The private data of the driver holds a sb_log_env + * structure with the unit test state and the expected UDP payload. + * + * The following checks are executed: + * + * * the Ethernet packet indicates a IP broadcast message + * * the IP header is for a local UDP broadcast message to port 514 + * * the UDP payload matches the expected string + * + * After testing the pointer to the expected string is set to NULL to signal + * that the callback function has been called. + * + * @dev: sandbox ethernet device + * @packet: Ethernet packet + * @len: length of Ethernet packet + * Return: 0 = success + */ +int sb_log_tx_handler(struct udevice *dev, void *packet, unsigned int len); + +/** + * syslog_test_setup() - Enable syslog logging ready for tests + * + * @uts: Test state + * @return 0 if OK, -ENOENT if the syslog log driver is not found + */ +int syslog_test_setup(struct unit_test_state *uts); + +/** + * syslog_test_finish() - Disable syslog logging after tests + * + * @uts: Test state + * @return 0 if OK, -ENOENT if the syslog log driver is not found + */ +int syslog_test_finish(struct unit_test_state *uts); + +#endif diff --git a/test/log/syslog_test_ndebug.c b/test/log/syslog_test_ndebug.c new file mode 100644 index 00000000000..84844a39440 --- /dev/null +++ b/test/log/syslog_test_ndebug.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Logging function tests for CONFIG_LOG_SYSLOG=y. + * + * Invoke the test with: ./u-boot -d arch/sandbox/dts/test.dtb + */ + +#include <common.h> +#include <dm/device.h> +#include <hexdump.h> +#include <test/log.h> +#include <test/test.h> +#include <test/suites.h> +#include <test/ut.h> +#include <asm/eth.h> +#include "syslog_test.h" + +DECLARE_GLOBAL_DATA_PTR; + +/** + * log_test_syslog_nodebug() - test logging level filter + * + * Verify that log_debug() does not lead to a log message if the logging level + * is set to LOGL_INFO. + * + * @uts: unit test state + * Return: 0 = success + */ +static int log_test_syslog_nodebug(struct unit_test_state *uts) +{ + int old_log_level = gd->default_log_level; + struct sb_log_env env; + + ut_assertok(syslog_test_setup(uts)); + gd->log_fmt = LOGF_TEST; + gd->default_log_level = LOGL_INFO; + env_set("ethact", "eth@10002000"); + env_set("log_hostname", "sandbox"); + env.expected = "<7>sandbox uboot: log_test_syslog_nodebug() " + "testing log_debug\n"; + env.uts = uts; + sandbox_eth_set_tx_handler(0, sb_log_tx_handler); + /* Used by ut_assert macros in the tx_handler */ + sandbox_eth_set_priv(0, &env); + log_debug("testing %s\n", "log_debug"); + sandbox_eth_set_tx_handler(0, NULL); + /* Check that the callback function was not called */ + ut_assertnonnull(env.expected); + gd->default_log_level = old_log_level; + gd->log_fmt = log_get_default_format(); + ut_assertok(syslog_test_finish(uts)); + + return 0; +} +LOG_TEST(log_test_syslog_nodebug); diff --git a/test/py/conftest.py b/test/py/conftest.py index 30920474b36..dc92c0be32e 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -227,7 +227,7 @@ def pytest_configure(config): console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig) re_ut_test_list = re.compile(r'_u_boot_list_2_(.*)_test_2_\1_test_(.*)\s*$') -def generate_ut_subtest(metafunc, fixture_name): +def generate_ut_subtest(metafunc, fixture_name, sym_path): """Provide parametrization for a ut_subtest fixture. Determines the set of unit tests built into a U-Boot binary by parsing the @@ -237,12 +237,13 @@ def generate_ut_subtest(metafunc, fixture_name): Args: metafunc: The pytest test function. fixture_name: The fixture name to test. + sym_path: Relative path to the symbol file with preceding '/' + (e.g. '/u-boot.sym') Returns: Nothing. """ - - fn = console.config.build_dir + '/u-boot.sym' + fn = console.config.build_dir + sym_path try: with open(fn, 'rt') as f: lines = f.readlines() @@ -317,10 +318,12 @@ def pytest_generate_tests(metafunc): Returns: Nothing. """ - for fn in metafunc.fixturenames: if fn == 'ut_subtest': - generate_ut_subtest(metafunc, fn) + generate_ut_subtest(metafunc, fn, '/u-boot.sym') + continue + if fn == 'ut_spl_subtest': + generate_ut_subtest(metafunc, fn, '/spl/u-boot-spl.sym') continue generate_config(metafunc, fn) diff --git a/test/py/tests/test_button.py b/test/py/tests/test_button.py index 98067a98f28..3b7f148c8fc 100644 --- a/test/py/tests/test_button.py +++ b/test/py/tests/test_button.py @@ -4,16 +4,34 @@ import pytest @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_button') -def test_button_exit_statuses(u_boot_console): - """Test that non-input button commands correctly return the command - success/failure status.""" +def test_button_list(u_boot_console): + """Test listing buttons""" - expected_response = 'rc:0' response = u_boot_console.run_command('button list; echo rc:$?') - assert(expected_response in response) - response = u_boot_console.run_command('button summer; echo rc:$?') - assert(expected_response in response) + assert('button1' in response) + assert('button2' in response) + assert('rc:0' in response) + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_button') +@pytest.mark.buildconfigspec('cmd_gpio') +def test_button_return_code(u_boot_console): + """Test correct reporting of the button status + + The sandbox gpio driver reports the last output value as input value. + We can use this in our test to emulate different input statuses. + """ + + u_boot_console.run_command('gpio set a3; gpio input a3'); + response = u_boot_console.run_command('button button1; echo rc:$?') + assert('on' in response) + assert('rc:0' in response) + + u_boot_console.run_command('gpio clear a3; gpio input a3'); + response = u_boot_console.run_command('button button1; echo rc:$?') + assert('off' in response) + assert('rc:1' in response) - expected_response = 'rc:1' response = u_boot_console.run_command('button nonexistent-button; echo rc:$?') - assert(expected_response in response) + assert('not found' in response) + assert('rc:1' in response) diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py index 6b7fc487017..dba874fc59c 100644 --- a/test/py/tests/test_fs/test_ext.py +++ b/test/py/tests/test_fs/test_ext.py @@ -74,7 +74,7 @@ class TestFsExt(object): '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), '%swrite host 0:0 %x /dir1/none/%s.w3 $filesize' % (fs_type, ADDR, MIN_FILE)]) - assert('Unable to write "/dir1/none/' in ''.join(output)) + assert('Unable to write file /dir1/none/' in ''.join(output)) assert_fs_integrity(fs_type, fs_img) def test_fs_ext4(self, u_boot_console, fs_obj_ext): @@ -216,7 +216,7 @@ class TestFsExt(object): output = u_boot_console.run_command( '%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x' % (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400)) - assert('Unable to write "/dir1' in output) + assert('Unable to write file /dir1' in output) assert_fs_integrity(fs_type, fs_img) def test_fs_ext9(self, u_boot_console, fs_obj_ext): @@ -231,7 +231,7 @@ class TestFsExt(object): '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), '%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400' % (fs_type, ADDR, MIN_FILE)]) - assert('Unable to write "/dir1' in ''.join(output)) + assert('Unable to write file /dir1' in ''.join(output)) assert_fs_integrity(fs_type, fs_img) def test_fs_ext10(self, u_boot_console, fs_obj_ext): diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py index ddc28f19ee8..387b392ce9e 100644 --- a/test/py/tests/test_log.py +++ b/test/py/tests/test_log.py @@ -10,102 +10,6 @@ and checks that the output is correct. import pytest -LOGL_FIRST, LOGL_WARNING, LOGL_INFO = (0, 4, 6) - -@pytest.mark.buildconfigspec('cmd_log') -def test_log(u_boot_console): - """Test that U-Boot logging works correctly.""" - def check_log_entries(lines, mask, max_level=LOGL_INFO): - """Check that the expected log records appear in the output - - Args: - lines: iterator containing lines to check - mask: bit mask to select which lines to check for: - bit 0: standard log line - bit 1: _log line - max_level: maximum log level to expect in the output - """ - for i in range(max_level): - if mask & 1: - assert 'log_run() log %d' % i == next(lines) - if mask & 3: - assert 'func() _log %d' % i == next(lines) - - def run_test(testnum): - """Run a particular test number (the 'log test' command) - - Args: - testnum: Test number to run - Returns: - iterator containing the lines output from the command - """ - output = u_boot_console.run_command('log format fm') - assert output == '' - with cons.log.section('basic'): - output = u_boot_console.run_command('log test %d' % testnum) - split = output.replace('\r', '').splitlines() - lines = iter(split) - assert 'test %d' % testnum == next(lines) - return lines - - def test0(): - lines = run_test(0) - check_log_entries(lines, 3) - - def test1(): - lines = run_test(1) - check_log_entries(lines, 3) - - def test2(): - lines = run_test(2) - - def test3(): - lines = run_test(3) - check_log_entries(lines, 2) - - def test4(): - lines = run_test(4) - assert next(lines, None) == None - - def test5(): - lines = run_test(5) - check_log_entries(lines, 2) - - def test6(): - lines = run_test(6) - check_log_entries(lines, 3) - - def test7(): - lines = run_test(7) - check_log_entries(lines, 3, LOGL_WARNING) - - def test8(): - lines = run_test(8) - check_log_entries(lines, 3) - - def test9(): - lines = run_test(9) - check_log_entries(lines, 3) - - def test10(): - lines = run_test(10) - for i in range(7): - assert 'log_test() level %d' % i == next(lines) - - # TODO(sjg@chromium.org): Consider structuring this as separate tests - cons = u_boot_console - test0() - test1() - test2() - test3() - test4() - test5() - test6() - test7() - test8() - test9() - test10() - @pytest.mark.buildconfigspec('cmd_log') def test_log_format(u_boot_console): """Test the 'log format' and 'log rec' commands""" diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py index 263334b0743..78837a3c008 100644 --- a/test/py/tests/test_ofplatdata.py +++ b/test/py/tests/test_ofplatdata.py @@ -4,53 +4,6 @@ import pytest import u_boot_utils as util -OF_PLATDATA_OUTPUT = ''' -of-platdata probe: -bool 1 -byte 05 -bytearray 06 00 00 -int 1 -intarray 2 3 4 0 -longbytearray 09 0a 0b 0c 0d 0e 0f 10 11 -string message -stringarray "multi-word" "message" "" -of-platdata probe: -bool 0 -byte 08 -bytearray 01 23 34 -int 3 -intarray 5 0 0 0 -longbytearray 09 00 00 00 00 00 00 00 00 -string message2 -stringarray "another" "multi-word" "message" -of-platdata probe: -bool 0 -byte 00 -bytearray 00 00 00 -int 0 -intarray 0 0 0 0 -longbytearray 00 00 00 00 00 00 00 00 00 -string <NULL> -stringarray "one" "" "" -of-platdata probe: -bool 0 -byte 00 -bytearray 00 00 00 -int 0 -intarray 0 0 0 0 -longbytearray 00 00 00 00 00 00 00 00 00 -string <NULL> -stringarray "spl" "" "" -''' - -@pytest.mark.buildconfigspec('spl_of_platdata') -def test_ofplatdata(u_boot_console): - """Test that of-platdata can be generated and used in sandbox""" - cons = u_boot_console - cons.restart_uboot_with_flags(['--show_of_platdata']) - output = cons.get_spawn_output().replace('\r', '') - assert OF_PLATDATA_OUTPUT in output - @pytest.mark.buildconfigspec('spl_of_platdata') def test_spl_devicetree(u_boot_console): """Test content of spl device-tree""" diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py index 4e6df992a4e..0cbbae000c8 100644 --- a/test/py/tests/test_pinmux.py +++ b/test/py/tests/test_pinmux.py @@ -28,15 +28,15 @@ def test_pinmux_status_all(u_boot_console): assert ('a6 : gpio output .' in output) assert ('pinctrl:' in output) - assert ('SCL : I2C SCL.' in output) - assert ('SDA : I2C SDA.' in output) - assert ('TX : Uart TX.' in output) - assert ('RX : Uart RX.' in output) - assert ('W1 : 1-wire gpio.' in output) - assert ('GPIO0 : gpio bias-pull-up input-disable.' in output) - assert ('GPIO1 : gpio drive-open-drain.' in output) - assert ('GPIO2 : gpio bias-pull-down input-enable.' in output) - assert ('GPIO3 : gpio bias-disable.' in output) + assert ('P0 : UART TX.' in output) + assert ('P1 : UART RX.' in output) + assert ('P2 : I2S SCK.' in output) + assert ('P3 : I2S SD.' in output) + assert ('P4 : I2S WS.' in output) + assert ('P5 : GPIO0 bias-pull-up input-disable.' in output) + assert ('P6 : GPIO1 drive-open-drain.' in output) + assert ('P7 : GPIO2 bias-pull-down input-enable.' in output) + assert ('P8 : GPIO3 bias-disable.' in output) @pytest.mark.buildconfigspec('cmd_pinmux') @pytest.mark.boardspec('sandbox') @@ -73,12 +73,12 @@ def test_pinmux_status(u_boot_console): assert (not 'pinctrl-gpio:' in output) assert (not 'pinctrl:' in output) - assert ('SCL : I2C SCL.' in output) - assert ('SDA : I2C SDA.' in output) - assert ('TX : Uart TX.' in output) - assert ('RX : Uart RX.' in output) - assert ('W1 : 1-wire gpio.' in output) - assert ('GPIO0 : gpio bias-pull-up input-disable.' in output) - assert ('GPIO1 : gpio drive-open-drain.' in output) - assert ('GPIO2 : gpio bias-pull-down input-enable.' in output) - assert ('GPIO3 : gpio bias-disable.' in output) + assert ('P0 : UART TX.' in output) + assert ('P1 : UART RX.' in output) + assert ('P2 : I2S SCK.' in output) + assert ('P3 : I2S SD.' in output) + assert ('P4 : I2S WS.' in output) + assert ('P5 : GPIO0 bias-pull-up input-disable.' in output) + assert ('P6 : GPIO1 drive-open-drain.' in output) + assert ('P7 : GPIO2 bias-pull-down input-enable.' in output) + assert ('P8 : GPIO3 bias-disable.' in output) diff --git a/test/py/tests/test_pstore.py b/test/py/tests/test_pstore.py new file mode 100644 index 00000000000..5a35724f60a --- /dev/null +++ b/test/py/tests/test_pstore.py @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2020, Collabora +# Author: Frédéric Danis <frederic.danis@collabora.com> + +import pytest +import u_boot_utils +import os +import tempfile +import shutil + +PSTORE_ADDR=0x3000000 +PSTORE_LENGTH=0x100000 +PSTORE_PANIC1='test/py/tests/test_pstore_data_panic1.hex' +PSTORE_PANIC2='test/py/tests/test_pstore_data_panic2.hex' +PSTORE_CONSOLE='test/py/tests/test_pstore_data_console.hex' +ADDR=0x01000008 + +def load_pstore(u_boot_console): + """Load PStore records from sample files""" + + output = u_boot_console.run_command_list([ + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR, + os.path.join(u_boot_console.config.source_dir, PSTORE_PANIC1)), + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR + 4096, + os.path.join(u_boot_console.config.source_dir, PSTORE_PANIC2)), + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR + 253 * 4096, + os.path.join(u_boot_console.config.source_dir, PSTORE_CONSOLE)), + 'pstore set 0x%x 0x%x' % (PSTORE_ADDR, PSTORE_LENGTH)]) + +def checkfile(u_boot_console, path, filesize, checksum): + """Check file against MD5 checksum""" + + output = u_boot_console.run_command_list([ + 'load hostfs - %x %s' % (ADDR, path), + 'printenv filesize']) + assert('filesize=%x' % (filesize) in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(checksum in ''.join(output)) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_display_all_records(u_boot_console): + """Test that pstore displays all records.""" + + u_boot_console.run_command('') + load_pstore(u_boot_console) + response = u_boot_console.run_command('pstore display') + assert('**** Dump' in response) + assert('**** Console' in response) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_display_one_record(u_boot_console): + """Test that pstore displays only one record.""" + + u_boot_console.run_command('') + load_pstore(u_boot_console) + response = u_boot_console.run_command('pstore display dump 1') + assert('Panic#2 Part1' in response) + assert('**** Console' not in response) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_save_records(u_boot_console): + """Test that pstore saves all records.""" + + outdir = tempfile.mkdtemp() + + u_boot_console.run_command('') + load_pstore(u_boot_console) + u_boot_console.run_command('pstore save hostfs - %s' % (outdir)) + + checkfile(u_boot_console, '%s/dmesg-ramoops-0' % (outdir), 3798, '8059335ab4cfa62c77324c491659c503') + checkfile(u_boot_console, '%s/dmesg-ramoops-1' % (outdir), 4035, '3ff30df3429d81939c75d0070b5187b9') + checkfile(u_boot_console, '%s/console-ramoops-0' % (outdir), 4084, 'bb44de4a9b8ebd9b17ae98003287325b') + + shutil.rmtree(outdir) diff --git a/test/py/tests/test_pstore_data_console.hex b/test/py/tests/test_pstore_data_console.hex Binary files differnew file mode 100644 index 00000000000..e7f426e8928 --- /dev/null +++ b/test/py/tests/test_pstore_data_console.hex diff --git a/test/py/tests/test_pstore_data_panic1.hex b/test/py/tests/test_pstore_data_panic1.hex Binary files differnew file mode 100644 index 00000000000..988929d12c2 --- /dev/null +++ b/test/py/tests/test_pstore_data_panic1.hex diff --git a/test/py/tests/test_pstore_data_panic2.hex b/test/py/tests/test_pstore_data_panic2.hex Binary files differnew file mode 100644 index 00000000000..8f9d56cbe01 --- /dev/null +++ b/test/py/tests/test_pstore_data_panic2.hex diff --git a/test/py/tests/test_spl.py b/test/py/tests/test_spl.py new file mode 100644 index 00000000000..bd273dad893 --- /dev/null +++ b/test/py/tests/test_spl.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2020 Google LLC +# Written by Simon Glass <sjg@chromium.org> + +import os.path +import pytest + +def test_spl(u_boot_console, ut_spl_subtest): + """Execute a "ut" subtest. + + The subtests are collected in function generate_ut_subtest() from linker + generated lists by applying a regular expression to the lines of file + spl/u-boot-spl.sym. The list entries are created using the C macro + UNIT_TEST(). + + Strict naming conventions have to be followed to match the regular + expression. Use UNIT_TEST(foo_test_bar, _flags, foo_test) for a test bar in + test suite foo that can be executed via command 'ut foo bar' and is + implemented in C function foo_test_bar(). + + Args: + u_boot_console (ConsoleBase): U-Boot console + ut_subtest (str): SPL test to be executed (e.g. 'dm platdata_phandle') + """ + try: + cons = u_boot_console + cons.restart_uboot_with_flags(['-u', '-k', ut_spl_subtest.split()[1]]) + output = cons.get_spawn_output().replace('\r', '') + assert 'Failures: 0' in output + finally: + # Restart afterward in case a non-SPL test is run next. This should not + # happen since SPL tests are run in their own invocation of test.py, but + # the cost of doing this is not too great at present. + u_boot_console.restart_uboot() diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index 6b998cfd70e..e45800d94c0 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -126,6 +126,23 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required): cons.log.action('%s: Sign images' % sha_algo) util.run_and_log(cons, args) + def sign_fit_norequire(sha_algo, options): + """Sign the FIT + + Signs the FIT and writes the signature into it. It also writes the + public key into the dtb. It does not mark key as 'required' in dtb. + + Args: + sha_algo: Either 'sha1' or 'sha256', to select the algorithm to + use. + options: Options to provide to mkimage. + """ + args = [mkimage, '-F', '-k', tmpdir, '-K', dtb, fit] + if options: + args += options.split(' ') + cons.log.action('%s: Sign images' % sha_algo) + util.run_and_log(cons, args) + def replace_fit_totalsize(size): """Replace FIT header's totalsize with something greater. @@ -279,15 +296,40 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required): # Build the FIT with dev key (keys NOT required). This adds the # signature into sandbox-u-boot.dtb, NOT marked 'required'. make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) - sign_fit(sha_algo, sign_options) + sign_fit_norequire(sha_algo, sign_options) # So now sandbox-u-boot.dtb two signatures, for the prod and dev keys. # Only the prod key is set as 'required'. But FIT we just built has - # a dev signature only (sign_fit() overwrites the FIT). + # a dev signature only (sign_fit_norequire() overwrites the FIT). # Try to boot the FIT with dev key. This FIT should not be accepted by # U-Boot because the prod key is required. run_bootm(sha_algo, 'required key', '', False) + # Build the FIT with dev key (keys required) and sign it. This puts the + # signature into sandbox-u-boot.dtb, marked 'required'. + make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) + sign_fit(sha_algo, sign_options) + + # Set the required-mode policy to "any". + # So now sandbox-u-boot.dtb two signatures, for the prod and dev keys. + # Both the dev and prod key are set as 'required'. But FIT we just built has + # a dev signature only (sign_fit() overwrites the FIT). + # Try to boot the FIT with dev key. This FIT should be accepted by + # U-Boot because the dev key is required and policy is "any" required key. + util.run_and_log(cons, 'fdtput -t s %s /signature required-mode any' % + (dtb)) + run_bootm(sha_algo, 'multi required key', 'dev+', True) + + # Set the required-mode policy to "all". + # So now sandbox-u-boot.dtb two signatures, for the prod and dev keys. + # Both the dev and prod key are set as 'required'. But FIT we just built has + # a dev signature only (sign_fit() overwrites the FIT). + # Try to boot the FIT with dev key. This FIT should not be accepted by + # U-Boot because the prod key is required and policy is "all" required key + util.run_and_log(cons, 'fdtput -t s %s /signature required-mode all' % + (dtb)) + run_bootm(sha_algo, 'multi required key', '', False) + cons = u_boot_console tmpdir = cons.config.result_dir + '/' datadir = cons.config.source_dir + '/test/py/tests/vboot/' @@ -28,7 +28,7 @@ fi # Run tests which require sandbox_spl run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \ - -k 'test_ofplatdata or test_handoff' + -k 'test_ofplatdata or test_handoff or test_spl' if [ -z "$tools_only" ]; then # Run tests for the flat-device-tree version of sandbox. This is a special |