Merge branch '7.0' (after codeathon 2023) into PSI-7.0

This commit is contained in:
2023-03-29 13:36:52 +02:00
36 changed files with 662 additions and 181 deletions

View File

@@ -167,6 +167,16 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db
TESTS += asyncproctest
TARGETS += $(COMMON_DIR)/subproctest.dbd
DBDDEPENDS_FILES += subproctest.dbd$(DEP)
subproctest_DBD += base.dbd
TESTPROD_HOST += subproctest
subproctest_SRCS += subproctest.c
subproctest_SRCS += subproctest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/subproctest.dbd ../subproctest.db
TESTS += subproctest
TESTPROD_HOST += linkFilterTest
linkFilterTest_SRCS += linkFilterTest.c
linkFilterTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp

View File

@@ -5,17 +5,24 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdlib.h>
#include "cantProceed.h"
#include "dbUnitTest.h"
#include "testMain.h"
#include "dbLock.h"
#include "errlog.h"
#include "dbAccess.h"
#include "epicsMath.h"
#include "menuYesNo.h"
#include "aiRecord.h"
#include "waveformRecord.h"
#include "compressRecord.h"
#define testDEq(A,B,D) testOk(fabs((A)-(B))<(D), #A " (%f) ~= " #B " (%f)", A, B)
#define fetchRecordOrDie(recname, addr) if (dbNameToAddr(recname, &addr)) {testAbort("Unknown PV '%s'", recname);}
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
@@ -33,8 +40,7 @@ void checkArrD(const char *pv, long elen, double a, double b, double c, double d
expect[2] = c;
expect[3] = d;
if (dbNameToAddr(pv, &addr))
testAbort("Unknown PV '%s'", pv);
fetchRecordOrDie(pv, addr);
if (dbGet(&addr, DBR_DOUBLE, buf, NULL, &nReq, NULL))
testAbort("Failed to get '%s'", pv);
@@ -66,8 +72,7 @@ void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32
expect[2] = c;
expect[3] = d;
if (dbNameToAddr(pv, &addr))
testAbort("Unknown PV '%s'", pv);
fetchRecordOrDie(pv, addr);
if (dbGet(&addr, DBR_LONG, buf, NULL, &nReq, NULL))
testAbort("Failed to get '%s'", pv);
@@ -85,6 +90,24 @@ void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32
}
}
void
writeToWaveform(DBADDR *addr, long count, ...) {
va_list args;
long i;
double *values = (double *)callocMustSucceed(count, sizeof(double), "writeToWaveform");
va_start(args, count);
for (i=0; i< count; i++) {
values[i] = va_arg(args, double);
}
va_end(args);
dbScanLock(addr->precord);
dbPut(addr, DBR_DOUBLE, values, count);
dbScanUnlock(addr->precord);
free(values);
}
static
void testFIFOCirc(void)
{
@@ -100,9 +123,9 @@ void testFIFOCirc(void)
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4");
testdbReadDatabase("compressTest.db", NULL, "INP=ai,ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4");
vrec = (aiRecord*)testdbRecordPtr("val");
vrec = (aiRecord*)testdbRecordPtr("ai");
crec = (compressRecord*)testdbRecordPtr("comp");
eltc(0);
@@ -230,9 +253,9 @@ void testLIFOCirc(void)
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL,
"ALG=Circular Buffer,BALG=LIFO Buffer,NSAM=4");
"INP=ai,ALG=Circular Buffer,BALG=LIFO Buffer,NSAM=4");
vrec = (aiRecord*)testdbRecordPtr("val");
vrec = (aiRecord*)testdbRecordPtr("ai");
crec = (compressRecord*)testdbRecordPtr("comp");
eltc(0);
@@ -346,10 +369,278 @@ void testLIFOCirc(void)
testdbCleanup();
}
void
testArrayAverage(void) {
DBADDR wfaddr, caddr;
testDiag("Test Array Average");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=Average,BALG=FIFO Buffer,NSAM=4,N=2");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
writeToWaveform(&wfaddr, 4, 2., 4., 6., 8.);
dbProcess(caddr.precord);
checkArrD("comp", 4, 1.5, 3., 4.5, 6.);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1Average(void) {
double buf = 0.0;
long nReq = 1;
DBADDR wfaddr, caddr;
testDiag("Test Average");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=1,N=4");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
testDiag("Test incomplete input data");
writeToWaveform(&wfaddr, 3, 1., 2., 3.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testOk1(nReq == 0);
testDEq(buf, 0., 0.01);
dbScanUnlock(caddr.precord);
testDiag("Test complete input data");
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
nReq = 1;
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 2.5, 0.01);
dbScanUnlock(caddr.precord);
testDiag("Test single input data");
writeToWaveform(&wfaddr, 1, 5.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
nReq = 1;
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
// Assert that nothing has changed from before
testDEq(buf, 2.5, 0.01);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1AveragePartial(void) {
double buf = 0.0;
long nReq = 1;
DBADDR wfaddr, caddr;
testDiag("Test Average, Partial");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=1,N=4,PBUF=YES");
eltc(0);
testIocInitOk();
eltc(1);
testDiag("Test incomplete input data");
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 3, 1., 2., 3.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 2.0, 0.01);
dbScanUnlock(caddr.precord);
testDiag("Test single entry from wf record");
writeToWaveform(&wfaddr, 1, 6.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 6.0, 0.01);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1LowValue(void) {
double buf = 0.0;
long nReq = 1;
DBADDR wfaddr, caddr;
testDiag("Test 'N to 1 Low Value'");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Low Value,BALG=FIFO Buffer,NSAM=1,N=4");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
testDiag("Test full array");
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 1.0, 0.01);
dbScanUnlock(caddr.precord);
writeToWaveform(&wfaddr, 4, 4., 3., 2., 1.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 1.0, 0.01);
dbScanUnlock(caddr.precord);
testDiag("Test partial data with PBUF set to NO");
writeToWaveform(&wfaddr, 3, 5., 6., 7.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
// We confirm that this hasn't changed i.e. the dbProcess above did nothing
testDEq(buf, 1.0, 0.01);
testDiag("Test partial data with PBUF set to YES");
((compressRecord *)caddr.precord)->pbuf = menuYesNoYES;
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
testDEq(buf, 5.0, 0.01);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testAIAveragePartial(void) {
double buf = 0.;
double data[5] = {1., 2., 3., 4., 5.};
/*
* Note that the fifth dbPut essentially resets the circular buffer, so the
* average is once again the average of the _first_ entry alone.
*/
double expected[5] = {1., 1.5, 2., 2.5, 5.};
long nReq = 1;
int i;
DBADDR aiaddr, caddr;
testDiag("Test 'N to 1 Average' with analog in, PBUF=YES");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=ai,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=1,N=4,PBUF=YES");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("ai", aiaddr);
fetchRecordOrDie("comp", caddr);
for (i = 0; i < 5; i++) {
dbScanLock(aiaddr.precord);
dbPut(&aiaddr, DBR_DOUBLE, &data[i], 1);
dbScanUnlock(aiaddr.precord);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
if (dbGet(&caddr, DBR_DOUBLE, &buf, NULL, &nReq, NULL))
testAbort("dbGet failed on compress record");
dbScanUnlock(caddr.precord);
testDEq(buf, expected[i], 0.01);
}
testIocShutdownOk();
testdbCleanup();
}
MAIN(compressTest)
{
testPlan(116);
testPlan(132);
testFIFOCirc();
testLIFOCirc();
testArrayAverage();
testNto1Average();
testNto1AveragePartial();
testAIAveragePartial();
testNto1LowValue();
return testDone();
}

View File

@@ -1,7 +1,13 @@
record(ai, "val") {}
record(ai, "ai") {}
record(waveform, "wf") {
field(FTVL, "DOUBLE")
field(NELM, "4")
}
record(compress, "comp") {
field(INP, "val NPP")
field(INP, "$(INP) NPP")
field(ALG, "$(ALG)")
field(PBUF,"$(PBUF=NO)")
field(BALG,"$(BALG)")
field(NSAM,"$(NSAM)")
field(N, "$(N=1)")
}

View File

@@ -123,7 +123,7 @@ MAIN(mbbioDirectTest)
testDiag("##### clear bit 31 (0x1f) #####");
putN("do%u.B1F", N, 0);
value &= ~(1<<31);
value &= ~(1u<<31u);
testN("val%d", N, value);
testmbbioRecords(N, value);

View File

@@ -0,0 +1,55 @@
/*************************************************************************\
* Copyright (c) 2022 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* This test covers tests related to invoking subrecords
*/
#include <testMain.h>
#include <dbUnitTest.h>
#include <dbAccess.h>
#include <iocsh.h>
#include "registryFunction.h"
#include <subRecord.h>
static
long subproc(subRecord *prec)
{
prec->proc = 77;
return 0;
}
void subproctest_registerRecordDeviceDriver(struct dbBase *);
MAIN(subproctest)
{
testPlan(2);
testdbPrepare();
testdbReadDatabase("subproctest.dbd", NULL, NULL);
subproctest_registerRecordDeviceDriver(pdbbase);
registryFunctionAdd("subproc", (REGISTRYFUNCTION) subproc);
testdbReadDatabase("subproctest.db", NULL, "TPRO=0");
testIocInitOk();
testDiag("===== Test that invalid link in INPA field fails a put request ======");
testdbPutFieldFail(-1, "InvalidINPARec.PROC", DBF_LONG, 1);
/* Since the put to PROC above fails, subproc() never runs
* and the value of PROC will not be set by subproc(). However,
* the testdbPutField call above goes through, so we get a partial
* result of the PROC field being left as 1. */
testdbGetFieldEqual("InvalidINPARec.PROC", DBF_LONG, 1);
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,4 @@
record(sub, "InvalidINPARec") {
field(SNAM, "subproc")
field(INPA, "nonexistent")
}