dbUnitTest: add testMonitor
Synchronize unittests by waiting for monitor updates
This commit is contained in:
+112
-1
@@ -16,18 +16,33 @@
|
||||
#include "epicsUnitTest.h"
|
||||
#include "osiFileName.h"
|
||||
#include "registry.h"
|
||||
#include "epicsEvent.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccess.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbChannel.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbUnitTest.h"
|
||||
#include "initHooks.h"
|
||||
#include "iocInit.h"
|
||||
|
||||
static dbEventCtx testEvtCtx;
|
||||
static epicsMutexId testEvtLock;
|
||||
static ELLLIST testEvtList; /* holds testMonitor::node */
|
||||
|
||||
struct testMonitor {
|
||||
ELLNODE node;
|
||||
dbEventSubscription sub;
|
||||
epicsEventId event;
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
void testdbPrepare(void)
|
||||
{
|
||||
/* No-op at the moment */
|
||||
if(!testEvtLock)
|
||||
testEvtLock = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
void testdbReadDatabase(const char* file,
|
||||
@@ -46,10 +61,21 @@ void testIocInitOk(void)
|
||||
{
|
||||
if(iocBuildIsolated() || iocRun())
|
||||
testAbort("Failed to start up test database");
|
||||
if(!(testEvtCtx=db_init_events()))
|
||||
testAbort("Failed to initialize test dbEvent context");
|
||||
if(DB_EVENT_OK!=db_start_events(testEvtCtx, "CAS-test", NULL, NULL, epicsThreadPriorityCAServerLow))
|
||||
testAbort("Failed to start test dbEvent context");
|
||||
}
|
||||
|
||||
void testIocShutdownOk(void)
|
||||
{
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
if(ellCount(&testEvtList))
|
||||
testDiag("Warning, testing monitors still active at testIocShutdownOk()");
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
db_close_events(testEvtCtx);
|
||||
testEvtCtx = NULL;
|
||||
if(iocShutdown())
|
||||
testAbort("Failed to shutdown test database");
|
||||
}
|
||||
@@ -199,3 +225,88 @@ dbCommon* testdbRecordPtr(const char* pv)
|
||||
|
||||
return addr.precord;
|
||||
}
|
||||
|
||||
static
|
||||
void testmonupdate(void *user_arg, struct dbChannel *chan,
|
||||
int eventsRemaining, struct db_field_log *pfl)
|
||||
{
|
||||
testMonitor *mon = user_arg;
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
mon->count++;
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
epicsEventMustTrigger(mon->event);
|
||||
}
|
||||
|
||||
testMonitor* testMonitorCreate(const char* pvname, unsigned mask, unsigned opt)
|
||||
{
|
||||
long status;
|
||||
testMonitor *mon;
|
||||
dbChannel *chan;
|
||||
assert(testEvtCtx);
|
||||
|
||||
mon = callocMustSucceed(1, sizeof(*mon), "testMonitorCreate");
|
||||
|
||||
mon->event = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
chan = dbChannelCreate(pvname);
|
||||
if(!chan)
|
||||
testAbort("testMonitorCreate - dbChannelCreate(\"%s\") fails", pvname);
|
||||
if(!!(status=dbChannelOpen(chan)))
|
||||
testAbort("testMonitorCreate - dbChannelOpen(\"%s\") fails w/ %ld", pvname, status);
|
||||
|
||||
mon->sub = db_add_event(testEvtCtx, chan, &testmonupdate, mon, mask);
|
||||
if(!mon->sub)
|
||||
testAbort("testMonitorCreate - db_add_event(\"%s\") fails", pvname);
|
||||
|
||||
db_event_enable(mon->sub);
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
ellAdd(&testEvtList, &mon->node);
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
return mon;
|
||||
}
|
||||
|
||||
void testMonitorDestroy(testMonitor *mon)
|
||||
{
|
||||
if(!mon) return;
|
||||
|
||||
db_event_disable(mon->sub);
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
ellDelete(&testEvtList, &mon->node);
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
db_cancel_event(mon->sub);
|
||||
|
||||
epicsEventDestroy(mon->event);
|
||||
|
||||
free(mon);
|
||||
}
|
||||
|
||||
void testMonitorWait(testMonitor *mon)
|
||||
{
|
||||
switch(epicsEventWaitWithTimeout(mon->event, 10.0))
|
||||
{
|
||||
case epicsEventOK:
|
||||
return;
|
||||
case epicsEventWaitTimeout:
|
||||
default:
|
||||
testAbort("testMonitorWait() exceeds timeout");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned testMonitorCount(testMonitor *mon, unsigned reset)
|
||||
{
|
||||
unsigned count;
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
count = mon->count;
|
||||
if(reset) {
|
||||
mon->count = 0;
|
||||
epicsEventWaitWithTimeout(mon->event, 0); /* clear the event */
|
||||
}
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,26 @@ epicsShareFunc void testdbVGetFieldEqual(const char* pv, short dbrType, va_list
|
||||
|
||||
epicsShareFunc dbCommon* testdbRecordPtr(const char* pv);
|
||||
|
||||
typedef struct testMonitor testMonitor;
|
||||
|
||||
/* Begin monitoring the named PV for changes */
|
||||
epicsShareFunc testMonitor* testMonitorCreate(const char* pvname, unsigned dbe_mask, unsigned opt);
|
||||
/* End monitoring */
|
||||
epicsShareFunc void testMonitorDestroy(testMonitor*);
|
||||
/* Return immediately if it has been updated since create, last wait,
|
||||
* or reset (count w/ reset=1).
|
||||
* Otherwise, block until the value of the target PV is updated.
|
||||
*/
|
||||
epicsShareFunc void testMonitorWait(testMonitor*);
|
||||
/* Return the number of monitor events which have occured since create,
|
||||
* or a pervious reset (called reset=1).
|
||||
* Calling w/ reset=0 only returns the count.
|
||||
* Calling w/ reset=1 resets the count to zero and ensures that the next
|
||||
* wait will block unless subsequent events occur. Returns the previous
|
||||
* count.
|
||||
*/
|
||||
epicsShareFunc unsigned testMonitorCount(testMonitor*, unsigned reset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user