Added tests for ts and dbnd plugins, fix in dbnd.c: make local functions static

This commit is contained in:
Michael Davidsaver
2012-04-27 13:22:04 -04:00
parent d2d91a545f
commit 0b32220e86
5 changed files with 356 additions and 3 deletions
+4 -3
View File
@@ -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;
+28
View File
@@ -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
+214
View File
@@ -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();
}
+13
View File
@@ -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) {}
+97
View File
@@ -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();
}