xref: /dpdk/app/test/test.c (revision a620df6df6d61660661afade09760b2dfba4eb42)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <string.h>
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <ctype.h>
12 #include <sys/queue.h>
13 
14 #include <cmdline_rdline.h>
15 #include <cmdline_parse.h>
16 #include <cmdline_socket.h>
17 #include <cmdline.h>
18 extern cmdline_parse_ctx_t main_ctx[];
19 
20 #include <rte_memory.h>
21 #include <rte_eal.h>
22 #include <rte_cycles.h>
23 #include <rte_log.h>
24 #include <rte_string_fns.h>
25 #ifdef RTE_LIB_TIMER
26 #include <rte_timer.h>
27 #endif
28 
29 #include "test.h"
30 #ifdef RTE_LIB_PDUMP
31 #include "test_pdump.h"
32 #endif
33 
34 #define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
35 
36 #define FOR_EACH_SUITE_TESTCASE(iter, suite, case)			\
37 	for (iter = 0, case = suite->unit_test_cases[0];		\
38 		suite->unit_test_cases[iter].testcase ||		\
39 		suite->unit_test_cases[iter].testcase_with_data;	\
40 		iter++, case = suite->unit_test_cases[iter])
41 
42 #define FOR_EACH_SUITE_TESTSUITE(iter, suite, sub_ts)			\
43 	for (iter = 0, sub_ts = suite->unit_test_suites ?		\
44 		suite->unit_test_suites[0]:NULL; sub_ts &&		\
45 		suite->unit_test_suites[iter]->suite_name != NULL;	\
46 		iter++, sub_ts = suite->unit_test_suites[iter])
47 
48 const char *prgname; /* to be set to argv[0] */
49 
50 static const char *recursive_call; /* used in linux for MP and other tests */
51 
52 static int
no_action(void)53 no_action(void){ return 0; }
54 
55 static int
do_recursive_call(void)56 do_recursive_call(void)
57 {
58 	unsigned i;
59 	struct {
60 		const char *env_var;
61 		int (*action_fn)(void);
62 	} actions[] =  {
63 #ifndef RTE_EXEC_ENV_WINDOWS
64 			{ "run_secondary_instances", test_mp_secondary },
65 #endif
66 #ifdef RTE_LIB_PDUMP
67 #ifdef RTE_NET_RING
68 			{ "run_pdump_server_tests", test_pdump },
69 #endif
70 #endif
71 			{ "test_missing_c_flag", no_action },
72 			{ "test_main_lcore_flag", no_action },
73 			{ "test_invalid_n_flag", no_action },
74 			{ "test_no_hpet_flag", no_action },
75 			{ "test_allow_flag", no_action },
76 			{ "test_invalid_b_flag", no_action },
77 			{ "test_invalid_vdev_flag", no_action },
78 			{ "test_invalid_r_flag", no_action },
79 			{ "test_misc_flags", no_action },
80 			{ "test_memory_flags", no_action },
81 			{ "test_file_prefix", no_action },
82 			{ "test_no_huge_flag", no_action },
83 #ifdef RTE_LIB_TIMER
84 #ifndef RTE_EXEC_ENV_WINDOWS
85 			{ "timer_secondary_spawn_wait", test_timer_secondary },
86 #endif
87 #endif
88 	};
89 
90 	if (recursive_call == NULL)
91 		return -1;
92 	for (i = 0; i < RTE_DIM(actions); i++) {
93 		if (strcmp(actions[i].env_var, recursive_call) == 0)
94 			return (actions[i].action_fn)();
95 	}
96 	printf("ERROR - missing action to take for %s\n", recursive_call);
97 	return -1;
98 }
99 
100 int last_test_result;
101 
102 #define MAX_EXTRA_ARGS 32
103 
104 int
main(int argc,char ** argv)105 main(int argc, char **argv)
106 {
107 	struct cmdline *cl;
108 	char *tests[argc]; /* store an array of tests to run */
109 	int test_count = 0;
110 	int i;
111 	char *extra_args;
112 	int ret;
113 
114 	extra_args = getenv("DPDK_TEST_PARAMS");
115 	if (extra_args != NULL && strlen(extra_args) > 0) {
116 		char **all_argv;
117 		char *eargv[MAX_EXTRA_ARGS];
118 		int all_argc;
119 		int eargc;
120 		int i;
121 
122 		RTE_LOG(INFO, APP, "Using additional DPDK_TEST_PARAMS: '%s'\n",
123 				extra_args);
124 		eargc = rte_strsplit(extra_args, strlen(extra_args),
125 				eargv, MAX_EXTRA_ARGS, ' ');
126 
127 		/* merge argc/argv and the environment args */
128 		all_argc = argc + eargc;
129 		all_argv = malloc(sizeof(*all_argv) * (all_argc + 1));
130 		if (all_argv == NULL) {
131 			ret = -1;
132 			goto out;
133 		}
134 
135 		for (i = 0; i < argc; i++)
136 			all_argv[i] = argv[i];
137 		for (i = 0; i < eargc; i++)
138 			all_argv[argc + i] = eargv[i];
139 		all_argv[all_argc] = NULL;
140 
141 		/* call eal_init with combined args */
142 		ret = rte_eal_init(all_argc, all_argv);
143 		free(all_argv);
144 	} else
145 		ret = rte_eal_init(argc, argv);
146 	if (ret < 0) {
147 		ret = -1;
148 		goto out;
149 	}
150 
151 	argv += ret;
152 	argc -= ret;
153 
154 	prgname = argv[0];
155 
156 #ifdef RTE_LIB_TIMER
157 	ret = rte_timer_subsystem_init();
158 	if (ret < 0 && ret != -EALREADY) {
159 		ret = -1;
160 		goto out;
161 	}
162 #endif
163 
164 	if (commands_init() < 0) {
165 		ret = -1;
166 		goto out;
167 	}
168 
169 	recursive_call = getenv(RECURSIVE_ENV_VAR);
170 	if (recursive_call != NULL) {
171 		ret = do_recursive_call();
172 		goto out;
173 	}
174 
175 #ifdef RTE_LIBEAL_USE_HPET
176 	if (rte_eal_hpet_init(1) < 0)
177 #endif
178 		RTE_LOG(INFO, APP,
179 				"HPET is not enabled, using TSC as default timer\n");
180 
181 
182 	char *dpdk_test = getenv("DPDK_TEST");
183 
184 	if (dpdk_test && strlen(dpdk_test) > 0)
185 		tests[test_count++] = dpdk_test;
186 	for (i = 1; i < argc; i++)
187 		tests[test_count++] = argv[i];
188 
189 	if (test_count > 0) {
190 		char buf[1024];
191 		char *dpdk_test_skip = getenv("DPDK_TEST_SKIP");
192 		char *skip_tests[128] = {0};
193 		size_t n_skip_tests = 0;
194 
195 		if (dpdk_test_skip != NULL && strlen(dpdk_test_skip) > 0) {
196 			int split_ret;
197 			char *dpdk_test_skip_cp = strdup(dpdk_test_skip);
198 			if (dpdk_test_skip_cp == NULL) {
199 				ret = -1;
200 				goto out;
201 			}
202 			dpdk_test_skip = dpdk_test_skip_cp;
203 			split_ret = rte_strsplit(dpdk_test_skip, strlen(dpdk_test_skip),
204 					skip_tests, RTE_DIM(skip_tests), ',');
205 			if (split_ret > 0)
206 				n_skip_tests = split_ret;
207 			else
208 				free(dpdk_test_skip);
209 		}
210 
211 		cl = cmdline_new(main_ctx, "RTE>>", 0, 1);
212 		if (cl == NULL) {
213 			ret = -1;
214 			goto out;
215 		}
216 
217 		for (i = 0; i < test_count; i++) {
218 			/* check if test is to be skipped */
219 			for (size_t j = 0; j < n_skip_tests; j++) {
220 				if (strcmp(tests[i], skip_tests[j]) == 0) {
221 					fprintf(stderr, "Skipping %s [DPDK_TEST_SKIP]\n", tests[i]);
222 					ret = TEST_SKIPPED;
223 					goto end_of_cmd;
224 				}
225 			}
226 
227 			snprintf(buf, sizeof(buf), "%s\n", tests[i]);
228 			if (cmdline_parse_check(cl, buf) < 0) {
229 				printf("Error: invalid test command: '%s'\n", tests[i]);
230 				ret = -1;
231 			} else if (cmdline_in(cl, buf, strlen(buf)) < 0) {
232 				printf("error on cmdline input\n");
233 				ret = -1;
234 			} else
235 				ret = last_test_result;
236 
237 end_of_cmd:
238 			if (ret != 0 && ret != TEST_SKIPPED)
239 				break;
240 		}
241 		if (n_skip_tests > 0)
242 			free(dpdk_test_skip);
243 
244 		cmdline_free(cl);
245 		goto out;
246 	} else {
247 		/* if no DPDK_TEST env variable, go interactive */
248 		cl = cmdline_stdin_new(main_ctx, "RTE>>");
249 		if (cl == NULL) {
250 			ret = -1;
251 			goto out;
252 		}
253 
254 		cmdline_interact(cl);
255 		cmdline_stdin_exit(cl);
256 	}
257 	ret = 0;
258 
259 out:
260 #ifdef RTE_LIB_TIMER
261 	rte_timer_subsystem_finalize();
262 #endif
263 	rte_eal_cleanup();
264 	return ret;
265 }
266 
267 static void
unit_test_suite_count_tcs_on_setup_fail(struct unit_test_suite * suite,int test_success,unsigned int * sub_ts_failed,unsigned int * sub_ts_skipped,unsigned int * sub_ts_total)268 unit_test_suite_count_tcs_on_setup_fail(struct unit_test_suite *suite,
269 		int test_success, unsigned int *sub_ts_failed,
270 		unsigned int *sub_ts_skipped, unsigned int *sub_ts_total)
271 {
272 	struct unit_test_case tc;
273 	struct unit_test_suite *ts;
274 	int i;
275 
276 	FOR_EACH_SUITE_TESTSUITE(i, suite, ts) {
277 		unit_test_suite_count_tcs_on_setup_fail(
278 			ts, test_success, sub_ts_failed,
279 			sub_ts_skipped, sub_ts_total);
280 		suite->total += ts->total;
281 		suite->failed += ts->failed;
282 		suite->skipped += ts->skipped;
283 		if (ts->failed)
284 			(*sub_ts_failed)++;
285 		else
286 			(*sub_ts_skipped)++;
287 		(*sub_ts_total)++;
288 	}
289 	FOR_EACH_SUITE_TESTCASE(i, suite, tc) {
290 		suite->total++;
291 		if (!tc.enabled || test_success == TEST_SKIPPED)
292 			suite->skipped++;
293 		else
294 			suite->failed++;
295 	}
296 }
297 
298 static void
unit_test_suite_reset_counts(struct unit_test_suite * suite)299 unit_test_suite_reset_counts(struct unit_test_suite *suite)
300 {
301 	struct unit_test_suite *ts;
302 	int i;
303 
304 	FOR_EACH_SUITE_TESTSUITE(i, suite, ts)
305 		unit_test_suite_reset_counts(ts);
306 	suite->total = 0;
307 	suite->executed = 0;
308 	suite->succeeded = 0;
309 	suite->skipped = 0;
310 	suite->failed = 0;
311 	suite->unsupported = 0;
312 }
313 
314 int
unit_test_suite_runner(struct unit_test_suite * suite)315 unit_test_suite_runner(struct unit_test_suite *suite)
316 {
317 	int test_success, i, ret;
318 	const char *status;
319 	struct unit_test_case tc;
320 	struct unit_test_suite *ts;
321 	unsigned int sub_ts_succeeded = 0, sub_ts_failed = 0;
322 	unsigned int sub_ts_skipped = 0, sub_ts_total = 0;
323 
324 	unit_test_suite_reset_counts(suite);
325 
326 	if (suite->suite_name) {
327 		printf(" + ------------------------------------------------------- +\n");
328 		printf(" + Test Suite : %s\n", suite->suite_name);
329 	}
330 
331 	if (suite->setup) {
332 		test_success = suite->setup();
333 		if (test_success != 0) {
334 			/*
335 			 * setup did not pass, so count all enabled tests and
336 			 * mark them as failed/skipped
337 			 */
338 			unit_test_suite_count_tcs_on_setup_fail(suite,
339 					test_success, &sub_ts_failed,
340 					&sub_ts_skipped, &sub_ts_total);
341 			goto suite_summary;
342 		}
343 	}
344 
345 	printf(" + ------------------------------------------------------- +\n");
346 
347 	FOR_EACH_SUITE_TESTCASE(suite->total, suite, tc) {
348 		if (!tc.enabled) {
349 			suite->skipped++;
350 			continue;
351 		} else {
352 			suite->executed++;
353 		}
354 
355 		/* run test case setup */
356 		if (tc.setup)
357 			test_success = tc.setup();
358 		else
359 			test_success = TEST_SUCCESS;
360 
361 		if (test_success == TEST_SUCCESS) {
362 			/* run the test case */
363 			if (tc.testcase)
364 				test_success = tc.testcase();
365 			else if (tc.testcase_with_data)
366 				test_success = tc.testcase_with_data(tc.data);
367 			else
368 				test_success = -ENOTSUP;
369 
370 			if (test_success == TEST_SUCCESS)
371 				suite->succeeded++;
372 			else if (test_success == TEST_SKIPPED) {
373 				suite->skipped++;
374 				suite->executed--;
375 			} else if (test_success == -ENOTSUP) {
376 				suite->unsupported++;
377 				suite->executed--;
378 			} else
379 				suite->failed++;
380 		} else if (test_success == -ENOTSUP) {
381 			suite->unsupported++;
382 		} else if (test_success == TEST_SKIPPED) {
383 			suite->skipped++;
384 		} else {
385 			suite->failed++;
386 		}
387 
388 		/* run the test case teardown */
389 		if (tc.teardown)
390 			tc.teardown();
391 
392 		if (test_success == TEST_SUCCESS)
393 			status = "succeeded";
394 		else if (test_success == TEST_SKIPPED)
395 			status = "skipped";
396 		else if (test_success == -ENOTSUP)
397 			status = "unsupported";
398 		else
399 			status = "failed";
400 
401 		printf(" + TestCase [%2d] : %s %s\n", suite->total,
402 				tc.name, status);
403 	}
404 	FOR_EACH_SUITE_TESTSUITE(i, suite, ts) {
405 		ret = unit_test_suite_runner(ts);
406 		if (ret == TEST_SUCCESS)
407 			sub_ts_succeeded++;
408 		else if (ret == TEST_SKIPPED)
409 			sub_ts_skipped++;
410 		else
411 			sub_ts_failed++;
412 		sub_ts_total++;
413 
414 		suite->total += ts->total;
415 		suite->succeeded += ts->succeeded;
416 		suite->failed += ts->failed;
417 		suite->skipped += ts->skipped;
418 		suite->unsupported += ts->unsupported;
419 		suite->executed += ts->executed;
420 	}
421 
422 	/* Run test suite teardown */
423 	if (suite->teardown)
424 		suite->teardown();
425 
426 	goto suite_summary;
427 
428 suite_summary:
429 	printf(" + ------------------------------------------------------- +\n");
430 	printf(" + Test Suite Summary : %s\n", suite->suite_name);
431 	printf(" + ------------------------------------------------------- +\n");
432 
433 	FOR_EACH_SUITE_TESTSUITE(i, suite, ts)
434 		printf(" + %s : %d/%d passed, %d/%d skipped, "
435 			"%d/%d failed, %d/%d unsupported\n", ts->suite_name,
436 			ts->succeeded, ts->total, ts->skipped, ts->total,
437 			ts->failed, ts->total, ts->unsupported, ts->total);
438 
439 	if (suite->unit_test_suites) {
440 		printf(" + ------------------------------------------------------- +\n");
441 		printf(" + Sub Testsuites Total :     %2d\n", sub_ts_total);
442 		printf(" + Sub Testsuites Skipped :   %2d\n", sub_ts_skipped);
443 		printf(" + Sub Testsuites Passed :    %2d\n", sub_ts_succeeded);
444 		printf(" + Sub Testsuites Failed :    %2d\n", sub_ts_failed);
445 		printf(" + ------------------------------------------------------- +\n");
446 	}
447 
448 	printf(" + Tests Total :       %2d\n", suite->total);
449 	printf(" + Tests Skipped :     %2d\n", suite->skipped);
450 	printf(" + Tests Executed :    %2d\n", suite->executed);
451 	printf(" + Tests Unsupported:  %2d\n", suite->unsupported);
452 	printf(" + Tests Passed :      %2d\n", suite->succeeded);
453 	printf(" + Tests Failed :      %2d\n", suite->failed);
454 	printf(" + ------------------------------------------------------- +\n");
455 
456 	last_test_result = suite->failed;
457 
458 	if (suite->failed)
459 		return TEST_FAILED;
460 	if (suite->total == suite->skipped)
461 		return TEST_SKIPPED;
462 	return TEST_SUCCESS;
463 }
464