blob: c96277d89a1726016ccd560e991dca896e51d9c6 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05002/*
3 * (C) Copyright 2015
4 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05005 */
6
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05007#include <command.h>
Simon Glass6db8ea52020-07-28 19:41:13 -06008#include <console.h>
Tom Rinidec7ea02024-05-20 13:35:03 -06009#include <vsprintf.h>
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050010#include <test/suites.h>
Simon Glass81cbe1c2017-11-25 11:57:29 -070011#include <test/test.h>
Simon Glass5722fb22021-03-07 17:34:47 -070012#include <test/ut.h>
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050013
Simon Glass78fd76b2025-01-20 14:25:33 -070014/**
15 * struct suite - A set of tests for a certain topic
16 *
17 * All tests end up in a single 'struct unit_test' linker-list array, in order
18 * of the suite they are in
19 *
20 * @name: Name of suite
21 * @start: First test in suite
22 * @end: End test in suite (points to the first test in the next suite)
23 * @cmd: Command to use to run the suite
Simon Glass46093b32025-01-20 14:26:05 -070024 * @help: Help-string to show for this suite
Simon Glass78fd76b2025-01-20 14:25:33 -070025 */
26struct suite {
27 const char *name;
28 struct unit_test *start;
29 struct unit_test *end;
30 ut_cmd_func cmd;
Simon Glass46093b32025-01-20 14:26:05 -070031 const char *help;
Simon Glass78fd76b2025-01-20 14:25:33 -070032};
33
Simon Glass6685ece2025-01-20 14:25:58 -070034static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
35 int flag, int argc, char *const argv[]);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050036
Simon Glassfb998c22022-10-29 19:47:12 -060037static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
38 char *const argv[]);
39
Simon Glass6685ece2025-01-20 14:25:58 -070040int cmd_ut_category(struct unit_test_state *uts, const char *name,
41 const char *prefix, struct unit_test *tests, int n_ents,
Simon Glassed38aef2020-05-10 11:40:03 -060042 int argc, char *const argv[])
Simon Glass81cbe1c2017-11-25 11:57:29 -070043{
Simon Glass85ba7c32022-10-29 19:47:13 -060044 const char *test_insert = NULL;
Simon Glass91a187b2022-08-01 07:58:45 -060045 int runs_per_text = 1;
Simon Glass1f1614b2022-10-20 18:22:50 -060046 bool force_run = false;
Simon Glass5722fb22021-03-07 17:34:47 -070047 int ret;
Simon Glass81cbe1c2017-11-25 11:57:29 -070048
Simon Glass1f1614b2022-10-20 18:22:50 -060049 while (argc > 1 && *argv[1] == '-') {
50 const char *str = argv[1];
51
52 switch (str[1]) {
53 case 'r':
54 runs_per_text = dectoul(str + 2, NULL);
55 break;
56 case 'f':
57 force_run = true;
58 break;
Simon Glass85ba7c32022-10-29 19:47:13 -060059 case 'I':
60 test_insert = str + 2;
61 break;
Simon Glass1f1614b2022-10-20 18:22:50 -060062 }
Simon Glass91a187b2022-08-01 07:58:45 -060063 argv++;
Simon Glass85ba7c32022-10-29 19:47:13 -060064 argc--;
Simon Glass91a187b2022-08-01 07:58:45 -060065 }
66
Simon Glass6685ece2025-01-20 14:25:58 -070067 ret = ut_run_list(uts, name, prefix, tests, n_ents,
Simon Glass793a98e2023-11-18 14:05:20 -070068 cmd_arg1(argc, argv), runs_per_text, force_run,
Simon Glass85ba7c32022-10-29 19:47:13 -060069 test_insert);
Simon Glass81cbe1c2017-11-25 11:57:29 -070070
Simon Glass5722fb22021-03-07 17:34:47 -070071 return ret ? CMD_RET_FAILURE : 0;
Simon Glass81cbe1c2017-11-25 11:57:29 -070072}
73
Simon Glass78fd76b2025-01-20 14:25:33 -070074/* declare linker-list symbols for the start and end of a suite */
75#define SUITE_DECL(_name) \
76 ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
77 ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
78
79/* declare a test suite which uses a subcommand to run */
Simon Glass46093b32025-01-20 14:26:05 -070080#define SUITE_CMD(_name, _cmd_func, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070081 #_name, \
82 suite_start_ ## _name, \
83 suite_end_ ## _name, \
84 _cmd_func, \
Simon Glass46093b32025-01-20 14:26:05 -070085 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070086 }
87
88/* declare a test suite which can be run directly without a subcommand */
Simon Glass46093b32025-01-20 14:26:05 -070089#define SUITE(_name, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070090 #_name, \
91 suite_start_ ## _name, \
92 suite_end_ ## _name, \
93 NULL, \
Simon Glass46093b32025-01-20 14:26:05 -070094 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070095 }
96
Simon Glass4c990702025-01-20 14:26:03 -070097SUITE_DECL(addrmap);
Simon Glass78fd76b2025-01-20 14:25:33 -070098SUITE_DECL(bdinfo);
Simon Glass4c990702025-01-20 14:26:03 -070099SUITE_DECL(bloblist);
100SUITE_DECL(bootm);
Simon Glass78fd76b2025-01-20 14:25:33 -0700101SUITE_DECL(bootstd);
102SUITE_DECL(cmd);
103SUITE_DECL(common);
104SUITE_DECL(dm);
105SUITE_DECL(env);
106SUITE_DECL(exit);
107SUITE_DECL(fdt);
108SUITE_DECL(font);
Simon Glass4c990702025-01-20 14:26:03 -0700109SUITE_DECL(hush);
Simon Glass78fd76b2025-01-20 14:25:33 -0700110SUITE_DECL(lib);
Simon Glass4c990702025-01-20 14:26:03 -0700111SUITE_DECL(loadm);
Simon Glass78fd76b2025-01-20 14:25:33 -0700112SUITE_DECL(log);
113SUITE_DECL(mbr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700114SUITE_DECL(measurement);
Simon Glass4c990702025-01-20 14:26:03 -0700115SUITE_DECL(mem);
116SUITE_DECL(optee);
117SUITE_DECL(overlay);
Simon Glass78fd76b2025-01-20 14:25:33 -0700118SUITE_DECL(pci_mps);
119SUITE_DECL(seama);
Simon Glass4c990702025-01-20 14:26:03 -0700120SUITE_DECL(setexpr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700121SUITE_DECL(upl);
122
123static struct suite suites[] = {
Simon Glass46093b32025-01-20 14:26:05 -0700124 SUITE(addrmap, "very basic test of addrmap command"),
125 SUITE(bdinfo, "bdinfo (board info) command"),
126 SUITE(bloblist, "bloblist implementation"),
127 SUITE(bootm, "bootm command"),
Simon Glass804aa372023-10-01 19:15:15 -0600128#ifdef CONFIG_UT_BOOTSTD
Simon Glass46093b32025-01-20 14:26:05 -0700129 SUITE_CMD(bootstd, do_ut_bootstd, "standard boot implementation"),
Simon Glassb255efc2022-04-24 23:31:24 -0600130#endif
Simon Glass46093b32025-01-20 14:26:05 -0700131 SUITE(cmd, "various commands"),
132 SUITE(common, "tests for common/ directory"),
133 SUITE(dm, "driver model"),
134 SUITE(env, "environment"),
135 SUITE(exit, "shell exit and variables"),
136 SUITE(fdt, "fdt command"),
137 SUITE(font, "font command"),
138 SUITE(hush, "hush behaviour"),
139 SUITE(lib, "library functions"),
140 SUITE(loadm, "loadm command parameters and loading memory blob"),
141 SUITE(log, "logging functions"),
142 SUITE(mbr, "mbr command"),
143 SUITE(measurement, "TPM-based measured boot"),
144 SUITE(mem, "memory-related commands"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200145#ifdef CONFIG_UT_OPTEE
Simon Glass46093b32025-01-20 14:26:05 -0700146 SUITE_CMD(optee, do_ut_optee, "OP-TEE"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200147#endif
Maxime Ripard0e31a112016-07-05 10:26:46 +0200148#ifdef CONFIG_UT_OVERLAY
Simon Glass46093b32025-01-20 14:26:05 -0700149 SUITE_CMD(overlay, do_ut_overlay, "device tree overlays"),
Maxime Ripard0e31a112016-07-05 10:26:46 +0200150#endif
Simon Glass46093b32025-01-20 14:26:05 -0700151 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
152 SUITE(seama, "seama command parameters loading and decoding"),
153 SUITE(setexpr, "setexpr command"),
154 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500155};
156
Simon Glassa3ce1292025-01-20 14:25:57 -0700157/**
158 * has_tests() - Check if a suite has tests, i.e. is supported in this build
159 *
160 * If the suite is run using a command, we have to assume that tests may be
161 * present, since we have no visibility
162 *
163 * @ste: Suite to check
164 * Return: true if supported, false if not
165 */
166static bool has_tests(struct suite *ste)
167{
168 int n_ents = ste->end - ste->start;
169
170 return n_ents || ste->cmd;
171}
172
Simon Glass78fd76b2025-01-20 14:25:33 -0700173/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700174static int run_suite(struct unit_test_state *uts, struct suite *ste,
175 struct cmd_tbl *cmdtp, int flag, int argc,
176 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700177{
178 int ret;
179
180 if (ste->cmd) {
Simon Glass6685ece2025-01-20 14:25:58 -0700181 ret = ste->cmd(uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700182 } else {
183 int n_ents = ste->end - ste->start;
184 char prefix[30];
185
186 /* use a standard prefix */
187 snprintf(prefix, sizeof(prefix), "%s_test", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700188 ret = cmd_ut_category(uts, ste->name, prefix, ste->start,
189 n_ents, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700190 }
191
192 return ret;
193}
194
Simon Glassbd9b1512025-02-07 11:30:36 -0700195static void show_stats(struct unit_test_state *uts)
196{
197 if (uts->run_count < 2)
198 return;
199
200 ut_report(&uts->total, uts->run_count);
201 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
202 uts->total.test_count && uts->worst) {
203 ulong avg = uts->total.duration_ms / uts->total.test_count;
204
205 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
206 avg, uts->worst->name, uts->worst_ms);
207 }
208}
209
210static void update_stats(struct unit_test_state *uts, const struct suite *ste)
211{
212 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
213 ulong avg;
214
215 avg = uts->cur.duration_ms ?
216 uts->cur.duration_ms /
217 uts->cur.test_count : 0;
218 if (avg > uts->worst_ms) {
219 uts->worst_ms = avg;
220 uts->worst = ste;
221 }
222 }
223}
224
Simon Glass6685ece2025-01-20 14:25:58 -0700225static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
226 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500227{
228 int i;
229 int retval;
230 int any_fail = 0;
231
Simon Glass78fd76b2025-01-20 14:25:33 -0700232 for (i = 0; i < ARRAY_SIZE(suites); i++) {
233 struct suite *ste = &suites[i];
234 char *const argv[] = {(char *)ste->name, NULL};
235
Simon Glassa3ce1292025-01-20 14:25:57 -0700236 if (has_tests(ste)) {
237 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700238 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700239 if (!any_fail)
240 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700241 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700242 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500243 }
Simon Glassfb82a042025-01-20 14:26:02 -0700244 ut_report(&uts->total, uts->run_count);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500245
246 return any_fail;
247}
248
Simon Glassfb998c22022-10-29 19:47:12 -0600249static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
250 char *const argv[])
251{
Simon Glassa3ce1292025-01-20 14:25:57 -0700252 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700253 const char *flags;
254
Simon Glassa3ce1292025-01-20 14:25:57 -0700255 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
256 struct suite *ste = &suites[i];
257
258 if (has_tests(ste))
259 suite_count++;
260 }
261
262 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600263 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
264
Simon Glasscfb38f82025-01-20 14:25:30 -0700265 flags = cmd_arg1(argc, argv);
266 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700267 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700268
Simon Glass46093b32025-01-20 14:26:05 -0700269 puts("\nTests Suite Purpose");
270 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700271 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700272 struct suite *ste = &suites[i];
273 long n_ent = ste->end - ste->start;
274
275 if (n_ent)
Simon Glass46093b32025-01-20 14:26:05 -0700276 printf("%5ld", n_ent);
Simon Glassa3ce1292025-01-20 14:25:57 -0700277 else if (ste->cmd)
Simon Glass46093b32025-01-20 14:26:05 -0700278 printf("%5s", "?");
279 else /* suite is not present */
280 continue;
281 printf(" %-13.13s %s\n", ste->name, ste->help);
Simon Glass3669a972025-02-07 11:30:34 -0700282 total += n_ent;
Simon Glass78fd76b2025-01-20 14:25:33 -0700283 }
Simon Glass3669a972025-02-07 11:30:34 -0700284 puts("----- ------------ -------------------------\n");
285 printf("%5d %-13.13s\n", total, "Total");
286
287 if (UNIT_TEST_ALL_COUNT() != total)
288 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700289 }
290
Simon Glassfb998c22022-10-29 19:47:12 -0600291 return 0;
292}
293
Simon Glass78fd76b2025-01-20 14:25:33 -0700294static struct suite *find_suite(const char *name)
295{
296 struct suite *ste;
297 int i;
298
299 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
300 if (!strcmp(ste->name, name))
301 return ste;
302 }
303
304 return NULL;
305}
306
Simon Glassed38aef2020-05-10 11:40:03 -0600307static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500308{
Simon Glass6685ece2025-01-20 14:25:58 -0700309 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700310 struct suite *ste;
311 const char *name;
312 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500313
314 if (argc < 2)
315 return CMD_RET_USAGE;
316
317 /* drop initial "ut" arg */
318 argc--;
319 argv++;
320
Simon Glass6685ece2025-01-20 14:25:58 -0700321 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700322 name = argv[0];
323 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700324 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700325 } else if (!strcmp(name, "info")) {
326 ret = do_ut_info(cmdtp, flag, argc, argv);
327 } else {
328 ste = find_suite(argv[0]);
329 if (!ste) {
330 printf("Suite '%s' not found\n", argv[0]);
331 return CMD_RET_FAILURE;
Simon Glassa3ce1292025-01-20 14:25:57 -0700332 } else if (!has_tests(ste)) {
333 /* perhaps a Kconfig option needs to be set? */
334 printf("Suite '%s' is not enabled\n", argv[0]);
335 return CMD_RET_FAILURE;
Simon Glass78fd76b2025-01-20 14:25:33 -0700336 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500337
Simon Glass6685ece2025-01-20 14:25:58 -0700338 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700339 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700340 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700341 if (ret)
342 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700343 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500344
Simon Glass78fd76b2025-01-20 14:25:33 -0700345 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500346}
347
Tom Rini03f146c2023-10-07 15:13:08 -0400348U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600349 "[-r] [-f] [<suite>] - run unit tests\n"
350 " -r<runs> Number of times to run each test\n"
351 " -f Force 'manual' tests to run as well\n"
352 " <suite> Test suite to run, or all\n"
353 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600354 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600355 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700356 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400357 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500358
359U_BOOT_CMD(
360 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
361 "unit tests", ut_help_text
362);