Added tests for ts and dbnd plugins, fix in dbnd.c: make local functions static
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
@@ -37,17 +38,17 @@ chfPluginArgDef opts[] = {
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
void * allocPvt(void)
|
||||
static void * allocPvt(void)
|
||||
{
|
||||
return freeListCalloc(myStructFreeList);
|
||||
}
|
||||
|
||||
void freePvt(void *pvt)
|
||||
static void freePvt(void *pvt)
|
||||
{
|
||||
freeListFree(myStructFreeList, pvt);
|
||||
}
|
||||
|
||||
int parse_ok(void *pvt)
|
||||
static int parse_ok(void *pvt)
|
||||
{
|
||||
myStruct *my = (myStruct*) pvt;
|
||||
my->hyst = my->cval;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_LIBS += dbIoc registryIoc dbStaticHost ca Com
|
||||
|
||||
TESTPROD_HOST += tsTest
|
||||
tsTest_SRCS += tsTest.c
|
||||
OBJS_IOC_vxWorks += tsTest
|
||||
TESTS += tsTest
|
||||
|
||||
TESTPROD_HOST += dbndTest
|
||||
dbndTest_SRCS += dbndTest.c
|
||||
OBJS_IOC_vxWorks += dbndTest
|
||||
TESTS += dbndTest
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbCommon.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTime.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
epicsShareExtern void (*pvar_func_dbndInitialize)(void);
|
||||
|
||||
static db_field_log fl;
|
||||
|
||||
static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
|
||||
return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
|
||||
}
|
||||
|
||||
static void fl_setup(dbChannel *chan, db_field_log *pfl) {
|
||||
struct dbCommon *prec = dbChannelRecord(chan);
|
||||
|
||||
pfl->ctx = dbfl_context_read;
|
||||
pfl->type = dbfl_type_val;
|
||||
pfl->stat = prec->stat;
|
||||
pfl->sevr = prec->sevr;
|
||||
pfl->time = prec->time;
|
||||
pfl->field_type = dbChannelFieldType(chan);
|
||||
pfl->no_elements = dbChannelElements(chan);
|
||||
/*
|
||||
* use memcpy to avoid a bus error on
|
||||
* union copy of char in the db at an odd
|
||||
* address
|
||||
*/
|
||||
memcpy(&pfl->u.v.field,
|
||||
dbChannelField(chan),
|
||||
dbChannelFieldSize(chan));
|
||||
}
|
||||
|
||||
static changeValue(db_field_log *pfl2, long val) {
|
||||
pfl2->u.v.field.dbf_long = val;
|
||||
testDiag("new value: %ld", val);
|
||||
}
|
||||
|
||||
static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
|
||||
changeValue(pfl2, val);
|
||||
testDiag("mode=%s delta=%g filter must pass once", m, d);
|
||||
db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
|
||||
testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
|
||||
testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
|
||||
pfl = dbChannelRunPreChain(pch, pfl2);
|
||||
testOk(NULL == pfl, "call 2 drops field_log");
|
||||
}
|
||||
|
||||
static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
|
||||
changeValue(pfl2, val);
|
||||
testDiag("mode=%s delta=%g filter must drop", m, d);
|
||||
db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
|
||||
testOk(NULL == pfl, "call 1 drops field_log");
|
||||
}
|
||||
|
||||
static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
|
||||
changeValue(pfl2, val);
|
||||
testDiag("mode=%s delta=%g filter must pass twice", m, d);
|
||||
db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
|
||||
testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
|
||||
testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
|
||||
pfl = dbChannelRunPreChain(pch, pfl2);
|
||||
testOk(pfl2 == pfl, "call 2 does not drop or replace field_log");
|
||||
testOk(fl_equal(pfl, pfl2), "call 2 does not change field_log data");
|
||||
}
|
||||
|
||||
static void testHead (char* title) {
|
||||
testDiag("--------------------------------------------------------");
|
||||
testDiag(title);
|
||||
testDiag("--------------------------------------------------------");
|
||||
}
|
||||
|
||||
MAIN(dbndTest)
|
||||
{
|
||||
dbChannel *pch;
|
||||
chFilter *filter;
|
||||
const chFilterPlugin *plug;
|
||||
char dbnd[] = "dbnd";
|
||||
ELLNODE *node;
|
||||
chPostEventFunc *cb_out = NULL;
|
||||
void *arg_out = NULL;
|
||||
db_field_log *pfl, *pfl2;
|
||||
db_field_log fl1;
|
||||
|
||||
testPlan(0);
|
||||
|
||||
db_init_events();
|
||||
|
||||
testOk1(!dbReadDatabase(&pdbbase, "filterTest.dbx", ".:..", NULL));
|
||||
testOk(!!pdbbase, "pdbbase was set");
|
||||
|
||||
(*pvar_func_dbndInitialize)(); /* manually initialize plugin */
|
||||
|
||||
testOk(!!(plug = dbFindFilter(dbnd, strlen(dbnd))), "plugin dbnd registered correctly");
|
||||
|
||||
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{}}")), "dbChannel with plugin dbnd (delta=0) created");
|
||||
testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
|
||||
|
||||
memset(&fl, PATTERN, sizeof(fl));
|
||||
fl1 = fl;
|
||||
node = ellFirst(&pch->filters);
|
||||
filter = CONTAINER(node, chFilter, list_node);
|
||||
plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
|
||||
testOk(!!(cb_out) && !!(arg_out), "register_pre registers one filter with argument");
|
||||
testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
|
||||
|
||||
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
|
||||
node = ellFirst(&pch->pre_chain);
|
||||
filter = CONTAINER(node, chFilter, pre_node);
|
||||
testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL),
|
||||
"dbnd has one filter with argument in pre chain");
|
||||
testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");
|
||||
|
||||
/* Field logs of type ref and rec: pass any update */
|
||||
|
||||
testHead("Field logs of type ref and rec");
|
||||
fl1.type = dbfl_type_rec;
|
||||
mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0);
|
||||
|
||||
fl1.type = dbfl_type_ref;
|
||||
mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
|
||||
|
||||
/* Delta = 0: pass any change */
|
||||
|
||||
testHead("Delta = 0: pass any change");
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 0., 0);
|
||||
mustPassOnce(pch, pfl2, "abs", 0., 1);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Delta = -1: pass any update */
|
||||
|
||||
testHead("Delta = -1: pass any update");
|
||||
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":-1.0}}")), "dbChannel with plugin dbnd (delta=-1) created");
|
||||
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassTwice(pch, pfl2, "abs", -1., 0);
|
||||
mustPassTwice(pch, pfl2, "abs", -1., 1);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Delta = absolute */
|
||||
|
||||
testHead("Delta = absolute");
|
||||
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":3}}")), "dbChannel with plugin dbnd (delta=3) created");
|
||||
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 3., 1);
|
||||
mustDrop(pch, pfl2, "abs", 3., 3);
|
||||
mustDrop(pch, pfl2, "abs", 3., 4);
|
||||
mustPassOnce(pch, pfl2, "abs", 3., 5);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Delta = relative */
|
||||
|
||||
testHead("Delta = relative");
|
||||
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"m\":\"rel\",\"d\":50}}")),
|
||||
"dbChannel with plugin dbnd (mode=rel, delta=50) created");
|
||||
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 1);
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 2);
|
||||
mustDrop(pch, pfl2, "rel", 50., 3);
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 4);
|
||||
mustDrop(pch, pfl2, "rel", 50., 5);
|
||||
mustDrop(pch, pfl2, "rel", 50., 6);
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 7);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
dbFreeBase(pdbbase);
|
||||
|
||||
return testDone();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# This is a combined minimal DBD and DB file
|
||||
|
||||
recordtype(x) {
|
||||
field(NAME, DBF_STRING) {
|
||||
prompt("Record Name")
|
||||
special(SPC_NOMOD)
|
||||
size(61)
|
||||
}
|
||||
field(VAL, DBF_LONG) {
|
||||
prompt("Value")
|
||||
}
|
||||
}
|
||||
record(x, x) {}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTime.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
epicsShareExtern void (*pvar_func_tsInitialize)(void);
|
||||
|
||||
static db_field_log fl;
|
||||
|
||||
static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
|
||||
return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
|
||||
}
|
||||
|
||||
static int fl_equal_ex_ts(const db_field_log *pfl1, const db_field_log *pfl2) {
|
||||
db_field_log fl1 = *pfl1;
|
||||
|
||||
fl1.time = pfl2->time;
|
||||
return fl_equal(&fl1, pfl2);
|
||||
}
|
||||
|
||||
MAIN(tsTest)
|
||||
{
|
||||
dbChannel *pch;
|
||||
chFilter *filter;
|
||||
const chFilterPlugin *plug;
|
||||
char ts[] = "ts";
|
||||
ELLNODE *node;
|
||||
chPostEventFunc *cb_out = NULL;
|
||||
void *arg_out = NULL;
|
||||
db_field_log fl1;
|
||||
db_field_log *pfl2;
|
||||
|
||||
testPlan(0);
|
||||
|
||||
db_init_events();
|
||||
|
||||
testOk1(!dbReadDatabase(&pdbbase, "filterTest.dbx", ".:..", NULL));
|
||||
testOk(!!pdbbase, "pdbbase was set");
|
||||
|
||||
(*pvar_func_tsInitialize)(); /* manually initialize plugin */
|
||||
|
||||
testOk(!!(plug = dbFindFilter(ts, strlen(ts))), "plugin ts registered correctly");
|
||||
|
||||
testOk(!!(pch = dbChannelCreate("x.VAL{\"ts\":{}}")), "dbChannel with plugin ts created");
|
||||
testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
|
||||
|
||||
memset(&fl, PATTERN, sizeof(fl));
|
||||
fl1 = fl;
|
||||
node = ellFirst(&pch->filters);
|
||||
filter = CONTAINER(node, chFilter, list_node);
|
||||
plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
|
||||
testOk(!!(cb_out) && !(arg_out), "register_pre registers one filter w/o argument");
|
||||
testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
|
||||
|
||||
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin ts opened");
|
||||
node = ellFirst(&pch->pre_chain);
|
||||
filter = CONTAINER(node, chFilter, pre_node);
|
||||
testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg == NULL),
|
||||
"ts has one filter w/o argument in pre chain");
|
||||
testOk((ellCount(&pch->post_chain) == 0), "ts has no filter in post chain");
|
||||
|
||||
memset(&fl, PATTERN, sizeof(fl));
|
||||
fl1 = fl;
|
||||
pfl2 = dbChannelRunPreChain(pch, &fl1);
|
||||
testOk(pfl2 == &fl1, "ts filter does not drop or replace field_log");
|
||||
testOk(fl_equal_ex_ts(&fl1, pfl2), "ts filter does not change field_log data");
|
||||
|
||||
testOk(pfl2 = db_create_read_log(pch), "create field log from channel");
|
||||
epicsTimeStamp stamp = pfl2->time;
|
||||
pfl2 = dbChannelRunPreChain(pch, &fl1);
|
||||
epicsTimeStamp now; epicsTimeGetCurrent(&now);
|
||||
testOk(epicsTimeDiffInSeconds(&pfl2->time, &stamp) > 0. &&
|
||||
epicsTimeDiffInSeconds(&now, &pfl2->time) > 0., "ts filter sets time stamp to \"now\"");
|
||||
|
||||
dbChannelDelete(pch);
|
||||
dbFreeBase(pdbbase);
|
||||
|
||||
return testDone();
|
||||
}
|
||||
Reference in New Issue
Block a user