From 428dfe7a5c91708ff92fdb916ce3b54a55263752 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 28 Feb 2017 18:00:51 -0600 Subject: [PATCH] add testing lset --- src/ioc/db/test/Makefile | 2 + src/ioc/db/test/dbPutLinkTest.c | 187 +++++++++++++------------ src/ioc/db/test/jlinkz.c | 232 ++++++++++++++++++++++++++++++++ src/ioc/db/test/jlinkz.dbd | 1 + 4 files changed, 335 insertions(+), 87 deletions(-) create mode 100644 src/ioc/db/test/jlinkz.c create mode 100644 src/ioc/db/test/jlinkz.dbd diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 66567d318..4fe389cbf 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -20,6 +20,7 @@ dbTestIoc_SRCS += xRecord.c dbTestIoc_SRCS += dbLinkdset.c dbTestIoc_SRCS += xLink.c dbTestIoc_SRCS += devx.c +dbTestIoc_SRCS += jlinkz.c dbTestIoc_LIBS = dbCore ca Com TARGETS += $(COMMON_DIR)/dbTestIoc.dbd @@ -31,6 +32,7 @@ dbTestIoc_DBD += xRecord.dbd dbTestIoc_DBD += arrRecord.dbd dbTestIoc_DBD += xLink.dbd dbTestIoc_DBD += devx.dbd +dbTestIoc_DBD += jlinkz.dbd dbTestIoc_DBD += dbLinkdset.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index a0a4d66ba..e46d2c4d9 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -68,7 +68,7 @@ static void testLinkParse(void) { const struct testParseDataT *td = testParseData; dbLinkInfo info; - testDiag("link parsing"); + testDiag("\n# Checking link parsing\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -81,22 +81,27 @@ static void testLinkParse(void) testIocInitOk(); eltc(1); - for(;td->str; td++) { + for (;td->str; td++) { int i, N; - testDiag("Parse \"%s\"", td->str); - testOk1(dbParseLink(td->str, DBF_INLINK, &info)==0); - testOk1(info.ltype==td->info.ltype); - if(td->info.target) + testDiag("Parsing \"%s\"", td->str); + testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK"); + if (!testOk(info.ltype == td->info.ltype, "Link type value")) + testDiag("Expected %d, got %d", td->info.ltype, info.ltype); + if (td->info.target) testStrcmp(0, info.target, td->info.target); - if(info.ltype==td->info.ltype) { - switch(info.ltype) { + if (info.ltype == td->info.ltype) { + switch (info.ltype) { case PV_LINK: - testOk1(info.modifiers==td->info.modifiers); + if (!testOk(info.modifiers == td->info.modifiers, + "PV Link modifier flags")) + testDiag("Expected %d, got %d", td->info.modifiers, + info.modifiers); break; case VME_IO: + case CAMAC_IO: testStrcmp(0, info.hwid, td->info.hwid); N = strlen(td->info.hwid); - for(i=0; iinfo.hwnums[i], "%d == %d", info.hwnums[i], td->info.hwnums[i]); } @@ -125,7 +130,7 @@ static void testLinkFailParse(void) { const char * const *td = testParseFailData; dbLinkInfo info; - testDiag("link parsing of invalid input"); + testDiag("\n# Check parsing of invalid inputs\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -139,8 +144,8 @@ static void testLinkFailParse(void) eltc(1); for(;*td; td++) { - testDiag("Expect failure \"%s\"", *td); - testOk1(dbParseLink(*td, DBF_INLINK, &info)==S_dbLib_badField); + testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField, + "dbParseLink correctly rejected \"%s\"", *td); } testIocShutdownOk(); @@ -180,7 +185,7 @@ static void testCADBSet(void) const struct testDataT *td = testSetData; xRecord *prec; DBLINK *plink; - testDiag("DB/CA link retargeting"); + testDiag("\n# Checking DB/CA link retargeting\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -197,21 +202,22 @@ static void testCADBSet(void) plink = &prec->lnk; for (;td->linkstring;td++) { - testDiag("x1.LNK <- \"%s\"", td->linkstring); + testDiag("Trying field value \"%s\"", td->linkstring); testdbPutFieldOk("x1.LNK", DBF_STRING, td->linkstring); if (td->linkback) testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkback); else testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkstring); - testOk1(plink->type==td->linkType); + if (!testOk(plink->type == td->linkType, "Link type")) + testDiag("Expected %d, got %d", td->linkType, plink->type); - if (plink->type==td->linkType) { - switch(td->linkType) { + if (plink->type == td->linkType) { + switch (td->linkType) { case CONSTANT: - if(plink->value.constantStr) - testOk1(strcmp(plink->value.constantStr,td->linkstring)==0); - else if(td->linkstring[0]=='\0') + if (plink->value.constantStr) + testOk1(strcmp(plink->value.constantStr, td->linkstring) == 0); + else if (td->linkstring[0]=='\0') testPass("Empty String"); else testFail("oops"); @@ -219,7 +225,7 @@ static void testCADBSet(void) case DB_LINK: case CA_LINK: - testOk(plink->value.pv_link.pvlMask==td->pvlMask, + testOk(plink->value.pv_link.pvlMask == td->pvlMask, "pvlMask %x == %x", plink->value.pv_link.pvlMask, td->pvlMask); break; } @@ -258,65 +264,65 @@ static void testLink(DBLINK *plink, const testHWDataT *td) { switch(td->ltype) { case JSON_LINK: - testOk1(strcmp(plink->value.json.string, td->parm)==0); + testOk1(strcmp(plink->value.json.string, td->parm) == 0); break; case VME_IO: - testOk1(plink->value.vmeio.card==td->vals[0]); - testOk1(plink->value.vmeio.signal==td->vals[1]); - testOk1(strcmp(plink->value.vmeio.parm, td->parm)==0); + testOk1(plink->value.vmeio.card == td->vals[0]); + testOk1(plink->value.vmeio.signal == td->vals[1]); + testOk1(strcmp(plink->value.vmeio.parm, td->parm) == 0); break; case CAMAC_IO: - testOk1(plink->value.camacio.b==td->vals[0]); - testOk1(plink->value.camacio.c==td->vals[1]); - testOk1(plink->value.camacio.n==td->vals[2]); - testOk1(plink->value.camacio.a==td->vals[3]); - testOk1(plink->value.camacio.f==td->vals[4]); - testOk1(strcmp(plink->value.camacio.parm, td->parm)==0); + testOk1(plink->value.camacio.b == td->vals[0]); + testOk1(plink->value.camacio.c == td->vals[1]); + testOk1(plink->value.camacio.n == td->vals[2]); + testOk1(plink->value.camacio.a == td->vals[3]); + testOk1(plink->value.camacio.f == td->vals[4]); + testOk1(strcmp(plink->value.camacio.parm, td->parm) == 0); break; case AB_IO: - testOk1(plink->value.abio.link==td->vals[0]); - testOk1(plink->value.abio.adapter==td->vals[1]); - testOk1(plink->value.abio.card==td->vals[2]); - testOk1(plink->value.abio.signal==td->vals[3]); - testOk1(strcmp(plink->value.abio.parm, td->parm)==0); + testOk1(plink->value.abio.link == td->vals[0]); + testOk1(plink->value.abio.adapter == td->vals[1]); + testOk1(plink->value.abio.card == td->vals[2]); + testOk1(plink->value.abio.signal == td->vals[3]); + testOk1(strcmp(plink->value.abio.parm, td->parm) == 0); break; case GPIB_IO: - testOk1(plink->value.gpibio.link==td->vals[0]); - testOk1(plink->value.gpibio.addr==td->vals[1]); - testOk1(strcmp(plink->value.gpibio.parm, td->parm)==0); + testOk1(plink->value.gpibio.link == td->vals[0]); + testOk1(plink->value.gpibio.addr == td->vals[1]); + testOk1(strcmp(plink->value.gpibio.parm, td->parm) == 0); break; case BITBUS_IO: - testOk1(plink->value.bitbusio.link==td->vals[0]); - testOk1(plink->value.bitbusio.node==td->vals[1]); - testOk1(plink->value.bitbusio.port==td->vals[2]); - testOk1(plink->value.bitbusio.signal==td->vals[3]); - testOk1(strcmp(plink->value.bitbusio.parm, td->parm)==0); + testOk1(plink->value.bitbusio.link == td->vals[0]); + testOk1(plink->value.bitbusio.node == td->vals[1]); + testOk1(plink->value.bitbusio.port == td->vals[2]); + testOk1(plink->value.bitbusio.signal == td->vals[3]); + testOk1(strcmp(plink->value.bitbusio.parm, td->parm) == 0); break; case INST_IO: - testOk1(strcmp(plink->value.instio.string, td->parm)==0); + testOk1(strcmp(plink->value.instio.string, td->parm) == 0); break; case BBGPIB_IO: - testOk1(plink->value.bbgpibio.link==td->vals[0]); - testOk1(plink->value.bbgpibio.bbaddr==td->vals[1]); - testOk1(plink->value.bbgpibio.gpibaddr==td->vals[2]); - testOk1(strcmp(plink->value.bbgpibio.parm, td->parm)==0); + testOk1(plink->value.bbgpibio.link == td->vals[0]); + testOk1(plink->value.bbgpibio.bbaddr == td->vals[1]); + testOk1(plink->value.bbgpibio.gpibaddr == td->vals[2]); + testOk1(strcmp(plink->value.bbgpibio.parm, td->parm) == 0); break; case RF_IO: - testOk1(plink->value.rfio.cryo==td->vals[0]); - testOk1(plink->value.rfio.micro==td->vals[1]); - testOk1(plink->value.rfio.dataset==td->vals[2]); - testOk1(plink->value.rfio.element==td->vals[3]); + testOk1(plink->value.rfio.cryo == td->vals[0]); + testOk1(plink->value.rfio.micro == td->vals[1]); + testOk1(plink->value.rfio.dataset == td->vals[2]); + testOk1(plink->value.rfio.element == td->vals[3]); break; case VXI_IO: - if(plink->value.vxiio.flag==VXIDYNAMIC) { - testOk1(plink->value.vxiio.frame==td->vals[0]); - testOk1(plink->value.vxiio.slot==td->vals[1]); - testOk1(plink->value.vxiio.signal==td->vals[2]); + if(plink->value.vxiio.flag == VXIDYNAMIC) { + testOk1(plink->value.vxiio.frame == td->vals[0]); + testOk1(plink->value.vxiio.slot == td->vals[1]); + testOk1(plink->value.vxiio.signal == td->vals[2]); } else { - testOk1(plink->value.vxiio.la==td->vals[0]); - testOk1(plink->value.vxiio.signal==td->vals[1]); + testOk1(plink->value.vxiio.la == td->vals[0]); + testOk1(plink->value.vxiio.signal == td->vals[1]); } - testOk1(strcmp(plink->value.vxiio.parm, td->parm)==0); + testOk1(strcmp(plink->value.vxiio.parm, td->parm) == 0); break; } } @@ -324,7 +330,7 @@ static void testLink(DBLINK *plink, const testHWDataT *td) static void testHWInitSet(void) { const testHWDataT *td = testHWData; - testDiag("HW link parsing during initialization"); + testDiag("\n# Checking HW link parsing during initialization\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -337,13 +343,14 @@ static void testHWInitSet(void) testIocInitOk(); eltc(1); - for(;td->recname;td++) { + for (;td->recname; td++) { char buf[MAX_STRING_SIZE]; xRecord *prec; DBLINK *plink; + testDiag("%s == \"%s\"", td->recname, td->wval); - prec = (xRecord*)testdbRecordPtr(td->recname); + prec = (xRecord *) testdbRecordPtr(td->recname); plink = &prec->inp; strcpy(buf, td->recname); @@ -351,9 +358,11 @@ static void testHWInitSet(void) testdbGetFieldEqual(buf, DBR_STRING, td->wval); - testOk(plink->type==td->ltype, "link type %d == %d", - plink->type, td->ltype); - if(plink->type==td->ltype) { + if (!testOk(plink->type == td->ltype, "Link type")) { + testDiag("Expected %d, got %d", + td->ltype, plink->type); + } + else { testLink(plink, td); } @@ -382,7 +391,8 @@ static const testHWDataT testHWData2[] = { static void testHWMod(void) { const testHWDataT *td = testHWData2; - testDiag("HW link parsing during retarget"); + + testDiag("\n# Checking HW link parsing during retarget\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -411,9 +421,11 @@ static void testHWMod(void) testdbGetFieldEqual(buf, DBR_STRING, td->wval); - testOk(plink->type==td->ltype, "link type %d == %d", - plink->type, td->ltype); - if(plink->type==td->ltype) { + if (!testOk(plink->type == td->ltype, "Link type")) { + testDiag("Expected %d, got %d", + td->ltype, plink->type); + } + else { testLink(plink, td); } @@ -428,42 +440,42 @@ static void testLinkInitFail(void) { xRecord *prec; DBLINK *plink; - testDiag("Link parsing failures during initialization"); + testDiag("\n# Checking link parse failures at iocInit\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); dbTestIoc_registerRecordDeviceDriver(pdbbase); - /* this load will fail */ eltc(0); - testOk1(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR - "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)!=0); + testOk(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR + ".." OSI_PATH_LIST_SEPARATOR "../O.Common" OSI_PATH_LIST_SEPARATOR + "O.Common", NULL) != 0, "dbReadDatabase returned error (expected)"); testIocInitOk(); eltc(1); testdbGetFieldEqual("eVME_IO1.INP", DBR_STRING, "#C0 S0 @"); - prec = (xRecord*)testdbRecordPtr("eVME_IO1"); + prec = (xRecord *) testdbRecordPtr("eVME_IO1"); plink = &prec->inp; - testOk1(plink->type==VME_IO); - testOk1(plink->value.vmeio.parm!=NULL); + testOk1(plink->type == VME_IO); + testOk1(plink->value.vmeio.parm != NULL); testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C0 S0 @"); - prec = (xRecord*)testdbRecordPtr("eVME_IO2"); + prec = (xRecord *) testdbRecordPtr("eVME_IO2"); plink = &prec->inp; - testOk1(plink->type==VME_IO); - testOk1(plink->value.vmeio.parm!=NULL); + testOk1(plink->type == VME_IO); + testOk1(plink->value.vmeio.parm != NULL); testdbGetFieldEqual("eINST_IO.INP", DBR_STRING, "@"); - prec = (xRecord*)testdbRecordPtr("eINST_IO"); + prec = (xRecord *) testdbRecordPtr("eINST_IO"); plink = &prec->inp; - testOk1(plink->type==INST_IO); - testOk1(plink->value.instio.string!=NULL); + testOk1(plink->type == INST_IO); + testOk1(plink->value.instio.string != NULL); testIocShutdownOk(); @@ -472,7 +484,7 @@ static void testLinkInitFail(void) static void testLinkFail(void) { - testDiag("Link parsing failures"); + testDiag("\n# Checking runtime link parse failures\n#"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -491,7 +503,8 @@ static void testLinkFail(void) /* INST_IO doesn't accept string without @ */ testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc"); - /* JSON_LINK dies properly */ + /* JSON_LINK dies when expected */ + testdbPutFieldOk("rJSON_LINK.INP", DBR_STRING, "{\"x\":true}"); testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":false}"); testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":null}"); testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":1}"); @@ -522,7 +535,7 @@ static void testLinkFail(void) MAIN(dbPutLinkTest) { - testPlan(269); + testPlan(280); testLinkParse(); testLinkFailParse(); testCADBSet(); diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c new file mode 100644 index 000000000..79b642ebd --- /dev/null +++ b/src/ioc/db/test/jlinkz.c @@ -0,0 +1,232 @@ +/*************************************************************************\ +* Copyright (c) 2016 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. + \*************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int numzalloc; + +typedef struct { + jlink base; + epicsMutexId lock; + unsigned isset:1; + unsigned isopen:1; + epicsInt32 value; +} zpriv; + + +static +void z_open(struct link *plink) +{ + zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base); + + if(priv->isopen) + testDiag("lsetZ re-open"); + priv->isopen = 1; +} + +static +void z_remove(struct dbLocker *locker, struct link *plink) +{ + zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base); + + epicsMutexLock(priv->lock); + + if(!priv->isopen) + testDiag("lsetZ remove without open"); + + epicsMutexUnlock(priv->lock); + + epicsAtomicDecrIntT(&numzalloc); + + free(priv); + plink->value.json.jlink = NULL; /* paranoia */ +} + +static +int z_connected(const struct link *plink) +{ + return 1; /* TODO: not provided should be connected */ +} + +static +int z_dbftype(const struct link *plink) +{ + return DBF_LONG; +} + +static +long z_elements(const struct link *plink, long *nelements) +{ + *nelements = 1; + return 0; +} + +static +long z_getval(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + long ret; + long (*pconv)(const epicsInt32 *, void *, const dbAddr *) = dbFastGetConvertRoutine[DBF_LONG][dbrType]; + zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base); + + if(pnRequest && *pnRequest==0) return 0; + + epicsMutexLock(priv->lock); + ret = (*pconv)(&priv->value, pbuffer, NULL); + epicsMutexUnlock(priv->lock); + if(ret==0 && pnRequest) *pnRequest = 1; + return ret; +} + +/* TODO: atomicly get value and alarm */ +static +long z_getalarm(const struct link *plink, epicsEnum16 *status, + epicsEnum16 *severity) +{ + zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base); + epicsEnum16 sevr, stat; + + epicsMutexLock(priv->lock); + sevr = priv->isset ? 0 : INVALID_ALARM; + stat = priv->isset ? 0 : LINK_ALARM; + epicsMutexUnlock(priv->lock); + + if(status) *status = stat; + if(severity) *severity = sevr; + return 0; +} + +static +long z_putval(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + long ret; + long (*pconv)(epicsInt32 *, const void *, const dbAddr *) = dbFastPutConvertRoutine[DBF_LONG][dbrType]; + zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base); + + if(nRequest==0) return 0; + + epicsMutexLock(priv->lock); + ret = (*pconv)(&priv->value, pbuffer, NULL); + epicsMutexUnlock(priv->lock); + return ret; +} + +static lset lsetZ = { + 0, 0, /* non-const, non-volatile */ + &z_open, + &z_remove, + NULL, NULL, NULL, /* load */ + &z_connected, + &z_dbftype, + &z_elements, + &z_getval, + NULL, /* control limits */ + NULL, /* display limits */ + NULL, /* alarm limits */ + NULL, /* prec */ + NULL, /* units */ + &z_getalarm, + NULL, /* time */ + &z_putval, + NULL, /* putasync */ + NULL, /* forward */ +}; + +static +jlink* z_alloc(short dbfType) +{ + zpriv *priv; + priv = calloc(1, sizeof(*priv)); + if(!priv) return NULL; + + epicsAtomicIncrIntT(&numzalloc); + + return &priv->base; +} + +static +void z_free(jlink *pj) +{ + zpriv *priv = CONTAINER(pj, zpriv, base); + + if(priv->isopen) + testDiag("lsetZ jlink free after open()\n"); + + epicsAtomicDecrIntT(&numzalloc); + + free(priv); +} + +static +jlif_result z_int(jlink *pj, long num) +{ + zpriv *priv = CONTAINER(pj, zpriv, base); + + priv->value = num; + priv->isset = 1; + + return jlif_continue; +} + +static +jlif_key_result z_start(jlink *pj) +{ + return jlif_continue; +} + +static +jlif_result z_key(jlink *pj, const char *key, size_t len) +{ + if(strcmp(key,"fail")==0) return jlif_stop; + else return jlif_continue; +} + +static +jlif_result z_end(jlink *pj) +{ + return jlif_continue; +} + +static +struct lset* z_lset(const jlink *pj) +{ + return &lsetZ; +} + +static jlif jlifZ = { + "z", + &z_alloc, + &z_free, + NULL, /* null */ + NULL, /* bool */ + &z_int, + NULL, /* double */ + NULL, /* string */ + &z_start, + &z_key, + &z_end, + NULL, /* start array */ + NULL, /* end array */ + NULL, /* end child */ + &z_lset, + NULL, /* report */ + NULL /* map child */ +}; + +epicsExportAddress(jlif, jlifZ); diff --git a/src/ioc/db/test/jlinkz.dbd b/src/ioc/db/test/jlinkz.dbd new file mode 100644 index 000000000..5408a88b6 --- /dev/null +++ b/src/ioc/db/test/jlinkz.dbd @@ -0,0 +1 @@ +link("z", "jlifZ")