1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2025 Oxide Computer Company 14 * Copyright 2024 Ryan Zezeski 15 */ 16 #include <sys/debug.h> 17 #include <sys/ktest.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <sys/list.h> 21 #include <fcntl.h> 22 #include <unistd.h> 23 #include <stropts.h> 24 #include <stdio.h> 25 #include <stddef.h> 26 #include <stdlib.h> 27 #include <errno.h> 28 #include <err.h> 29 #include <stdarg.h> 30 #include <strings.h> 31 #include <libgen.h> 32 #include <libnvpair.h> 33 #include <regex.h> 34 #include <libcmdutils.h> 35 #include <ofmt.h> 36 #include <zone.h> 37 #include <libktest.h> 38 39 #define EXIT_USAGE 2 40 #define KTEST_CMD_SZ 24 41 42 static const char *ktest_prog; 43 44 45 /* An adapter to use errx with libofmt. */ 46 void 47 ktest_ofmt_errx(const char *fmt, ...) 48 { 49 va_list ap; 50 51 va_start(ap, fmt); 52 verrx(EXIT_FAILURE, fmt, ap); 53 } 54 55 typedef enum ktest_fmt_fields { 56 KTEST_FMT_RESULT, 57 KTEST_FMT_MODULE, 58 KTEST_FMT_SUITE, 59 KTEST_FMT_TEST, 60 KTEST_FMT_INPUT_FLAG, 61 KTEST_FMT_INPUT_PATH, 62 KTEST_FMT_LINE, 63 KTEST_FMT_REASON, 64 } ktest_fmt_fields_t; 65 66 typedef struct ktest_list_ofmt { 67 char *klof_module; 68 char *klof_suite; 69 char *klof_test; 70 boolean_t klof_input; 71 } ktest_list_ofmt_t; 72 73 static boolean_t 74 ktest_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len) 75 { 76 ktest_entry_t *ent = ofarg->ofmt_cbarg; 77 78 switch (ofarg->ofmt_id) { 79 case KTEST_FMT_MODULE: 80 if (snprintf(buf, len, "%s", ent->ke_module) >= len) { 81 return (B_FALSE); 82 } 83 break; 84 85 case KTEST_FMT_SUITE: 86 if (snprintf(buf, len, "%s", ent->ke_suite) >= len) { 87 return (B_FALSE); 88 } 89 break; 90 91 case KTEST_FMT_TEST: 92 if (snprintf(buf, len, "%s", ent->ke_test) >= len) { 93 return (B_FALSE); 94 } 95 break; 96 97 case KTEST_FMT_INPUT_FLAG: { 98 const char *flag = ent->ke_requires_input ? "Y" : "N"; 99 100 if (snprintf(buf, len, "%s", flag) >= len) { 101 return (B_FALSE); 102 } 103 } 104 } 105 106 return (B_TRUE); 107 } 108 109 #define KTEST_LIST_CMD_DEF_FIELDS "module,suite,test,input" 110 111 static const ofmt_field_t ktest_list_ofmt[] = { 112 { "MODULE", 12, KTEST_FMT_MODULE, ktest_list_ofmt_cb }, 113 { "SUITE", 16, KTEST_FMT_SUITE, ktest_list_ofmt_cb }, 114 { "TEST", 45, KTEST_FMT_TEST, ktest_list_ofmt_cb }, 115 { "INPUT", 7, KTEST_FMT_INPUT_FLAG, ktest_list_ofmt_cb }, 116 { NULL, 0, 0, NULL }, 117 }; 118 119 typedef struct ktest_run_output { 120 ktest_run_req_t *kro_req; 121 ktest_run_result_t *kro_result; 122 char *kro_input_path; 123 } ktest_run_output_t; 124 125 static boolean_t 126 ktest_run_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len) 127 { 128 const ktest_run_output_t *kro = ofarg->ofmt_cbarg; 129 const ktest_run_req_t *req = kro->kro_req; 130 const ktest_run_result_t *result = kro->kro_result; 131 const char *input_path = 132 kro->kro_input_path != NULL ? kro->kro_input_path : ""; 133 134 switch (ofarg->ofmt_id) { 135 case KTEST_FMT_RESULT: 136 if (snprintf(buf, len, "%s", 137 ktest_code_name(result->krr_code)) >= len) { 138 return (B_FALSE); 139 } 140 break; 141 case KTEST_FMT_MODULE: 142 if (snprintf(buf, len, "%s", req->krq_module) >= len) { 143 return (B_FALSE); 144 } 145 break; 146 147 case KTEST_FMT_SUITE: 148 if (snprintf(buf, len, "%s", req->krq_suite) >= len) { 149 return (B_FALSE); 150 } 151 break; 152 153 case KTEST_FMT_TEST: 154 if (snprintf(buf, len, "%s", req->krq_test) >= len) { 155 return (B_FALSE); 156 } 157 break; 158 case KTEST_FMT_INPUT_PATH: 159 if (snprintf(buf, len, "%s", input_path) >= len) { 160 return (B_FALSE); 161 } 162 break; 163 case KTEST_FMT_LINE: 164 if (snprintf(buf, len, "%u", result->krr_line) >= len) { 165 return (B_FALSE); 166 } 167 break; 168 case KTEST_FMT_REASON: 169 if (snprintf(buf, len, "%s", result->krr_msg) >= len) { 170 return (B_FALSE); 171 } 172 break; 173 } 174 175 return (B_TRUE); 176 } 177 178 #define KTEST_RUN_CMD_DEF_FIELDS "result,line,module,suite,test" 179 180 /* 181 * The input column for the run command is for displaying the path to 182 * the input file, as opposed to the list command which indicates if 183 * the test requires input or not. 184 */ 185 static const ofmt_field_t ktest_run_ofmt[] = { 186 { "RESULT", 7, KTEST_FMT_RESULT, ktest_run_ofmt_cb }, 187 { "MODULE", 12, KTEST_FMT_MODULE, ktest_run_ofmt_cb }, 188 { "SUITE", 16, KTEST_FMT_SUITE, ktest_run_ofmt_cb }, 189 { "TEST", 45, KTEST_FMT_TEST, ktest_run_ofmt_cb }, 190 { "INPUT", 48, KTEST_FMT_INPUT_PATH, ktest_run_ofmt_cb }, 191 { "LINE", 6, KTEST_FMT_LINE, ktest_run_ofmt_cb }, 192 { "REASON", 256, KTEST_FMT_REASON, ktest_run_ofmt_cb }, 193 { NULL, 0, 0, NULL }, 194 }; 195 196 typedef enum ktest_stat_type { 197 KTEST_STAT_MOD, 198 KTEST_STAT_SUITE, 199 } ktest_stat_type_t; 200 201 typedef struct ktest_stats { 202 list_node_t ks_node; 203 ktest_stat_type_t ks_type; 204 char *ks_name; 205 uint32_t ks_total; 206 uint32_t ks_pass; 207 uint32_t ks_fail; 208 uint32_t ks_err; 209 uint32_t ks_skip; 210 uint32_t ks_none; 211 } ktest_stats_t; 212 213 static ktest_stats_t * 214 ktest_stats_new(ktest_stat_type_t type, const char *name) 215 { 216 ktest_stats_t *stats; 217 218 if ((stats = malloc(sizeof (ktest_stats_t))) == NULL) { 219 err(EXIT_FAILURE, "failed to allocate stats structure"); 220 } 221 222 stats->ks_type = type; 223 stats->ks_name = strndup(name, KTEST_MAX_NAME_LEN); 224 225 if (stats->ks_name == NULL) { 226 err(EXIT_FAILURE, "failed to allocate stats name"); 227 } 228 229 stats->ks_total = 0; 230 stats->ks_pass = 0; 231 stats->ks_fail = 0; 232 stats->ks_err = 0; 233 stats->ks_skip = 0; 234 stats->ks_none = 0; 235 return (stats); 236 } 237 238 static void 239 ktest_record_stat(ktest_stats_t *mod, ktest_stats_t *suite, 240 const ktest_run_result_t *res) 241 { 242 mod->ks_total++; 243 suite->ks_total++; 244 245 switch (res->krr_code) { 246 case KTEST_CODE_NONE: 247 mod->ks_none++; 248 suite->ks_none++; 249 break; 250 251 case KTEST_CODE_PASS: 252 mod->ks_pass++; 253 suite->ks_pass++; 254 break; 255 256 case KTEST_CODE_FAIL: 257 mod->ks_fail++; 258 suite->ks_fail++; 259 break; 260 261 case KTEST_CODE_SKIP: 262 mod->ks_skip++; 263 suite->ks_skip++; 264 break; 265 266 case KTEST_CODE_ERROR: 267 mod->ks_err++; 268 suite->ks_err++; 269 break; 270 } 271 } 272 273 typedef enum ktest_fmt_stats { 274 KTEST_FMT_STATS_MS, 275 KTEST_FMT_STATS_TOTAL, 276 KTEST_FMT_STATS_PASS, 277 KTEST_FMT_STATS_FAIL, 278 KTEST_FMT_STATS_ERR, 279 KTEST_FMT_STATS_SKIP, 280 KTEST_FMT_STATS_NONE, 281 } ktest_fmt_stats_t; 282 283 static boolean_t 284 ktest_stats_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len) 285 { 286 ktest_stats_t *stats = ofarg->ofmt_cbarg; 287 288 switch (ofarg->ofmt_id) { 289 case KTEST_FMT_STATS_MS: { 290 char *pre = (stats->ks_type == KTEST_STAT_MOD) ? "" : " "; 291 292 if (snprintf(buf, len, "%s%s", pre, stats->ks_name) >= len) { 293 return (B_FALSE); 294 } 295 break; 296 } 297 298 case KTEST_FMT_STATS_TOTAL: 299 if (snprintf(buf, len, "%" PRIu32, stats->ks_total) >= len) { 300 return (B_FALSE); 301 } 302 break; 303 304 case KTEST_FMT_STATS_PASS: 305 if (snprintf(buf, len, "%" PRIu32, stats->ks_pass) >= len) { 306 return (B_FALSE); 307 } 308 break; 309 310 case KTEST_FMT_STATS_FAIL: 311 if (snprintf(buf, len, "%" PRIu32, stats->ks_fail) >= len) { 312 return (B_FALSE); 313 } 314 break; 315 316 case KTEST_FMT_STATS_ERR: 317 if (snprintf(buf, len, "%" PRIu32, stats->ks_err) >= len) { 318 return (B_FALSE); 319 } 320 break; 321 322 case KTEST_FMT_STATS_SKIP: 323 if (snprintf(buf, len, "%" PRIu32, stats->ks_skip) >= len) { 324 return (B_FALSE); 325 } 326 break; 327 328 case KTEST_FMT_STATS_NONE: 329 if (snprintf(buf, len, "%" PRIu32, stats->ks_none) >= len) { 330 return (B_FALSE); 331 } 332 break; 333 } 334 335 return (B_TRUE); 336 } 337 338 #define KTEST_STATS_FIELDS "module/suite,total,pass,fail,err,skip,none" 339 340 static const ofmt_field_t ktest_stats_ofmt[] = { 341 { "MODULE/SUITE", 40, KTEST_FMT_STATS_MS, ktest_stats_ofmt_cb }, 342 { "TOTAL", 6, KTEST_FMT_STATS_TOTAL, ktest_stats_ofmt_cb }, 343 { "PASS", 6, KTEST_FMT_STATS_PASS, ktest_stats_ofmt_cb }, 344 { "FAIL", 6, KTEST_FMT_STATS_FAIL, ktest_stats_ofmt_cb }, 345 { "ERR", 6, KTEST_FMT_STATS_ERR, ktest_stats_ofmt_cb }, 346 { "SKIP", 6, KTEST_FMT_STATS_SKIP, ktest_stats_ofmt_cb }, 347 { "NONE", 6, KTEST_FMT_STATS_NONE, ktest_stats_ofmt_cb }, 348 }; 349 350 static void 351 ktest_usage(const char *fmt, ...) 352 { 353 if (fmt != NULL) { 354 va_list ap; 355 356 va_start(ap, fmt); 357 vwarnx(fmt, ap); 358 va_end(ap); 359 } 360 361 (void) fprintf(stderr, 362 "usage: %s <subcommand> [<opts>] [<args>]\n\n" 363 "\tlist [-H] [[-p] -o field,...] [<triple> ...]: " 364 "list registered tests\n" 365 "\trun [-Hn] [[-p] -o field,...] [-i <file>] <triple> ...: " 366 "run specified tests\n" 367 "\tload <name> | -a\n" 368 "\tunload <name> | -a\n", 369 ktest_prog); 370 } 371 372 /* 373 * A user-specified test triple. The input path is set to the empty 374 * string if no input is provided. The line number provides useful 375 * error reporting when an error is encountered in the run file. 376 */ 377 typedef struct ktest_triple { 378 list_node_t ktr_node; 379 char *ktr_module; 380 char *ktr_suite; 381 char *ktr_test; 382 /* Did this triple match one or more tests during a ktest-run? */ 383 boolean_t ktr_was_matched; 384 } ktest_triple_t; 385 386 /* Match-all triple used as default when user provides no triples */ 387 static ktest_triple_t ktest_def_triple = { 388 .ktr_module = "*", 389 .ktr_suite = "*", 390 .ktr_test = "*", 391 }; 392 393 static void 394 ktest_free_triples(list_t *triples) 395 { 396 ktest_triple_t *t = NULL; 397 398 while ((t = list_remove_head(triples)) != NULL) { 399 if (t == &ktest_def_triple) { 400 /* 401 * Default triple is not heap allocated, and is used 402 * only when no other matches are specified 403 */ 404 VERIFY(list_is_empty(triples)); 405 continue; 406 } 407 free(t->ktr_module); 408 free(t->ktr_suite); 409 free(t->ktr_test); 410 free(t); 411 } 412 413 list_destroy(triples); 414 } 415 416 /* 417 * Does the test entry match this triple? 418 */ 419 static boolean_t 420 ktest_match_triple(const ktest_entry_t *ent, const ktest_triple_t *triple) 421 { 422 return (gmatch(ent->ke_module, triple->ktr_module) != 0 && 423 gmatch(ent->ke_suite, triple->ktr_suite) != 0 && 424 gmatch(ent->ke_test, triple->ktr_test) != 0); 425 } 426 427 /* 428 * Does the test entry match any triples in the provided list? 429 * 430 * Returns a pointer to the matching triple, if one found. 431 */ 432 static ktest_triple_t * 433 ktest_match_triples(const ktest_entry_t *ent, list_t *triples) 434 { 435 for (ktest_triple_t *triple = list_head(triples); 436 triple != NULL; 437 triple = list_next(triples, triple)) { 438 if (ktest_match_triple(ent, triple)) { 439 return (triple); 440 } 441 } 442 return (NULL); 443 } 444 445 /* 446 * Attempt to parse the test triple string and return the resulting 447 * triple struct. This leaves the original triple string untouched. 448 * 449 * This function produces a warning when failing to parse a triple, 450 * this is on purpose. This allows the run file parser to produce an 451 * error that points out the line number with the bad triple. 452 */ 453 static ktest_triple_t * 454 ktest_parse_triple(const char *tstr) 455 { 456 char *cp = NULL, *orig = NULL; 457 char *module = NULL; 458 char *suite = NULL; 459 char *test = NULL; 460 ktest_triple_t *triple = NULL; 461 462 if ((triple = calloc(1, sizeof (*triple))) == NULL) { 463 warn("failed to allocate triple"); 464 return (NULL); 465 } 466 467 if (strnlen(tstr, KTEST_MAX_TRIPLE_LEN) >= KTEST_MAX_TRIPLE_LEN) { 468 warnx("triple is too long"); 469 goto fail; 470 } 471 472 if ((cp = strndup(tstr, KTEST_MAX_TRIPLE_LEN)) == NULL) { 473 warn("failed to dup triple string"); 474 goto fail; 475 } 476 477 orig = cp; 478 module = strsep(&cp, KTEST_SEPARATOR); 479 480 if (strnlen(module, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) { 481 warnx("module pattern too long: %s", module); 482 goto fail; 483 } 484 485 if (*module == '\0') { 486 module = "*"; 487 } 488 489 if (cp == NULL) { 490 suite = "*"; 491 test = "*"; 492 goto copy; 493 } 494 495 suite = strsep(&cp, KTEST_SEPARATOR); 496 497 if (strnlen(suite, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) { 498 warnx("suite pattern too long: %s", suite); 499 goto fail; 500 } 501 502 if (*suite == '\0') { 503 suite = "*"; 504 } 505 506 if (cp == NULL) { 507 test = "*"; 508 goto copy; 509 } 510 511 test = cp; 512 513 if (strstr(cp, KTEST_SEPARATOR) != NULL) { 514 warnx("malformed triple, unexpected ':' in test pattern: %s", 515 test); 516 goto fail; 517 } 518 519 if (strnlen(test, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) { 520 warnx("test pattern too long: %s", test); 521 goto fail; 522 } 523 524 if (*test == '\0') { 525 test = "*"; 526 } 527 528 copy: 529 triple->ktr_module = strdup(module); 530 triple->ktr_suite = strdup(suite); 531 triple->ktr_test = strdup(test); 532 free(orig); 533 return (triple); 534 535 fail: 536 free(orig); 537 free(triple); 538 return (NULL); 539 } 540 541 static void 542 ktest_parse_triples(list_t *triples, uint_t count, const char *tinput[]) 543 { 544 list_create(triples, sizeof (ktest_triple_t), 545 offsetof(ktest_triple_t, ktr_node)); 546 547 if (count == 0) { 548 list_insert_tail(triples, &ktest_def_triple); 549 return; 550 } 551 552 for (uint_t i = 0; i < count; i++) { 553 ktest_triple_t *triple = ktest_parse_triple(tinput[i]); 554 555 if (triple == NULL) { 556 errx(EXIT_FAILURE, "failed to parse triple: %s", 557 tinput[i]); 558 } 559 560 list_insert_tail(triples, triple); 561 } 562 } 563 564 565 /* 566 * Does the test entry match any of the triples? 567 */ 568 static boolean_t 569 ktest_match_any(const ktest_entry_t *ent, list_t *triples) 570 { 571 for (ktest_triple_t *triple = list_head(triples); triple != NULL; 572 triple = list_next(triples, triple)) { 573 if (ktest_match_triple(ent, triple)) { 574 return (B_TRUE); 575 } 576 } 577 578 return (B_FALSE); 579 } 580 581 static void 582 ktest_print_stats(list_t *stats) 583 { 584 ktest_stats_t *stat; 585 ofmt_handle_t stats_ofmt; 586 ofmt_status_t oferr; 587 boolean_t first = B_FALSE; 588 589 oferr = ofmt_open(KTEST_STATS_FIELDS, ktest_stats_ofmt, 0, 0, 590 &stats_ofmt); 591 ofmt_check(oferr, B_FALSE, stats_ofmt, ktest_ofmt_errx, warnx); 592 593 for (stat = list_head(stats); stat != NULL; 594 stat = list_next(stats, stat)) { 595 if (!first && stat->ks_type == KTEST_STAT_MOD) { 596 printf("\n"); 597 } 598 599 ofmt_print(stats_ofmt, stat); 600 601 if (stat->ks_type == KTEST_STAT_MOD) { 602 first = B_FALSE; 603 /* Print a 72-char horizontal rule. */ 604 printf("-----------------------------------" 605 "-----------------------------------\n"); 606 } 607 } 608 609 ofmt_close(stats_ofmt); 610 } 611 612 /* 613 * Read file at path into the byte array. If an error occurs, `err` will be 614 * populated with an allocated string describing the problem. If the file was 615 * read successfully, the allocated buffer will be placed in `bytes` with its 616 * size recorded in `len`. 617 */ 618 static boolean_t 619 ktest_read_file(const char *path, uchar_t **bytes, size_t *len, char **err) 620 { 621 FILE *fp = fopen(path, "r"); 622 if (fp == NULL) { 623 *err = strdup("failed to open input file"); 624 return (B_FALSE); 625 } 626 627 struct stat stats; 628 if (fstat(fileno(fp), &stats) == -1) { 629 (void) fclose(fp); 630 *err = strdup("failed to stat input file"); 631 return (B_FALSE); 632 } 633 634 const size_t target_sz = (size_t)stats.st_size; 635 const size_t max_sz = ktest_max_input_size(); 636 if (target_sz > max_sz) { 637 (void) fclose(fp); 638 (void) asprintf(err, 639 "input size greater than max of %u bytes", max_sz); 640 return (B_FALSE); 641 } else if (target_sz == 0) { 642 (void) fclose(fp); 643 *err = strdup("input file cannot be zero-length"); 644 return (B_FALSE); 645 } 646 647 uchar_t *buf = malloc(target_sz); 648 if (buf == NULL) { 649 (void) fclose(fp); 650 *err = strdup("failed to allocate byte array of size"); 651 return (B_FALSE); 652 } 653 654 if (fread(buf, 1, target_sz, fp) != target_sz) { 655 (void) fclose(fp); 656 (void) asprintf(err, 657 "failed to read %u bytes from input file", target_sz); 658 return (B_FALSE); 659 } 660 661 *bytes = buf; 662 *len = target_sz; 663 return (B_TRUE); 664 } 665 666 static boolean_t 667 ktest_run_test(ktest_hdl_t *kthdl, const ktest_entry_t *ent, 668 char *input_path, ktest_stats_t *mod_stats, ktest_stats_t *suite_stats, 669 ofmt_handle_t ofmt) 670 { 671 ktest_run_req_t req = { 672 .krq_module = ent->ke_module, 673 .krq_suite = ent->ke_suite, 674 .krq_test = ent->ke_test, 675 }; 676 ktest_run_result_t res = { 0 }; 677 ktest_run_output_t kro = { 678 .kro_req = &req, 679 .kro_result = &res, 680 .kro_input_path = input_path, 681 }; 682 683 /* Fail with error when lacking input for test which requires it */ 684 if (ent->ke_requires_input && input_path == NULL) { 685 res.krr_msg = strdup("test requires input and none provided"); 686 res.krr_code = KTEST_CODE_ERROR; 687 ktest_record_stat(mod_stats, suite_stats, &res); 688 ofmt_print(ofmt, &kro); 689 free(res.krr_msg); 690 return (B_FALSE); 691 } 692 693 if (input_path != NULL) { 694 /* We treat a failure to read the input file as a test error. */ 695 if (!ktest_read_file(input_path, &req.krq_input, 696 &req.krq_input_len, &res.krr_msg)) { 697 res.krr_code = KTEST_CODE_ERROR; 698 ktest_record_stat(mod_stats, suite_stats, &res); 699 ofmt_print(ofmt, &kro); 700 free(res.krr_msg); 701 return (B_FALSE); 702 } 703 } 704 705 if (!ktest_run(kthdl, &req, &res)) { 706 if (input_path != NULL) { 707 err(EXIT_FAILURE, "failed to run test %s:%s:%s with " 708 "input %s", ent->ke_module, ent->ke_suite, 709 ent->ke_test, input_path); 710 } else { 711 err(EXIT_FAILURE, "failed to run test %s:%s:%s", 712 ent->ke_module, ent->ke_suite, ent->ke_test); 713 } 714 } 715 716 ktest_record_stat(mod_stats, suite_stats, &res); 717 ofmt_print(ofmt, &kro); 718 free(res.krr_msg); 719 return (res.krr_code == KTEST_CODE_PASS || 720 res.krr_code == KTEST_CODE_SKIP); 721 } 722 723 typedef enum ktest_run_test_flags { 724 KRTF_PRINT_STATS = (1 << 0), 725 KRTF_SKIP_INPUT_REQ = (1 << 1), 726 } ktest_run_test_flags_t; 727 728 /* 729 * Run all tests specified in the run list and print the result of each test. 730 * 731 * Returns the number of tests which failed. 732 */ 733 static uint_t 734 ktest_run_tests(ktest_hdl_t *kthdl, list_t *run_list, char *input_path, 735 ofmt_handle_t ofmt, ktest_run_test_flags_t flags) 736 { 737 ktest_stats_t *mod_stats = NULL; 738 ktest_stats_t *suite_stats = NULL; 739 list_t stats; 740 ktest_stats_t *stat = NULL; 741 742 list_create(&stats, sizeof (ktest_stats_t), 743 offsetof(ktest_stats_t, ks_node)); 744 745 ktest_list_iter_t *iter = ktest_list(kthdl); 746 if (iter == NULL) { 747 err(EXIT_FAILURE, "Could not list ktests"); 748 } 749 750 uint_t tests_matched = 0, tests_failed = 0; 751 ktest_entry_t ent; 752 while (ktest_list_next(iter, &ent)) { 753 ktest_triple_t *triple; 754 if ((triple = ktest_match_triples(&ent, run_list)) == NULL) { 755 continue; 756 } 757 758 if (ent.ke_requires_input && input_path == NULL && 759 (flags & KRTF_SKIP_INPUT_REQ)) { 760 /* 761 * User has provided no input and requested that 762 * input-required tests be explicitly skipped. 763 */ 764 continue; 765 } 766 767 /* 768 * Since this matching test will not be skipped for input 769 * reasons, record that its corresponding triple was used. 770 * 771 * This could be inadequate if the user specifies triples which 772 * overlap in their matches. We can make it more robust to such 773 * cases later. 774 */ 775 triple->ktr_was_matched |= B_TRUE; 776 tests_matched++; 777 778 /* 779 * Either this is our first matching test or we are 780 * transitioning to a new module and/or suite. In either case, 781 * create new stats structures and add them to the list. 782 */ 783 if (mod_stats == NULL || 784 strcmp(mod_stats->ks_name, ent.ke_module) != 0) { 785 mod_stats = ktest_stats_new(KTEST_STAT_MOD, 786 ent.ke_module); 787 list_insert_tail(&stats, mod_stats); 788 } 789 if (suite_stats == NULL || 790 strcmp(suite_stats->ks_name, ent.ke_suite) != 0) { 791 suite_stats = ktest_stats_new(KTEST_STAT_SUITE, 792 ent.ke_suite); 793 list_insert_tail(&stats, suite_stats); 794 } 795 796 /* Run the test */ 797 if (!ktest_run_test(kthdl, &ent, input_path, 798 mod_stats, suite_stats, ofmt)) { 799 tests_failed++; 800 } 801 } 802 803 /* Make sure we ran _something_ */ 804 if (tests_matched == 0) { 805 errx(EXIT_FAILURE, "No tests matched selection triple(s)"); 806 } 807 808 /* Confirm that all triples matched something */ 809 boolean_t fail_match = B_FALSE; 810 for (ktest_triple_t *triple = list_head(run_list); 811 triple != NULL; 812 triple = list_next(run_list, triple)) { 813 if (!triple->ktr_was_matched) { 814 fail_match = B_TRUE; 815 break; 816 } 817 } 818 if (fail_match) { 819 (void) fprintf(stderr, "These triples failed to match " 820 "any tests, or were superseded by other matches:\n"); 821 for (ktest_triple_t *triple = list_head(run_list); 822 triple != NULL; 823 triple = list_next(run_list, triple)) { 824 if (!triple->ktr_was_matched) { 825 (void) fprintf(stderr, "\t%s:%s:%s\n", 826 triple->ktr_module, triple->ktr_suite, 827 triple->ktr_test); 828 } 829 } 830 exit(EXIT_FAILURE); 831 } 832 833 if (flags & KRTF_PRINT_STATS) { 834 printf("\n"); 835 ktest_print_stats(&stats); 836 } 837 838 while ((stat = list_remove_head(&stats)) != NULL) { 839 free(stat); 840 } 841 list_destroy(&stats); 842 free(iter); 843 return (tests_failed); 844 } 845 846 static void 847 ktest_run_cmd(int argc, char *argv[]) 848 { 849 int c; 850 char *input_path = NULL; 851 boolean_t parsable = B_FALSE; 852 boolean_t fields_set = B_FALSE; 853 ktest_run_test_flags_t flags = KRTF_PRINT_STATS; 854 char *fields = KTEST_RUN_CMD_DEF_FIELDS; 855 uint_t oflags = 0; 856 ofmt_handle_t ofmt = NULL; 857 ofmt_status_t oferr; 858 859 while ((c = getopt(argc, argv, ":Hno:pi:")) != -1) { 860 switch (c) { 861 case 'H': 862 oflags |= OFMT_NOHEADER; 863 break; 864 case 'n': 865 flags |= KRTF_SKIP_INPUT_REQ; 866 break; 867 case 'o': 868 fields = optarg; 869 fields_set = B_TRUE; 870 break; 871 case 'p': 872 parsable = B_TRUE; 873 flags &= ~KRTF_PRINT_STATS; 874 oflags |= OFMT_PARSABLE; 875 break; 876 case 'i': 877 if (input_path != NULL) { 878 ktest_usage("cannot specify -i more than once"); 879 exit(EXIT_USAGE); 880 } 881 882 input_path = optarg; 883 884 if (strnlen(input_path, MAXPATHLEN) >= MAXPATHLEN) { 885 err(EXIT_FAILURE, "input path too long"); 886 } 887 888 break; 889 case ':': 890 ktest_usage("missing argument to -%c", optopt); 891 exit(EXIT_USAGE); 892 893 case '?': 894 ktest_usage("unknown run option: -%c", optopt); 895 exit(EXIT_USAGE); 896 } 897 } 898 899 if (parsable && !fields_set) { 900 ktest_usage("must specify -o with -p"); 901 exit(EXIT_USAGE); 902 } 903 904 oferr = ofmt_open(fields, ktest_run_ofmt, oflags, 0, &ofmt); 905 ofmt_check(oferr, parsable, ofmt, ktest_ofmt_errx, warnx); 906 907 argc -= optind; 908 argv += optind; 909 910 /* 911 * We don't run all tests by default. We assume that as the library of 912 * test modules grows we want to be sure the user actually wants to run 913 * all tests by forcing them to at least specify the `*` glob. 914 */ 915 if (argc < 1) { 916 ktest_usage("must specify at least one triple"); 917 exit(EXIT_USAGE); 918 } 919 list_t triples; 920 ktest_parse_triples(&triples, argc, (const char **)argv); 921 922 ktest_hdl_t *kthdl = ktest_init(); 923 if (kthdl == NULL) { 924 err(EXIT_FAILURE, "Could not open ktest"); 925 } 926 uint_t failed_count = 927 ktest_run_tests(kthdl, &triples, input_path, ofmt, flags); 928 929 ofmt_close(ofmt); 930 ktest_free_triples(&triples); 931 ktest_fini(kthdl); 932 933 if (failed_count != 0) { 934 errx(EXIT_FAILURE, "%u %s did not pass", 935 failed_count, failed_count > 1 ? "tests" : "test"); 936 } 937 } 938 939 static void 940 ktest_list_cmd(int argc, char *argv[]) 941 { 942 int c; 943 boolean_t parsable = B_FALSE; 944 boolean_t fields_set = B_FALSE; 945 char *fields = KTEST_LIST_CMD_DEF_FIELDS; 946 uint_t oflags = 0; 947 ofmt_handle_t list_ofmt = NULL; 948 ofmt_status_t oferr; 949 950 while ((c = getopt(argc, argv, ":Ho:p")) != -1) { 951 switch (c) { 952 case 'H': 953 oflags |= OFMT_NOHEADER; 954 break; 955 case 'o': 956 fields = optarg; 957 fields_set = B_TRUE; 958 break; 959 case 'p': 960 parsable = B_TRUE; 961 oflags |= OFMT_PARSABLE; 962 break; 963 case ':': 964 ktest_usage("missing argument to -%c", optopt); 965 exit(EXIT_USAGE); 966 case '?': 967 ktest_usage("unknown option: -%c", optopt); 968 exit(EXIT_USAGE); 969 } 970 } 971 972 if (parsable && !fields_set) { 973 ktest_usage("must specify -o with -p"); 974 exit(EXIT_USAGE); 975 } 976 977 oferr = ofmt_open(fields, ktest_list_ofmt, oflags, 0, &list_ofmt); 978 ofmt_check(oferr, parsable, list_ofmt, ktest_ofmt_errx, warnx); 979 980 argc -= optind; 981 argv += optind; 982 983 list_t triples; 984 ktest_parse_triples(&triples, argc, (const char **)argv); 985 986 ktest_hdl_t *kthdl = ktest_init(); 987 if (kthdl == NULL) { 988 err(EXIT_FAILURE, "Could not open ktest"); 989 } 990 ktest_list_iter_t *iter = ktest_list(kthdl); 991 if (iter == NULL) { 992 err(EXIT_FAILURE, "Could not list ktests"); 993 } 994 995 ktest_entry_t ent; 996 while (ktest_list_next(iter, &ent)) { 997 if (!ktest_match_any(&ent, &triples)) { 998 continue; 999 } 1000 ofmt_print(list_ofmt, &ent); 1001 } 1002 1003 ktest_list_free(iter); 1004 ktest_fini(kthdl); 1005 1006 ofmt_close(list_ofmt); 1007 ktest_free_triples(&triples); 1008 } 1009 1010 static void 1011 ktest_load_cmd(int argc, char *argv[]) 1012 { 1013 int c; 1014 boolean_t load_all = B_FALSE; 1015 1016 while ((c = getopt(argc, argv, "a")) != -1) { 1017 switch (c) { 1018 case 'a': 1019 load_all = B_TRUE; 1020 break; 1021 case '?': 1022 ktest_usage("unknown option: -%c", optopt); 1023 exit(EXIT_USAGE); 1024 } 1025 } 1026 1027 argc -= optind; 1028 argv += optind; 1029 1030 if (load_all) { 1031 /* 1032 * We just ignore specified module names if the user requested 1033 * that everything should be loaded. 1034 */ 1035 if (!ktest_mod_load_all()) { 1036 err(EXIT_FAILURE, "Could not load all ktests"); 1037 } 1038 return; 1039 } 1040 if (argc <= 0) { 1041 ktest_usage("must specify module name(s) or -a"); 1042 exit(EXIT_USAGE); 1043 } 1044 boolean_t any_failed = B_FALSE; 1045 for (int i = 0; i < argc; i++) { 1046 if (!ktest_mod_load(argv[i])) { 1047 any_failed = B_TRUE; 1048 warn("Could not load module %s", argv[i]); 1049 } 1050 } 1051 if (any_failed) { 1052 errx(EXIT_FAILURE, "Some modules failed to load"); 1053 } 1054 } 1055 1056 static void 1057 ktest_unload_cmd(int argc, char *argv[]) 1058 { 1059 int c; 1060 boolean_t unload_all = B_FALSE; 1061 1062 while ((c = getopt(argc, argv, "a")) != -1) { 1063 switch (c) { 1064 case 'a': 1065 unload_all = B_TRUE; 1066 break; 1067 case '?': 1068 ktest_usage("unknown option: -%c", optopt); 1069 exit(EXIT_USAGE); 1070 } 1071 } 1072 1073 argc -= optind; 1074 argv += optind; 1075 1076 if (unload_all) { 1077 /* 1078 * We just ignore specified module names if the user requested 1079 * that everything should be unloaded. 1080 */ 1081 if (!ktest_mod_unload_all()) { 1082 err(EXIT_FAILURE, "Could not unload all ktests"); 1083 } 1084 return; 1085 } 1086 if (argc <= 0) { 1087 ktest_usage("must specify module name(s) or -a"); 1088 exit(EXIT_USAGE); 1089 } 1090 for (int i = 0; i < argc; i++) { 1091 ktest_mod_unload(argv[i]); 1092 } 1093 } 1094 1095 int 1096 main(int argc, char *argv[]) 1097 { 1098 const char *cmd; 1099 1100 ktest_prog = basename(argv[0]); 1101 1102 if (getzoneid() != GLOBAL_ZONEID || getuid() != 0) { 1103 errx(EXIT_FAILURE, "can only be used by root from" 1104 " the global zone"); 1105 } 1106 1107 if (argc < 2) { 1108 ktest_usage("no command specified"); 1109 exit(EXIT_USAGE); 1110 } 1111 1112 /* 1113 * Peel off program name and command. 1114 */ 1115 cmd = argv[1]; 1116 argc -= 2; 1117 argv += 2; 1118 optind = 0; 1119 1120 if (strncasecmp("list", cmd, KTEST_CMD_SZ) == 0) { 1121 ktest_list_cmd(argc, argv); 1122 } else if (strncasecmp("run", cmd, KTEST_CMD_SZ) == 0) { 1123 ktest_run_cmd(argc, argv); 1124 } else if (strncasecmp("load", cmd, KTEST_CMD_SZ) == 0) { 1125 ktest_load_cmd(argc, argv); 1126 } else if (strncasecmp("unload", cmd, KTEST_CMD_SZ) == 0) { 1127 ktest_unload_cmd(argc, argv); 1128 } else if (strncasecmp("help", cmd, KTEST_CMD_SZ) == 0) { 1129 ktest_usage(NULL); 1130 } else { 1131 ktest_usage("unknown command: %s", cmd); 1132 exit(EXIT_USAGE); 1133 } 1134 1135 return (EXIT_SUCCESS); 1136 } 1137