mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-04-01 12:01:31 +00:00
Merge branch '2021-03-12-test-improvements' into next
- Assorted improvements to the pytest framework
This commit is contained in:
commit
c57ec2c2ba
46 changed files with 1407 additions and 446 deletions
|
@ -777,7 +777,7 @@ int os_jump_to_image(const void *dest, int size)
|
||||||
return os_jump_to_file(fname);
|
return os_jump_to_file(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int os_find_u_boot(char *fname, int maxlen)
|
int os_find_u_boot(char *fname, int maxlen, bool use_img)
|
||||||
{
|
{
|
||||||
struct sandbox_state *state = state_get_current();
|
struct sandbox_state *state = state_get_current();
|
||||||
const char *progname = state->argv[0];
|
const char *progname = state->argv[0];
|
||||||
|
@ -801,8 +801,8 @@ int os_find_u_boot(char *fname, int maxlen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for 'u-boot-tpl' in the tpl/ directory */
|
/* Look for 'u-boot-spl' in the spl/ directory */
|
||||||
p = strstr(fname, "/tpl/");
|
p = strstr(fname, "/spl/");
|
||||||
if (p) {
|
if (p) {
|
||||||
p[1] = 's';
|
p[1] = 's';
|
||||||
fd = os_open(fname, O_RDONLY);
|
fd = os_open(fname, O_RDONLY);
|
||||||
|
@ -829,6 +829,8 @@ int os_find_u_boot(char *fname, int maxlen)
|
||||||
if (p) {
|
if (p) {
|
||||||
/* Remove the "spl" characters */
|
/* Remove the "spl" characters */
|
||||||
memmove(p, p + 4, strlen(p + 4) + 1);
|
memmove(p, p + 4, strlen(p + 4) + 1);
|
||||||
|
if (use_img)
|
||||||
|
strcat(p, ".img");
|
||||||
fd = os_open(fname, O_RDONLY);
|
fd = os_open(fname, O_RDONLY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <asm/global_data.h>
|
#include <asm/global_data.h>
|
||||||
#include <asm/spl.h>
|
#include <asm/spl.h>
|
||||||
#include <asm/state.h>
|
#include <asm/state.h>
|
||||||
#include <test/test.h>
|
#include <test/ut.h>
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image,
|
||||||
char fname[256];
|
char fname[256];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = os_find_u_boot(fname, sizeof(fname));
|
ret = os_find_u_boot(fname, sizeof(fname), false);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("(%s not found, error %d)\n", fname, ret);
|
printf("(%s not found, error %d)\n", fname, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -63,9 +63,12 @@ void spl_board_init(void)
|
||||||
preloader_console_init();
|
preloader_console_init();
|
||||||
|
|
||||||
if (state->run_unittests) {
|
if (state->run_unittests) {
|
||||||
|
struct unit_test *tests = UNIT_TEST_ALL_START();
|
||||||
|
const int count = UNIT_TEST_ALL_COUNT();
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = dm_test_main(state->select_unittests);
|
ret = ut_run_list("spl", NULL, tests, count,
|
||||||
|
state->select_unittests);
|
||||||
/* continue execution into U-Boot */
|
/* continue execution into U-Boot */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,7 +491,6 @@ int main(int argc, char *argv[])
|
||||||
gd->reloc_off = (ulong)gd->arch.text_base;
|
gd->reloc_off = (ulong)gd->arch.text_base;
|
||||||
|
|
||||||
/* sandbox test: log functions called before log_init in board_init_f */
|
/* sandbox test: log functions called before log_init in board_init_f */
|
||||||
log_info("sandbox: starting...\n");
|
|
||||||
log_debug("debug: %s\n", __func__);
|
log_debug("debug: %s\n", __func__);
|
||||||
|
|
||||||
/* Do pre- and post-relocation init */
|
/* Do pre- and post-relocation init */
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
#include <irq_func.h>
|
#include <irq_func.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
|
#include <mapmem.h>
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
#include <spl.h>
|
#include <spl.h>
|
||||||
#include <asm/global_data.h>
|
#include <asm/global_data.h>
|
||||||
|
@ -168,7 +169,7 @@ __weak void spl_board_prepare_for_boot(void)
|
||||||
|
|
||||||
__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
|
__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
|
||||||
{
|
{
|
||||||
return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
|
return map_sysmem(CONFIG_SYS_TEXT_BASE + offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
|
void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <image.h>
|
#include <image.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <mapmem.h>
|
||||||
#include <spl.h>
|
#include <spl.h>
|
||||||
#include <sysinfo.h>
|
#include <sysinfo.h>
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
|
@ -235,11 +236,11 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
|
||||||
size_t length;
|
size_t length;
|
||||||
int len;
|
int len;
|
||||||
ulong size;
|
ulong size;
|
||||||
ulong load_addr, load_ptr;
|
ulong load_addr;
|
||||||
|
void *load_ptr;
|
||||||
void *src;
|
void *src;
|
||||||
ulong overhead;
|
ulong overhead;
|
||||||
int nr_sectors;
|
int nr_sectors;
|
||||||
int align_len = ARCH_DMA_MINALIGN - 1;
|
|
||||||
uint8_t image_comp = -1, type = -1;
|
uint8_t image_comp = -1, type = -1;
|
||||||
const void *data;
|
const void *data;
|
||||||
const void *fit = ctx->fit;
|
const void *fit = ctx->fit;
|
||||||
|
@ -269,11 +270,13 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (external_data) {
|
if (external_data) {
|
||||||
|
void *src_ptr;
|
||||||
|
|
||||||
/* External data */
|
/* External data */
|
||||||
if (fit_image_get_data_size(fit, node, &len))
|
if (fit_image_get_data_size(fit, node, &len))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
load_ptr = (load_addr + align_len) & ~align_len;
|
src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len);
|
||||||
length = len;
|
length = len;
|
||||||
|
|
||||||
overhead = get_aligned_image_overhead(info, offset);
|
overhead = get_aligned_image_overhead(info, offset);
|
||||||
|
@ -281,12 +284,12 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
|
||||||
|
|
||||||
if (info->read(info,
|
if (info->read(info,
|
||||||
sector + get_aligned_image_offset(info, offset),
|
sector + get_aligned_image_offset(info, offset),
|
||||||
nr_sectors, (void *)load_ptr) != nr_sectors)
|
nr_sectors, src_ptr) != nr_sectors)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
debug("External data: dst=%lx, offset=%x, size=%lx\n",
|
debug("External data: dst=%p, offset=%x, size=%lx\n",
|
||||||
load_ptr, offset, (unsigned long)length);
|
src_ptr, offset, (unsigned long)length);
|
||||||
src = (void *)load_ptr + overhead;
|
src = src_ptr + overhead;
|
||||||
} else {
|
} else {
|
||||||
/* Embedded data */
|
/* Embedded data */
|
||||||
if (fit_image_get_data(fit, node, &data, &length)) {
|
if (fit_image_get_data(fit, node, &data, &length)) {
|
||||||
|
@ -295,7 +298,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
|
||||||
}
|
}
|
||||||
debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
|
debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
|
||||||
(unsigned long)length);
|
(unsigned long)length);
|
||||||
src = (void *)data;
|
src = (void *)data; /* cast away const */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
|
if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
|
||||||
|
@ -309,16 +312,16 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
|
||||||
if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS))
|
if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS))
|
||||||
board_fit_image_post_process(&src, &length);
|
board_fit_image_post_process(&src, &length);
|
||||||
|
|
||||||
|
load_ptr = map_sysmem(load_addr, length);
|
||||||
if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
|
if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
|
||||||
size = length;
|
size = length;
|
||||||
if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
|
if (gunzip(load_ptr, CONFIG_SYS_BOOTM_LEN, src, &size)) {
|
||||||
src, &size)) {
|
|
||||||
puts("Uncompressing error\n");
|
puts("Uncompressing error\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
length = size;
|
length = size;
|
||||||
} else {
|
} else {
|
||||||
memcpy((void *)load_addr, src, length);
|
memcpy(load_ptr, src, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image_info) {
|
if (image_info) {
|
||||||
|
@ -383,7 +386,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the load-address of the FDT available for the SPL framework */
|
/* Make the load-address of the FDT available for the SPL framework */
|
||||||
spl_image->fdt_addr = (void *)image_info.load_addr;
|
spl_image->fdt_addr = map_sysmem(image_info.load_addr, 0);
|
||||||
if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
|
if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
CONFIG_SYS_TEXT_BASE=0
|
CONFIG_SYS_TEXT_BASE=0x200000
|
||||||
CONFIG_SPL_LIBCOMMON_SUPPORT=y
|
CONFIG_SPL_LIBCOMMON_SUPPORT=y
|
||||||
CONFIG_SPL_LIBGENERIC_SUPPORT=y
|
CONFIG_SPL_LIBGENERIC_SUPPORT=y
|
||||||
CONFIG_NR_DRAM_BANKS=1
|
CONFIG_NR_DRAM_BANKS=1
|
||||||
|
|
|
@ -17,6 +17,12 @@ of the sandbox U-Boot. The purpose of running U-Boot under Linux is to test
|
||||||
all the generic code, not specific to any one architecture. The idea is to
|
all the generic code, not specific to any one architecture. The idea is to
|
||||||
create unit tests which we can run to test this upper level code.
|
create unit tests which we can run to test this upper level code.
|
||||||
|
|
||||||
|
Sandbox allows development of many types of new features in a traditional way,
|
||||||
|
rather than needing to test each iteration on real hardware. Many U-Boot
|
||||||
|
features were developed on sandbox, including the core driver model, most
|
||||||
|
uclasses, verified boot, bloblist, logging and dozens of others. Sandbox has
|
||||||
|
enabled many large-scale code refactors as well.
|
||||||
|
|
||||||
CONFIG_SANDBOX is defined when building a native board.
|
CONFIG_SANDBOX is defined when building a native board.
|
||||||
|
|
||||||
The board name is 'sandbox' but the vendor name is unset, so there is a
|
The board name is 'sandbox' but the vendor name is unset, so there is a
|
||||||
|
@ -486,42 +492,10 @@ Testing
|
||||||
-------
|
-------
|
||||||
|
|
||||||
U-Boot sandbox can be used to run various tests, mostly in the test/
|
U-Boot sandbox can be used to run various tests, mostly in the test/
|
||||||
directory. These include:
|
directory.
|
||||||
|
|
||||||
command_ut:
|
See :doc:`../develop/tests_sandbox` for more information and
|
||||||
Unit tests for command parsing and handling
|
:doc:`../develop/testing` for information about testing generally.
|
||||||
compression:
|
|
||||||
Unit tests for U-Boot's compression algorithms, useful for
|
|
||||||
security checking. It supports gzip, bzip2, lzma and lzo.
|
|
||||||
driver model:
|
|
||||||
Run this pytest::
|
|
||||||
|
|
||||||
./test/py/test.py --bd sandbox --build -k ut_dm -v
|
|
||||||
|
|
||||||
image:
|
|
||||||
Unit tests for images:
|
|
||||||
test/image/test-imagetools.sh - multi-file images
|
|
||||||
test/image/test-fit.py - FIT images
|
|
||||||
tracing:
|
|
||||||
test/trace/test-trace.sh tests the tracing system (see README.trace)
|
|
||||||
verified boot:
|
|
||||||
See test/vboot/vboot_test.sh for this
|
|
||||||
|
|
||||||
If you change or enhance any of the above subsystems, you shold write or
|
|
||||||
expand a test and include it with your patch series submission. Test
|
|
||||||
coverage in U-Boot is limited, as we need to work to improve it.
|
|
||||||
|
|
||||||
Note that many of these tests are implemented as commands which you can
|
|
||||||
run natively on your board if desired (and enabled).
|
|
||||||
|
|
||||||
To run all tests use "make check".
|
|
||||||
|
|
||||||
To run a single test in an existing sandbox build, you can use -T to use the
|
|
||||||
test device tree, and -c to select the test:
|
|
||||||
|
|
||||||
/tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev"
|
|
||||||
|
|
||||||
This runs dm_test_pci_busdev() which is in test/dm/pci.c
|
|
||||||
|
|
||||||
|
|
||||||
Memory Map
|
Memory Map
|
||||||
|
@ -537,5 +511,7 @@ Addr Config Usage
|
||||||
e000 CONFIG_BLOBLIST_ADDR Blob list
|
e000 CONFIG_BLOBLIST_ADDR Blob list
|
||||||
10000 CONFIG_MALLOC_F_ADDR Early memory allocation
|
10000 CONFIG_MALLOC_F_ADDR Early memory allocation
|
||||||
f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer
|
f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer
|
||||||
100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled)
|
100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used
|
||||||
|
as the SPL load buffer in spl_test_load().
|
||||||
|
200000 CONFIG_SYS_TEXT_BASE Load buffer for U-Boot (sandbox_spl only)
|
||||||
======= ======================== ===============================
|
======= ======================== ===============================
|
||||||
|
|
|
@ -33,3 +33,5 @@ Testing
|
||||||
coccinelle
|
coccinelle
|
||||||
testing
|
testing
|
||||||
py_testing
|
py_testing
|
||||||
|
tests_writing
|
||||||
|
tests_sandbox
|
||||||
|
|
|
@ -13,7 +13,8 @@ results. Advantages of this approach are:
|
||||||
U-Boot; there can be no disconnect.
|
U-Boot; there can be no disconnect.
|
||||||
- There is no need to write or embed test-related code into U-Boot itself.
|
- There is no need to write or embed test-related code into U-Boot itself.
|
||||||
It is asserted that writing test-related code in Python is simpler and more
|
It is asserted that writing test-related code in Python is simpler and more
|
||||||
flexible than writing it all in C.
|
flexible than writing it all in C. But see :doc:`tests_writing` for caveats
|
||||||
|
and more discussion / analysis.
|
||||||
- It is reasonably simple to interact with U-Boot in this way.
|
- It is reasonably simple to interact with U-Boot in this way.
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
|
|
|
@ -8,17 +8,27 @@ tested and what tests you should write when adding a new feature.
|
||||||
Running tests
|
Running tests
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
To run most tests on sandbox, type this:
|
To run most tests on sandbox, type this::
|
||||||
|
|
||||||
make check
|
make check
|
||||||
|
|
||||||
in the U-Boot directory. Note that only the pytest suite is run using this
|
in the U-Boot directory. Note that only the pytest suite is run using this
|
||||||
command.
|
command.
|
||||||
|
|
||||||
Some tests take ages to run. To run just the quick ones, type this:
|
Some tests take ages to run and are marked with @pytest.mark.slow. To run just
|
||||||
|
the quick ones, type this::
|
||||||
|
|
||||||
make qcheck
|
make qcheck
|
||||||
|
|
||||||
|
It is also possible to run just the tests for tools (patman, binman, etc.).
|
||||||
|
Such tests are included with those tools, i.e. no actual U-Boot unit tests are
|
||||||
|
run. Type this::
|
||||||
|
|
||||||
|
make tcheck
|
||||||
|
|
||||||
|
All of the above use the test/run script with a paremeter to select which tests
|
||||||
|
are run.
|
||||||
|
|
||||||
|
|
||||||
Sandbox
|
Sandbox
|
||||||
-------
|
-------
|
||||||
|
@ -26,6 +36,7 @@ U-Boot can be built as a user-space application (e.g. for Linux). This
|
||||||
allows test to be executed without needing target hardware. The 'sandbox'
|
allows test to be executed without needing target hardware. The 'sandbox'
|
||||||
target provides this feature and it is widely used in tests.
|
target provides this feature and it is widely used in tests.
|
||||||
|
|
||||||
|
See :doc:`tests_sandbox` for more information.
|
||||||
|
|
||||||
Pytest Suite
|
Pytest Suite
|
||||||
------------
|
------------
|
||||||
|
@ -35,14 +46,27 @@ either on sandbox or on real hardware. It relies on the U-Boot console to
|
||||||
inject test commands and check the result. It is slower to run than C code,
|
inject test commands and check the result. It is slower to run than C code,
|
||||||
but provides the ability to unify lots of tests and summarise their results.
|
but provides the ability to unify lots of tests and summarise their results.
|
||||||
|
|
||||||
You can run the tests on sandbox with:
|
You can run the tests on sandbox with::
|
||||||
|
|
||||||
./test/py/test.py --bd sandbox --build
|
./test/py/test.py --bd sandbox --build
|
||||||
|
|
||||||
This will produce HTML output in build-sandbox/test-log.html
|
This will produce HTML output in build-sandbox/test-log.html
|
||||||
|
|
||||||
|
Some tests run with other versions of sandbox. For example sandbox_flattree
|
||||||
|
runs the tests with livetree (the hierachical devicetree) disabled. You can
|
||||||
|
also select particular tests with -k::
|
||||||
|
|
||||||
|
./test/py/test.py --bd sandbox_flattree --build -k hello
|
||||||
|
|
||||||
|
There are some special tests that run in SPL. For this you need the sandbox_spl
|
||||||
|
build::
|
||||||
|
|
||||||
|
./test/py/test.py --bd sandbox_spl --build -k test_spl
|
||||||
|
|
||||||
See test/py/README.md for more information about the pytest suite.
|
See test/py/README.md for more information about the pytest suite.
|
||||||
|
|
||||||
|
See :doc:`tests_sandbox` for how to run tests directly (not through pytest).
|
||||||
|
|
||||||
|
|
||||||
tbot
|
tbot
|
||||||
----
|
----
|
||||||
|
@ -58,10 +82,14 @@ Ad-hoc tests
|
||||||
|
|
||||||
There are several ad-hoc tests which run outside the pytest environment:
|
There are several ad-hoc tests which run outside the pytest environment:
|
||||||
|
|
||||||
test/fs - File system test (shell script)
|
test/fs
|
||||||
test/image - FIT and legacy image tests (shell script and Python)
|
File system test (shell script)
|
||||||
test/stdint - A test that stdint.h can be used in U-Boot (shell script)
|
test/image
|
||||||
trace - Test for the tracing feature (shell script)
|
FIT and legacy image tests (shell script and Python)
|
||||||
|
test/stdint
|
||||||
|
A test that stdint.h can be used in U-Boot (shell script)
|
||||||
|
trace
|
||||||
|
Test for the tracing feature (shell script)
|
||||||
|
|
||||||
TODO: Move these into pytest.
|
TODO: Move these into pytest.
|
||||||
|
|
||||||
|
@ -89,6 +117,8 @@ or is covered sparingly. So here are some suggestions:
|
||||||
is much easier to add onto a test - writing a new large test can seem
|
is much easier to add onto a test - writing a new large test can seem
|
||||||
daunting to most contributors.
|
daunting to most contributors.
|
||||||
|
|
||||||
|
See doc:`tests_writing` for how to write tests.
|
||||||
|
|
||||||
|
|
||||||
Future work
|
Future work
|
||||||
-----------
|
-----------
|
||||||
|
|
209
doc/develop/tests_sandbox.rst
Normal file
209
doc/develop/tests_sandbox.rst
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
Sandbox tests
|
||||||
|
=============
|
||||||
|
|
||||||
|
Test Design
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Most uclasses and many functions of U-Boot have sandbox tests. This allows much
|
||||||
|
of the code to be checked in an developer-friendly environment.
|
||||||
|
|
||||||
|
Sandbox provides a way to write and run unit tests. The traditional approach to
|
||||||
|
unit tests is to build lots of little executables, one for each test or
|
||||||
|
category of tests. With sandbox, so far as possible, all the tests share a
|
||||||
|
small number of executables (e.g. 'u-boot' for sandbox, 'u-boot-spl' and
|
||||||
|
'u-boot' for sandbox_spl) and can be run very quickly. The vast majority of
|
||||||
|
tests can run on the 'sandbox' build,
|
||||||
|
|
||||||
|
Available tests
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Some of the available tests are:
|
||||||
|
|
||||||
|
- command_ut: Unit tests for command parsing and handling
|
||||||
|
- compression: Unit tests for U-Boot's compression algorithms, useful for
|
||||||
|
security checking. It supports gzip, bzip2, lzma and lzo.
|
||||||
|
- image: Unit tests for images:
|
||||||
|
|
||||||
|
- test/image/test-imagetools.sh - multi-file images
|
||||||
|
- test/py/tests/test-fit.py - FIT images
|
||||||
|
- tracing: test/trace/test-trace.sh tests the tracing system (see
|
||||||
|
README.trace)
|
||||||
|
- verified boot: test/py/tests/test_vboot.py
|
||||||
|
|
||||||
|
If you change or enhance any U-Boot subsystem, you should write or expand a
|
||||||
|
test and include it with your patch series submission. Test coverage in some
|
||||||
|
older areas of U-Boot is still somewhat limited and we need to work to improve
|
||||||
|
it.
|
||||||
|
|
||||||
|
Note that many of these tests are implemented as commands which you can
|
||||||
|
run natively on your board if desired (and enabled).
|
||||||
|
|
||||||
|
To run all tests, use 'make check'.
|
||||||
|
|
||||||
|
|
||||||
|
Running sandbox tests directly
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Typically tests are run using the pytest suite. Running pytests on sandbox is
|
||||||
|
easy and always gets things right. For example some tests require files to be
|
||||||
|
set up before they can work.
|
||||||
|
|
||||||
|
But it is also possible to run some sandbox tests directly. For example, this
|
||||||
|
runs the dm_test_gpio() test which you can find in test/dm/gpio.c::
|
||||||
|
|
||||||
|
$ ./u-boot -T -c "ut dm gpio"
|
||||||
|
|
||||||
|
|
||||||
|
U-Boot 2021.01
|
||||||
|
|
||||||
|
Model: sandbox
|
||||||
|
DRAM: 128 MiB
|
||||||
|
WDT: Started with servicing (60s timeout)
|
||||||
|
MMC: mmc2: 2 (SD), mmc1: 1 (SD), mmc0: 0 (SD)
|
||||||
|
In: serial
|
||||||
|
Out: vidconsole
|
||||||
|
Err: vidconsole
|
||||||
|
Model: sandbox
|
||||||
|
SCSI:
|
||||||
|
Net: eth0: eth@10002000, eth5: eth@10003000, eth3: sbe5, eth6: eth@10004000
|
||||||
|
Test: dm_test_gpio: gpio.c
|
||||||
|
Test: dm_test_gpio: gpio.c (flat tree)
|
||||||
|
Failures: 0
|
||||||
|
|
||||||
|
The -T option tells the U-Boot sandbox to run with the 'test' devicetree
|
||||||
|
(test.dts) instead of -D which selects the normal sandbox.dts - this is
|
||||||
|
necessary because many tests rely on nodes or properties in the test devicetree.
|
||||||
|
If you try running tests without -T then you may see failures, like::
|
||||||
|
|
||||||
|
$ ./u-boot -c "ut dm gpio"
|
||||||
|
|
||||||
|
|
||||||
|
U-Boot 2021.01
|
||||||
|
|
||||||
|
DRAM: 128 MiB
|
||||||
|
WDT: Not found!
|
||||||
|
MMC:
|
||||||
|
In: serial
|
||||||
|
Out: serial
|
||||||
|
Err: serial
|
||||||
|
SCSI:
|
||||||
|
Net: No ethernet found.
|
||||||
|
Please run with test device tree:
|
||||||
|
./u-boot -d arch/sandbox/dts/test.dtb
|
||||||
|
Test: dm_test_gpio: gpio.c
|
||||||
|
test/dm/gpio.c:37, dm_test_gpio(): 0 == gpio_lookup_name("b4", &dev, &offset, &gpio): Expected 0x0 (0), got 0xffffffea (-22)
|
||||||
|
Test: dm_test_gpio: gpio.c (flat tree)
|
||||||
|
test/dm/gpio.c:37, dm_test_gpio(): 0 == gpio_lookup_name("b4", &dev, &offset, &gpio): Expected 0x0 (0), got 0xffffffea (-22)
|
||||||
|
Failures: 2
|
||||||
|
|
||||||
|
The message above should provide a hint if you forget to use the -T flag. Even
|
||||||
|
running with -D will produce different results.
|
||||||
|
|
||||||
|
You can easily use gdb on these tests, without needing --gdbserver::
|
||||||
|
|
||||||
|
$ gdb u-boot --args -T -c "ut dm gpio"
|
||||||
|
...
|
||||||
|
(gdb) break dm_test_gpio
|
||||||
|
Breakpoint 1 at 0x1415bd: file test/dm/gpio.c, line 37.
|
||||||
|
(gdb) run -T -c "ut dm gpio"
|
||||||
|
Starting program: u-boot -T -c "ut dm gpio"
|
||||||
|
Test: dm_test_gpio: gpio.c
|
||||||
|
|
||||||
|
Breakpoint 1, dm_test_gpio (uts=0x5555558029a0 <global_dm_test_state>)
|
||||||
|
at files/test/dm/gpio.c:37
|
||||||
|
37 ut_assertok(gpio_lookup_name("b4", &dev, &offset, &gpio));
|
||||||
|
(gdb)
|
||||||
|
|
||||||
|
You can then single-step and look at variables as needed.
|
||||||
|
|
||||||
|
|
||||||
|
Running sandbox_spl tests directly
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
SPL is the phase before U-Boot proper. It is present in the sandbox_spl build,
|
||||||
|
so you can run SPL like this::
|
||||||
|
|
||||||
|
./spl/u-boot-spl
|
||||||
|
|
||||||
|
SPL tests are special in that they run (only in the SPL phase, of course) if the
|
||||||
|
-u flag is given::
|
||||||
|
|
||||||
|
./spl/u-boot-spl -u
|
||||||
|
|
||||||
|
U-Boot SPL 2021.01-00723-g43c77b51be5-dirty (Jan 24 2021 - 16:38:24 -0700)
|
||||||
|
Running 5 driver model tests
|
||||||
|
Test: dm_test_of_plat_base: of_platdata.c (flat tree)
|
||||||
|
Test: dm_test_of_plat_dev: of_platdata.c (flat tree)
|
||||||
|
Test: dm_test_of_plat_parent: of_platdata.c (flat tree)
|
||||||
|
Test: dm_test_of_plat_phandle: of_platdata.c (flat tree)
|
||||||
|
Test: dm_test_of_plat_props: of_platdata.c (flat tree)
|
||||||
|
Failures: 0
|
||||||
|
|
||||||
|
|
||||||
|
U-Boot 2021.01-00723-g43c77b51be5-dirty (Jan 24 2021 - 16:38:24 -0700)
|
||||||
|
|
||||||
|
DRAM: 128 MiB
|
||||||
|
...
|
||||||
|
|
||||||
|
It is not possible to run SPL tests in U-Boot proper, firstly because they are
|
||||||
|
not built into U-Boot proper and secondly because the environment is very
|
||||||
|
different, e.g. some SPL tests rely on of-platdata which is only available in
|
||||||
|
SPL.
|
||||||
|
|
||||||
|
Note that after running, SPL continues to boot into U-Boot proper. You can add
|
||||||
|
'-c exit' to make U-Boot quit without doing anything further. It is not
|
||||||
|
currently possible to run SPL tests and then stop, since the pytests require
|
||||||
|
that U-Boot produces the expected banner.
|
||||||
|
|
||||||
|
You can use the -k flag to select which tests run::
|
||||||
|
|
||||||
|
./spl/u-boot-spl -u -k dm_test_of_plat_parent
|
||||||
|
|
||||||
|
Of course you can use gdb with sandbox_spl, just as with sandbox.
|
||||||
|
|
||||||
|
|
||||||
|
Running all tests directly
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
A fast way to run all sandbox tests is::
|
||||||
|
|
||||||
|
./u-boot -T -c "ut all"
|
||||||
|
|
||||||
|
It typically runs single-thread in 6 seconds on 2021 hardware, with 2s of that
|
||||||
|
to the delays in the time test.
|
||||||
|
|
||||||
|
This should not be considered a substitute for 'make check', but can be helpful
|
||||||
|
for git bisect, etc.
|
||||||
|
|
||||||
|
|
||||||
|
What tests are built in?
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Whatever sandbox build is used, which tests are present is determined by which
|
||||||
|
source files are built. For sandbox_spl, the of_platdata tests are built
|
||||||
|
because of the build rule in test/dm/Makefile::
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SPL_BUILD),y)
|
||||||
|
obj-$(CONFIG_SPL_OF_PLATDATA) += of_platdata.o
|
||||||
|
else
|
||||||
|
...other tests for non-spl
|
||||||
|
endif
|
||||||
|
|
||||||
|
You can get a list of tests in a U-Boot ELF file by looking for the
|
||||||
|
linker_list::
|
||||||
|
|
||||||
|
$ nm /tmp/b/sandbox_spl/spl/u-boot-spl |grep 2_dm_test
|
||||||
|
000000000001f200 D _u_boot_list_2_dm_test_2_dm_test_of_plat_base
|
||||||
|
000000000001f220 D _u_boot_list_2_dm_test_2_dm_test_of_plat_dev
|
||||||
|
000000000001f240 D _u_boot_list_2_dm_test_2_dm_test_of_plat_parent
|
||||||
|
000000000001f260 D _u_boot_list_2_dm_test_2_dm_test_of_plat_phandle
|
||||||
|
000000000001f280 D _u_boot_list_2_dm_test_2_dm_test_of_plat_props
|
||||||
|
|
||||||
|
|
||||||
|
Writing tests
|
||||||
|
-------------
|
||||||
|
|
||||||
|
See :doc:`tests_writing` for how to write new tests.
|
||||||
|
|
346
doc/develop/tests_writing.rst
Normal file
346
doc/develop/tests_writing.rst
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
.. Copyright 2021 Google LLC
|
||||||
|
.. sectionauthor:: Simon Glass <sjg@chromium.org>
|
||||||
|
|
||||||
|
Writing Tests
|
||||||
|
=============
|
||||||
|
|
||||||
|
This describes how to write tests in U-Boot and describes the possible options.
|
||||||
|
|
||||||
|
Test types
|
||||||
|
----------
|
||||||
|
|
||||||
|
There are two basic types of test in U-Boot:
|
||||||
|
|
||||||
|
- Python tests, in test/py/tests
|
||||||
|
- C tests, in test/ and its subdirectories
|
||||||
|
|
||||||
|
(there are also UEFI tests in lib/efi_selftest/ not considered here.)
|
||||||
|
|
||||||
|
Python tests talk to U-Boot via the command line. They support both sandbox and
|
||||||
|
real hardware. They typically do not require building test code into U-Boot
|
||||||
|
itself. They are fairly slow to run, due to the command-line interface and there
|
||||||
|
being two separate processes. Python tests are fairly easy to write. They can
|
||||||
|
be a little tricky to debug sometimes due to the voluminous output of pytest.
|
||||||
|
|
||||||
|
C tests are written directly in U-Boot. While they can be used on boards, they
|
||||||
|
are more commonly used with sandbox, as they obviously add to U-Boot code size.
|
||||||
|
C tests are easy to write so long as the required facilities exist. Where they
|
||||||
|
do not it can involve refactoring or adding new features to sandbox. They are
|
||||||
|
fast to run and easy to debug.
|
||||||
|
|
||||||
|
Regardless of which test type is used, all tests are collected and run by the
|
||||||
|
pytest framework, so there is typically no need to run them separately. This
|
||||||
|
means that C tests can be used when it makes sense, and Python tests when it
|
||||||
|
doesn't.
|
||||||
|
|
||||||
|
|
||||||
|
This table shows how to decide whether to write a C or Python test:
|
||||||
|
|
||||||
|
===================== =========================== =============================
|
||||||
|
Attribute C test Python test
|
||||||
|
===================== =========================== =============================
|
||||||
|
Fast to run? Yes No (two separate processes)
|
||||||
|
Easy to write? Yes, if required test Yes
|
||||||
|
features exist in sandbox
|
||||||
|
or the target system
|
||||||
|
Needs code in U-Boot? Yes No, provided the test can be
|
||||||
|
executed and the result
|
||||||
|
determined using the command
|
||||||
|
line
|
||||||
|
Easy to debug? Yes No, since access to the U-Boot
|
||||||
|
state is not available and the
|
||||||
|
amount of output can
|
||||||
|
sometimes require a bit of
|
||||||
|
digging
|
||||||
|
Can use gdb? Yes, directly Yes, with --gdbserver
|
||||||
|
Can run on boards? Some can, but only if Some
|
||||||
|
compiled in and not
|
||||||
|
dependent on sandboxau
|
||||||
|
===================== =========================== =============================
|
||||||
|
|
||||||
|
|
||||||
|
Python or C
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Typically in U-Boot we encourage C test using sandbox for all features. This
|
||||||
|
allows fast testing, easy development and allows contributors to make changes
|
||||||
|
without needing dozens of boards to test with.
|
||||||
|
|
||||||
|
When a test requires setup or interaction with the running host (such as to
|
||||||
|
generate images and then running U-Boot to check that they can be loaded), or
|
||||||
|
cannot be run on sandbox, Python tests should be used. These should typically
|
||||||
|
NOT rely on running with sandbox, but instead should function correctly on any
|
||||||
|
board supported by U-Boot.
|
||||||
|
|
||||||
|
|
||||||
|
How slow are Python tests?
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Under the hood, when running on sandbox, Python tests work by starting a sandbox
|
||||||
|
test and connecting to it via a pipe. Each interaction with the U-Boot process
|
||||||
|
requires at least a context switch to handle the pipe interaction. The test
|
||||||
|
sends a command to U-Boot, which then reacts and shows some output, then the
|
||||||
|
test sees that and continues. Of course on real hardware, communications delays
|
||||||
|
(e.g. with a serial console) make this slower.
|
||||||
|
|
||||||
|
For comparison, consider a test that checks the 'md' (memory dump). All times
|
||||||
|
below are approximate, as measured on an AMD 2950X system. Here is is the test
|
||||||
|
in Python::
|
||||||
|
|
||||||
|
@pytest.mark.buildconfigspec('cmd_memory')
|
||||||
|
def test_md(u_boot_console):
|
||||||
|
"""Test that md reads memory as expected, and that memory can be modified
|
||||||
|
using the mw command."""
|
||||||
|
|
||||||
|
ram_base = u_boot_utils.find_ram_base(u_boot_console)
|
||||||
|
addr = '%08x' % ram_base
|
||||||
|
val = 'a5f09876'
|
||||||
|
expected_response = addr + ': ' + val
|
||||||
|
u_boot_console.run_command('mw ' + addr + ' 0 10')
|
||||||
|
response = u_boot_console.run_command('md ' + addr + ' 10')
|
||||||
|
assert(not (expected_response in response))
|
||||||
|
u_boot_console.run_command('mw ' + addr + ' ' + val)
|
||||||
|
response = u_boot_console.run_command('md ' + addr + ' 10')
|
||||||
|
assert(expected_response in response)
|
||||||
|
|
||||||
|
This runs a few commands and checks the output. Note that it runs a command,
|
||||||
|
waits for the response and then checks it agains what is expected. If run by
|
||||||
|
itself it takes around 800ms, including test collection. For 1000 runs it takes
|
||||||
|
19 seconds, or 19ms per run. Of course 1000 runs it not that useful since we
|
||||||
|
only want to run it once.
|
||||||
|
|
||||||
|
There is no exactly equivalent C test, but here is a similar one that tests 'ms'
|
||||||
|
(memory search)::
|
||||||
|
|
||||||
|
/* Test 'ms' command with bytes */
|
||||||
|
static int mem_test_ms_b(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
u8 *buf;
|
||||||
|
|
||||||
|
buf = map_sysmem(0, BUF_SIZE + 1);
|
||||||
|
memset(buf, '\0', BUF_SIZE);
|
||||||
|
buf[0x0] = 0x12;
|
||||||
|
buf[0x31] = 0x12;
|
||||||
|
buf[0xff] = 0x12;
|
||||||
|
buf[0x100] = 0x12;
|
||||||
|
ut_assertok(console_record_reset_enable());
|
||||||
|
run_command("ms.b 1 ff 12", 0);
|
||||||
|
ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................");
|
||||||
|
ut_assert_nextline("--");
|
||||||
|
ut_assert_nextline("000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 ................");
|
||||||
|
ut_assert_nextline("2 matches");
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
ut_asserteq(2, env_get_hex("memmatches", 0));
|
||||||
|
ut_asserteq(0xff, env_get_hex("memaddr", 0));
|
||||||
|
ut_asserteq(0xfe, env_get_hex("mempos", 0));
|
||||||
|
|
||||||
|
unmap_sysmem(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MEM_TEST(mem_test_ms_b, UT_TESTF_CONSOLE_REC);
|
||||||
|
|
||||||
|
This runs the command directly in U-Boot, then checks the console output, also
|
||||||
|
directly in U-Boot. If run by itself this takes 100ms. For 1000 runs it takes
|
||||||
|
660ms, or 0.66ms per run.
|
||||||
|
|
||||||
|
So overall running a C test is perhaps 8 times faster individually and the
|
||||||
|
interactions are perhaps 25 times faster.
|
||||||
|
|
||||||
|
It should also be noted that the C test is fairly easy to debug. You can set a
|
||||||
|
breakpoint on do_mem_search(), which is what implements the 'ms' command,
|
||||||
|
single step to see what might be wrong, etc. That is also possible with the
|
||||||
|
pytest, but requires two terminals and --gdbserver.
|
||||||
|
|
||||||
|
|
||||||
|
Why does speed matter?
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Many development activities rely on running tests:
|
||||||
|
|
||||||
|
- 'git bisect run make qcheck' can be used to find a failing commit
|
||||||
|
- test-driven development relies on quick iteration of build/test
|
||||||
|
- U-Boot's continuous integration (CI) systems make use of tests. Running
|
||||||
|
all sandbox tests typically takes 90 seconds and running each qemu test
|
||||||
|
takes about 30 seconds. This is currently dwarfed by the time taken to
|
||||||
|
build all boards
|
||||||
|
|
||||||
|
As U-Boot continues to grow its feature set, fast and reliable tests are a
|
||||||
|
critical factor factor in developer productivity and happiness.
|
||||||
|
|
||||||
|
|
||||||
|
Writing C tests
|
||||||
|
---------------
|
||||||
|
|
||||||
|
C tests are arranged into suites which are typically executed by the 'ut'
|
||||||
|
command. Each suite is in its own file. This section describes how to accomplish
|
||||||
|
some common test tasks.
|
||||||
|
|
||||||
|
(there are also UEFI C tests in lib/efi_selftest/ not considered here.)
|
||||||
|
|
||||||
|
Add a new driver model test
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Use this when adding a test for a new or existing uclass, adding new operations
|
||||||
|
or features to a uclass, adding new ofnode or dev_read_() functions, or anything
|
||||||
|
else related to driver model.
|
||||||
|
|
||||||
|
Find a suitable place for your test, perhaps near other test functions in
|
||||||
|
existing code, or in a new file. Each uclass should have its own test file.
|
||||||
|
|
||||||
|
Declare the test with::
|
||||||
|
|
||||||
|
/* Test that ... */
|
||||||
|
static int dm_test_uclassname_what(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
/* test code here */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_uclassname_what, UT_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
Replace 'uclassname' with the name of your uclass, if applicable. Replace 'what'
|
||||||
|
with what you are testing.
|
||||||
|
|
||||||
|
The flags for DM_TEST() are defined in test/test.h and you typically want
|
||||||
|
UT_TESTF_SCAN_FDT so that the devicetree is scanned and all devices are bound
|
||||||
|
and ready for use. The DM_TEST macro adds UT_TESTF_DM automatically so that
|
||||||
|
the test runner knows it is a driver model test.
|
||||||
|
|
||||||
|
Driver model tests are special in that the entire driver model state is
|
||||||
|
recreated anew for each test. This ensures that if a previous test deletes a
|
||||||
|
device, for example, it does not affect subsequent tests. Driver model tests
|
||||||
|
also run both with livetree and flattree, to ensure that both devicetree
|
||||||
|
implementations work as expected.
|
||||||
|
|
||||||
|
Example commit: c48cb7ebfb4 ("sandbox: add ADC unit tests") [1]
|
||||||
|
|
||||||
|
[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/c48cb7ebfb4
|
||||||
|
|
||||||
|
|
||||||
|
Add a C test to an existing suite
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Use this when you are adding to or modifying an existing feature outside driver
|
||||||
|
model. An example is bloblist.
|
||||||
|
|
||||||
|
Add a new function in the same file as the rest of the suite and register it
|
||||||
|
with the suite. For example, to add a new mem_search test::
|
||||||
|
|
||||||
|
/* Test 'ms' command with 32-bit values */
|
||||||
|
static int mem_test_ms_new_thing(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
/* test code here*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MEM_TEST(mem_test_ms_new_thing, UT_TESTF_CONSOLE_REC);
|
||||||
|
|
||||||
|
Note that the MEM_TEST() macros is defined at the top of the file.
|
||||||
|
|
||||||
|
Example commit: 9fe064646d2 ("bloblist: Support relocating to a larger space") [1]
|
||||||
|
|
||||||
|
[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/9fe064646d2
|
||||||
|
|
||||||
|
|
||||||
|
Add a new test suite
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Each suite should focus on one feature or subsystem, so if you are writing a
|
||||||
|
new one of those, you should add a new suite.
|
||||||
|
|
||||||
|
Create a new file in test/ or a subdirectory and define a macro to register the
|
||||||
|
suite. For example::
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <console.h>
|
||||||
|
#include <mapmem.h>
|
||||||
|
#include <dm/test.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
/* Declare a new wibble test */
|
||||||
|
#define WIBBLE_TEST(_name, _flags) UNIT_TEST(_name, _flags, wibble_test)
|
||||||
|
|
||||||
|
/* Tetss go here */
|
||||||
|
|
||||||
|
/* At the bottom of the file: */
|
||||||
|
|
||||||
|
int do_ut_wibble(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
struct unit_test *tests = UNIT_TEST_SUITE_START(wibble_test);
|
||||||
|
const int n_ents = UNIT_TEST_SUITE_COUNT(wibble_test);
|
||||||
|
|
||||||
|
return cmd_ut_category("cmd_wibble", "wibble_test_", tests, n_ents, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Then add new tests to it as above.
|
||||||
|
|
||||||
|
Register this new suite in test/cmd_ut.c by adding to cmd_ut_sub[]::
|
||||||
|
|
||||||
|
/* Within cmd_ut_sub[]... */
|
||||||
|
|
||||||
|
U_BOOT_CMD_MKENT(wibble, CONFIG_SYS_MAXARGS, 1, do_ut_wibble, "", ""),
|
||||||
|
|
||||||
|
and adding new help to ut_help_text[]::
|
||||||
|
|
||||||
|
"ut wibble - Test the wibble feature\n"
|
||||||
|
|
||||||
|
If your feature is conditional on a particular Kconfig, then you can use #ifdef
|
||||||
|
to control that.
|
||||||
|
|
||||||
|
Finally, add the test to the build by adding to the Makefile in the same
|
||||||
|
directory::
|
||||||
|
|
||||||
|
obj-$(CONFIG_$(SPL_)CMDLINE) += wibble.o
|
||||||
|
|
||||||
|
Note that CMDLINE is never enabled in SPL, so this test will only be present in
|
||||||
|
U-Boot proper. See below for how to do SPL tests.
|
||||||
|
|
||||||
|
As before, you can add an extra Kconfig check if needed::
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_$(SPL_)WIBBLE),)
|
||||||
|
obj-$(CONFIG_$(SPL_)CMDLINE) += wibble.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
Example commit: 919e7a8fb64 ("test: Add a simple test for bloblist") [1]
|
||||||
|
|
||||||
|
[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/919e7a8fb64
|
||||||
|
|
||||||
|
|
||||||
|
Making the test run from pytest
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
All C tests must run from pytest. Typically this is automatic, since pytest
|
||||||
|
scans the U-Boot executable for available tests to run. So long as you have a
|
||||||
|
'ut' subcommand for your test suite, it will run. The same applies for driver
|
||||||
|
model tests since they use the 'ut dm' subcommand.
|
||||||
|
|
||||||
|
See test/py/tests/test_ut.py for how unit tests are run.
|
||||||
|
|
||||||
|
|
||||||
|
Add a C test for SPL
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Note: C tests are only available for sandbox_spl at present. There is currently
|
||||||
|
no mechanism in other boards to existing SPL tests even if they are built into
|
||||||
|
the image.
|
||||||
|
|
||||||
|
SPL tests cannot be run from the 'ut' command since there are no commands
|
||||||
|
available in SPL. Instead, sandbox (only) calls ut_run_list() on start-up, when
|
||||||
|
the -u flag is given. This runs the available unit tests, no matter what suite
|
||||||
|
they are in.
|
||||||
|
|
||||||
|
To create a new SPL test, follow the same rules as above, either adding to an
|
||||||
|
existing suite or creating a new one.
|
||||||
|
|
||||||
|
An example SPL test is spl_test_load().
|
||||||
|
|
||||||
|
|
||||||
|
Writing Python tests
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
See :doc:`py_testing` for brief notes how to write Python tests. You
|
||||||
|
should be able to use the existing tests in test/py/tests as examples.
|
|
@ -92,15 +92,19 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||||
if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
|
if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
|
||||||
dev->seq_ = uclass_find_next_free_seq(uc);
|
dev->seq_ = uclass_find_next_free_seq(uc);
|
||||||
|
|
||||||
|
/* Check if we need to allocate plat */
|
||||||
if (drv->plat_auto) {
|
if (drv->plat_auto) {
|
||||||
bool alloc = !plat;
|
bool alloc = !plat;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For of-platdata, we try use the existing data, but if
|
||||||
|
* plat_auto is larger, we must allocate a new space
|
||||||
|
*/
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||||
if (of_plat_size) {
|
if (of_plat_size)
|
||||||
dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
|
dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
|
||||||
if (of_plat_size < drv->plat_auto)
|
if (of_plat_size < drv->plat_auto)
|
||||||
alloc = true;
|
alloc = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (alloc) {
|
if (alloc) {
|
||||||
dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
|
dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
|
||||||
|
@ -109,6 +113,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail_alloc1;
|
goto fail_alloc1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For of-platdata, copy the old plat into the new
|
||||||
|
* space
|
||||||
|
*/
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
|
if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
|
||||||
memcpy(ptr, plat, of_plat_size);
|
memcpy(ptr, plat, of_plat_size);
|
||||||
dev_set_plat(dev, ptr);
|
dev_set_plat(dev, ptr);
|
||||||
|
|
|
@ -125,25 +125,9 @@ extern int dm_testdrv_op_count[DM_TEST_OP_COUNT];
|
||||||
|
|
||||||
extern struct unit_test_state global_dm_test_state;
|
extern struct unit_test_state global_dm_test_state;
|
||||||
|
|
||||||
/*
|
|
||||||
* struct dm_test_state - Entire state of dm test system
|
|
||||||
*
|
|
||||||
* This is often abreviated to dms.
|
|
||||||
*
|
|
||||||
* @root: Root device
|
|
||||||
* @testdev: Test device
|
|
||||||
* @force_fail_alloc: Force all memory allocs to fail
|
|
||||||
* @skip_post_probe: Skip uclass post-probe processing
|
|
||||||
*/
|
|
||||||
struct dm_test_state {
|
|
||||||
struct udevice *root;
|
|
||||||
struct udevice *testdev;
|
|
||||||
int force_fail_alloc;
|
|
||||||
int skip_post_probe;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Declare a new driver model test */
|
/* Declare a new driver model test */
|
||||||
#define DM_TEST(_name, _flags) UNIT_TEST(_name, _flags, dm_test)
|
#define DM_TEST(_name, _flags) \
|
||||||
|
UNIT_TEST(_name, UT_TESTF_DM | UT_TESTF_CONSOLE_REC | (_flags), dm_test)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct sandbox_sdl_plat - Platform data for the SDL video driver
|
* struct sandbox_sdl_plat - Platform data for the SDL video driver
|
||||||
|
|
|
@ -324,9 +324,10 @@ int os_jump_to_image(const void *dest, int size);
|
||||||
*
|
*
|
||||||
* @fname: place to put full path to U-Boot
|
* @fname: place to put full path to U-Boot
|
||||||
* @maxlen: maximum size of @fname
|
* @maxlen: maximum size of @fname
|
||||||
|
* @use_img: select the 'u-boot.img' file instead of the 'u-boot' ELF file
|
||||||
* Return: 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
|
* Return: 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
|
||||||
*/
|
*/
|
||||||
int os_find_u_boot(char *fname, int maxlen);
|
int os_find_u_boot(char *fname, int maxlen, bool use_img);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* os_spl_to_uboot() - Run U-Boot proper
|
* os_spl_to_uboot() - Run U-Boot proper
|
||||||
|
|
|
@ -222,6 +222,15 @@ struct spl_load_info {
|
||||||
void *priv;
|
void *priv;
|
||||||
int bl_len;
|
int bl_len;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
/**
|
||||||
|
* read() - Read from device
|
||||||
|
*
|
||||||
|
* @load: Information about the load state
|
||||||
|
* @sector: Sector number to read from (each @load->bl_len bytes)
|
||||||
|
* @count: Number of sectors to read
|
||||||
|
* @buf: Buffer to read into
|
||||||
|
* @return number of sectors read, 0 on error
|
||||||
|
*/
|
||||||
ulong (*read)(struct spl_load_info *load, ulong sector, ulong count,
|
ulong (*read)(struct spl_load_info *load, ulong sector, ulong count,
|
||||||
void *buf);
|
void *buf);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,16 +14,24 @@
|
||||||
*
|
*
|
||||||
* @fail_count: Number of tests that failed
|
* @fail_count: Number of tests that failed
|
||||||
* @start: Store the starting mallinfo when doing leak test
|
* @start: Store the starting mallinfo when doing leak test
|
||||||
* @priv: A pointer to some other info some suites want to track
|
* @of_live: true to use livetree if available, false to use flattree
|
||||||
* @of_root: Record of the livetree root node (used for setting up tests)
|
* @of_root: Record of the livetree root node (used for setting up tests)
|
||||||
|
* @root: Root device
|
||||||
|
* @testdev: Test device
|
||||||
|
* @force_fail_alloc: Force all memory allocs to fail
|
||||||
|
* @skip_post_probe: Skip uclass post-probe processing
|
||||||
* @expect_str: Temporary string used to hold expected string value
|
* @expect_str: Temporary string used to hold expected string value
|
||||||
* @actual_str: Temporary string used to hold actual string value
|
* @actual_str: Temporary string used to hold actual string value
|
||||||
*/
|
*/
|
||||||
struct unit_test_state {
|
struct unit_test_state {
|
||||||
int fail_count;
|
int fail_count;
|
||||||
struct mallinfo start;
|
struct mallinfo start;
|
||||||
void *priv;
|
|
||||||
struct device_node *of_root;
|
struct device_node *of_root;
|
||||||
|
bool of_live;
|
||||||
|
struct udevice *root;
|
||||||
|
struct udevice *testdev;
|
||||||
|
int force_fail_alloc;
|
||||||
|
int skip_post_probe;
|
||||||
char expect_str[256];
|
char expect_str[256];
|
||||||
char actual_str[256];
|
char actual_str[256];
|
||||||
};
|
};
|
||||||
|
@ -36,6 +44,8 @@ enum {
|
||||||
UT_TESTF_FLAT_TREE = BIT(3), /* test needs flat DT */
|
UT_TESTF_FLAT_TREE = BIT(3), /* test needs flat DT */
|
||||||
UT_TESTF_LIVE_TREE = BIT(4), /* needs live device tree */
|
UT_TESTF_LIVE_TREE = BIT(4), /* needs live device tree */
|
||||||
UT_TESTF_CONSOLE_REC = BIT(5), /* needs console recording */
|
UT_TESTF_CONSOLE_REC = BIT(5), /* needs console recording */
|
||||||
|
/* do extra driver model init and uninit */
|
||||||
|
UT_TESTF_DM = BIT(6),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,13 +86,24 @@ struct unit_test {
|
||||||
* @_suite: name of the test suite concatenated with "_test"
|
* @_suite: name of the test suite concatenated with "_test"
|
||||||
*/
|
*/
|
||||||
#define UNIT_TEST(_name, _flags, _suite) \
|
#define UNIT_TEST(_name, _flags, _suite) \
|
||||||
ll_entry_declare(struct unit_test, _name, _suite) = { \
|
ll_entry_declare(struct unit_test, _name, ut_ ## _suite) = { \
|
||||||
.file = __FILE__, \
|
.file = __FILE__, \
|
||||||
.name = #_name, \
|
.name = #_name, \
|
||||||
.flags = _flags, \
|
.flags = _flags, \
|
||||||
.func = _name, \
|
.func = _name, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the start of a list of unit tests for a particular suite */
|
||||||
|
#define UNIT_TEST_SUITE_START(_suite) \
|
||||||
|
ll_entry_start(struct unit_test, ut_ ## _suite)
|
||||||
|
#define UNIT_TEST_SUITE_COUNT(_suite) \
|
||||||
|
ll_entry_count(struct unit_test, ut_ ## _suite)
|
||||||
|
|
||||||
|
/* Use ! and ~ so that all tests will be sorted between these two values */
|
||||||
|
#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut_!)
|
||||||
|
#define UNIT_TEST_ALL_END() ll_entry_start(struct unit_test, ut_~)
|
||||||
|
#define UNIT_TEST_ALL_COUNT() (UNIT_TEST_ALL_END() - UNIT_TEST_ALL_START())
|
||||||
|
|
||||||
/* Sizes for devres tests */
|
/* Sizes for devres tests */
|
||||||
enum {
|
enum {
|
||||||
TEST_DEVRES_SIZE = 100,
|
TEST_DEVRES_SIZE = 100,
|
||||||
|
@ -103,15 +124,4 @@ enum {
|
||||||
*/
|
*/
|
||||||
struct udevice *testbus_get_clear_removed(void);
|
struct udevice *testbus_get_clear_removed(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* dm_test_main() - Run driver model tests
|
|
||||||
*
|
|
||||||
* Run all the available driver model tests, or a selection
|
|
||||||
*
|
|
||||||
* @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just
|
|
||||||
* "fdt_pre_reloc"), or NULL to run all
|
|
||||||
* @return 0 if all tests passed, 1 if not
|
|
||||||
*/
|
|
||||||
int dm_test_main(const char *test_name);
|
|
||||||
|
|
||||||
#endif /* __TEST_TEST_H */
|
#endif /* __TEST_TEST_H */
|
||||||
|
|
|
@ -356,4 +356,49 @@ void ut_silence_console(struct unit_test_state *uts);
|
||||||
*/
|
*/
|
||||||
void ut_unsilence_console(struct unit_test_state *uts);
|
void ut_unsilence_console(struct unit_test_state *uts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_set_skip_delays() - Sets whether delays should be skipped
|
||||||
|
*
|
||||||
|
* Normally functions like mdelay() cause U-Boot to wait for a while. This
|
||||||
|
* allows all such delays to be skipped on sandbox, to speed up tests
|
||||||
|
*
|
||||||
|
* @uts: Test state (in case in future we want to keep state here)
|
||||||
|
* @skip_delays: true to skip delays, false to process them normally
|
||||||
|
*/
|
||||||
|
void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_get_state() - Get the active test state
|
||||||
|
*
|
||||||
|
* @return the currently active test state, or NULL if none
|
||||||
|
*/
|
||||||
|
struct unit_test_state *test_get_state(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_set_state() - Set the active test state
|
||||||
|
*
|
||||||
|
* @uts: Test state to use as currently active test state, or NULL if none
|
||||||
|
*/
|
||||||
|
void test_set_state(struct unit_test_state *uts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_run_tests() - Run a set of tests
|
||||||
|
*
|
||||||
|
* This runs the test, handling any preparation and clean-up needed. It prints
|
||||||
|
* the name of each test before running it.
|
||||||
|
*
|
||||||
|
* @category: Category of these tests. This is a string printed at the start to
|
||||||
|
* announce the the number of tests
|
||||||
|
* @prefix: String prefix for the tests. Any tests that have this prefix will be
|
||||||
|
* printed without the prefix, so that it is easier to see the unique part
|
||||||
|
* of the test name. If NULL, no prefix processing is done
|
||||||
|
* @tests: List of tests to run
|
||||||
|
* @count: Number of tests to run
|
||||||
|
* @select_name: Name of a single test to run (from the list provided). If NULL
|
||||||
|
* then all tests are run
|
||||||
|
* @return 0 if all tests passed, -1 if any failed
|
||||||
|
*/
|
||||||
|
int ut_run_list(const char *name, const char *prefix, struct unit_test *tests,
|
||||||
|
int count, const char *select_name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
#
|
#
|
||||||
# (C) Copyright 2012 The Chromium Authors
|
# (C) Copyright 2012 The Chromium Authors
|
||||||
|
|
||||||
|
obj-y += test-main.o
|
||||||
|
obj-$(CONFIG_SANDBOX) += image/
|
||||||
|
|
||||||
ifneq ($(CONFIG_$(SPL_)BLOBLIST),)
|
ifneq ($(CONFIG_$(SPL_)BLOBLIST),)
|
||||||
obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o
|
obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o
|
||||||
obj-$(CONFIG_$(SPL_)CMDLINE) += bootm.o
|
obj-$(CONFIG_$(SPL_)CMDLINE) += bootm.o
|
||||||
|
|
|
@ -387,9 +387,8 @@ BLOBLIST_TEST(bloblist_test_reloc, 0);
|
||||||
int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
|
int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(bloblist_test);
|
||||||
bloblist_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(bloblist_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
|
|
||||||
|
|
||||||
return cmd_ut_category("bloblist", "bloblist_test_",
|
return cmd_ut_category("bloblist", "bloblist_test_",
|
||||||
tests, n_ents, argc, argv);
|
tests, n_ents, argc, argv);
|
||||||
|
|
|
@ -240,8 +240,8 @@ BOOTM_TEST(bootm_test_subst_both, 0);
|
||||||
|
|
||||||
int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, bootm_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(bootm_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, bootm_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(bootm_test);
|
||||||
|
|
||||||
return cmd_ut_category("bootm", "bootm_test_", tests, n_ents,
|
return cmd_ut_category("bootm", "bootm_test_", tests, n_ents,
|
||||||
argc, argv);
|
argc, argv);
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, mem_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(mem_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, mem_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(mem_test);
|
||||||
|
|
||||||
return cmd_ut_category("cmd_mem", "mem_test_", tests, n_ents, argc,
|
return cmd_ut_category("cmd_mem", "mem_test_", tests, n_ents, argc,
|
||||||
argv);
|
argv);
|
||||||
|
|
|
@ -306,8 +306,8 @@ static int setexpr_test_str(struct unit_test_state *uts)
|
||||||
ut_asserteq(1, run_command("setexpr.s fred 0", 0));
|
ut_asserteq(1, run_command("setexpr.s fred 0", 0));
|
||||||
ut_assertok(ut_check_delta(start_mem));
|
ut_assertok(ut_check_delta(start_mem));
|
||||||
|
|
||||||
start_mem = ut_check_free();
|
|
||||||
ut_assertok(env_set("fred", "12345"));
|
ut_assertok(env_set("fred", "12345"));
|
||||||
|
start_mem = ut_check_free();
|
||||||
ut_assertok(run_command("setexpr.s fred *0", 0));
|
ut_assertok(run_command("setexpr.s fred *0", 0));
|
||||||
ut_asserteq_str("hello", env_get("fred"));
|
ut_asserteq_str("hello", env_get("fred"));
|
||||||
ut_assertok(ut_check_delta(start_mem));
|
ut_assertok(ut_check_delta(start_mem));
|
||||||
|
@ -345,7 +345,22 @@ static int setexpr_test_str_oper(struct unit_test_state *uts)
|
||||||
start_mem = ut_check_free();
|
start_mem = ut_check_free();
|
||||||
ut_assertok(run_command("setexpr.s fred *0 + *10", 0));
|
ut_assertok(run_command("setexpr.s fred *0 + *10", 0));
|
||||||
ut_asserteq_str("hello there", env_get("fred"));
|
ut_asserteq_str("hello there", env_get("fred"));
|
||||||
ut_assertok(ut_check_delta(start_mem));
|
|
||||||
|
/*
|
||||||
|
* This check does not work with sandbox_flattree, apparently due to
|
||||||
|
* memory allocations in env_set().
|
||||||
|
*
|
||||||
|
* The truetype console produces lots of memory allocations even though
|
||||||
|
* the LCD display is not visible. But even without these, it does not
|
||||||
|
* work.
|
||||||
|
*
|
||||||
|
* A better test would be for dlmalloc to record the allocs and frees
|
||||||
|
* for a particular caller, but that is not supported.
|
||||||
|
*
|
||||||
|
* For now, drop this test.
|
||||||
|
*
|
||||||
|
* ut_assertok(ut_check_delta(start_mem));
|
||||||
|
*/
|
||||||
|
|
||||||
unmap_sysmem(buf);
|
unmap_sysmem(buf);
|
||||||
|
|
||||||
|
@ -375,10 +390,9 @@ SETEXPR_TEST(setexpr_test_str_long, UT_TESTF_CONSOLE_REC);
|
||||||
|
|
||||||
int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(setexpr_test);
|
||||||
setexpr_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(setexpr_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, setexpr_test);
|
|
||||||
|
|
||||||
return cmd_ut_category("cmd_setexpr", "cmd_mem_", tests, n_ents, argc,
|
return cmd_ut_category("cmd_setexpr", "setexpr_test_", tests, n_ents,
|
||||||
argv);
|
argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
#include <test/suites.h>
|
#include <test/suites.h>
|
||||||
#include <test/test.h>
|
#include <test/test.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[]);
|
char *const argv[]);
|
||||||
|
@ -17,41 +18,12 @@ int cmd_ut_category(const char *name, const char *prefix,
|
||||||
struct unit_test *tests, int n_ents,
|
struct unit_test *tests, int n_ents,
|
||||||
int argc, char *const argv[])
|
int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test_state uts = { .fail_count = 0 };
|
int ret;
|
||||||
struct unit_test *test;
|
|
||||||
int prefix_len = prefix ? strlen(prefix) : 0;
|
|
||||||
|
|
||||||
if (argc == 1)
|
ret = ut_run_list(name, prefix, tests, n_ents,
|
||||||
printf("Running %d %s tests\n", n_ents, name);
|
argc > 1 ? argv[1] : NULL);
|
||||||
|
|
||||||
for (test = tests; test < tests + n_ents; test++) {
|
return ret ? CMD_RET_FAILURE : 0;
|
||||||
const char *test_name = test->name;
|
|
||||||
|
|
||||||
/* Remove the prefix */
|
|
||||||
if (prefix && !strncmp(test_name, prefix, prefix_len))
|
|
||||||
test_name += prefix_len;
|
|
||||||
|
|
||||||
if (argc > 1 && strcmp(argv[1], test_name))
|
|
||||||
continue;
|
|
||||||
printf("Test: %s\n", test->name);
|
|
||||||
|
|
||||||
if (test->flags & UT_TESTF_CONSOLE_REC) {
|
|
||||||
int ret = console_record_reset_enable();
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
printf("Skipping: Console recording disabled\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uts.start = mallinfo();
|
|
||||||
|
|
||||||
test->func(&uts);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Failures: %d\n", uts.fail_count);
|
|
||||||
|
|
||||||
return uts.fail_count ? CMD_RET_FAILURE : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmd_tbl cmd_ut_sub[] = {
|
static struct cmd_tbl cmd_ut_sub[] = {
|
||||||
|
|
|
@ -539,9 +539,8 @@ COMPRESSION_TEST(compression_test_bootm_none, 0);
|
||||||
int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc,
|
int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(compression_test);
|
||||||
compression_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(compression_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, compression_test);
|
|
||||||
|
|
||||||
return cmd_ut_category("compression", "compression_test_",
|
return cmd_ut_category("compression", "compression_test_",
|
||||||
tests, n_ents, argc, argv);
|
tests, n_ents, argc, argv);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Google, Inc
|
# Copyright (c) 2013 Google, Inc
|
||||||
|
|
||||||
obj-$(CONFIG_UT_DM) += test-main.o
|
obj-$(CONFIG_UT_DM) += test-dm.o
|
||||||
|
|
||||||
# Tests for particular subsystems - when enabling driver model for a new
|
# Tests for particular subsystems - when enabling driver model for a new
|
||||||
# subsystem you must add sandbox tests here.
|
# subsystem you must add sandbox tests here.
|
||||||
|
|
|
@ -117,14 +117,13 @@ int dm_leak_check_end(struct unit_test_state *uts)
|
||||||
/* Test that binding with plat occurs correctly */
|
/* Test that binding with plat occurs correctly */
|
||||||
static int dm_test_autobind(struct unit_test_state *uts)
|
static int dm_test_autobind(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should have a single class (UCLASS_ROOT) and a single root
|
* We should have a single class (UCLASS_ROOT) and a single root
|
||||||
* device with no children.
|
* device with no children.
|
||||||
*/
|
*/
|
||||||
ut_assert(dms->root);
|
ut_assert(uts->root);
|
||||||
ut_asserteq(1, list_count_items(gd->uclass_root));
|
ut_asserteq(1, list_count_items(gd->uclass_root));
|
||||||
ut_asserteq(0, list_count_items(&gd->dm_root->child_head));
|
ut_asserteq(0, list_count_items(&gd->dm_root->child_head));
|
||||||
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
|
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
|
||||||
|
@ -207,7 +206,6 @@ DM_TEST(dm_test_autobind_uclass_pdata_valid, UT_TESTF_SCAN_PDATA);
|
||||||
/* Test that autoprobe finds all the expected devices */
|
/* Test that autoprobe finds all the expected devices */
|
||||||
static int dm_test_autoprobe(struct unit_test_state *uts)
|
static int dm_test_autoprobe(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
int expected_base_add;
|
int expected_base_add;
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
struct uclass *uc;
|
struct uclass *uc;
|
||||||
|
@ -221,7 +219,7 @@ static int dm_test_autoprobe(struct unit_test_state *uts)
|
||||||
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]);
|
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]);
|
||||||
|
|
||||||
/* The root device should not be activated until needed */
|
/* The root device should not be activated until needed */
|
||||||
ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED);
|
ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should be able to find the three test devices, and they should
|
* We should be able to find the three test devices, and they should
|
||||||
|
@ -241,7 +239,7 @@ static int dm_test_autoprobe(struct unit_test_state *uts)
|
||||||
|
|
||||||
/* Activating a device should activate the root device */
|
/* Activating a device should activate the root device */
|
||||||
if (!i)
|
if (!i)
|
||||||
ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED);
|
ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -293,7 +291,6 @@ DM_TEST(dm_test_plat, UT_TESTF_SCAN_PDATA);
|
||||||
/* Test that we can bind, probe, remove, unbind a driver */
|
/* Test that we can bind, probe, remove, unbind a driver */
|
||||||
static int dm_test_lifecycle(struct unit_test_state *uts)
|
static int dm_test_lifecycle(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
int op_count[DM_TEST_OP_COUNT];
|
int op_count[DM_TEST_OP_COUNT];
|
||||||
struct udevice *dev, *test_dev;
|
struct udevice *dev, *test_dev;
|
||||||
int pingret;
|
int pingret;
|
||||||
|
@ -301,7 +298,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
|
||||||
|
|
||||||
memcpy(op_count, dm_testdrv_op_count, sizeof(op_count));
|
memcpy(op_count, dm_testdrv_op_count, sizeof(op_count));
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev));
|
&dev));
|
||||||
ut_assert(dev);
|
ut_assert(dev);
|
||||||
ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND]
|
ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND]
|
||||||
|
@ -309,7 +306,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
|
||||||
ut_assert(!dev_get_priv(dev));
|
ut_assert(!dev_get_priv(dev));
|
||||||
|
|
||||||
/* Probe the device - it should fail allocating private data */
|
/* Probe the device - it should fail allocating private data */
|
||||||
dms->force_fail_alloc = 1;
|
uts->force_fail_alloc = 1;
|
||||||
ret = device_probe(dev);
|
ret = device_probe(dev);
|
||||||
ut_assert(ret == -ENOMEM);
|
ut_assert(ret == -ENOMEM);
|
||||||
ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
|
ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
|
||||||
|
@ -317,7 +314,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
|
||||||
ut_assert(!dev_get_priv(dev));
|
ut_assert(!dev_get_priv(dev));
|
||||||
|
|
||||||
/* Try again without the alloc failure */
|
/* Try again without the alloc failure */
|
||||||
dms->force_fail_alloc = 0;
|
uts->force_fail_alloc = 0;
|
||||||
ut_assertok(device_probe(dev));
|
ut_assertok(device_probe(dev));
|
||||||
ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
|
ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
|
||||||
== op_count[DM_TEST_OP_PROBE] + 2);
|
== op_count[DM_TEST_OP_PROBE] + 2);
|
||||||
|
@ -349,19 +346,18 @@ DM_TEST(dm_test_lifecycle, UT_TESTF_SCAN_PDATA | UT_TESTF_PROBE_TEST);
|
||||||
/* Test that we can bind/unbind and the lists update correctly */
|
/* Test that we can bind/unbind and the lists update correctly */
|
||||||
static int dm_test_ordering(struct unit_test_state *uts)
|
static int dm_test_ordering(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *dev, *dev_penultimate, *dev_last, *test_dev;
|
struct udevice *dev, *dev_penultimate, *dev_last, *test_dev;
|
||||||
int pingret;
|
int pingret;
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev));
|
&dev));
|
||||||
ut_assert(dev);
|
ut_assert(dev);
|
||||||
|
|
||||||
/* Bind two new devices (numbers 4 and 5) */
|
/* Bind two new devices (numbers 4 and 5) */
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev_penultimate));
|
&dev_penultimate));
|
||||||
ut_assert(dev_penultimate);
|
ut_assert(dev_penultimate);
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev_last));
|
&dev_last));
|
||||||
ut_assert(dev_last);
|
ut_assert(dev_last);
|
||||||
|
|
||||||
|
@ -376,7 +372,7 @@ static int dm_test_ordering(struct unit_test_state *uts)
|
||||||
ut_assert(dev_last == test_dev);
|
ut_assert(dev_last == test_dev);
|
||||||
|
|
||||||
/* Add back the original device 3, now in position 5 */
|
/* Add back the original device 3, now in position 5 */
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev));
|
&dev));
|
||||||
ut_assert(dev);
|
ut_assert(dev);
|
||||||
|
|
||||||
|
@ -568,7 +564,6 @@ static int create_children(struct unit_test_state *uts, struct udevice *parent,
|
||||||
|
|
||||||
static int dm_test_children(struct unit_test_state *uts)
|
static int dm_test_children(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *top[NODE_COUNT];
|
struct udevice *top[NODE_COUNT];
|
||||||
struct udevice *child[NODE_COUNT];
|
struct udevice *child[NODE_COUNT];
|
||||||
struct udevice *grandchild[NODE_COUNT];
|
struct udevice *grandchild[NODE_COUNT];
|
||||||
|
@ -578,12 +573,12 @@ static int dm_test_children(struct unit_test_state *uts)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* We don't care about the numbering for this test */
|
/* We don't care about the numbering for this test */
|
||||||
dms->skip_post_probe = 1;
|
uts->skip_post_probe = 1;
|
||||||
|
|
||||||
ut_assert(NODE_COUNT > 5);
|
ut_assert(NODE_COUNT > 5);
|
||||||
|
|
||||||
/* First create 10 top-level children */
|
/* First create 10 top-level children */
|
||||||
ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
|
ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top));
|
||||||
|
|
||||||
/* Now a few have their own children */
|
/* Now a few have their own children */
|
||||||
ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
|
ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
|
||||||
|
@ -654,7 +649,6 @@ DM_TEST(dm_test_children, 0);
|
||||||
|
|
||||||
static int dm_test_device_reparent(struct unit_test_state *uts)
|
static int dm_test_device_reparent(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *top[NODE_COUNT];
|
struct udevice *top[NODE_COUNT];
|
||||||
struct udevice *child[NODE_COUNT];
|
struct udevice *child[NODE_COUNT];
|
||||||
struct udevice *grandchild[NODE_COUNT];
|
struct udevice *grandchild[NODE_COUNT];
|
||||||
|
@ -664,12 +658,12 @@ static int dm_test_device_reparent(struct unit_test_state *uts)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* We don't care about the numbering for this test */
|
/* We don't care about the numbering for this test */
|
||||||
dms->skip_post_probe = 1;
|
uts->skip_post_probe = 1;
|
||||||
|
|
||||||
ut_assert(NODE_COUNT > 5);
|
ut_assert(NODE_COUNT > 5);
|
||||||
|
|
||||||
/* First create 10 top-level children */
|
/* First create 10 top-level children */
|
||||||
ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
|
ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top));
|
||||||
|
|
||||||
/* Now a few have their own children */
|
/* Now a few have their own children */
|
||||||
ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
|
ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
|
||||||
|
@ -815,15 +809,14 @@ DM_TEST(dm_test_device_reparent, 0);
|
||||||
/* Test that pre-relocation devices work as expected */
|
/* Test that pre-relocation devices work as expected */
|
||||||
static int dm_test_pre_reloc(struct unit_test_state *uts)
|
static int dm_test_pre_reloc(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
/* The normal driver should refuse to bind before relocation */
|
/* The normal driver should refuse to bind before relocation */
|
||||||
ut_asserteq(-EPERM, device_bind_by_name(dms->root, true,
|
ut_asserteq(-EPERM, device_bind_by_name(uts->root, true,
|
||||||
&driver_info_manual, &dev));
|
&driver_info_manual, &dev));
|
||||||
|
|
||||||
/* But this one is marked pre-reloc */
|
/* But this one is marked pre-reloc */
|
||||||
ut_assertok(device_bind_by_name(dms->root, true,
|
ut_assertok(device_bind_by_name(uts->root, true,
|
||||||
&driver_info_pre_reloc, &dev));
|
&driver_info_pre_reloc, &dev));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -836,10 +829,9 @@ DM_TEST(dm_test_pre_reloc, 0);
|
||||||
*/
|
*/
|
||||||
static int dm_test_remove_active_dma(struct unit_test_state *uts)
|
static int dm_test_remove_active_dma(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma,
|
||||||
&dev));
|
&dev));
|
||||||
ut_assert(dev);
|
ut_assert(dev);
|
||||||
|
|
||||||
|
@ -872,7 +864,7 @@ static int dm_test_remove_active_dma(struct unit_test_state *uts)
|
||||||
* the active DMA remove call
|
* the active DMA remove call
|
||||||
*/
|
*/
|
||||||
ut_assertok(device_unbind(dev));
|
ut_assertok(device_unbind(dev));
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&dev));
|
&dev));
|
||||||
ut_assert(dev);
|
ut_assert(dev);
|
||||||
|
|
||||||
|
@ -895,25 +887,24 @@ DM_TEST(dm_test_remove_active_dma, 0);
|
||||||
/* Test removal of 'vital' devices */
|
/* Test removal of 'vital' devices */
|
||||||
static int dm_test_remove_vital(struct unit_test_state *uts)
|
static int dm_test_remove_vital(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *normal, *dma, *vital, *dma_vital;
|
struct udevice *normal, *dma, *vital, *dma_vital;
|
||||||
|
|
||||||
/* Skip the behaviour in test_post_probe() */
|
/* Skip the behaviour in test_post_probe() */
|
||||||
dms->skip_post_probe = 1;
|
uts->skip_post_probe = 1;
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
|
||||||
&normal));
|
&normal));
|
||||||
ut_assertnonnull(normal);
|
ut_assertnonnull(normal);
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma,
|
ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma,
|
||||||
&dma));
|
&dma));
|
||||||
ut_assertnonnull(dma);
|
ut_assertnonnull(dma);
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false,
|
ut_assertok(device_bind_by_name(uts->root, false,
|
||||||
&driver_info_vital_clk, &vital));
|
&driver_info_vital_clk, &vital));
|
||||||
ut_assertnonnull(vital);
|
ut_assertnonnull(vital);
|
||||||
|
|
||||||
ut_assertok(device_bind_by_name(dms->root, false,
|
ut_assertok(device_bind_by_name(uts->root, false,
|
||||||
&driver_info_act_dma_vital_clk,
|
&driver_info_act_dma_vital_clk,
|
||||||
&dma_vital));
|
&dma_vital));
|
||||||
ut_assertnonnull(dma_vital);
|
ut_assertnonnull(dma_vital);
|
||||||
|
@ -1133,11 +1124,10 @@ DM_TEST(dm_test_uclass_names, UT_TESTF_SCAN_PDATA);
|
||||||
|
|
||||||
static int dm_test_inactive_child(struct unit_test_state *uts)
|
static int dm_test_inactive_child(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
struct udevice *parent, *dev1, *dev2;
|
struct udevice *parent, *dev1, *dev2;
|
||||||
|
|
||||||
/* Skip the behaviour in test_post_probe() */
|
/* Skip the behaviour in test_post_probe() */
|
||||||
dms->skip_post_probe = 1;
|
uts->skip_post_probe = 1;
|
||||||
|
|
||||||
ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent));
|
ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent));
|
||||||
|
|
||||||
|
|
51
test/dm/test-dm.c
Normal file
51
test/dm/test-dm.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Google, Inc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <command.h>
|
||||||
|
#include <console.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <log.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <asm/global_data.h>
|
||||||
|
#include <asm/state.h>
|
||||||
|
#include <dm/root.h>
|
||||||
|
#include <dm/uclass-internal.h>
|
||||||
|
#include <test/test.h>
|
||||||
|
#include <test/test.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_run() - Run driver model tests
|
||||||
|
*
|
||||||
|
* Run all the available driver model tests, or a selection
|
||||||
|
*
|
||||||
|
* @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just
|
||||||
|
* "fdt_pre_reloc"), or NULL to run all
|
||||||
|
* @return 0 if all tests passed, 1 if not
|
||||||
|
*/
|
||||||
|
static int dm_test_run(const char *test_name)
|
||||||
|
{
|
||||||
|
struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test);
|
||||||
|
const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ut_run_list("driver model", "dm_test_", tests, n_ents, test_name);
|
||||||
|
|
||||||
|
return ret ? CMD_RET_FAILURE : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
const char *test_name = NULL;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
test_name = argv[1];
|
||||||
|
|
||||||
|
return dm_test_run(test_name);
|
||||||
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
#include <test/ut.h>
|
#include <test/ut.h>
|
||||||
|
|
||||||
int dm_testdrv_op_count[DM_TEST_OP_COUNT];
|
int dm_testdrv_op_count[DM_TEST_OP_COUNT];
|
||||||
static struct unit_test_state *uts = &global_dm_test_state;
|
|
||||||
|
|
||||||
static int testdrv_ping(struct udevice *dev, int pingval, int *pingret)
|
static int testdrv_ping(struct udevice *dev, int pingval, int *pingret)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +36,8 @@ static const struct test_ops test_ops = {
|
||||||
|
|
||||||
static int test_bind(struct udevice *dev)
|
static int test_bind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
/* Private data should not be allocated */
|
/* Private data should not be allocated */
|
||||||
ut_assert(!dev_get_priv(dev));
|
ut_assert(!dev_get_priv(dev));
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ static int test_bind(struct udevice *dev)
|
||||||
|
|
||||||
static int test_probe(struct udevice *dev)
|
static int test_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
struct dm_test_priv *priv = dev_get_priv(dev);
|
struct dm_test_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
/* Private data should be allocated */
|
/* Private data should be allocated */
|
||||||
|
@ -58,6 +60,8 @@ static int test_probe(struct udevice *dev)
|
||||||
|
|
||||||
static int test_remove(struct udevice *dev)
|
static int test_remove(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
/* Private data should still be allocated */
|
/* Private data should still be allocated */
|
||||||
ut_assert(dev_get_priv(dev));
|
ut_assert(dev_get_priv(dev));
|
||||||
|
|
||||||
|
@ -67,6 +71,8 @@ static int test_remove(struct udevice *dev)
|
||||||
|
|
||||||
static int test_unbind(struct udevice *dev)
|
static int test_unbind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
/* Private data should not be allocated */
|
/* Private data should not be allocated */
|
||||||
ut_assert(!dev_get_priv(dev));
|
ut_assert(!dev_get_priv(dev));
|
||||||
|
|
||||||
|
@ -116,10 +122,10 @@ static int test_manual_bind(struct udevice *dev)
|
||||||
|
|
||||||
static int test_manual_probe(struct udevice *dev)
|
static int test_manual_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct dm_test_state *dms = uts->priv;
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
dm_testdrv_op_count[DM_TEST_OP_PROBE]++;
|
dm_testdrv_op_count[DM_TEST_OP_PROBE]++;
|
||||||
if (!dms->force_fail_alloc)
|
if (!uts->force_fail_alloc)
|
||||||
dev_set_priv(dev, calloc(1, sizeof(struct dm_test_priv)));
|
dev_set_priv(dev, calloc(1, sizeof(struct dm_test_priv)));
|
||||||
if (!dev_get_priv(dev))
|
if (!dev_get_priv(dev))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -1,230 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2013 Google, Inc
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <common.h>
|
|
||||||
#include <command.h>
|
|
||||||
#include <console.h>
|
|
||||||
#include <dm.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <log.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <asm/global_data.h>
|
|
||||||
#include <asm/state.h>
|
|
||||||
#include <dm/test.h>
|
|
||||||
#include <dm/root.h>
|
|
||||||
#include <dm/uclass-internal.h>
|
|
||||||
#include <test/test.h>
|
|
||||||
#include <test/test.h>
|
|
||||||
#include <test/ut.h>
|
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
|
||||||
|
|
||||||
struct unit_test_state global_dm_test_state;
|
|
||||||
static struct dm_test_state _global_priv_dm_test_state;
|
|
||||||
|
|
||||||
/* Get ready for testing */
|
|
||||||
static int dm_test_init(struct unit_test_state *uts, bool of_live)
|
|
||||||
{
|
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
|
|
||||||
memset(dms, '\0', sizeof(*dms));
|
|
||||||
gd->dm_root = NULL;
|
|
||||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
|
||||||
memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
|
|
||||||
state_reset_for_test(state_get_current());
|
|
||||||
|
|
||||||
/* Determine whether to make the live tree available */
|
|
||||||
gd_set_of_root(of_live ? uts->of_root : NULL);
|
|
||||||
ut_assertok(dm_init(of_live));
|
|
||||||
dms->root = dm_root();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure all the test devices are probed */
|
|
||||||
static int do_autoprobe(struct unit_test_state *uts)
|
|
||||||
{
|
|
||||||
struct udevice *dev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Scanning the uclass is enough to probe all the devices */
|
|
||||||
for (ret = uclass_first_device(UCLASS_TEST, &dev);
|
|
||||||
dev;
|
|
||||||
ret = uclass_next_device(&dev))
|
|
||||||
;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dm_test_destroy(struct unit_test_state *uts)
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
|
|
||||||
for (id = 0; id < UCLASS_COUNT; id++) {
|
|
||||||
struct uclass *uc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the uclass doesn't exist we don't want to create it. So
|
|
||||||
* check that here before we call uclass_find_device().
|
|
||||||
*/
|
|
||||||
uc = uclass_find(id);
|
|
||||||
if (!uc)
|
|
||||||
continue;
|
|
||||||
ut_assertok(uclass_destroy(uc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dm_do_test(struct unit_test_state *uts, struct unit_test *test,
|
|
||||||
bool of_live)
|
|
||||||
{
|
|
||||||
struct sandbox_state *state = state_get_current();
|
|
||||||
const char *fname = strrchr(test->file, '/') + 1;
|
|
||||||
|
|
||||||
printf("Test: %s: %s%s\n", test->name, fname,
|
|
||||||
!of_live ? " (flat tree)" : "");
|
|
||||||
ut_assertok(dm_test_init(uts, of_live));
|
|
||||||
|
|
||||||
uts->start = mallinfo();
|
|
||||||
if (test->flags & UT_TESTF_SCAN_PDATA)
|
|
||||||
ut_assertok(dm_scan_plat(false));
|
|
||||||
if (test->flags & UT_TESTF_PROBE_TEST)
|
|
||||||
ut_assertok(do_autoprobe(uts));
|
|
||||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
|
||||||
(test->flags & UT_TESTF_SCAN_FDT))
|
|
||||||
ut_assertok(dm_extended_scan(false));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Silence the console and rely on console recording to get
|
|
||||||
* our output.
|
|
||||||
*/
|
|
||||||
console_record_reset_enable();
|
|
||||||
if (!state->show_test_output)
|
|
||||||
gd->flags |= GD_FLG_SILENT;
|
|
||||||
test->func(uts);
|
|
||||||
gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
|
|
||||||
state_set_skip_delays(false);
|
|
||||||
|
|
||||||
ut_assertok(dm_test_destroy(uts));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dm_test_run_on_flattree() - Check if we should run a test with flat DT
|
|
||||||
*
|
|
||||||
* This skips long/slow tests where there is not much value in running a flat
|
|
||||||
* DT test in addition to a live DT test.
|
|
||||||
*
|
|
||||||
* @return true to run the given test on the flat device tree
|
|
||||||
*/
|
|
||||||
static bool dm_test_run_on_flattree(struct unit_test *test)
|
|
||||||
{
|
|
||||||
const char *fname = strrchr(test->file, '/') + 1;
|
|
||||||
|
|
||||||
return !strstr(fname, "video") || strstr(test->name, "video_base");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
struct unit_test_state *uts = &global_dm_test_state;
|
|
||||||
struct unit_test *test;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
uts->priv = &_global_priv_dm_test_state;
|
|
||||||
uts->fail_count = 0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
uts->of_root = gd_of_root();
|
|
||||||
for (test = tests; test < tests + n_ents; test++) {
|
|
||||||
const char *name = test->name;
|
|
||||||
int runs;
|
|
||||||
|
|
||||||
if (!test_matches(name, test_name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Run with the live tree if possible */
|
|
||||||
runs = 0;
|
|
||||||
if (CONFIG_IS_ENABLED(OF_LIVE)) {
|
|
||||||
if (!(test->flags & UT_TESTF_FLAT_TREE)) {
|
|
||||||
ut_assertok(dm_do_test(uts, test, true));
|
|
||||||
runs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run with the flat tree if we couldn't run it with live tree,
|
|
||||||
* or it is a core test.
|
|
||||||
*/
|
|
||||||
if (!(test->flags & UT_TESTF_LIVE_TREE) &&
|
|
||||||
(!runs || dm_test_run_on_flattree(test))) {
|
|
||||||
ut_assertok(dm_do_test(uts, test, false));
|
|
||||||
runs++;
|
|
||||||
}
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (test_name && !found)
|
|
||||||
printf("Test '%s' not found\n", test_name);
|
|
||||||
else
|
|
||||||
printf("Failures: %d\n", uts->fail_count);
|
|
||||||
|
|
||||||
/* Put everything back to normal so that sandbox works as expected */
|
|
||||||
gd_set_of_root(uts->of_root);
|
|
||||||
gd->dm_root = NULL;
|
|
||||||
ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE)));
|
|
||||||
dm_scan_plat(false);
|
|
||||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
|
||||||
dm_scan_fdt(false);
|
|
||||||
|
|
||||||
return uts->fail_count ? CMD_RET_FAILURE : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
||||||
{
|
|
||||||
const char *test_name = NULL;
|
|
||||||
|
|
||||||
if (argc > 1)
|
|
||||||
test_name = argv[1];
|
|
||||||
|
|
||||||
return dm_test_main(test_name);
|
|
||||||
}
|
|
|
@ -17,8 +17,6 @@
|
||||||
#include <test/test.h>
|
#include <test/test.h>
|
||||||
#include <test/ut.h>
|
#include <test/ut.h>
|
||||||
|
|
||||||
static struct unit_test_state *uts = &global_dm_test_state;
|
|
||||||
|
|
||||||
int test_ping(struct udevice *dev, int pingval, int *pingret)
|
int test_ping(struct udevice *dev, int pingval, int *pingret)
|
||||||
{
|
{
|
||||||
const struct test_ops *ops = device_get_ops(dev);
|
const struct test_ops *ops = device_get_ops(dev);
|
||||||
|
@ -31,6 +29,7 @@ int test_ping(struct udevice *dev, int pingval, int *pingret)
|
||||||
|
|
||||||
static int test_post_bind(struct udevice *dev)
|
static int test_post_bind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
struct dm_test_perdev_uc_pdata *uc_pdata;
|
struct dm_test_perdev_uc_pdata *uc_pdata;
|
||||||
|
|
||||||
dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++;
|
dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++;
|
||||||
|
@ -56,6 +55,7 @@ static int test_pre_unbind(struct udevice *dev)
|
||||||
static int test_pre_probe(struct udevice *dev)
|
static int test_pre_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
|
struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]++;
|
dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]++;
|
||||||
ut_assert(priv);
|
ut_assert(priv);
|
||||||
|
@ -66,18 +66,18 @@ static int test_pre_probe(struct udevice *dev)
|
||||||
|
|
||||||
static int test_post_probe(struct udevice *dev)
|
static int test_post_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
struct udevice *prev = list_entry(dev->uclass_node.prev,
|
struct udevice *prev = list_entry(dev->uclass_node.prev,
|
||||||
struct udevice, uclass_node);
|
struct udevice, uclass_node);
|
||||||
|
|
||||||
struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
|
struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
|
||||||
struct uclass *uc = dev->uclass;
|
struct uclass *uc = dev->uclass;
|
||||||
struct dm_test_state *dms = uts->priv;
|
|
||||||
|
|
||||||
dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]++;
|
dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]++;
|
||||||
ut_assert(priv);
|
ut_assert(priv);
|
||||||
ut_assert(device_active(dev));
|
ut_assert(device_active(dev));
|
||||||
priv->base_add = 0;
|
priv->base_add = 0;
|
||||||
if (dms->skip_post_probe)
|
if (uts->skip_post_probe)
|
||||||
return 0;
|
return 0;
|
||||||
if (&prev->uclass_node != &uc->dev_head) {
|
if (&prev->uclass_node != &uc->dev_head) {
|
||||||
struct dm_test_uclass_perdev_priv *prev_uc_priv
|
struct dm_test_uclass_perdev_priv *prev_uc_priv
|
||||||
|
@ -101,6 +101,8 @@ static int test_pre_remove(struct udevice *dev)
|
||||||
|
|
||||||
static int test_init(struct uclass *uc)
|
static int test_init(struct uclass *uc)
|
||||||
{
|
{
|
||||||
|
struct unit_test_state *uts = test_get_state();
|
||||||
|
|
||||||
dm_testdrv_op_count[DM_TEST_OP_INIT]++;
|
dm_testdrv_op_count[DM_TEST_OP_INIT]++;
|
||||||
ut_assert(uclass_get_priv(uc));
|
ut_assert(uclass_get_priv(uc));
|
||||||
|
|
||||||
|
|
4
test/env/cmd_ut_env.c
vendored
4
test/env/cmd_ut_env.c
vendored
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, env_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(env_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, env_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(env_test);
|
||||||
|
|
||||||
return cmd_ut_category("environment", "env_test_",
|
return cmd_ut_category("environment", "env_test_",
|
||||||
tests, n_ents, argc, argv);
|
tests, n_ents, argc, argv);
|
||||||
|
|
5
test/image/Makefile
Normal file
5
test/image/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# Copyright 2021 Google LLC
|
||||||
|
|
||||||
|
obj-$(CONFIG_SPL_BUILD) += spl_load.o
|
91
test/image/spl_load.c
Normal file
91
test/image/spl_load.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <image.h>
|
||||||
|
#include <mapmem.h>
|
||||||
|
#include <os.h>
|
||||||
|
#include <spl.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
/* Declare a new SPL test */
|
||||||
|
#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test)
|
||||||
|
|
||||||
|
/* Context used for this test */
|
||||||
|
struct text_ctx {
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ulong read_fit_image(struct spl_load_info *load, ulong sector,
|
||||||
|
ulong count, void *buf)
|
||||||
|
{
|
||||||
|
struct text_ctx *text_ctx = load->priv;
|
||||||
|
off_t offset, ret;
|
||||||
|
ssize_t res;
|
||||||
|
|
||||||
|
offset = sector * load->bl_len;
|
||||||
|
ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET);
|
||||||
|
if (ret != offset) {
|
||||||
|
printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset,
|
||||||
|
ret, errno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = os_read(text_ctx->fd, buf, count * load->bl_len);
|
||||||
|
if (res == -1) {
|
||||||
|
printf("Failed to read %lx bytes, got %ld (errno=%d)\n",
|
||||||
|
count * load->bl_len, res, errno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_fit_config_name_match(const char *name)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
|
||||||
|
{
|
||||||
|
return map_sysmem(0x100000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spl_test_load(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct spl_image_info image;
|
||||||
|
struct image_header *header;
|
||||||
|
struct text_ctx text_ctx;
|
||||||
|
struct spl_load_info load;
|
||||||
|
char fname[256];
|
||||||
|
int ret;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
memset(&load, '\0', sizeof(load));
|
||||||
|
load.bl_len = 512;
|
||||||
|
load.read = read_fit_image;
|
||||||
|
|
||||||
|
ret = os_find_u_boot(fname, sizeof(fname), true);
|
||||||
|
if (ret) {
|
||||||
|
printf("(%s not found, error %d)\n", fname, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
load.filename = fname;
|
||||||
|
|
||||||
|
header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
|
||||||
|
|
||||||
|
fd = os_open(fname, OS_O_RDONLY);
|
||||||
|
ut_assert(fd >= 0);
|
||||||
|
ut_asserteq(512, os_read(fd, header, 512));
|
||||||
|
text_ctx.fd = fd;
|
||||||
|
|
||||||
|
load.priv = &text_ctx;
|
||||||
|
|
||||||
|
ut_assertok(spl_load_simple_fit(&image, &load, 0, header));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SPL_TEST(spl_test_load, 0);
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, lib_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(lib_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, lib_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(lib_test);
|
||||||
|
|
||||||
return cmd_ut_category("lib", "lib_test_", tests, n_ents, argc, argv);
|
return cmd_ut_category("lib", "lib_test_", tests, n_ents, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ obj-$(CONFIG_CMD_LOG) += log_filter.o
|
||||||
|
|
||||||
ifdef CONFIG_UT_LOG
|
ifdef CONFIG_UT_LOG
|
||||||
|
|
||||||
obj-y += test-main.o
|
obj-y += log_ut.o
|
||||||
|
|
||||||
ifdef CONFIG_SANDBOX
|
ifdef CONFIG_SANDBOX
|
||||||
obj-$(CONFIG_LOG_SYSLOG) += syslog_test.o
|
obj-$(CONFIG_LOG_SYSLOG) += syslog_test.o
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
|
int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, log_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(log_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, log_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(log_test);
|
||||||
|
|
||||||
return cmd_ut_category("log", "log_test_",
|
return cmd_ut_category("log", "log_test_",
|
||||||
tests, n_ents, argc, argv);
|
tests, n_ents, argc, argv);
|
|
@ -94,9 +94,8 @@ OPTEE_TEST(optee_fdt_protected_memory, 0);
|
||||||
|
|
||||||
int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(optee_test);
|
||||||
optee_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(optee_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, optee_test);
|
|
||||||
struct unit_test_state *uts;
|
struct unit_test_state *uts;
|
||||||
void *fdt_optee = &__dtb_test_optee_optee_begin;
|
void *fdt_optee = &__dtb_test_optee_optee_begin;
|
||||||
void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
|
void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
|
||||||
|
|
|
@ -213,9 +213,8 @@ OVERLAY_TEST(fdt_overlay_stacked, 0);
|
||||||
|
|
||||||
int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(overlay_test);
|
||||||
overlay_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(overlay_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, overlay_test);
|
|
||||||
struct unit_test_state *uts;
|
struct unit_test_state *uts;
|
||||||
void *fdt_base = &__dtb_test_fdt_base_begin;
|
void *fdt_base = &__dtb_test_fdt_base_begin;
|
||||||
void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
|
void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
|
||||||
|
|
|
@ -226,7 +226,7 @@ def pytest_configure(config):
|
||||||
import u_boot_console_exec_attach
|
import u_boot_console_exec_attach
|
||||||
console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
|
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*$')
|
re_ut_test_list = re.compile(r'_u_boot_list_2_ut_(.*)_test_2_\1_test_(.*)\s*$')
|
||||||
def generate_ut_subtest(metafunc, fixture_name, sym_path):
|
def generate_ut_subtest(metafunc, fixture_name, sym_path):
|
||||||
"""Provide parametrization for a ut_subtest fixture.
|
"""Provide parametrization for a ut_subtest fixture.
|
||||||
|
|
||||||
|
|
|
@ -45,5 +45,4 @@ def test_log_dropped(u_boot_console):
|
||||||
cons = u_boot_console
|
cons = u_boot_console
|
||||||
cons.restart_uboot()
|
cons.restart_uboot()
|
||||||
output = cons.get_spawn_output().replace('\r', '')
|
output = cons.get_spawn_output().replace('\r', '')
|
||||||
assert 'sandbox: starting...' in output
|
|
||||||
assert (not 'debug: main' in output)
|
assert (not 'debug: main' in output)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
import u_boot_utils as util
|
import u_boot_utils as util
|
||||||
|
|
||||||
@pytest.mark.boardspec('sandbox')
|
@pytest.mark.boardspec('sandbox_spl')
|
||||||
@pytest.mark.buildconfigspec('spl_of_platdata')
|
@pytest.mark.buildconfigspec('spl_of_platdata')
|
||||||
def test_spl_devicetree(u_boot_console):
|
def test_spl_devicetree(u_boot_console):
|
||||||
"""Test content of spl device-tree"""
|
"""Test content of spl device-tree"""
|
||||||
|
|
|
@ -107,9 +107,8 @@ STR_TEST(str_simple_strtoul, 0);
|
||||||
|
|
||||||
int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = UNIT_TEST_SUITE_START(str_test);
|
||||||
str_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(str_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, str_test);
|
|
||||||
|
|
||||||
return cmd_ut_category("str", "str_", tests, n_ents, argc, argv);
|
return cmd_ut_category("str", "str_", tests, n_ents, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
426
test/test-main.c
Normal file
426
test/test-main.c
Normal file
|
@ -0,0 +1,426 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <console.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <asm/state.h>
|
||||||
|
#include <dm/root.h>
|
||||||
|
#include <dm/test.h>
|
||||||
|
#include <dm/uclass-internal.h>
|
||||||
|
#include <test/test.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
|
/* This is valid when a test is running, NULL otherwise */
|
||||||
|
static struct unit_test_state *cur_test_state;
|
||||||
|
|
||||||
|
struct unit_test_state *test_get_state(void)
|
||||||
|
{
|
||||||
|
return cur_test_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_set_state(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
cur_test_state = uts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_pre_run() - Get ready to run a driver model test
|
||||||
|
*
|
||||||
|
* This clears out the driver model data structures. For sandbox it resets the
|
||||||
|
* state structure
|
||||||
|
*
|
||||||
|
* @uts: Test state
|
||||||
|
*/
|
||||||
|
static int dm_test_pre_run(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
bool of_live = uts->of_live;
|
||||||
|
|
||||||
|
uts->root = NULL;
|
||||||
|
uts->testdev = NULL;
|
||||||
|
uts->force_fail_alloc = false;
|
||||||
|
uts->skip_post_probe = false;
|
||||||
|
gd->dm_root = NULL;
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||||
|
memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
|
||||||
|
state_reset_for_test(state_get_current());
|
||||||
|
|
||||||
|
/* Determine whether to make the live tree available */
|
||||||
|
gd_set_of_root(of_live ? uts->of_root : NULL);
|
||||||
|
ut_assertok(dm_init(of_live));
|
||||||
|
uts->root = dm_root();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_test_post_run(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
|
||||||
|
for (id = 0; id < UCLASS_COUNT; id++) {
|
||||||
|
struct uclass *uc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the uclass doesn't exist we don't want to create it. So
|
||||||
|
* check that here before we call uclass_find_device().
|
||||||
|
*/
|
||||||
|
uc = uclass_find(id);
|
||||||
|
if (!uc)
|
||||||
|
continue;
|
||||||
|
ut_assertok(uclass_destroy(uc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure all the test devices are probed */
|
||||||
|
static int do_autoprobe(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Scanning the uclass is enough to probe all the devices */
|
||||||
|
for (ret = uclass_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_next_device(&dev))
|
||||||
|
;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ut_test_run_on_flattree() - Check if we should run a test with flat DT
|
||||||
|
*
|
||||||
|
* This skips long/slow tests where there is not much value in running a flat
|
||||||
|
* DT test in addition to a live DT test.
|
||||||
|
*
|
||||||
|
* @return true to run the given test on the flat device tree
|
||||||
|
*/
|
||||||
|
static bool ut_test_run_on_flattree(struct unit_test *test)
|
||||||
|
{
|
||||||
|
const char *fname = strrchr(test->file, '/') + 1;
|
||||||
|
|
||||||
|
if (!(test->flags & UT_TESTF_DM))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !strstr(fname, "video") || strstr(test->name, "video_base");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_matches() - Check if a test should be run
|
||||||
|
*
|
||||||
|
* This checks if the a test should be run. In the normal case of running all
|
||||||
|
* tests, @select_name is NULL.
|
||||||
|
*
|
||||||
|
* @prefix: String prefix for the tests. Any tests that have this prefix will be
|
||||||
|
* printed without the prefix, so that it is easier to see the unique part
|
||||||
|
* of the test name. If NULL, any suite name (xxx_test) is considered to be
|
||||||
|
* a prefix.
|
||||||
|
* @test_name: Name of current test
|
||||||
|
* @select_name: Name of test to run (or NULL for all)
|
||||||
|
* @return true to run this test, false to skip it
|
||||||
|
*/
|
||||||
|
static bool test_matches(const char *prefix, const char *test_name,
|
||||||
|
const char *select_name)
|
||||||
|
{
|
||||||
|
if (!select_name)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!strcmp(test_name, select_name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!prefix) {
|
||||||
|
const char *p = strstr(test_name, "_test_");
|
||||||
|
|
||||||
|
/* convert xxx_test_yyy to yyy, i.e. remove the suite name */
|
||||||
|
if (p)
|
||||||
|
test_name = p + 6;
|
||||||
|
} else {
|
||||||
|
/* All tests have this prefix */
|
||||||
|
if (!strncmp(test_name, prefix, strlen(prefix)))
|
||||||
|
test_name += strlen(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(test_name, select_name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_list_has_dm_tests() - Check if a list of tests has driver model ones
|
||||||
|
*
|
||||||
|
* @tests: List of tests to run
|
||||||
|
* @count: Number of tests to ru
|
||||||
|
* @return true if any of the tests have the UT_TESTF_DM flag
|
||||||
|
*/
|
||||||
|
static bool ut_list_has_dm_tests(struct unit_test *tests, int count)
|
||||||
|
{
|
||||||
|
struct unit_test *test;
|
||||||
|
|
||||||
|
for (test = tests; test < tests + count; test++) {
|
||||||
|
if (test->flags & UT_TESTF_DM)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_restore() Put things back to normal so sandbox works as expected
|
||||||
|
*
|
||||||
|
* @of_root: Value to set for of_root
|
||||||
|
* @return 0 if OK, -ve on error
|
||||||
|
*/
|
||||||
|
static int dm_test_restore(struct device_node *of_root)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
gd_set_of_root(of_root);
|
||||||
|
gd->dm_root = NULL;
|
||||||
|
ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
dm_scan_plat(false);
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||||
|
dm_scan_fdt(false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_pre_run() - Handle any preparation needed to run a test
|
||||||
|
*
|
||||||
|
* @uts: Test state
|
||||||
|
* @test: Test to prepare for
|
||||||
|
* @return 0 if OK, -EAGAIN to skip this test since some required feature is not
|
||||||
|
* available, other -ve on error (meaning that testing cannot likely
|
||||||
|
* continue)
|
||||||
|
*/
|
||||||
|
static int test_pre_run(struct unit_test_state *uts, struct unit_test *test)
|
||||||
|
{
|
||||||
|
if (test->flags & UT_TESTF_DM)
|
||||||
|
ut_assertok(dm_test_pre_run(uts));
|
||||||
|
|
||||||
|
ut_set_skip_delays(uts, false);
|
||||||
|
|
||||||
|
uts->start = mallinfo();
|
||||||
|
|
||||||
|
if (test->flags & UT_TESTF_SCAN_PDATA)
|
||||||
|
ut_assertok(dm_scan_plat(false));
|
||||||
|
|
||||||
|
if (test->flags & UT_TESTF_PROBE_TEST)
|
||||||
|
ut_assertok(do_autoprobe(uts));
|
||||||
|
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||||
|
(test->flags & UT_TESTF_SCAN_FDT))
|
||||||
|
ut_assertok(dm_extended_scan(false));
|
||||||
|
|
||||||
|
if (test->flags & UT_TESTF_CONSOLE_REC) {
|
||||||
|
int ret = console_record_reset_enable();
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
printf("Skipping: Console recording disabled\n");
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ut_silence_console(uts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_post_run() - Handle cleaning up after a test
|
||||||
|
*
|
||||||
|
* @uts: Test state
|
||||||
|
* @test: Test to clean up after
|
||||||
|
* @return 0 if OK, -ve on error (meaning that testing cannot likely continue)
|
||||||
|
*/
|
||||||
|
static int test_post_run(struct unit_test_state *uts, struct unit_test *test)
|
||||||
|
{
|
||||||
|
ut_unsilence_console(uts);
|
||||||
|
if (test->flags & UT_TESTF_DM)
|
||||||
|
ut_assertok(dm_test_post_run(uts));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_run_test() - Run a single test
|
||||||
|
*
|
||||||
|
* This runs the test, handling any preparation and clean-up needed. It prints
|
||||||
|
* the name of each test before running it.
|
||||||
|
*
|
||||||
|
* @uts: Test state to update. The caller should ensure that this is zeroed for
|
||||||
|
* the first call to this function. On exit, @uts->fail_count is
|
||||||
|
* incremented by the number of failures (0, one hopes)
|
||||||
|
* @test_name: Test to run
|
||||||
|
* @name: Name of test, possibly skipping a prefix that should not be displayed
|
||||||
|
* @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if
|
||||||
|
* any failed
|
||||||
|
*/
|
||||||
|
static int ut_run_test(struct unit_test_state *uts, struct unit_test *test,
|
||||||
|
const char *test_name)
|
||||||
|
{
|
||||||
|
const char *fname = strrchr(test->file, '/') + 1;
|
||||||
|
const char *note = "";
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((test->flags & UT_TESTF_DM) && !uts->of_live)
|
||||||
|
note = " (flat tree)";
|
||||||
|
printf("Test: %s: %s%s\n", test_name, fname, note);
|
||||||
|
|
||||||
|
/* Allow access to test state from drivers */
|
||||||
|
test_set_state(uts);
|
||||||
|
|
||||||
|
ret = test_pre_run(uts, test);
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
return -EAGAIN;
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
test->func(uts);
|
||||||
|
|
||||||
|
ret = test_post_run(uts, test);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
test_set_state( NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_run_test_live_flat() - Run a test with both live and flat tree
|
||||||
|
*
|
||||||
|
* This calls ut_run_test() with livetree enabled, which is the standard setup
|
||||||
|
* for runnig tests. Then, for driver model test, it calls it again with
|
||||||
|
* livetree disabled. This allows checking of flattree being used when OF_LIVE
|
||||||
|
* is enabled, as is the case in U-Boot proper before relocation, as well as in
|
||||||
|
* SPL.
|
||||||
|
*
|
||||||
|
* @uts: Test state to update. The caller should ensure that this is zeroed for
|
||||||
|
* the first call to this function. On exit, @uts->fail_count is
|
||||||
|
* incremented by the number of failures (0, one hopes)
|
||||||
|
* @test: Test to run
|
||||||
|
* @name: Name of test, possibly skipping a prefix that should not be displayed
|
||||||
|
* @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if
|
||||||
|
* any failed
|
||||||
|
*/
|
||||||
|
static int ut_run_test_live_flat(struct unit_test_state *uts,
|
||||||
|
struct unit_test *test, const char *name)
|
||||||
|
{
|
||||||
|
int runs;
|
||||||
|
|
||||||
|
/* Run with the live tree if possible */
|
||||||
|
runs = 0;
|
||||||
|
if (CONFIG_IS_ENABLED(OF_LIVE)) {
|
||||||
|
if (!(test->flags & UT_TESTF_FLAT_TREE)) {
|
||||||
|
uts->of_live = true;
|
||||||
|
ut_assertok(ut_run_test(uts, test, test->name));
|
||||||
|
runs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run with the flat tree if we couldn't run it with live tree,
|
||||||
|
* or it is a core test.
|
||||||
|
*/
|
||||||
|
if (!(test->flags & UT_TESTF_LIVE_TREE) &&
|
||||||
|
(!runs || ut_test_run_on_flattree(test))) {
|
||||||
|
uts->of_live = false;
|
||||||
|
ut_assertok(ut_run_test(uts, test, test->name));
|
||||||
|
runs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ut_run_tests() - Run a set of tests
|
||||||
|
*
|
||||||
|
* This runs the tests, handling any preparation and clean-up needed. It prints
|
||||||
|
* the name of each test before running it.
|
||||||
|
*
|
||||||
|
* @uts: Test state to update. The caller should ensure that this is zeroed for
|
||||||
|
* the first call to this function. On exit, @uts->fail_count is
|
||||||
|
* incremented by the number of failures (0, one hopes)
|
||||||
|
* @prefix: String prefix for the tests. Any tests that have this prefix will be
|
||||||
|
* printed without the prefix, so that it is easier to see the unique part
|
||||||
|
* of the test name. If NULL, no prefix processing is done
|
||||||
|
* @tests: List of tests to run
|
||||||
|
* @count: Number of tests to run
|
||||||
|
* @select_name: Name of a single test to run (from the list provided). If NULL
|
||||||
|
* then all tests are run
|
||||||
|
* @return 0 if all tests passed, -ENOENT if test @select_name was not found,
|
||||||
|
* -EBADF if any failed
|
||||||
|
*/
|
||||||
|
static int ut_run_tests(struct unit_test_state *uts, const char *prefix,
|
||||||
|
struct unit_test *tests, int count,
|
||||||
|
const char *select_name)
|
||||||
|
{
|
||||||
|
struct unit_test *test;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
for (test = tests; test < tests + count; test++) {
|
||||||
|
const char *test_name = test->name;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!test_matches(prefix, test_name, select_name))
|
||||||
|
continue;
|
||||||
|
ret = ut_run_test_live_flat(uts, test, select_name);
|
||||||
|
found++;
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
continue;
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (select_name && !found)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
return uts->fail_count ? -EBADF : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ut_run_list(const char *category, const char *prefix,
|
||||||
|
struct unit_test *tests, int count, const char *select_name)
|
||||||
|
{
|
||||||
|
struct unit_test_state uts = { .fail_count = 0 };
|
||||||
|
bool has_dm_tests = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||||
|
ut_list_has_dm_tests(tests, count)) {
|
||||||
|
has_dm_tests = true;
|
||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!select_name)
|
||||||
|
printf("Running %d %s tests\n", count, category);
|
||||||
|
|
||||||
|
uts.of_root = gd_of_root();
|
||||||
|
ret = ut_run_tests(&uts, prefix, tests, count, select_name);
|
||||||
|
|
||||||
|
if (ret == -ENOENT)
|
||||||
|
printf("Test '%s' not found\n", select_name);
|
||||||
|
else
|
||||||
|
printf("Failures: %d\n", uts.fail_count);
|
||||||
|
|
||||||
|
/* Best efforts only...ignore errors */
|
||||||
|
if (has_dm_tests)
|
||||||
|
dm_test_restore(uts.of_root);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -615,8 +615,8 @@ UNICODE_TEST(unicode_test_efi_create_indexed_name);
|
||||||
|
|
||||||
int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test);
|
||||||
const int n_ents = ll_entry_count(struct unit_test, unicode_test);
|
const int n_ents = UNIT_TEST_SUITE_COUNT(unicode_test);
|
||||||
|
|
||||||
return cmd_ut_category("Unicode", "unicode_test_",
|
return cmd_ut_category("Unicode", "unicode_test_",
|
||||||
tests, n_ents, argc, argv);
|
tests, n_ents, argc, argv);
|
||||||
|
|
|
@ -133,3 +133,10 @@ void ut_unsilence_console(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
|
gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SANDBOX
|
||||||
|
state_set_skip_delays(skip_delays);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue