1/* Mach virtual memory unit tests 2 * 3 * The main goal of this code is to facilitate the construction, 4 * running, result logging and clean up of a test suite, taking care 5 * of all the scaffolding. A test suite is a sequence of very targeted 6 * unit tests, each running as a separate process to isolate its 7 * address space. 8 * A unit test is abstracted as a unit_test_t structure, consisting of 9 * a test function and a logging identifier. A test suite is a suite_t 10 * structure, consisting of an unit_test_t array, a logging identifier, 11 * and fixture set up and tear down functions. 12 * Test suites are created dynamically. Each of its unit test runs in 13 * its own fork()d process, with the fixture set up and tear down 14 * running before and after each test. The parent process will log a 15 * pass result if the child exits normally, and a fail result in any 16 * other case (non-zero exit status, abnormal signal). The suite 17 * results are then aggregated and logged, and finally the test suite 18 * is destroyed. 19 * Everything is logged to stdout in the standard Testbot format, which 20 * can be easily converted to Munin or SimonSays logging 21 * format. Logging is factored out as much as possible for future 22 * flexibility. In our particular case, a unit test is logged as a 23 * Testbot Test Case ([BEGIN]/[PASS]/[FAIL], and a test suite is 24 * logged as a Testbot Test ([TEST]). This is confusing but 25 * unfortunately cannot be avoided for compatibility. Suite results 26 * are aggregated after the [SUMMARY] keyword. 27 * The included test suites cover the various pipe buffer operations 28 * with dynamic expansion. 29 * 30 * Vishal Patel (vishal_patel@apple.com) 31 */ 32 33#include <stdlib.h> 34#include <ctype.h> 35#include <inttypes.h> 36#include <stdio.h> 37#include <math.h> 38#include <errno.h> 39#include <signal.h> 40#include <getopt.h> 41#include <sys/sysctl.h> 42#include <string.h> 43#include <stdarg.h> 44#include <unistd.h> 45#include <sys/types.h> 46#include <dispatch/dispatch.h> 47 48/**************************/ 49/**************************/ 50/* Unit Testing Framework */ 51/**************************/ 52/**************************/ 53 54/*********************/ 55/* Private interface */ 56/*********************/ 57 58static const char frameworkname[] = "pipes_unitester"; 59 60/* Type for test, fixture set up and fixture tear down functions. */ 61typedef void (*test_fn_t)(); 62 63/* Unit test structure. */ 64typedef struct { 65 const char *name; 66 test_fn_t test; 67} unit_test_t; 68 69/* Test suite structure. */ 70typedef struct { 71 const char *name; 72 int numoftests; 73 test_fn_t set_up; 74 unit_test_t *tests; 75 test_fn_t tear_down; 76} suite_t; 77 78int _quietness = 0; 79unsigned int _timeout = 0; 80int _expected_signal = 0; 81 82struct { 83 uintmax_t numoftests; 84 uintmax_t passed_tests; 85} results = { 0, 0 }; 86 87void logr(char *format, ...) __printflike(1, 2); 88 89static void die(int condition, const char *culprit) 90{ 91 if (condition) { 92 printf("%s: %s error: %s.\n", frameworkname, culprit, 93 strerror(errno)); 94 exit(1); 95 } 96} 97 98static void die_on_stdout_error() 99{ 100 die(ferror(stdout), "stdout"); 101} 102 103/* Individual test result logging. */ 104void logr(char *format, ...) 105{ 106 if (_quietness <= 1) { 107 va_list ap; 108 109 va_start(ap, format); 110 vprintf(format, ap); 111 va_end(ap); 112 die_on_stdout_error(); 113 } 114} 115 116static suite_t *create_suite(const char *name, int numoftests, 117 test_fn_t set_up, unit_test_t *tests, 118 test_fn_t tear_down) 119{ 120 suite_t *suite = (suite_t *)malloc(sizeof(suite_t)); 121 die(suite == NULL, "malloc()"); 122 123 suite->name = name; 124 suite->numoftests = numoftests; 125 suite->set_up = set_up; 126 suite->tests = tests; 127 suite->tear_down = tear_down; 128 return suite; 129} 130 131static void destroy_suite(suite_t *suite) 132{ 133 free(suite); 134} 135 136static void log_suite_info(suite_t *suite) 137{ 138 logr("[TEST] %s\n", suite->name); 139 logr("Number of tests: %d\n\n", suite->numoftests); 140} 141 142static void log_suite_results(suite_t *suite, int passed_tests) 143{ 144 results.numoftests += (uintmax_t)suite->numoftests; 145 results.passed_tests += (uintmax_t)passed_tests; 146} 147 148static void log_test_info(unit_test_t *unit_test) 149{ 150 logr("[BEGIN] %s\n", unit_test->name); 151} 152 153static void log_test_result(unit_test_t *unit_test, 154 boolean_t test_passed) 155{ 156 logr("[%s] %s\n\n", test_passed ? "PASS" : "FAIL", 157 unit_test->name); 158} 159 160/* Handler for test time out. */ 161static void alarm_handler(int signo) 162{ 163 write(1,"Child process timed out.\n", 164 strlen("Child process timed out.\n")); 165 _Exit(6); 166} 167 168/* Run a test with fixture set up and teardown, while enforcing the 169 * time out constraint. */ 170static void run_test(suite_t *suite, unit_test_t *unit_test) 171{ 172 struct sigaction alarm_act; 173 174 log_test_info(unit_test); 175 alarm_act.sa_handler = alarm_handler; 176 sigemptyset(&alarm_act.sa_mask); 177 alarm_act.sa_flags = 0; 178 die(sigaction(SIGALRM, &alarm_act, NULL) != 0, "sigaction()"); 179 alarm(_timeout); 180 181 suite->set_up(); 182 unit_test->test(); 183 suite->tear_down(); 184} 185 186/* Check a child return status. */ 187static boolean_t child_terminated_normally(int child_status) 188{ 189 boolean_t normal_exit = FALSE; 190 191 if (WIFEXITED(child_status)) { 192 int exit_status = WEXITSTATUS(child_status); 193 if (exit_status) { 194 printf("Child process unexpectedly exited with code " 195 "%d.\n", exit_status); 196 } else if (!_expected_signal) { 197 normal_exit = TRUE; 198 } 199 } else if (WIFSIGNALED(child_status)) { 200 int signal = WTERMSIG(child_status); 201 if (signal == _expected_signal) { 202 if (_quietness <= 0) { 203 printf("Child process died with expected signal " 204 "%d.\n", signal); 205 } 206 normal_exit = TRUE; 207 } else { 208 printf("Child process unexpectedly died with signal " 209 "%d.\n", signal); 210 } 211 } else { 212 printf("Child process unexpectedly did not exit nor " 213 "die.\n"); 214 } 215 die_on_stdout_error(); 216 return normal_exit; 217} 218 219/* Run a test in its own process, and report the result. */ 220static boolean_t child_test_passed(suite_t *suite, 221 unit_test_t *unit_test) 222{ 223 int test_status; 224 225 pid_t test_pid = fork(); 226 die(test_pid == -1, "fork()"); 227 if (!test_pid) { 228 run_test(suite, unit_test); 229 exit(0); 230 } 231 while (waitpid(test_pid, &test_status, 0) != test_pid) { 232 continue; 233 } 234 boolean_t test_result = child_terminated_normally(test_status); 235 log_test_result(unit_test, test_result); 236 return test_result; 237} 238 239/* Run each test in a suite, and report the results. */ 240static int count_passed_suite_tests(suite_t *suite) 241{ 242 int passed_tests = 0; 243 int i; 244 245 for (i = 0; i < suite->numoftests; i++) { 246 passed_tests += child_test_passed(suite, 247 &(suite->tests[i])); 248 } 249 return passed_tests; 250} 251 252/********************/ 253/* Public interface */ 254/********************/ 255 256#define DEFAULT_TIMEOUT 5U 257#define DEFAULT_QUIETNESS 1 258 259#define assert(condition, exit_status, ...) \ 260 if (!(condition)) { \ 261 _fatal(__FILE__, __LINE__, __func__, \ 262 (exit_status), __VA_ARGS__); \ 263 } 264 265/* Include in tests whose expected outcome is a specific signal. */ 266#define expect_signal(signal) \ 267 struct sigaction _act; \ 268 _act.sa_handler = expected_signal_handler; \ 269 sigemptyset(&_act.sa_mask); \ 270 _act.sa_flags = 0; \ 271 assert(sigaction((signal), &_act, NULL) == 0, 1, \ 272 "sigaction() error: %s.", strerror(errno)); 273 274#define run_suite(set_up, tests, tear_down, ...) \ 275 _run_suite((sizeof(tests)/sizeof(tests[0])), \ 276 (set_up), (tests), (tear_down), __VA_ARGS__) 277 278typedef unit_test_t UnitTests[]; 279 280void _fatal(const char *file, int line, const char *function, 281 int exit_status, const char *format, ...) 282 __printflike(5, 6); 283void _run_suite(int numoftests, test_fn_t set_up, UnitTests tests, 284 test_fn_t tear_down, const char *format, ...) 285 __printflike(5, 6); 286void logv(char *format, ...) __printflike(1, 2); 287 288void _fatal(const char *file, int line, const char *function, 289 int exit_status, const char *format, ...) 290{ 291 va_list ap; 292 293 va_start(ap, format); 294 vprintf(format, ap); 295 printf("\n"); 296 printf("Assert failed in file %s, function %s(), line %d.\n", 297 file, function, line); 298 va_end(ap); 299 exit(exit_status); 300} 301 302void _run_suite(int numoftests, test_fn_t set_up, UnitTests tests, 303 test_fn_t tear_down, const char *format, ...) 304{ 305 va_list ap; 306 char *name; 307 308 va_start(ap, format); 309 die(vasprintf(&name, format, ap) == -1, "vasprintf()"); 310 va_end(ap); 311 suite_t *suite = create_suite(name, numoftests, set_up, tests, 312 tear_down); 313 log_suite_info(suite); 314 log_suite_results(suite, count_passed_suite_tests(suite)); 315 free(name); 316 destroy_suite(suite); 317} 318 319/* Signal handler for tests expected to terminate with a specific 320 * signal. */ 321void expected_signal_handler(int signo) 322{ 323 write(1,"Child process received expected signal.\n", 324 strlen("Child process received expected signal.\n")); 325 _Exit(0); 326} 327 328/* Setters and getters for various test framework global 329 * variables. Should only be used outside of the test, set up and tear 330 * down functions. */ 331 332/* Time out constraint for running a single test. */ 333void set_timeout(unsigned int time) 334{ 335 _timeout = time; 336} 337 338unsigned int get_timeout() 339{ 340 return _timeout; 341} 342 343/* Expected signal for a test, default is 0. */ 344void set_expected_signal(int signal) 345{ 346 _expected_signal = signal; 347} 348 349int get_expected_signal() 350{ 351 return _expected_signal; 352} 353 354/* Logging verbosity. */ 355void set_quietness(int value) 356{ 357 _quietness = value; 358} 359 360int get_quietness() 361{ 362 return _quietness; 363} 364 365/* For fixture set up and tear down functions, and units tests. */ 366void do_nothing() { 367} 368 369/* Verbose (default) logging. */ 370void logv(char *format, ...) 371{ 372 if (get_quietness() <= 0) { 373 va_list ap; 374 375 va_start(ap, format); 376 vprintf(format, ap); 377 va_end(ap); 378 die_on_stdout_error(); 379 } 380} 381 382void log_aggregated_results() 383{ 384 printf("[SUMMARY] Aggregated Test Results\n"); 385 printf("Total: %ju\n", results.numoftests); 386 printf("Passed: %ju\n", results.passed_tests); 387 printf("Failed: %ju\n\n", results.numoftests 388 - results.passed_tests); 389 die_on_stdout_error(); 390} 391 392/*******************************/ 393/*******************************/ 394/* pipes buffer unit testing */ 395/*******************************/ 396/*******************************/ 397 398static const char progname[] = "pipes_unitester"; 399 400static void die_on_error(int condition, const char *culprit) 401{ 402 assert(!condition, 1, "%s: %s error: %s.", progname, culprit, 403 strerror(errno)); 404} 405 406 407/*******************************/ 408/* Usage and option processing */ 409/*******************************/ 410 411static void usage(int exit_status) 412{ 413 printf("Usage : %s\n", progname); 414 exit(exit_status); 415} 416 417static void die_on_invalid_value(int condition, 418 const char *value_string) 419{ 420 if (condition) { 421 printf("%s: invalid value: %s.\n", progname, value_string); 422 usage(1); 423 } 424} 425 426/* Convert a storage unit suffix into an exponent. */ 427static int strtoexp(const char *string) 428{ 429 if (string[0] == '\0') { 430 return 0; 431 } 432 433 char first_letter = toupper(string[0]); 434 char prefixes[] = "BKMGTPE"; 435 const int numofprefixes = strlen(prefixes); 436 prefixes[numofprefixes] = first_letter; 437 int i = 0; 438 439 while (prefixes[i] != first_letter) { 440 i++; 441 } 442 die_on_invalid_value(i >= numofprefixes || (string[1] != '\0' && 443 (toupper(string[1]) 444 != 'B' || string[2] 445 != '\0')), string); 446 return 10 * i; 447} 448 449static void process_options(int argc, char *argv[]) 450{ 451 int opt; 452 char *endptr; 453 454 setvbuf(stdout, NULL, _IONBF, 0); 455 456 set_timeout(DEFAULT_TIMEOUT); 457 set_quietness(DEFAULT_QUIETNESS); 458 459 while ((opt = getopt(argc, argv, "t:vqh")) != -1) { 460 switch (opt) { 461 case 't': 462 errno = 0; 463 set_timeout(strtoul(optarg, &endptr, 0)); 464 die_on_invalid_value(errno == ERANGE || *endptr != '\0' 465 || endptr == optarg, optarg); 466 break; 467 case 'q': 468 set_quietness(get_quietness() + 1); 469 break; 470 case 'v': 471 set_quietness(0); 472 break; 473 case 'h': 474 usage(0); 475 break; 476 default: 477 usage(1); 478 break; 479 } 480 } 481} 482 483/*********************************/ 484/* Various function declarations */ 485/*********************************/ 486 487void initialize_data(int *ptr, int len); 488 489int verify_data(int *base, int *target, int len); 490 491void clear_data(int *ptr, int len); 492 493/*******************************/ 494/* Arrays for test suite loops */ 495/*******************************/ 496 497#define BUFMAX 20000 498#define BUFMAXLEN (BUFMAX * sizeof(int)) 499 500const unsigned int pipesize_blocks[] = {128,256,1024,2048,PAGE_SIZE,PAGE_SIZE*2,PAGE_SIZE*4}; 501static const int bufsizes[] = { 128, 512, 1024, 2048, 4096, 16384 }; 502 503int data[BUFMAX],readbuf[BUFMAX]; 504int pipefd[2] = {0,0}; 505 506typedef int * pipe_t; 507 508struct thread_work_data { 509 pipe_t p; 510 unsigned int total_bytes; 511 unsigned int chunk_size; 512}; 513 514void * reader_thread(void *ptr); 515void * writer_thread(void *ptr); 516 517dispatch_semaphore_t r_sem, w_sem; 518 519unsigned long current_buf_size=0; 520 521/*************************************/ 522/* Global variables set up functions */ 523/*************************************/ 524 525 526void initialize_data(int *ptr, int len) 527{ 528 int i; 529 if (!ptr || len <=0 ) 530 return; 531 532 for (i = 0; i < len; i ++) 533 ptr[i] = i; 534} 535 536void clear_data(int *ptr, int len) 537{ 538 539 int i; 540 if (!ptr) 541 return; 542 for (i = 0; i < len; i++) 543 ptr[i]=0; 544} 545 546int verify_data(int *base, int *target, int len) 547{ 548 int i = 0; 549 550 if (!base || !target) 551 return 0; 552 553 for (i = 0; i < len; i++){ 554 if (base[i] != target[i]) 555 return 0; 556 } 557 558 return 1; 559} 560 561void initialize_data_buffer() 562{ 563 initialize_data(data, BUFMAX); 564 initialize_data(readbuf, BUFMAX); 565} 566 567/*******************************/ 568/* core read write helper funtions */ 569/*******************************/ 570 571ssize_t read_whole_buffer(pipe_t p, void *scratch_buf, int size); 572ssize_t pipe_read_data(pipe_t p, void *dest_buf, int size); 573ssize_t pipe_write_data(pipe_t p, void *src_buf, int size); 574 575ssize_t read_whole_buffer(pipe_t p, void *scratch_buf, int size) 576{ 577 int fd = p[0]; 578 logv("reading whole buffer from fd %d, size %d", fd, size); 579 int retval = pread(fd, scratch_buf, size, 0); 580 if (retval == -1 ){ 581 logv("Error reading whole buffer. (%d) %s\n",errno, strerror(errno)); 582 } 583 return retval; 584 585} 586 587ssize_t pipe_read_data(pipe_t p, void *dest_buf, int size) 588{ 589 int fd = p[0]; 590 //logv("reading from pipe %d, for size %d", fd, size); 591 int retval = read(fd, dest_buf, size); 592 if (retval == -1) { 593 logv("Error reading from buffer. (%d)",errno); 594 } 595 return retval; 596} 597 598ssize_t pipe_write_data(pipe_t p, void *src_buf, int size) 599{ 600 int fd = p[1]; 601 //logv("writing to pipe %d, for size %d", fd, size); 602 int retval = write(fd, src_buf, size); 603 if (retval == -1) { 604 logv("Error writing to buffer. (%d) %s",errno, strerror(errno)); 605 } 606 return retval; 607} 608 609 610void * reader_thread(void *ptr) 611{ 612 struct thread_work_data *m; 613 m = (struct thread_work_data *) ptr; 614 int i = m->total_bytes/m->chunk_size; 615 int retval, data_idx=0; 616 while (i > 0){ 617 dispatch_semaphore_wait(r_sem, 8000); 618 retval = pipe_read_data(m->p, &readbuf[data_idx], m->chunk_size); 619 assert(retval == m->chunk_size, 1, "Pipe read returned different amount of numbe"); 620 data_idx +=m->chunk_size; 621 //logv("RD %d \n", m->chunk_size); 622 dispatch_semaphore_signal(w_sem); 623 i--; 624 } 625 return 0; 626} 627 628void * writer_thread(void *ptr) 629{ 630 struct thread_work_data *m; 631 m = (struct thread_work_data *)ptr; 632 int i = m->total_bytes/m->chunk_size; 633 int retval, data_idx=0; 634 while ( i > 0 ){ 635 636 dispatch_semaphore_wait(w_sem, 8000); 637 //logv("WR %d \n", m->chunk_size); 638 retval=pipe_write_data(m->p, &data[data_idx], m->chunk_size); 639 assert(retval == m->chunk_size, 1, "Pipe write failed"); 640 data_idx +=m->chunk_size; 641 dispatch_semaphore_signal(r_sem); 642 i--; 643 } 644 return 0; 645} 646 647 648void create_threads(struct thread_work_data *rdata, struct thread_work_data *wdata){ 649 650 pthread_t thread1, thread2; 651 r_sem = dispatch_semaphore_create(0); 652 w_sem = dispatch_semaphore_create(1); 653 int iret1, iret2; 654 void * thread_ret1 =0; 655 void * thread_ret2 =0; 656 /* Create independent threads each of which will execute function */ 657 658 iret1 = pthread_create( &thread1, NULL, reader_thread, (void*) rdata); 659 iret2 = pthread_create( &thread2, NULL, writer_thread, (void*) wdata); 660 661 pthread_join( thread2, &thread_ret1); 662 pthread_join( thread1, &thread_ret1); 663 assert(thread_ret1 == 0, 1, "Reader Thread Failed"); 664 assert(thread_ret2 == 0, 1, "Writer Thread Failed"); 665} 666 667 668/*******************************/ 669/* Pipes unit test functions */ 670/*******************************/ 671void test_pipebuffer_setup () 672{ 673 674 logv("Setting up buffers data and readbuf\n"); 675 clear_data(data, BUFMAX); 676 clear_data(readbuf, BUFMAX); 677 logv("Initializing buffers data and readbuf\n"); 678 initialize_data(data, BUFMAX); 679 initialize_data(readbuf, BUFMAX); 680 logv("verifying data for correctness\n"); 681 die_on_error(!verify_data(data, readbuf, BUFMAX), "data initialization"); 682 clear_data(readbuf, BUFMAX); 683} 684 685void test_pipe_create(){ 686 int pipefds[2] = {0,0}; 687 pipe_t p = pipefds; 688 int err = pipe(p); 689 if ( err ){ 690 logv("error opening pipes (%d) %s", errno, strerror(errno)); 691 return; 692 } 693 694 die_on_error(0 != close(pipefds[0]), "close()"); 695 die_on_error(0 != close(pipefds[1]), "close()"); 696} 697 698void test_pipe_write_single_byte(){ 699 int pipefds[2] = { 0 , 0 }; 700 pipe_t p = pipefds; 701 die_on_error( 0 != pipe(p), "pipe()"); 702 initialize_data_buffer(); 703 int i = 0,retval; 704 for ( ; i < current_buf_size; i++){ 705 if ( i > 16384){ 706 logv("cannot fill continuously beyond 16K."); 707 break; 708 } 709 retval=pipe_write_data(p, &data[i], 1); 710 assert(retval == 1, 1, "Pipe write failed"); 711 } 712 713 close(p[0]); 714 close(p[1]); 715} 716 717void test_pipe_single_read_write(){ 718 int pipefds[2] = { 0 , 0 }; 719 pipe_t p = pipefds; 720 die_on_error( 0 != pipe(p), "pipe()"); 721 initialize_data_buffer(); 722 struct thread_work_data d = { p, current_buf_size, 1}; 723 create_threads(&d, &d); 724 verify_data(data, readbuf, current_buf_size); 725 close(p[0]); 726 close(p[1]); 727 728} 729 730void test_pipe_single_read_2write(){ 731 int pipefds[2] = { 0 , 0 }; 732 pipe_t p = pipefds; 733 die_on_error( 0 != pipe(p), "pipe()"); 734 initialize_data_buffer(); 735 struct thread_work_data rd = { p, current_buf_size, 1}; 736 struct thread_work_data wd = { p, current_buf_size, 2}; 737 create_threads(&rd, &wd); 738 verify_data(data, readbuf, current_buf_size); 739 close(p[0]); 740 close(p[1]); 741 742} 743 744void test_pipe_expansion_buffer(){ 745 int pipefds[2] = { 0 , 0 }; 746 int iter = 0; 747 pipe_t p = pipefds; 748 die_on_error( 0 != pipe(p), "pipe()"); 749 initialize_data_buffer(); 750 for ( iter=0; iter < sizeof(pipesize_blocks)/sizeof(unsigned int); iter++){ 751 assert(pipesize_blocks[iter] == pipe_write_data(p, &data[0], pipesize_blocks[iter] ), 1, "expansion write failed"); 752 assert(pipesize_blocks[iter] == pipe_read_data(p, &readbuf[0], pipesize_blocks[iter]+200), 1, "reading from expanded data failed"); 753 /* logv("finished round for size %u \n", pipesize_blocks[iter]); */ 754 } 755 verify_data(data, readbuf, current_buf_size); 756 close(p[0]); 757 close(p[1]); 758 759} 760 761void test_pipe_initial_big_allocation(){ 762 int pipefds[2] = { 0 , 0 }; 763 int iter = 0; 764 pipe_t p = pipefds; 765 die_on_error( 0 != pipe(p), "pipe()"); 766 initialize_data_buffer(); 767 assert(current_buf_size == pipe_write_data(p, &data[0], current_buf_size ), 1, "initial big allocation failed"); 768 assert(current_buf_size == pipe_read_data(p, &readbuf[0], current_buf_size+200), 1, "reading from initial big write failed"); 769 assert(verify_data(data, readbuf, current_buf_size), 1, "big pipe initial allocation -not able to verify data"); 770 close(p[0]); 771 close(p[1]); 772 773} 774 775void test_pipe_cycle_small_writes(){ 776 int pipefds[2] = { 0 , 0 }; 777 int iter = 0; 778 pipe_t p = pipefds; 779 die_on_error( 0 != pipe(p), "pipe()"); 780 initialize_data_buffer(); 781 int buf_size = current_buf_size / 2; 782 783 assert(buf_size == pipe_write_data(p, &data[0], buf_size ), 1, "cycle write failed"); 784 assert(buf_size == pipe_read_data(p, &readbuf[0], buf_size+200), 1, "reading from cycle read failed"); 785 assert(verify_data(data, readbuf, buf_size), 1, "data verification failed"); 786 787 assert(buf_size == pipe_write_data(p, &data[0], buf_size ), 1, "cycle write failed"); 788 assert(buf_size == pipe_read_data(p, &readbuf[0], buf_size+200), 1, "reading from cycle read failed"); 789 assert(verify_data(data, readbuf, buf_size), 1, "data verification failed"); 790 791 assert(buf_size == pipe_write_data(p, &data[0], buf_size ), 1, "cycle write failed"); 792 assert(buf_size == pipe_read_data(p, &readbuf[0], buf_size+200), 1, "reading from cycle read failed"); 793 assert(verify_data(data, readbuf, buf_size), 1, "data verification failed"); 794 795 close(p[0]); 796 close(p[1]); 797 798} 799 800void test_pipe_moving_data(){ 801 int pipefds[2] = { 0 , 0 }; 802 int iter = 0; 803 pipe_t p = pipefds; 804 die_on_error( 0 != pipe(p), "pipe()"); 805 initialize_data_buffer(); 806 int buf_size = current_buf_size / 2; 807 if (buf_size > PAGE_SIZE) 808 buf_size = PAGE_SIZE; 809 810 assert(buf_size == pipe_write_data(p, &data[0], buf_size ), 1, "cycle write failed"); 811 logv("write of size =%d\n", buf_size); 812 assert(buf_size == pipe_write_data(p, &data[buf_size/sizeof(int)], buf_size ), 1, "cycle write failed"); 813 logv("write of size =%d\n", buf_size*2); 814 assert(buf_size == pipe_write_data(p, &data[(buf_size*2)/sizeof(int)], buf_size ), 1, "cycle write failed"); 815 logv("write of size =%d\n", buf_size*3); 816 assert((3*buf_size) == pipe_read_data(p, &readbuf[0], (3*buf_size)+200), 1, "reading from cycle read failed"); 817 assert(verify_data(data, readbuf, (3*buf_size)/sizeof(int)), 1, "data verification failed"); 818 819 close(p[0]); 820 close(p[1]); 821 822} 823 824 825/*************/ 826/* pipe Suites */ 827/*************/ 828 829void run_pipe_basic_tests() 830{ 831 int sizes_idx; 832 int numofsizes = sizeof(bufsizes)/sizeof(int); 833 834 logv("running tests for %d different sizes \n", numofsizes); 835 836 UnitTests pipe_basic_tests = { 837 { "1. create buffer and verify both reads/writes are valid", 838 test_pipebuffer_setup }, 839 { "2. open and close pipes", test_pipe_create }, 840 { "3. single byte write to full", test_pipe_write_single_byte}, 841 { "4. single byte read/write in sync", test_pipe_single_read_write}, 842 { "5. single byte read/2write in sync", test_pipe_single_read_2write}, 843 { "6. expansion from existing size", test_pipe_expansion_buffer}, 844 { "7. initial big allocation " , test_pipe_initial_big_allocation}, 845 { "8. cycle_small_writes " ,test_pipe_cycle_small_writes }, 846 { "9. test moving data " ,test_pipe_moving_data } 847 }; 848 for (sizes_idx = 0; sizes_idx < numofsizes; sizes_idx++) { 849 current_buf_size = bufsizes[sizes_idx]; 850 run_suite(do_nothing, 851 pipe_basic_tests, 852 do_nothing, "pipe create base test " 853 "Size: 0x%jx (%ju)", 854 (uintmax_t)bufsizes[sizes_idx], 855 (uintmax_t)bufsizes[sizes_idx]); 856 } 857} 858 859 860int pipes_test(void *the_argp) 861{ 862 set_quietness(2); 863 run_pipe_basic_tests(); 864 //log_aggregated_results(); 865 return results.numoftests - results.passed_tests; 866} 867 868/* 869 * retaining the old main function to debug issues with the tests and not the xnu_quick_test framework 870 * or the system 871 */ 872int main_nonuse(int argc, char *argv[]) 873{ 874 process_options(argc, argv); 875 876 run_pipe_basic_tests(); 877 878 log_aggregated_results(); 879 return 0; 880} 881