Exemple #1
0
static void hookPass0(initHookState state)
{
    DBENTRY entry;
    if(state!=initHookAfterInitDevSup)
        return;
    testDiag("initHookAfterInitDevSup");

    dbInitEntry(pdbbase, &entry);

    testDiag("restore integer pass0");
    /* rec0.VAL is initially 1, set it to 2 */
    if(dbFindRecord(&entry, "rec0.VAL")==0) {
        aoRecord *prec = entry.precnode->precord;
        testOk(prec->val==1, "VAL %d==1 (initial value from .db)", (int)prec->val);
        checkGetString(&entry, "1");
        testOk1(dbPutString(&entry, "2")==0);
        testOk(prec->val==2, "VAL %d==2", (int)prec->val);
        checkGetString(&entry, "2");
    } else {
        testFail("Missing rec0");
        testSkip(4, "missing record");
    }

    testDiag("restore string pass0");
    if(dbFindRecord(&entry, "rec0.DESC")==0) {
        aoRecord *prec = entry.precnode->precord;
        testOk1(strcmp(prec->desc, "foobar")==0);
        checkGetString(&entry, "foobar");
        testOk1(dbPutString(&entry, "hello")==0);
        testOk1(strcmp(prec->desc, "hello")==0);
        checkGetString(&entry, "hello");
    } else {
        testFail("Missing rec0");
        testSkip(4, "missing record");
    }

    if(dbFindRecord(&entry, "rec1.DESC")==0) {
        aoRecord *prec = entry.precnode->precord;
        testOk1(strcmp(prec->desc, "")==0);
        checkGetString(&entry, "");
        testOk1(dbPutString(&entry, "world")==0);
        testOk1(strcmp(prec->desc, "world")==0);
        checkGetString(&entry, "world");
    } else {
        testFail("Missing rec1");
        testSkip(4, "missing record");
    }

    testDiag("restore link pass0");
    /* rec0.OUT is initially "rec0.DISV", set it to "rec0.SEVR" */
    if(dbFindRecord(&entry, "rec0.OUT")==0) {
        aoRecord *prec = entry.precnode->precord;
        if(prec->out.type==CONSTANT)
            testOk(strcmp(prec->out.text,"rec0.DISV")==0,
                   "%s==rec0.DISV (initial value from .db)",
                   prec->out.text);
        else
            testFail("Wrong link type: %d", (int)prec->out.type);

        /* note that dbGetString() reads an empty string before links are initialized
         * should probably be considered a bug, but has been the case for so long
         * we call it a 'feature'.
         */
        checkGetString(&entry, "");

        testOk1(dbPutString(&entry, "rec0.SEVR")==0);
    } else{
        testFail("Missing rec0");
        testSkip(1, "missing record");
    }

    /* rec0.SDIS is initially NULL, set it to "rec0.STAT" */
    if(dbFindRecord(&entry, "rec0.SDIS")==0) {
        aoRecord *prec = entry.precnode->precord;
        if(prec->sdis.type==CONSTANT)
            testOk1(prec->sdis.value.constantStr==NULL);
        else
            testFail("Wrong link type: %d", (int)prec->sdis.type);

        testOk1(dbPutString(&entry, "rec0.STAT")==0);
    } else{
        testFail("Missing rec0");
        testSkip(1, "missing record");
    }

    /* can't restore array field in pass0 */

    dbFinishEntry(&entry);
}
Exemple #2
0
static void testSingleThreading(void)
{
    int i;
    testsingle data[2];
    xdrv *drvs[2];

    memset(data, 0, sizeof(data));

    for(i=0; i<2; i++) {
        int p;
        for(p=0; p<NUM_CALLBACK_PRIORITIES; p++) {
            data[i].wake[p] = epicsEventMustCreate(epicsEventEmpty);
            data[i].wait[p] = epicsEventMustCreate(epicsEventEmpty);
        }
    }

    testDiag("Test single-threaded I/O Intr scanning");

    testdbPrepare();
    testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
    dbTestIoc_registerRecordDeviceDriver(pdbbase);

    /* create two scan lists with one record on each of three priorities */

    /* group#, member#, priority */
    loadRecord(0, 0, "LOW");
    loadRecord(1, 0, "LOW");
    loadRecord(0, 1, "MEDIUM");
    loadRecord(1, 1, "MEDIUM");
    loadRecord(0, 2, "HIGH");
    loadRecord(1, 2, "HIGH");

    drvs[0] = xdrv_add(0, &testcb, &data[0]);
    drvs[1] = xdrv_add(1, &testcb, &data[1]);
    scanIoSetComplete(drvs[0]->scan, &testcomp, &data[0]);
    scanIoSetComplete(drvs[1]->scan, &testcomp, &data[1]);

    eltc(0);
    testIocInitOk();
    eltc(1);

    testDiag("Scan first list");
    scanIoRequest(drvs[0]->scan);
    testDiag("Scan second list");
    scanIoRequest(drvs[1]->scan);

    testDiag("Wait for first list to complete");
    for(i=0; i<NUM_CALLBACK_PRIORITIES; i++)
        epicsEventMustWait(data[0].wait[i]);

    testDiag("Wait one more second");
    epicsThreadSleep(1.0);

    testOk1(data[0].hasprocd[0]==1);
    testOk1(data[0].hasprocd[1]==1);
    testOk1(data[0].hasprocd[2]==1);
    testOk1(data[0].getcomplete[0]==1);
    testOk1(data[0].getcomplete[1]==1);
    testOk1(data[0].getcomplete[2]==1);
    testOk1(data[1].hasprocd[0]==0);
    testOk1(data[1].hasprocd[1]==0);
    testOk1(data[1].hasprocd[2]==0);
    testOk1(data[1].getcomplete[0]==0);
    testOk1(data[1].getcomplete[1]==0);
    testOk1(data[1].getcomplete[2]==0);

    testDiag("Release the first scan and wait for the second");
    for(i=0; i<NUM_CALLBACK_PRIORITIES; i++)
        epicsEventMustTrigger(data[0].wake[i]);
    for(i=0; i<NUM_CALLBACK_PRIORITIES; i++)
        epicsEventMustWait(data[1].wait[i]);

    testOk1(data[0].hasprocd[0]==1);
    testOk1(data[0].hasprocd[1]==1);
    testOk1(data[0].hasprocd[2]==1);
    testOk1(data[0].getcomplete[0]==1);
    testOk1(data[0].getcomplete[1]==1);
    testOk1(data[0].getcomplete[2]==1);
    testOk1(data[1].hasprocd[0]==1);
    testOk1(data[1].hasprocd[1]==1);
    testOk1(data[1].hasprocd[2]==1);
    testOk1(data[1].getcomplete[0]==1);
    testOk1(data[1].getcomplete[1]==1);
    testOk1(data[1].getcomplete[2]==1);

    testDiag("Release the second scan and complete");
    for(i=0; i<NUM_CALLBACK_PRIORITIES; i++)
        epicsEventMustTrigger(data[1].wake[i]);

    testIocShutdownOk();

    testdbCleanup();

    xdrv_reset();

    for(i=0; i<2; i++) {
        int p;
        for(p=0; p<NUM_CALLBACK_PRIORITIES; p++) {
            epicsEventDestroy(data[i].wake[p]);
            epicsEventDestroy(data[i].wait[p]);
        }
    }
}
Exemple #3
0
static void testUDP(void)
{
    caster_t caster;
    shSocket sender;
    osiSockAddr dest;
    union casterUDP buf;

    shSocketInit(&sender);

    sender.sd = shCreateSocket(AF_INET, SOCK_DGRAM, 0);
    if(sender.sd==INVALID_SOCKET) {
        testAbort("Failed to create socket");
        return;
    }

    lock = epicsMutexMustCreate();
    cycled[0] = epicsEventMustCreate(epicsEventEmpty);
    cycled[1] = epicsEventMustCreate(epicsEventEmpty);

    casterInit(&caster);

    caster.udpport = 0; /* test with random port */
    caster.testhook = &testerhook;

    epicsThreadMustCreate("udptester",
                          epicsThreadPriorityMedium,
                          epicsThreadGetStackSize(epicsThreadStackSmall),
                          &tester, &caster);

    epicsEventSignal(cycled[1]);

    /* wait for tester thread to setup socket */
    epicsEventMustWait(cycled[0]);

    epicsMutexMustLock(lock);

    testOk1(caster.udpport!=0);

    testDiag("UDP test with port %d", caster.udpport);

    memset(&dest, 0, sizeof(dest));
    dest.ia.sin_family = AF_INET;
    dest.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    dest.ia.sin_port = htons(caster.udpport);

    epicsMutexUnlock(lock);

    /* allow tester thread to begin recv() */
    epicsEventSignal(cycled[1]);

    testDiag("Test announcement directly from server");

    memset(&buf, 0, sizeof(buf));
    buf.m_msg.pid = htons(RECAST_MAGIC);
    buf.m_msg.serverIP = htonl(0xffffffff);
    buf.m_msg.serverPort = htons(0x1020);
    buf.m_msg.serverKey = htonl(0x12345678);

    testOk1(0==shSendTo(&sender, &buf.m_bytes, 0x10, 0, &dest));

    /* wait for tester thread to completer recv() and end cycle */
    epicsEventMustWait(cycled[0]);

    epicsMutexMustLock(lock);
    testOk1(cycles==1);
    testOk1(result==0);
    testOk1(caster.haveserv==1);
    testOk1(caster.nameserv.ia.sin_family==AF_INET);
    testOk1(caster.nameserv.ia.sin_addr.s_addr==htonl(INADDR_LOOPBACK));
    testOk1(caster.nameserv.ia.sin_port==htons(0x1020));
    testOk1(caster.servkey==0x12345678);
    epicsMutexUnlock(lock);

    testDiag("Test proxied announcement");

    /* start next cycle */
    epicsEventSignal(cycled[1]);

    /* wait for tester thread to setup socket */
    epicsEventMustWait(cycled[0]);

    epicsMutexMustLock(lock);

    dest.ia.sin_port = htons(caster.udpport);

    epicsMutexUnlock(lock);

    buf.m_msg.serverIP = htonl(0x50607080);

    /* allow tester thread to begin recv() */
    epicsEventSignal(cycled[1]);

    testOk1(0==shSendTo(&sender, &buf.m_bytes, 0x10, 0, &dest));

    /* wait for tester thread to completer recv() and end cycle */
    epicsEventMustWait(cycled[0]);

    epicsMutexMustLock(lock);
    testOk1(cycles==2);
    testOk1(result==0);
    testOk1(caster.haveserv==1);
    testOk1(caster.nameserv.ia.sin_family==AF_INET);
    testOk1(caster.nameserv.ia.sin_addr.s_addr==htonl(0x50607080));
    testOk1(caster.nameserv.ia.sin_port==htons(0x1020));
    epicsMutexUnlock(lock);

    /* begin shutdown cycle */
    epicsEventSignal(cycled[1]);
    epicsEventMustWait(cycled[0]);
    epicsEventSignal(cycled[1]);


    casterShutdown(&caster);

    epicsEventDestroy(cycled[0]);
    epicsEventDestroy(cycled[1]);
    epicsMutexDestroy(lock);
}
/*
 * Tests the log prefix code
 * The prefix is only applied to log messages as they go out to the socket,
 * so we need to create a server listening on a port, accept connections etc.
 * This code is a reduced version of the code in iocLogServer.
 */
