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