start PDB unittest
This commit is contained in:
16
Makefile
16
Makefile
@ -18,8 +18,16 @@ include $(TOP)/configure/RULES_TOP
|
||||
|
||||
UNINSTALL_DIRS += $(wildcard $(INSTALL_LOCATION)/python*)
|
||||
|
||||
#useful targets includ: doc-html and doc-clean
|
||||
doc-%:
|
||||
PYTHONPATH=$$PWD/python$(PY_VER)/$(EPICS_HOST_ARCH) $(MAKE) -C documentation $*
|
||||
# jump to a sub-directory where CONFIG_PY has been included
|
||||
# can't include CONFIG_PY here as it may not exist yet
|
||||
nose sphinx sh ipython: all
|
||||
$(MAKE) -C devsupApp/src/O.$(EPICS_HOST_ARCH) $@ PYTHON=$(PYTHON)
|
||||
|
||||
doc: doc-html
|
||||
sphinx-clean:
|
||||
$(MAKE) -C documentation clean PYTHON=$(PYTHON)
|
||||
|
||||
sphinx-commit: sphinx
|
||||
touch documentation/_build/html/.nojekyll
|
||||
./commit-gh.sh documentation/_build/html
|
||||
|
||||
.PHONY: nose sphinx sphinx-commit sphinx-clean
|
||||
|
@ -39,5 +39,7 @@ PY_VER=2.7
|
||||
# Python interpreter
|
||||
PYTHON ?= python$(PY_VER)
|
||||
|
||||
USR_CPPFLAGS += -DUSE_TYPED_RSET
|
||||
|
||||
-include $(TOP)/configure/CONFIG_SITE.local
|
||||
-include $(TOP)/../CONFIG_SITE.local
|
||||
|
@ -24,9 +24,12 @@ _dbapi_SRCS += dbapi.c
|
||||
_dbapi_SRCS += dbrec.c
|
||||
_dbapi_SRCS += dbfield.c
|
||||
_dbapi_SRCS += dbdset.c
|
||||
_dbapi_SRCS += utest.c
|
||||
|
||||
_dbapi_SRCS += pyDevSupCommon_registerRecordDeviceDriver.cpp
|
||||
|
||||
_dbapi_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
PY += devsup/__init__.py
|
||||
PY += devsup/_nullapi.py
|
||||
PY += devsup/db.py
|
||||
@ -37,6 +40,9 @@ PY += devsup/util.py
|
||||
PY += devsup/disect.py
|
||||
PY += devsup/ptable.py
|
||||
|
||||
PY += devsup/test/__init__.py
|
||||
PY += devsup/test/test_db.py
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
@ -52,3 +58,20 @@ pyconfig:
|
||||
@echo "Library path: $(PY_LIBDIRS)"
|
||||
@echo "USR_CPPFLAGS: $(USR_CPPFLAGS)"
|
||||
@echo "USR_LDFLAGS: $(USR_LDFLAGS)"
|
||||
|
||||
ifneq (,$(T_A))
|
||||
nose:
|
||||
PYTHONPATH="${PYTHONPATH}:$(abspath $(TOP))/python$(PY_LD_VER)/$(EPICS_HOST_ARCH)" $(PYTHON) -m nose -P devsup $(NOSEFLAGS)
|
||||
|
||||
# bounce back down to the sphinx generated Makefile
|
||||
# aren't Makefiles fun...
|
||||
sphinx:
|
||||
PYTHONPATH="${PYTHONPATH}:$(abspath $(TOP))/python$(PY_LD_VER)/$(EPICS_HOST_ARCH)" $(MAKE) -C $(TOP)/documentation html
|
||||
|
||||
sh:
|
||||
echo "export PYTHONPATH=\$${PYTHONPATH}:$(abspath $(TOP))/python$(PY_LD_VER)/$(EPICS_HOST_ARCH)" > $(OUTPUT)
|
||||
|
||||
ipython:
|
||||
PYTHONPATH="${PYTHONPATH}:$(abspath $(TOP))/python$(PY_LD_VER)/$(EPICS_HOST_ARCH)" $(PYTHON) -c "import sys; sys.argv[0] = '$(PYTHON)'; from IPython.terminal.ipapp import launch_new_instance; launch_new_instance()"
|
||||
|
||||
endif
|
||||
|
@ -194,9 +194,9 @@ PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
if(fname)
|
||||
if(fname) {
|
||||
status = dbReadDatabase(&pdbbase, fname, path, sub);
|
||||
else {
|
||||
} else {
|
||||
FILE *ff = fdopen(fd, "r");
|
||||
status = dbReadDatabaseFP(&pdbbase, ff, path, sub);
|
||||
// dbReadDatabaseFP() has called fclose()
|
||||
@ -213,18 +213,31 @@ PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_iocInit(PyObject *unused)
|
||||
PyObject *py_iocInit(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
{
|
||||
static char* names[] = {"isolate", NULL};
|
||||
PyObject *pyisolate = Py_True;
|
||||
int isolate, ret;
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kws, "|O", names, &pyisolate))
|
||||
return NULL;
|
||||
|
||||
isolate = PyObject_IsTrue(pyisolate);
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
iocInit();
|
||||
ret = isolate ? iocBuildIsolated() : iocBuild();
|
||||
if(!ret)
|
||||
ret = iocRun();
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
if(ret)
|
||||
return PyErr_Format(PyExc_RuntimeError, "Error %d", ret);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_pyDevSupCommon(PyObject *unused)
|
||||
{
|
||||
static int once;
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
pyDevSupCommon_registerRecordDeviceDriver(pdbbase);
|
||||
} Py_END_ALLOW_THREADS
|
||||
@ -258,7 +271,7 @@ static struct PyModuleDef dbapimodule = {
|
||||
|
||||
PyMODINIT_FUNC init_dbapi(void)
|
||||
{
|
||||
PyObject *mod = NULL, *hookdict, *vertup, *obj;
|
||||
PyObject *mod = NULL, *hookdict, *vertup;
|
||||
pystate *st;
|
||||
|
||||
pyDevReasonID = epicsThreadPrivateCreate();
|
||||
@ -354,19 +367,12 @@ PyMODINIT_FUNC init_dbapi(void)
|
||||
if(vertup)
|
||||
PyModule_AddObject(mod, "pydevver", vertup);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION>=7)
|
||||
obj = PyCapsule_New(pdbbase, "pdbbase", NULL);
|
||||
#else
|
||||
obj = PyCObject_FromVoidPtrAndDesc(pdbbase, "pdbbase", NULL);
|
||||
#endif
|
||||
if(!obj)
|
||||
goto fail;
|
||||
PyModule_AddObject(mod, "pdbbase", obj);
|
||||
|
||||
if(pyField_prepare(mod))
|
||||
goto fail;
|
||||
if(pyRecord_prepare(mod))
|
||||
goto fail;
|
||||
if(pyUTest_prepare(mod))
|
||||
goto fail;
|
||||
|
||||
MODINIT_RET(mod);
|
||||
|
||||
|
@ -22,16 +22,11 @@ from ._dbapi import (EPICS_VERSION_STRING,
|
||||
|
||||
__all__ = []
|
||||
|
||||
_ready = [False]
|
||||
|
||||
def _init(iocMain=False):
|
||||
if _ready[0]:
|
||||
return
|
||||
_ready[0] = True
|
||||
|
||||
if not iocMain:
|
||||
# we haven't read/register base.dbd
|
||||
_dbapi.dbReadDatabase(os.path.join(XEPICS_BASE, "dbd", "base.dbd"))
|
||||
_dbapi.dbReadDatabase(os.path.join(XEPICS_BASE, "dbd", "base.dbd"),
|
||||
path=os.path.join(XEPICS_BASE, "dbd"))
|
||||
_dbapi._dbd_rrd_base()
|
||||
|
||||
with tempfile.NamedTemporaryFile() as F:
|
||||
|
0
devsupApp/src/devsup/test/__init__.py
Normal file
0
devsupApp/src/devsup/test/__init__.py
Normal file
82
devsupApp/src/devsup/test/test_db.py
Normal file
82
devsupApp/src/devsup/test/test_db.py
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import tempfile
|
||||
|
||||
from ..db import getRecord
|
||||
from .. import _dbapi
|
||||
from .. import _init
|
||||
|
||||
# short-circuit warning from _dbapi._init()
|
||||
os.environ['TOP'] = _dbapi.XPYDEV_BASE
|
||||
|
||||
class IOCHelper(unittest.TestCase):
|
||||
db = None
|
||||
autostart = running = False
|
||||
def setUp(self):
|
||||
print("testdbPrepare()")
|
||||
_dbapi._UTest.testdbPrepare()
|
||||
_init(iocMain=False) # load base.dbd
|
||||
|
||||
if self.db is not None:
|
||||
with tempfile.NamedTemporaryFile() as F:
|
||||
F.write(self.db)
|
||||
F.flush()
|
||||
_dbapi.dbReadDatabase(F.name)
|
||||
|
||||
if self.autostart:
|
||||
self.iocInit()
|
||||
|
||||
def tearDown(self):
|
||||
self.iocShutdown();
|
||||
print("testdbCleanup()")
|
||||
_dbapi._UTest.testdbCleanup()
|
||||
|
||||
def iocInit(self):
|
||||
if not self.running:
|
||||
print("testIocInitOk")
|
||||
_dbapi._UTest.testIocInitOk()
|
||||
self.running = True
|
||||
|
||||
def iocShutdown(self):
|
||||
if self.running:
|
||||
print("testIocShutdownOk")
|
||||
_dbapi._UTest.testIocShutdownOk()
|
||||
self.running = False
|
||||
|
||||
class TestIOC(IOCHelper):
|
||||
def test_base(self):
|
||||
pass
|
||||
|
||||
def test_start(self):
|
||||
self.iocInit()
|
||||
self.iocShutdown()
|
||||
|
||||
def test_db(self):
|
||||
with tempfile.NamedTemporaryFile() as F:
|
||||
F.write('record(longin, "test") {}\n')
|
||||
F.flush()
|
||||
_dbapi.dbReadDatabase(F.name)
|
||||
|
||||
rec = getRecord("test")
|
||||
self.assertEqual(rec.VAL, 0)
|
||||
rec.VAL = 5
|
||||
self.assertEqual(rec.VAL, 5)
|
||||
|
||||
class TestScan(IOCHelper):
|
||||
db = """
|
||||
record(longout, src) {
|
||||
field(OUT, "tgt PP")
|
||||
}
|
||||
record(longin, "tgt") {}
|
||||
"""
|
||||
autostart = True
|
||||
|
||||
def test_link(self):
|
||||
src, tgt = getRecord('src'), getRecord('tgt')
|
||||
|
||||
src.VAL = 42
|
||||
self.assertEqual(src.VAL, 42)
|
||||
self.assertEqual(tgt.VAL, 0)
|
||||
src.scan(sync=True)
|
||||
self.assertEqual(tgt.VAL, 42)
|
@ -20,6 +20,8 @@ initHookState pyInitLastState;
|
||||
PyObject* pyDBD_setup(PyObject *unused);
|
||||
PyObject* pyDBD_cleanup(PyObject *unused);
|
||||
|
||||
int pyUTest_prepare(PyObject *module);
|
||||
|
||||
int pyField_prepare(PyObject *module);
|
||||
|
||||
int pyRecord_prepare(PyObject *module);
|
||||
|
121
devsupApp/src/utest.c
Normal file
121
devsupApp/src/utest.c
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
/* python has its own ideas about which version to support */
|
||||
#undef _POSIX_C_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <dbUnitTest.h>
|
||||
#include <dbEvent.h>
|
||||
#include <iocInit.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include "pydevsup.h"
|
||||
|
||||
static dbEventCtx testEvtCtx;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
} UTest;
|
||||
|
||||
static PyTypeObject UTest_type = {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
#else
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0,
|
||||
#endif
|
||||
"_dbapi._UTest",
|
||||
sizeof(UTest),
|
||||
};
|
||||
|
||||
static PyObject* utest_prepare(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
//testdbPrepare(); doesn't do anything essential for us as of 7.0.2
|
||||
} Py_END_ALLOW_THREADS
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject* utest_init(PyObject *unused)
|
||||
{
|
||||
int ret;
|
||||
if(testEvtCtx)
|
||||
return PyErr_Format(PyExc_RuntimeError, "Missing testIocShutdownOk()");
|
||||
|
||||
// like, testIocInitOk() without testAbort()
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
eltc(0);
|
||||
ret = iocBuildIsolated() || iocRun();
|
||||
eltc(1);
|
||||
} Py_END_ALLOW_THREADS
|
||||
if(ret) {
|
||||
return PyErr_Format(PyExc_RuntimeError, "iocInit fails with %d", ret);
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
testEvtCtx=db_init_events();
|
||||
} Py_END_ALLOW_THREADS
|
||||
if(!testEvtCtx) {
|
||||
iocShutdown();
|
||||
return PyErr_Format(PyExc_RuntimeError, "iocInit fails create dbEvent context");
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
ret = db_start_events(testEvtCtx, "CAS-test-py", NULL, NULL, epicsThreadPriorityCAServerLow);
|
||||
} Py_END_ALLOW_THREADS
|
||||
if(ret!=DB_EVENT_OK) {
|
||||
db_close_events(testEvtCtx);
|
||||
testEvtCtx = NULL;
|
||||
iocShutdown();
|
||||
return PyErr_Format(PyExc_RuntimeError, "db_start_events fails with %d", ret);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject* utest_shutdown(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
//testIocShutdownOk();
|
||||
db_close_events(testEvtCtx);
|
||||
testEvtCtx = NULL;
|
||||
iocShutdown();
|
||||
} Py_END_ALLOW_THREADS
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject* utest_cleanup(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
testdbCleanup();
|
||||
errlogFlush();
|
||||
} Py_END_ALLOW_THREADS
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef UTest_methods[] = {
|
||||
{"testdbPrepare", (PyCFunction)&utest_prepare, METH_STATIC|METH_NOARGS, ""},
|
||||
{"testIocInitOk", (PyCFunction)&utest_init, METH_STATIC|METH_NOARGS, ""},
|
||||
{"testIocShutdownOk", (PyCFunction)&utest_shutdown, METH_STATIC|METH_NOARGS, ""},
|
||||
{"testdbCleanup", (PyCFunction)&utest_cleanup, METH_STATIC|METH_NOARGS, ""},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
int pyUTest_prepare(PyObject *module)
|
||||
{
|
||||
PyObject *typeobj=(PyObject*)&UTest_type;
|
||||
|
||||
UTest_type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
|
||||
UTest_type.tp_methods = UTest_methods;
|
||||
|
||||
if(PyType_Ready(&UTest_type)<0)
|
||||
return -1;
|
||||
|
||||
Py_INCREF(typeobj);
|
||||
if(PyModule_AddObject(module, "_UTest", typeobj)) {
|
||||
Py_DECREF(typeobj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user