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 53 no_action(void){ return 0; } 54 55 static int 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 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 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 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 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 else if (test_success == -ENOTSUP) 375 suite->unsupported++; 376 else 377 suite->failed++; 378 } else if (test_success == -ENOTSUP) { 379 suite->unsupported++; 380 } else if (test_success == TEST_SKIPPED) { 381 suite->skipped++; 382 } else { 383 suite->failed++; 384 } 385 386 /* run the test case teardown */ 387 if (tc.teardown) 388 tc.teardown(); 389 390 if (test_success == TEST_SUCCESS) 391 status = "succeeded"; 392 else if (test_success == TEST_SKIPPED) 393 status = "skipped"; 394 else if (test_success == -ENOTSUP) 395 status = "unsupported"; 396 else 397 status = "failed"; 398 399 printf(" + TestCase [%2d] : %s %s\n", suite->total, 400 tc.name, status); 401 } 402 FOR_EACH_SUITE_TESTSUITE(i, suite, ts) { 403 ret = unit_test_suite_runner(ts); 404 if (ret == TEST_SUCCESS) 405 sub_ts_succeeded++; 406 else if (ret == TEST_SKIPPED) 407 sub_ts_skipped++; 408 else 409 sub_ts_failed++; 410 sub_ts_total++; 411 412 suite->total += ts->total; 413 suite->succeeded += ts->succeeded; 414 suite->failed += ts->failed; 415 suite->skipped += ts->skipped; 416 suite->unsupported += ts->unsupported; 417 suite->executed += ts->executed; 418 } 419 420 /* Run test suite teardown */ 421 if (suite->teardown) 422 suite->teardown(); 423 424 goto suite_summary; 425 426 suite_summary: 427 printf(" + ------------------------------------------------------- +\n"); 428 printf(" + Test Suite Summary : %s\n", suite->suite_name); 429 printf(" + ------------------------------------------------------- +\n"); 430 431 FOR_EACH_SUITE_TESTSUITE(i, suite, ts) 432 printf(" + %s : %d/%d passed, %d/%d skipped, " 433 "%d/%d failed, %d/%d unsupported\n", ts->suite_name, 434 ts->succeeded, ts->total, ts->skipped, ts->total, 435 ts->failed, ts->total, ts->unsupported, ts->total); 436 437 if (suite->unit_test_suites) { 438 printf(" + ------------------------------------------------------- +\n"); 439 printf(" + Sub Testsuites Total : %2d\n", sub_ts_total); 440 printf(" + Sub Testsuites Skipped : %2d\n", sub_ts_skipped); 441 printf(" + Sub Testsuites Passed : %2d\n", sub_ts_succeeded); 442 printf(" + Sub Testsuites Failed : %2d\n", sub_ts_failed); 443 printf(" + ------------------------------------------------------- +\n"); 444 } 445 446 printf(" + Tests Total : %2d\n", suite->total); 447 printf(" + Tests Skipped : %2d\n", suite->skipped); 448 printf(" + Tests Executed : %2d\n", suite->executed); 449 printf(" + Tests Unsupported: %2d\n", suite->unsupported); 450 printf(" + Tests Passed : %2d\n", suite->succeeded); 451 printf(" + Tests Failed : %2d\n", suite->failed); 452 printf(" + ------------------------------------------------------- +\n"); 453 454 last_test_result = suite->failed; 455 456 if (suite->failed) 457 return TEST_FAILED; 458 if (suite->total == suite->skipped) 459 return TEST_SKIPPED; 460 return TEST_SUCCESS; 461 } 462