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