diff --git a/modules/database/src/ioc/db/dbNotify.c b/modules/database/src/ioc/db/dbNotify.c index 22f993555..60f7ef31b 100644 --- a/modules/database/src/ioc/db/dbNotify.c +++ b/modules/database/src/ioc/db/dbNotify.c @@ -245,7 +245,8 @@ static void processNotifyCommon(processNotify *ppn, dbCommon *precord, int first (dbChannelFldDes(ppn->chan)->process_passive && precord->scan == 0))) doProcess = 1; else - if (ppn->requestType == processGetRequest && + if ((ppn->requestType == processRequest || + ppn->requestType == processGetRequest) && precord->scan == 0) doProcess = 1; diff --git a/modules/database/test/ioc/db/Makefile b/modules/database/test/ioc/db/Makefile index f6f009de7..43e73ad15 100644 --- a/modules/database/test/ioc/db/Makefile +++ b/modules/database/test/ioc/db/Makefile @@ -49,6 +49,13 @@ dbScanTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp testHarness_SRCS += dbScanTest.c TESTS += dbScanTest +TESTPROD_HOST += dbNotifyTest +dbNotifyTest_SRCS += dbNotifyTest.c +dbNotifyTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += dbNotifyTest.c +TESTFILES += ../dbNotifyTest.db +TESTS += dbNotifyTest + TESTPROD_HOST += dbShutdownTest dbShutdownTest_SRCS += dbShutdownTest.c dbShutdownTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp diff --git a/modules/database/test/ioc/db/dbNotifyTest.c b/modules/database/test/ioc/db/dbNotifyTest.c new file mode 100644 index 000000000..477c12e57 --- /dev/null +++ b/modules/database/test/ioc/db/dbNotifyTest.c @@ -0,0 +1,144 @@ +/*************************************************************************\ +* SPDX-License-Identifier: EPICS +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* Which requestType leads dbProcessNotify() to process the record, per the + * three rules stated in dbNotify.h. + */ + +#include + +#include "dbAccess.h" +#include "dbChannel.h" +#include "dbNotify.h" +#include "epicsEvent.h" +#include "errlog.h" + +#include "dbUnitTest.h" +#include "testMain.h" + +void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); + +typedef struct { + processNotify notify; + epicsEventId done; + int puts; /* putCallback calls */ + int gets; /* getCallback calls */ + int didPut; /* what putCallback reports back */ + /* Read in doneCallback: dbNotifyCancel() overwrites notify.status. */ + notifyStatus status; + int wasProcessed; +} request; + +static int putCallback(processNotify *ppn, notifyPutType type) +{ + request *r = (request *) ppn->usrPvt; + epicsUInt8 one = 1; + + r->puts++; + if (!r->didPut) + return 0; + if (dbChannelPut(ppn->chan, DBR_UCHAR, &one, 1)) + ppn->status = notifyError; + return 1; +} + +static void getCallback(processNotify *ppn, notifyGetType type) +{ + request *r = (request *) ppn->usrPvt; + epicsUInt8 scratch; + long count = 1; + + r->gets++; + dbChannelGet(ppn->chan, DBR_UCHAR, &scratch, NULL, &count, NULL); +} + +static void doneCallback(processNotify *ppn) +{ + request *r = (request *) ppn->usrPvt; + + r->status = ppn->status; + r->wasProcessed = ppn->wasProcessed; + epicsEventMustTrigger(r->done); +} + +/* One complete request against pv, run to its doneCallback. */ +static void run(request *r, const char *what, const char *pv, + notifyRequestType type, int didPut) +{ + memset(r, 0, sizeof(*r)); + r->didPut = didPut; + r->done = epicsEventMustCreate(epicsEventEmpty); + r->notify.requestType = type; + r->notify.putCallback = putCallback; + r->notify.getCallback = getCallback; + r->notify.doneCallback = doneCallback; + r->notify.usrPvt = r; + r->notify.chan = dbChannelCreate(pv); + if (!r->notify.chan || dbChannelOpen(r->notify.chan)) + testAbort("dbChannelCreate(\"%s\") failed", pv); + + testDiag("%s: %s", what, pv); + dbProcessNotify(&r->notify); + testOk(epicsEventWaitWithTimeout(r->done, 10.0) == epicsEventWaitOK, + "doneCallback ran"); + + dbNotifyCancel(&r->notify); + dbChannelDelete(r->notify.chan); + epicsEventDestroy(r->done); +} + +MAIN(dbNotifyTest) +{ + request r; + + testPlan(19); + + testdbPrepare(); + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + dbTestIoc_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("dbNotifyTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + run(&r, "rule 1, process request on a passive record", + "passive.VAL", processRequest, 0); + testOk1(r.wasProcessed == 1); + testOk1(r.status == notifyOK); + testOk(r.puts == 0 && r.gets == 0, + "processRequest calls neither the put nor the get callback"); + + run(&r, "rule 1 does not apply when the record is not passive", + "scanned.VAL", processRequest, 0); + testOk1(r.wasProcessed == 0); + testOk1(r.status == notifyOK); + + run(&r, "rule 2, a put through PROC", + "passive.PROC", putProcessRequest, 1); + testOk1(r.wasProcessed == 1); + testOk1(r.puts == 1); + + run(&r, "rule 2 needs the put to have happened", + "passive.PROC", putProcessRequest, 0); + testOk1(r.wasProcessed == 0); + testOk1(r.puts == 1); + + run(&r, "rule 2 needs PROC or a process-passive field", + "passive.VAL", putProcessRequest, 1); + testOk1(r.wasProcessed == 0); + testOk1(r.puts == 1); + + run(&r, "rule 3, processGet on a passive record", + "passive.VAL", processGetRequest, 0); + testOk1(r.wasProcessed == 1); + testOk1(r.gets == 1); + + testIocShutdownOk(); + testdbCleanup(); + + return testDone(); +} diff --git a/modules/database/test/ioc/db/dbNotifyTest.db b/modules/database/test/ioc/db/dbNotifyTest.db new file mode 100644 index 000000000..0e7d2bf07 --- /dev/null +++ b/modules/database/test/ioc/db/dbNotifyTest.db @@ -0,0 +1,7 @@ +record(x, "passive") { +} + +record(x, "scanned") { + field(SCAN, "Event") + field(EVNT, "neverTriggered") +} diff --git a/modules/database/test/ioc/db/epicsRunDbTests.c b/modules/database/test/ioc/db/epicsRunDbTests.c index 6c7ce84c9..8d68ecf03 100644 --- a/modules/database/test/ioc/db/epicsRunDbTests.c +++ b/modules/database/test/ioc/db/epicsRunDbTests.c @@ -25,6 +25,7 @@ int dbServerTest(void); int dbCaStatsTest(void); int dbShutdownTest(void); int dbScanTest(void); +int dbNotifyTest(void); int scanIoTest(void); int dbLockTest(void); int dbPutLinkTest(void); @@ -48,6 +49,7 @@ void epicsRunDbTests(void) runTest(dbCaStatsTest); runTest(dbShutdownTest); runTest(dbScanTest); + runTest(dbNotifyTest); runTest(scanIoTest); runTest(dbLockTest); runTest(dbPutLinkTest);