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