int main(int argc, char *argv[]) { char *zooname; zoo_t test_zoo; char *test_tag = "unittest"; int i,j; zooname = zoo_getname(); if (!zooname) { zooname = strdup("test_zoo"); } printf("Test zoo filename is %s\n", zooname); if ((test_zoo = zoo_open(zooname)) == NULL) { printf("Error opennning zoo\n"); exit(-1); } zoo_mark_args(test_zoo, getpid(), test_tag, argc, argv); for (j = 0; j < 5; j++) { for (i = 0; i < 20; i++) { zt_add(test_zoo, i); } for (; i >=0; i--) { zoo_clear(test_zoo, i); } } zoo_clear(test_zoo, getpid()); return 0; }
int main(int argc, char **argv) { extern char *optarg; extern int optind; char *zooname = NULL; /* name of the zoo file to use */ char *filename = "/dev/null"; /* filename to read test tags from */ char *logfilename = NULL; char *failcmdfilename = NULL; char *tconfcmdfilename = NULL; char *outputfilename = NULL; struct collection *coll = NULL; struct tag_pgrp *running; struct orphan_pgrp *orphans, *orph; struct utsname unamebuf; FILE *logfile = NULL; FILE *failcmdfile = NULL; FILE *tconfcmdfile = NULL; int keep_active = 1; int num_active = 0; int failcnt = 0; /* count of total testcases that failed. */ int tconfcnt = 0; /* count of total testcases that return TCONF */ int err, i; int starts = -1; int timed = 0; int run_time = -1; char modifier = 'm'; int ret = 0; int stop; int go_idle; int has_brakes = 0; /* stop everything if a test case fails */ int sequential = 0; /* run tests sequentially */ int fork_in_road = 0; int exit_stat; int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */ int fmt_print = 0; /* enables formatted printing of logfiles. */ int quiet_mode = 0; /* supresses test start and test end tags. */ int c; pid_t cpid; struct sigaction sa; while ((c = getopt(argc, argv, "AO:Sa:C:T:d:ef:hl:n:o:pqr:s:t:x:y")) != -1) { switch (c) { case 'A': /* all-stop flag */ has_brakes = 1; track_exit_stats = 1; break; case 'O': /* output buffering directory */ test_out_dir = strdup(optarg); break; case 'S': /* run tests sequentially */ sequential = 1; break; case 'a': /* name of the zoo file to use */ zooname = strdup(optarg); break; case 'C': /* name of the file where all failed commands will be */ failcmdfilename = strdup(optarg); break; case 'T': /* * test cases that are not fully tested will be recorded * in this file */ tconfcmdfilename = strdup(optarg); break; case 'd': /* debug options */ sscanf(optarg, "%i", &Debug); break; case 'e': /* exit non-zero if any test exists non-zero */ track_exit_stats = 1; break; case 'f': /* filename to read test tags from */ filename = strdup(optarg); break; case 'h': /* help */ fprintf(stdout, "Usage: pan -n name [ -SyAehpq ] [ -s starts ]" " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t" "[ -a active-file ] [ -f command-file ] " "[ -C fail-command-file ] " "[ -d debug-level ]\n\t[-o output-file] " "[-O output-buffer-directory] [cmd]\n"); exit(0); case 'l': /* log file */ logfilename = strdup(optarg); break; case 'n': /* tag given to pan */ panname = strdup(optarg); break; case 'o': /* send test output here */ outputfilename = strdup(optarg); break; case 'p': /* formatted printing. */ fmt_print = 1; break; case 'q': /* supress test start and test end messages */ quiet_mode = 1; break; case 'r': /* reporting type: none, rts */ reporttype = strdup(optarg); break; case 's': /* number of tags to run */ starts = atoi(optarg); break; case 't': /* run_time to run */ ret = sscanf(optarg, "%d%c", &run_time, &modifier); if (ret == 0) { fprintf(stderr, "Need proper time input: ####x where" "x is one of s,m,h,d\n"); break; } else if (ret == 1) { fprintf(stderr, "Only got a time value of %d " "modifiers need to come immediately after #" " assuming %c\n", run_time, modifier); } else { switch (modifier) { case 's': run_time = run_time; break; case 'm': run_time = run_time * 60; break; case 'h': run_time = run_time * 60 * 60; break; case 'd': run_time = run_time * 60 * 60 * 24; break; default: fprintf(stderr, "Invalid time modifier, try: s|h|m|d\n"); exit(-1); } if (!quiet_mode) printf("PAN will run for %d seconds\n", run_time); } timed = 1; //-t implies run as many starts as possible, by default break; case 'x': /* number of tags to keep running */ keep_active = atoi(optarg); break; case 'y': /* restart on failure or signal */ fork_in_road = 1; break; } } if (panname == NULL) { fprintf(stderr, "pan: Must supply -n\n"); exit(1); } if (zooname == NULL) { zooname = zoo_getname(); if (zooname == NULL) { fprintf(stderr, "pan(%s): Must supply -a or set ZOO env variable\n", panname); exit(1); } } if (reporttype) { /* make sure we understand the report type */ if (strcasecmp(reporttype, "rts") && strcasecmp(reporttype, "none") /* && strcasecmp(reporttype, "xml") */ ) reporttype = "rts"; } else { /* set the default */ reporttype = "rts"; } if (logfilename != NULL) { time_t startup; char *s; if (!strcmp(logfilename, "-")) { logfile = stdout; } else { if ((logfile = fopen(logfilename, "a+")) == NULL) { fprintf(stderr, "pan(%s): Error %s (%d) opening log file '%s'\n", panname, strerror(errno), errno, logfilename); exit(1); } } time(&startup); s = ctime(&startup); *(s + strlen(s) - 1) = '\0'; if (!fmt_print) fprintf(logfile, "startup='%s'\n", s); else { fprintf(logfile, "Test Start Time: %s\n", s); fprintf(logfile, "-----------------------------------------\n"); fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", "Testcase", "Result", "Exit Value"); fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", "--------", "------", "------------"); } fflush(logfile); } coll = get_collection(filename, optind, argc, argv); if (!coll) exit(1); if (coll->cnt == 0) { fprintf(stderr, "pan(%s): Must supply a file collection or a command\n", panname); exit(1); } if (Debug & Dsetup) dump_coll(coll); /* a place to store the pgrps we're watching */ running = malloc((keep_active + 1) * sizeof(struct tag_pgrp)); if (running == NULL) { fprintf(stderr, "pan(%s): Failed to allocate memory: %s\n", panname, strerror(errno)); exit(2); } memset(running, 0, keep_active * sizeof(struct tag_pgrp)); running[keep_active].pgrp = -1; /* end sentinel */ /* a head to the orphaned pgrp list */ orphans = malloc(sizeof(struct orphan_pgrp)); memset(orphans, 0, sizeof(struct orphan_pgrp)); srand48(time(NULL) ^ (getpid() + (getpid() << 15))); /* Supply a default for starts. If we are in sequential mode, use * the number of commands available; otherwise 1. */ if (timed == 1 && starts == -1) { /* timed, infinite by default */ starts = -1; } else if (starts == -1) { if (sequential) { starts = coll->cnt; } else { starts = 1; } } else if (starts == 0) { /* if the user specified infinite, set it */ starts = -1; } else { /* else, make sure we are starting at least keep_active processes */ if (starts < keep_active) starts = keep_active; } /* if we're buffering output, but we're only running on process at a time, * then essentially "turn off buffering" */ if (test_out_dir && (keep_active == 1)) { free(test_out_dir); test_out_dir = NULL; } if (test_out_dir) { struct stat sbuf; if (stat(test_out_dir, &sbuf) < 0) { fprintf(stderr, "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n", panname, test_out_dir, errno, strerror(errno)); exit(1); } if (!S_ISDIR(sbuf.st_mode)) { fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n", panname, test_out_dir); exit(1); } if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) { fprintf(stderr, "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n", panname, test_out_dir, errno, strerror(errno)); exit(1); } } if (outputfilename) { if (!freopen(outputfilename, "a+", stdout)) { fprintf(stderr, "pan(%s): Error %s (%d) opening output file '%s'\n", panname, strerror(errno), errno, outputfilename); exit(1); } } if (failcmdfilename) { if (!(failcmdfile = fopen(failcmdfilename, "a+"))) { fprintf(stderr, "pan(%s): Error %s (%d) opening fail cmd file '%s'\n", panname, strerror(errno), errno, failcmdfilename); exit(1); } } if (tconfcmdfilename) { tconfcmdfile = fopen(tconfcmdfilename, "a+"); if (!tconfcmdfile) { fprintf(stderr, "pan(%s): Error %s (%d) opening " "tconf cmd file '%s'\n", panname, strerror(errno), errno, tconfcmdfilename); exit(1); } } if ((zoofile = zoo_open(zooname)) == NULL) { fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); exit(1); } if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) { fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); exit(1); } /* Allocate N spaces for max-arg commands. * this is an "active file cleanliness" thing */ { for (c = 0; c < keep_active; c++) { if (zoo_mark_cmdline(zoofile, c, panname, "")) { fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); exit(1); } } for (c = 0; c < keep_active; c++) { if (zoo_clear(zoofile, c)) { fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); exit(1); } } } rec_signal = send_signal = 0; if (run_time != -1) { alarm(run_time); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = wait_handler; sigaction(SIGALRM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); /* ignore fork_in_road */ sigaction(SIGUSR2, &sa, NULL); /* stop the scheduler */ c = 0; /* in this loop, c is the command index */ stop = 0; exit_stat = 0; go_idle = 0; while (1) { while ((num_active < keep_active) && (starts != 0)) { if (stop || rec_signal || go_idle) break; if (!sequential) c = lrand48() % coll->cnt; /* find a slot for the child */ for (i = 0; i < keep_active; ++i) { if (running[i].pgrp == 0) break; } if (i == keep_active) { fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n", panname, i); wait_handler(SIGINT); exit_stat++; break; } cpid = run_child(coll->ary[c], running + i, quiet_mode, &failcnt, fmt_print, logfile); if (cpid != -1) ++num_active; if ((cpid != -1 || sequential) && starts > 0) --starts; if (sequential) if (++c >= coll->cnt) c = 0; } /* while ((num_active < keep_active) && (starts != 0)) */ if (starts == 0) { if (!quiet_mode) printf("incrementing stop\n"); ++stop; } else if (starts == -1) //wjh { FILE *f = (FILE *) - 1; if ((f = fopen(PAN_STOP_FILE, "r")) != 0) { printf("Got %s Stopping!\n", PAN_STOP_FILE); fclose(f); unlink(PAN_STOP_FILE); stop++; } } if (rec_signal) { /* propagate everything except sigusr2 */ if (rec_signal == SIGUSR2) { if (fork_in_road) ++go_idle; else ++stop; rec_signal = send_signal = 0; } else { if (rec_signal == SIGUSR1) fork_in_road = 0; propagate_signal(running, keep_active, orphans); if (fork_in_road) ++go_idle; else ++stop; } } err = check_pids(running, &num_active, keep_active, logfile, failcmdfile, tconfcmdfile, orphans, fmt_print, &failcnt, &tconfcnt, quiet_mode); if (Debug & Drunning) { pids_running(running, keep_active); orphans_running(orphans); } if (err) { if (fork_in_road) ++go_idle; if (track_exit_stats) exit_stat++; if (has_brakes) { fprintf(stderr, "pan(%s): All stop!%s\n", panname, go_idle ? " (idling)" : ""); wait_handler(SIGINT); } } if (stop && (num_active == 0)) break; if (go_idle && (num_active == 0)) { go_idle = 0; /* It is idle, now resume scheduling. */ wait_handler(0); /* Reset the signal ratchet. */ } } /* Wait for orphaned pgrps */ while (1) { for (orph = orphans; orph != NULL; orph = orph->next) { if (orph->pgrp == 0) continue; /* Yes, we have orphaned pgrps */ sleep(5); if (!rec_signal) { /* force an artificial signal, move us * through the signal ratchet. */ wait_handler(SIGINT); } propagate_signal(running, keep_active, orphans); if (Debug & Drunning) orphans_running(orphans); break; } if (orph == NULL) break; } if (zoo_clear(zoofile, getpid())) { fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); ++exit_stat; } fclose(zoofile); if (logfile && fmt_print) { if (uname(&unamebuf) == -1) fprintf(stderr, "ERROR: uname(): %s\n", strerror(errno)); fprintf(logfile, "\n-----------------------------------------------\n"); fprintf(logfile, "Total Tests: %d\n", coll->cnt); fprintf(logfile, "Total Skipped Tests: %d\n", tconfcnt); fprintf(logfile, "Total Failures: %d\n", failcnt); fprintf(logfile, "Kernel Version: %s\n", unamebuf.release); fprintf(logfile, "Machine Architecture: %s\n", unamebuf.machine); fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename); } if (logfile && (logfile != stdout)) fclose(logfile); if (failcmdfile) fclose(failcmdfile); if (tconfcmdfile) fclose(tconfcmdfile); exit(exit_stat); }