static void testLogPrefix(void) {
    struct sockaddr_in serverAddr;
    int status;
    struct timeval timeout;
    struct sockaddr_in actualServerAddr;
    osiSocklen_t actualServerAddrSize;
    char portstring[16];


    testDiag("Testing iocLogPrefix");

    timeout.tv_sec = 5; /* in seconds */
    timeout.tv_usec = 0;

    memset((void*)prefixmsgbuffer, 0, sizeof prefixmsgbuffer);

    /* Clear "errlog: <n> messages were discarded" status */
    errlogPrintfNoConsole(".");
    errlogFlush();

    sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        testAbort("epicsSocketCreate failed.");
    }

    /* We listen on a an available port. */
    memset((void *)&serverAddr, 0, sizeof serverAddr);
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(0);

    status = bind (sock, (struct sockaddr *)&serverAddr,
                   sizeof (serverAddr) );
    if (status < 0) {
        testAbort("bind failed; all ports in use?");
    }

    status = listen(sock, 10);
    if (status < 0) {
        testAbort("listen failed!");
    }

    /* Determine the port that the OS chose */
    actualServerAddrSize = sizeof actualServerAddr;
    memset((void *)&actualServerAddr, 0, sizeof serverAddr);
    status = getsockname(sock, (struct sockaddr *) &actualServerAddr,
         &actualServerAddrSize);
    if (status < 0) {
        testAbort("Can't find port number!");
    }

    sprintf(portstring, "%d", ntohs(actualServerAddr.sin_port));
    testDiag("Listening on port %s", portstring);

    /* Set the EPICS environment variables for logging. */
    epicsEnvSet ( "EPICS_IOC_LOG_INET", "localhost" );
    epicsEnvSet ( "EPICS_IOC_LOG_PORT", portstring );

    pfdctx = (void *) fdmgr_init();
    if (status < 0) {
        testAbort("fdmgr_init failed!");
    }

    status = fdmgr_add_callback(pfdctx, sock, fdi_read,
        acceptNewClient, &serverAddr);

    if (status < 0) {
        testAbort("fdmgr_add_callback failed!");
    }

    testOk1(iocLogInit() == 0);
    fdmgr_pend_event(pfdctx, &timeout);

    testPrefixLogandCompare(prefixactualmsg[0]);

    iocLogPrefix(prefixstring);
    testPrefixLogandCompare(prefixactualmsg[1]);
    testPrefixLogandCompare(prefixactualmsg[2]);
    epicsSocketDestroy(sock);
}
Exemple #5
0
static void testMultiThreading(void)
{
    int i;
    int masks[2];
    testmulti data[6];
    xdrv *drvs[2];

    memset(masks, 0, sizeof(masks));
    memset(data, 0, sizeof(data));

    for(i=0; i<NELEMENTS(data); i++) {
        data[i].wake = epicsEventMustCreate(epicsEventEmpty);
        data[i].wait = epicsEventMustCreate(epicsEventEmpty);
    }

    testDiag("Test multi-threaded I/O Intr scanning");

    testdbPrepare();
    testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
    dbTestIoc_registerRecordDeviceDriver(pdbbase);

    /* create two scan lists with one record on each of three priorities */

    /* group#, member#, priority */
    loadRecord(0, 0, "LOW");
    loadRecord(1, 1, "LOW");
    loadRecord(0, 2, "MEDIUM");
    loadRecord(1, 3, "MEDIUM");
    loadRecord(0, 4, "HIGH");
    loadRecord(1, 5, "HIGH");

    drvs[0] = xdrv_add(0, &testcbmulti, data);
    drvs[1] = xdrv_add(1, &testcbmulti, data);
    scanIoSetComplete(drvs[0]->scan, &testcompmulti, &masks[0]);
    scanIoSetComplete(drvs[1]->scan, &testcompmulti, &masks[1]);

    /* just enough workers to process all records concurrently */
    callbackParallelThreads(2, "LOW");
    callbackParallelThreads(2, "MEDIUM");
    callbackParallelThreads(2, "HIGH");

    eltc(0);
    testIocInitOk();
    eltc(1);

    testDiag("Scan first list");
    testOk1(scanIoRequest(drvs[0]->scan)==0x7);
    testDiag("Scan second list");
    testOk1(scanIoRequest(drvs[1]->scan)==0x7);

    testDiag("Wait for everything to start");
    for(i=0; i<NELEMENTS(data); i++)
        epicsEventMustWait(data[i].wait);

    testDiag("Wait one more second");
    epicsThreadSleep(1.0);

    for(i=0; i<NELEMENTS(data); i++) {
        testOk(data[i].hasprocd==1, "data[%d].hasprocd==1 (%d)", i, data[i].hasprocd);
        testOk(data[i].getcomplete==0, "data[%d].getcomplete==0 (%d)", i, data[i].getcomplete);
    }

    testDiag("Release all and complete");
    for(i=0; i<NELEMENTS(data); i++)
        epicsEventMustTrigger(data[i].wake);

    testIocShutdownOk();

    for(i=0; i<NELEMENTS(data); i++) {
        testOk(data[i].getcomplete==1, "data[%d].getcomplete==0 (%d)", i, data[i].getcomplete);
    }
    testOk1(masks[0]==0x7);
    testOk1(masks[1]==0x7);

    testdbCleanup();

    xdrv_reset();

    for(i=0; i<NELEMENTS(data); i++) {
        epicsEventDestroy(data[i].wake);
        epicsEventDestroy(data[i].wait);
    }
}
Exemple #6
0
static
void testFIFOCirc(void)
{
    aiRecord *vrec;
    compressRecord *crec;
    double *cbuf;

    testDiag("Test FIFO");

    testdbPrepare();

    testdbReadDatabase("recTestIoc.dbd", NULL, NULL);

    recTestIoc_registerRecordDeviceDriver(pdbbase);

    testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4");

    vrec = (aiRecord*)testdbRecordPtr("val");
    crec = (compressRecord*)testdbRecordPtr("comp");

    eltc(0);
    testIocInitOk();
    eltc(1);

    dbScanLock((dbCommon*)crec);
    cbuf = crec->bptr;

    testOk1(crec->off==0);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==0);

    testDiag("Push 1.1");
    vrec->val = 1.1;
    dbProcess((dbCommon*)crec);

    /* In FIFO mode the valid elements are
     *   cbuf[(off-nuse-1) % size] through cbuf[(off-1) % size]
     */
    testOk1(crec->off==1);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==1);
    testDEq(cbuf[0], 1.1, 0.1);
    testDEq(cbuf[1], 0.0, 0.1);
    testDEq(cbuf[2], 0.0, 0.1);
    testDEq(cbuf[3], 0.0, 0.1);
    checkArrD("comp", 1, 1.1, 0, 0, 0);

    testDiag("Push 2.1");
    vrec->val = 2.1;
    dbProcess((dbCommon*)crec);

    testOk1(crec->off==2);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==2);
    testDEq(cbuf[0], 1.1, 0.1);
    testDEq(cbuf[1], 2.1, 0.1);
    testDEq(cbuf[2], 0.0, 0.1);
    testDEq(cbuf[3], 0.0, 0.1);
    checkArrD("comp", 2, 1.1, 2.1, 0, 0);

    testDiag("Push 3.1");
    vrec->val = 3.1;
    dbProcess((dbCommon*)crec);

    testOk1(crec->off==3);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==3);
    testDEq(cbuf[0], 1.1, 0.1);
    testDEq(cbuf[1], 2.1, 0.1);
    testDEq(cbuf[2], 3.1, 0.1);
    testDEq(cbuf[3], 0.0, 0.1);
    checkArrD("comp", 3, 1.1, 2.1, 3.1, 0);

    testDiag("Push 4.1");
    vrec->val = 4.1;
    dbProcess((dbCommon*)crec);

    testOk1(crec->off==0);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==4);
    testDEq(cbuf[0], 1.1, 0.1);
    testDEq(cbuf[1], 2.1, 0.1);
    testDEq(cbuf[2], 3.1, 0.1);
    testDEq(cbuf[3], 4.1, 0.1);
    checkArrD("comp", 4, 1.1, 2.1, 3.1, 4.1);

    testDiag("Push 5.1");
    vrec->val = 5.1;
    dbProcess((dbCommon*)crec);

    testOk1(crec->off==1);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==4);
    testDEq(cbuf[0], 5.1, 0.1);
    testDEq(cbuf[1], 2.1, 0.1);
    testDEq(cbuf[2], 3.1, 0.1);
    testDEq(cbuf[3], 4.1, 0.1);
    checkArrD("comp", 4, 2.1, 3.1, 4.1, 5.1);

    testDiag("Push 6.1");
    vrec->val = 6.1;
    dbProcess((dbCommon*)crec);

    testOk1(crec->off==2);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==4);
    testDEq(cbuf[0], 5.1, 0.1);
    testDEq(cbuf[1], 6.1, 0.1);
    testDEq(cbuf[2], 3.1, 0.1);
    testDEq(cbuf[3], 4.1, 0.1);
    checkArrD("comp", 4, 3.1, 4.1, 5.1, 6.1);

    dbScanUnlock((dbCommon*)crec);

    testDiag("Reset");
    testdbPutFieldOk("comp.RES", DBF_LONG, 0);

    dbScanLock((dbCommon*)crec);
    testOk1(crec->off==0);
    testOk1(crec->inx==0);
    testOk1(crec->nuse==0);
    checkArrD("comp", 0, 0, 0, 0, 0);
    dbScanUnlock((dbCommon*)crec);

    testIocShutdownOk();

    testdbCleanup();
}
static
void testcancel(void)
{
    epicsJob *job[2];
    epicsThreadPool *pool;
    testOk1((pool=epicsThreadPoolCreate(NULL))!=NULL);
    if(!pool)
        return;

    cancel[0]=epicsEventCreate(epicsEventEmpty);
    cancel[1]=epicsEventCreate(epicsEventEmpty);

    testOk1((job[0]=epicsJobCreate(pool, &neverrun, EPICSJOB_SELF))!=NULL);
    testOk1((job[1]=epicsJobCreate(pool, &toolate, EPICSJOB_SELF))!=NULL);

    /* freeze */
    epicsThreadPoolControl(pool, epicsThreadPoolQueueRun, 0);

    testOk1(epicsJobUnqueue(job[0])==S_pool_jobIdle); /* not queued yet */

    epicsJobQueue(job[0]);
    testOk1(epicsJobUnqueue(job[0])==0);
    testOk1(epicsJobUnqueue(job[0])==S_pool_jobIdle);

    epicsThreadSleep(0.01);
    epicsJobQueue(job[0]);
    testOk1(epicsJobUnqueue(job[0])==0);
    testOk1(epicsJobUnqueue(job[0])==S_pool_jobIdle);

    epicsThreadPoolControl(pool, epicsThreadPoolQueueRun, 1);

    epicsJobQueue(job[1]); /* actually let it run this time */

    epicsEventMustWait(cancel[0]);
    testOk1(epicsJobUnqueue(job[0])==S_pool_jobIdle);
    epicsEventSignal(cancel[1]);

    epicsThreadPoolDestroy(pool);
    epicsEventDestroy(cancel[0]);
    epicsEventDestroy(cancel[1]);

    testOk1(shouldneverrun==0);
    testOk1(numtoolate==1);
}
void epicsInlineTest3(void)
{
    testDiag("epicsInlineTest3()");
    testOk1(epicsInlineTestFn1()==3);
    testOk1(epicsInlineTestFn2()==42);
}
extern "C" void messageQueueTest(void *parm)
{
    unsigned int i;
    char cbuf[80];
    int len;
    int pass;
    int used;
    int want;

    epicsMessageQueue *q1 = new epicsMessageQueue(4, 20);

    testDiag("Simple single-thread tests:");
    i = 0;
    used = 0;
    testOk1(q1->pending() == 0);
    while (q1->trySend((void *)msg1, i ) == 0) {
        i++;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
    }
    testOk1(q1->pending() == 4);

    want = 0;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 3);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->trySend((void *)msg1, i++);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->trySend((void *)msg1, i++);
    testOk1(q1->pending() == 3);

    i = 3;
    while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
        --i;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
        want++;
        if (!testOk1((len == want) & (strncmp(msg1, cbuf, len) == 0)))
            testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    }
    testOk1(q1->pending() == 0);

    testDiag("Test sender timeout:");
    i = 0;
    used = 0;
    testOk1(q1->pending() == 0);
    while (q1->send((void *)msg1, i, 1.0 ) == 0) {
        i++;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
    }
    testOk1(q1->pending() == 4);

    want = 0;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 3);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->send((void *)msg1, i++, 1.0);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->send((void *)msg1, i++, 1.0);
    testOk1(q1->pending() == 3);

    i = 3;
    while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
        --i;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
        want++;
        if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
            testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    }
    testOk1(q1->pending() == 0);

    testDiag("Test receiver with timeout:");
    for (i = 0 ; i < 4 ; i++)
        testOk1 (q1->send((void *)msg1, i, 1.0) == 0);
    testOk1(q1->pending() == 4);
    for (i = 0 ; i < 4 ; i++)
        testOk(q1->receive((void *)cbuf, sizeof cbuf, 1.0) == (int)i,
            "q1->receive(...) == %d", i);
    testOk1(q1->pending() == 0);
    testOk1(q1->receive((void *)cbuf, sizeof cbuf, 1.0) < 0);
    testOk1(q1->pending() == 0);

    testDiag("Single receiver with invalid size, single sender tests:");
    epicsThreadCreate("Bad Receiver", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), badReceiver, q1);
    epicsThreadSleep(1.0);
    testOk(q1->send((void *)msg1, 10) == 0, "Send with waiting receiver");
    epicsThreadSleep(2.0);
    testOk(q1->send((void *)msg1, 10) == 0, "Send with no receiver");
    epicsThreadSleep(2.0);

    testDiag("Single receiver, single sender tests:");
    epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityHigh);
    epicsThreadCreate("Receiver one", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), receiver, q1);
    for (pass = 1 ; pass <= 3 ; pass++) {
        for (i = 0 ; i < 10 ; i++) {
            if (q1->trySend((void *)msg1, i) < 0)
                break;
            if (pass >= 3)
                epicsThreadSleep(0.5);
        }
        switch (pass) {
        case 1:
            if (i<6)
                testDiag("  priority-based scheduler, sent %d messages", i);
            epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityLow);
            break;
        case 2:
            if (i<10)
                testDiag("  scheduler not strict priority, sent %d messages", i);
            else
                testDiag("  strict priority scheduler, sent 10 messages");
            break;
        case 3:
            testOk(i == 10, "%d of 10 messages sent with sender pauses", i);
            break;
        }
        epicsThreadSleep(1.0);
    }

    /*
     * Single receiver, multiple sender tests
     */
    testDiag("Single receiver, multiple sender tests:");
    testDiag("This test takes 5 minutes...");
    epicsThreadCreate("Sender 1", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 2", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 3", epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 4", epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);

    epicsThreadSleep(300.0);

    testExit = 1;
}
void testStdoutRedir (const char *report)
{
    FILE *realStdout = stdout;
    FILE *stream = 0;
    char linebuf[80];
    size_t buflen = sizeof linebuf;
    
    testOk1(epicsGetStdout() == stdout);

    errno = 0;
    if (!testOk1((stream = fopen(report, "w")) != NULL)) {
        testDiag("'%s' could not be opened for writing: %s",
                 report, strerror(errno));
        testSkip(11, "Can't create stream file");
        return;
    }

    epicsSetThreadStdout(stream);
    testOk1(stdout == stream);

    printf(LINE_1);
    printf(LINE_2);

    epicsSetThreadStdout(0);
    testOk1(epicsGetStdout() == realStdout);
    testOk1(stdout == realStdout);

    errno = 0;
    if (!testOk1(!fclose(stream))) {
        testDiag("fclose error: %s", strerror(errno));
#ifdef vxWorks
        testDiag("The above test fails if you don't cd to a writable directory");
        testDiag("before running the test. The next test will also fail...");
#endif
    }

    if (!testOk1((stream = fopen(report, "r")) != NULL)) {
        testDiag("'%s' could not be opened for reading: %s",
                 report, strerror(errno));
        testSkip(6, "Can't reopen stream file.");
        return;
    }

    if (!testOk1(fgets(linebuf, buflen, stream) != NULL)) {
        testDiag("File read error: %s", strerror(errno));
        testSkip(5, "Read failed.");
        fclose(stream);
        return;
    }
    testOk(strcmp(linebuf, LINE_1) == 0, "First line correct");

    if (!testOk1(fgets(linebuf, buflen, stream) != NULL)) {
        testDiag("File read error: %s", strerror(errno));
        testSkip(1, "No line to compare.");
    } else
        testOk(strcmp(linebuf, LINE_2) == 0, "Second line");

    testOk(!fgets(linebuf, buflen, stream), "File ends");

    if (!testOk1(!fclose(stream)))
        testDiag("fclose error: %s\n", strerror(errno));
}