src/lib/tests/pipelineTester.c 1.5
1.5 2009/12/19 00:23:21 angie
Added must{Open,Read,Write,Close}Fd and mustLseek to common.c, for operations on file descriptors. Some were already in lib/tests/pipelineTester.c - replaced those.
Index: src/lib/tests/pipelineTester.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/tests/pipelineTester.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -b -B -U 1000000 -r1.4 -r1.5
--- src/lib/tests/pipelineTester.c 4 Aug 2006 06:00:20 -0000 1.4
+++ src/lib/tests/pipelineTester.c 19 Dec 2009 00:23:21 -0000 1.5
@@ -1,290 +1,275 @@
/* pipelineTester - test program for pipeline object */
#include "common.h"
#include "pipeline.h"
#include "linefile.h"
#include "options.h"
static char const rcsid[] = "$Id$";
void usage(char *msg)
/* Explain usage and exit. */
{
errAbort(
"%s\n\n"
"pipelineTester - test program for pipeline object\n"
"\n"
"Usage:\n"
" pipelineTester [options] cmdArgs1 [cmdArgs2 ..]\n"
"\n"
"Each cmdArgs are a command and whitespace separated\n"
"arguments to pipe together. Within a cmdArgs, single or\n"
"double quote maybe used to quote words.\n"
"\n"
"Options:\n"
" -exitCode=n - run with no-abort and expect this error code,\n"
" which can be zero.\n"
" -write - create a write pipeline\n"
" -memApi - test memory buffer API\n"
" -pipeData=file - for a read pipeline, data read from the pipeline is copied\n"
" to this file for verification. For a write pipeline, data from this\n"
" file is written to the pipeline.\n"
" -otherEnd=file - file for other end of pipeline\n"
" -stderr=file - file for stderr of pipeline\n"
" -fdApi - use the file descriptor API\n",
msg);
}
static struct optionSpec options[] =
{
{"exitCode", OPTION_INT},
{"write", OPTION_BOOLEAN},
{"memApi", OPTION_BOOLEAN},
{"pipeData", OPTION_STRING},
{"otherEnd", OPTION_STRING},
{"stderr", OPTION_STRING},
{"fdApi", OPTION_BOOLEAN},
{NULL, 0},
};
/* options from command line */
boolean noAbort = FALSE; /* don't abort, check exit code */
int expectExitCode = 0; /* expected exit code */
boolean fdApi = FALSE; /* use the file descriptor API */
boolean isWrite = FALSE; /* make a write pipeline */
boolean memApi = FALSE; /* test memory buffer API */
char *pipeDataFile = NULL; /* use for input or output to the pipeline */
char *otherEndFile = NULL; /* file for other end of pipeline */
char *stderrFile = NULL; /* file for other stderr of pipeline */
int countOpenFiles()
/* count the number of opens. This is used to make sure no stray
* pipes have been left open. */
{
int cnt = 0;
int fd;
struct stat statBuf;
for (fd = 0; fd < 64; fd++)
{
if (fstat(fd, &statBuf) == 0)
cnt++;
}
return cnt;
}
-int mustOpenFd(char *fname, boolean isWrite)
-/* open a file, returning a descriptor or aborting */
-{
-int fd = open(fname, (isWrite ? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY), 0777);
-if (fd < 0)
- errnoAbort("open of %s failed", fname);
-return fd;
-}
-
-void mustCloseFd(int fd)
-/* close a file, abort on an error */
-{
-if (close(fd) < 0)
- errnoAbort("close failed");
-}
-
char *parseQuoted(char **spPtr, char *cmdArgs)
/* parse a quoted string */
{
char *start = *spPtr;
char quote = *start++;
char *end = strchr(start, quote);
if (end == NULL)
errAbort("no closing quote in: %s", cmdArgs);
*spPtr = end+1;
return cloneStringZ(start, end-start);
}
char **splitCmd(char *cmdArgs)
/* split a command and arguments into null termiated list, handling quoting */
{
// this will get the maximum number of words, as it doesn't consider quoting
int maxNumWords = chopByWhite(cmdArgs, NULL, 0);
char **words = needMem((maxNumWords+1)*sizeof(char*));
int iWord = 0;
char *sp = skipLeadingSpaces(cmdArgs);
while (*sp != '\0')
{
assert(iWord < maxNumWords);
if ((*sp == '"') || (*sp == '\''))
words[iWord++] = parseQuoted(&sp, cmdArgs);
else
{
char *end = skipToSpaces(sp);
if (end == NULL)
end = sp + strlen(sp);
words[iWord++] = cloneStringZ(sp, (end - sp));
sp = end;
}
sp = skipLeadingSpaces(sp);
}
return words;
}
char ***splitCmds(int nCmdsArgs, char **cmdsArgs)
/* split all commands into a pipeline */
{
char ***cmds = needMem((nCmdsArgs+1)*sizeof(char**));
int i;
for (i = 0; i < nCmdsArgs; i++)
cmds[i] = splitCmd(cmdsArgs[i]);
return cmds;
}
void readTest(struct pipeline *pl)
/* test a read pipeline */
{
struct lineFile *pipeLf = pipelineLineFile(pl);
FILE *dataFh = mustOpen(pipeDataFile, "w");
char *line;
while (lineFileNext(pipeLf, &line, NULL))
{
fputs(line, dataFh);
fputc('\n', dataFh);
if (ferror(dataFh))
errnoAbort("error writing data from pipeline to: %s", pipeDataFile);
}
carefulClose(&dataFh);
}
void writeTest(struct pipeline *pl)
/* test a write pipeline */
{
FILE *pipeFh = pipelineFile(pl);
struct lineFile *dataLf = lineFileOpen(pipeDataFile, TRUE);
char *line;
while (lineFileNext(dataLf, &line, NULL))
{
fputs(line, pipeFh);
fputc('\n', pipeFh);
if (ferror(pipeFh))
errnoAbort("error writing data to pipeline: %s", pipelineDesc(pl));
}
lineFileClose(&dataLf);
}
void *loadMemData(char *dataFile, size_t *dataSizeRet)
/* load a file into memory */
{
off_t dataSize = fileSize(dataFile);
void *buf = needLargeMem(dataSize);
FILE *fh = mustOpen(dataFile, "r");
mustRead(fh, buf, dataSize);
carefulClose(&fh);
*dataSizeRet = dataSize;
return buf;
}
void runPipelineTest(struct pipeline *pl)
/* execute and validate test once pipeline has been created */
{
/* if no data file is specified, we just let the pipeline run without
* interacting with it */
if (pipeDataFile != NULL)
{
if (isWrite)
writeTest(pl);
else
readTest(pl);
}
int exitCode = pipelineWait(pl);
if (exitCode != expectExitCode)
errAbort("expected exitCode %d, got %d", expectExitCode, exitCode);
}
void pipelineTestFd(char ***cmds, unsigned options)
/* test for file descriptor API */
{
-int otherEndFd = mustOpenFd(otherEndFile, isWrite);
+int mode = (isWrite ? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY);
+int otherEndFd = mustOpenFd(otherEndFile, mode);
int stderrFd = (stderrFile == NULL) ? STDERR_FILENO
- : mustOpenFd(stderrFile, TRUE);
+ : mustOpenFd(stderrFile, O_WRONLY|O_CREAT|O_TRUNC);
struct pipeline *pl = pipelineOpenFd(cmds, options, otherEndFd, stderrFd);
runPipelineTest(pl);
pipelineFree(&pl);
-mustCloseFd(otherEndFd);
+mustCloseFd(&otherEndFd);
if (stderrFile != NULL)
- mustCloseFd(stderrFd);
+ mustCloseFd(&stderrFd);
}
void pipelineTestMem(char ***cmds, unsigned options)
/* test for memory buffer API */
{
int stderrFd = (stderrFile == NULL) ? STDERR_FILENO
- : mustOpenFd(stderrFile, TRUE);
+ : mustOpenFd(stderrFile, O_WRONLY|O_CREAT|O_TRUNC);
size_t otherEndBufSize = 0;
void *otherEndBuf = loadMemData(otherEndFile, &otherEndBufSize);
struct pipeline *pl = pipelineOpenMem(cmds, options, otherEndBuf, otherEndBufSize, stderrFd);
runPipelineTest(pl);
pipelineFree(&pl);
freeMem(otherEndBuf);
if (stderrFile != NULL)
- mustCloseFd(stderrFd);
+ mustCloseFd(&stderrFd);
}
void pipelineTestFName(char ***cmds, unsigned options)
/* test for file name API */
{
struct pipeline *pl = pipelineOpen(cmds, options, otherEndFile, stderrFile);
runPipelineTest(pl);
pipelineFree(&pl);
}
void pipelineTester(int nCmdsArgs, char **cmdsArgs)
/* pipeline tester */
{
unsigned options = (isWrite ? pipelineWrite : pipelineRead);
if (noAbort)
options |= pipelineNoAbort;
int startOpenCnt = countOpenFiles();
char ***cmds = splitCmds(nCmdsArgs, cmdsArgs);
if (fdApi)
pipelineTestFd(cmds, options);
else if (memApi)
pipelineTestMem(cmds, options);
else
pipelineTestFName(cmds, options);
/* it's ok to have less open, as would happen if we read from stdin */
int endOpenCnt = countOpenFiles();
if (endOpenCnt > startOpenCnt)
errAbort("started with %d files open, now have %d open", startOpenCnt,
endOpenCnt);
}
int main(int argc, char *argv[])
/* Process command line. */
{
optionInit(&argc, argv, options);
if (argc < 2)
usage("wrong number of args");
if (optionExists("exitCode"))
{
noAbort = TRUE;
expectExitCode = optionInt("exitCode", 0);
}
isWrite = optionExists("write");
memApi = optionExists("memApi");
fdApi = optionExists("fdApi");
if (fdApi && memApi)
errAbort("can't specify both -fdApi and -memApi");
pipeDataFile = optionVal("pipeData", NULL);
otherEndFile = optionVal("otherEnd", NULL);
if (fdApi && (otherEndFile == NULL))
errAbort("-fdApi requires -otherEndFile");
if (memApi && (otherEndFile == NULL))
errAbort("-memApi requires -otherEndFile");
stderrFile = optionVal("stderr", NULL);
pipelineTester(argc-1, argv+1);
return 0;
}