]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/xnu_quick_test/pipes_tests.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / pipes_tests.c
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
59 static const char frameworkname[] = "pipes_unitester";
60
61 /* Type for test, fixture set up and fixture tear down functions. */
62 typedef void (*test_fn_t)();
63
64 /* Unit test structure. */
65 typedef struct {
66 const char *name;
67 test_fn_t test;
68 } unit_test_t;
69
70 /* Test suite structure. */
71 typedef 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
79 int _quietness = 0;
80 unsigned int _timeout = 0;
81 int _expected_signal = 0;
82
83 struct {
84 uintmax_t numoftests;
85 uintmax_t passed_tests;
86 } results = { 0, 0 };
87
88 void logr(char *format, ...) __printflike(1, 2);
89
90 static 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
99 static void die_on_stdout_error()
100 {
101 die(ferror(stdout), "stdout");
102 }
103
104 /* Individual test result logging. */
105 void 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
117 static 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
132 static void destroy_suite(suite_t *suite)
133 {
134 free(suite);
135 }
136
137 static 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
143 static 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
149 static void log_test_info(unit_test_t *unit_test)
150 {
151 logr("[BEGIN] %s\n", unit_test->name);
152 }
153
154 static 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. */
162 static 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. */
171 static 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. */
188 static 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. */
221 static 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. */
241 static 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
279 typedef unit_test_t UnitTests[];
280
281 void _fatal(const char *file, int line, const char *function,
282 int exit_status, const char *format, ...)
283 __printflike(5, 6);
284 void _run_suite(int numoftests, test_fn_t set_up, UnitTests tests,
285 test_fn_t tear_down, const char *format, ...)
286 __printflike(5, 6);
287 void logv(char *format, ...) __printflike(1, 2);
288
289 void _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
303 void _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. */
322 void 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. */
334 void set_timeout(unsigned int time)
335 {
336 _timeout = time;
337 }
338
339 unsigned int get_timeout()
340 {
341 return _timeout;
342 }
343
344 /* Expected signal for a test, default is 0. */
345 void set_expected_signal(int signal)
346 {
347 _expected_signal = signal;
348 }
349
350 int get_expected_signal()
351 {
352 return _expected_signal;
353 }
354
355 /* Logging verbosity. */
356 void set_quietness(int value)
357 {
358 _quietness = value;
359 }
360
361 int get_quietness()
362 {
363 return _quietness;
364 }
365
366 /* For fixture set up and tear down functions, and units tests. */
367 void do_nothing() {
368 }
369
370 /* Verbose (default) logging. */
371 void 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
383 void 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
399 static const char progname[] = "pipes_unitester";
400
401 static 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
412 static void usage(int exit_status)
413 {
414 printf("Usage : %s\n", progname);
415 exit(exit_status);
416 }
417
418 static 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. */
428 static 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
450 static 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
488 void initialize_data(int *ptr, int len);
489
490 int verify_data(int *base, int *target, int len);
491
492 void 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
501 const unsigned int pipesize_blocks[] = {128,256,1024,2048,PAGE_SIZE,PAGE_SIZE*2,PAGE_SIZE*4};
502 static const int bufsizes[] = { 128, 512, 1024, 2048, 4096, 16384 };
503
504 int data[BUFMAX],readbuf[BUFMAX];
505 int pipefd[2] = {0,0};
506
507 typedef int * pipe_t;
508
509 struct thread_work_data {
510 pipe_t p;
511 unsigned int total_bytes;
512 unsigned int chunk_size;
513 };
514
515 void * reader_thread(void *ptr);
516 void * writer_thread(void *ptr);
517
518 dispatch_semaphore_t r_sem, w_sem;
519
520 unsigned long current_buf_size=0;
521
522 /*************************************/
523 /* Global variables set up functions */
524 /*************************************/
525
526
527 void 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
537 void 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
547 int 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
562 void 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
572 ssize_t read_whole_buffer(pipe_t p, void *scratch_buf, int size);
573 ssize_t pipe_read_data(pipe_t p, void *dest_buf, int size);
574 ssize_t pipe_write_data(pipe_t p, void *src_buf, int size);
575
576 ssize_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
588 ssize_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
599 ssize_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
611 void * 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
629 void * 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
649 void 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 /*******************************/
672 void 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
686 void 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
699 void 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
718 void 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
731 void 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
745 void 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
762 void 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
776 void 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
801 void 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
830 void 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
861 int 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 */
873 int 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 }