Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Support glob matching for test selector.

This patch adds '-a' and '-d' arguments supporting both exact string match as
well as using '*' wildcard in test/subtests selection. '-a' and '-t' can
co-exists, same as '-d' and '-b', in which case they just add to the list of
allowed or denied test selectors.

Caveat: Same as the current substring matching mechanism, test and subtest
selector applies independently, 'a*/b*' will execute all tests matching "a*",
and with subtest name matching "b*", but tests matching "a*" that has no
subtests will also be executed.

Signed-off-by: Yucong Sun <fallentree@fb.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20210817044732.3263066-5-fallentree@fb.com

authored by

Yucong Sun and committed by
Andrii Nakryiko
74339a8f 99c4fd8b

+62 -16
+62 -16
tools/testing/selftests/bpf/test_progs.c
··· 13 13 #include <execinfo.h> /* backtrace */ 14 14 #include <linux/membarrier.h> 15 15 16 + /* Adapted from perf/util/string.c */ 17 + static bool glob_match(const char *str, const char *pat) 18 + { 19 + while (*str && *pat && *pat != '*') { 20 + if (*str != *pat) 21 + return false; 22 + str++; 23 + pat++; 24 + } 25 + /* Check wild card */ 26 + if (*pat == '*') { 27 + while (*pat == '*') 28 + pat++; 29 + if (!*pat) /* Tail wild card matches all */ 30 + return true; 31 + while (*str) 32 + if (glob_match(str++, pat)) 33 + return true; 34 + } 35 + return !*str && !*pat; 36 + } 37 + 16 38 #define EXIT_NO_TEST 2 17 39 #define EXIT_ERR_SETUP_INFRA 3 18 40 ··· 77 55 int i; 78 56 79 57 for (i = 0; i < sel->blacklist.cnt; i++) { 80 - if (strstr(name, sel->blacklist.strs[i])) 58 + if (glob_match(name, sel->blacklist.strs[i])) 81 59 return false; 82 60 } 83 61 84 62 for (i = 0; i < sel->whitelist.cnt; i++) { 85 - if (strstr(name, sel->whitelist.strs[i])) 63 + if (glob_match(name, sel->whitelist.strs[i])) 86 64 return true; 87 65 } 88 66 ··· 472 450 ARG_VERBOSE = 'v', 473 451 ARG_GET_TEST_CNT = 'c', 474 452 ARG_LIST_TEST_NAMES = 'l', 453 + ARG_TEST_NAME_GLOB_ALLOWLIST = 'a', 454 + ARG_TEST_NAME_GLOB_DENYLIST = 'd', 475 455 }; 476 456 477 457 static const struct argp_option opts[] = { ··· 491 467 "Get number of selected top-level tests " }, 492 468 { "list", ARG_LIST_TEST_NAMES, NULL, 0, 493 469 "List test names that would run (without running them) " }, 470 + { "allow", ARG_TEST_NAME_GLOB_ALLOWLIST, "NAMES", 0, 471 + "Run tests with name matching the pattern (supports '*' wildcard)." }, 472 + { "deny", ARG_TEST_NAME_GLOB_DENYLIST, "NAMES", 0, 473 + "Don't run tests with name matching the pattern (supports '*' wildcard)." }, 494 474 {}, 495 475 }; 496 476 ··· 519 491 free(set->strs); 520 492 } 521 493 522 - static int parse_str_list(const char *s, struct str_set *set) 494 + static int parse_str_list(const char *s, struct str_set *set, bool is_glob_pattern) 523 495 { 524 496 char *input, *state = NULL, *next, **tmp, **strs = NULL; 525 - int cnt = 0; 497 + int i, cnt = 0; 526 498 527 499 input = strdup(s); 528 500 if (!input) 529 501 return -ENOMEM; 530 - 531 - set->cnt = 0; 532 - set->strs = NULL; 533 502 534 503 while ((next = strtok_r(state ? NULL : input, ",", &state))) { 535 504 tmp = realloc(strs, sizeof(*strs) * (cnt + 1)); ··· 534 509 goto err; 535 510 strs = tmp; 536 511 537 - strs[cnt] = strdup(next); 538 - if (!strs[cnt]) 539 - goto err; 512 + if (is_glob_pattern) { 513 + strs[cnt] = strdup(next); 514 + if (!strs[cnt]) 515 + goto err; 516 + } else { 517 + strs[cnt] = malloc(strlen(next) + 2 + 1); 518 + if (!strs[cnt]) 519 + goto err; 520 + sprintf(strs[cnt], "*%s*", next); 521 + } 540 522 541 523 cnt++; 542 524 } 543 525 544 - set->cnt = cnt; 545 - set->strs = (const char **)strs; 526 + tmp = realloc(set->strs, sizeof(*strs) * (cnt + set->cnt)); 527 + if (!tmp) 528 + goto err; 529 + memcpy(tmp + set->cnt, strs, sizeof(*strs) * cnt); 530 + set->strs = (const char **)tmp; 531 + set->cnt += cnt; 532 + 546 533 free(input); 534 + free(strs); 547 535 return 0; 548 536 err: 537 + for (i = 0; i < cnt; i++) 538 + free(strs[i]); 549 539 free(strs); 550 540 free(input); 551 541 return -ENOMEM; ··· 593 553 } 594 554 break; 595 555 } 556 + case ARG_TEST_NAME_GLOB_ALLOWLIST: 596 557 case ARG_TEST_NAME: { 597 558 char *subtest_str = strchr(arg, '/'); 598 559 599 560 if (subtest_str) { 600 561 *subtest_str = '\0'; 601 562 if (parse_str_list(subtest_str + 1, 602 - &env->subtest_selector.whitelist)) 563 + &env->subtest_selector.whitelist, 564 + key == ARG_TEST_NAME_GLOB_ALLOWLIST)) 603 565 return -ENOMEM; 604 566 } 605 - if (parse_str_list(arg, &env->test_selector.whitelist)) 567 + if (parse_str_list(arg, &env->test_selector.whitelist, 568 + key == ARG_TEST_NAME_GLOB_ALLOWLIST)) 606 569 return -ENOMEM; 607 570 break; 608 571 } 572 + case ARG_TEST_NAME_GLOB_DENYLIST: 609 573 case ARG_TEST_NAME_BLACKLIST: { 610 574 char *subtest_str = strchr(arg, '/'); 611 575 612 576 if (subtest_str) { 613 577 *subtest_str = '\0'; 614 578 if (parse_str_list(subtest_str + 1, 615 - &env->subtest_selector.blacklist)) 579 + &env->subtest_selector.blacklist, 580 + key == ARG_TEST_NAME_GLOB_DENYLIST)) 616 581 return -ENOMEM; 617 582 } 618 - if (parse_str_list(arg, &env->test_selector.blacklist)) 583 + if (parse_str_list(arg, &env->test_selector.blacklist, 584 + key == ARG_TEST_NAME_GLOB_DENYLIST)) 619 585 return -ENOMEM; 620 586 break; 621 587 }