Run the fragment verification suite
Check the common iocsh fragments of an installed tree against running
Experimental Physics and Industrial Control System (EPICS) input/output
controllers (IOCs). The suite has two parts in examples/commonIocsh:
verify_caputlog.py checks caPutLog.iocsh through the example IOC, and
the scripts in tests/ check every fragment through an external test IOC
named tc32sim.
Common iocsh fragments explains
what each fragment does.
Prerequisites
- An installed tree built with
make install; see Build and install the environment. - An EPICS-env clone, which holds the example IOC in
examples/commonIocsh. - Python 3 and
stdbufonPATH. - Transmission Control Protocol (TCP) port 7004 free on the local host.
verify_caputlog.pyfails a case that finds another process on that port. - For the optional
tests/scripts in step 5: a checkout of https://github.com/jeonghanlee/tc32sim,socat,ss, and free TCP ports 7011 and 7013.
-
In
<example_dir>/configure/RELEASE.local, set the installed EPICS base and caPutLog module:EPICS_BASE = <installed_tree>/base CAPUTLOG = <installed_tree>/modules/caPutLog<example_dir>is theexamples/commonIocshdirectory of the EPICS-env clone.<installed_tree>is the path thatmake print-INSTALL_LOCATION_EPICSprints in the EPICS-env clone that built the tree.
-
Build the example IOC:
make -C <example_dir> CHECK_RELEASE=NOThe installed caPutLog module keeps the
configure/RELEASEfile of its upstream source, which names a differentEPICS_BASE. With the release check on, the build stops atDefinition of EPICS_BASE conflicts with CAPUTLOG support. The build writes<example_dir>/bin/linux-x86_64/commonIocshExample. -
Change to the installed tree, so that the script arguments stay short:
cd <installed_tree> -
Run the caPutLog checks against the installed fragment:
python3 <example_dir>/verify_caputlog.py --base base --iocsh-top modules/commonIocsh --output <evidence_dir>--basenames the EPICS base directory that providescaputandiocLogServer.--iocsh-topnames thecommonIocshdirectory that holds theiocshdirectory of the fragments, and the script readsiocsh/caPutLog.iocshbelow it. The default iscommonIocshof the clone that holds the script.<evidence_dir>is the absolute path of a directory that does not exist; the script creates it and refuses an existing one.
Two more options have defaults:
--archsets the architecture directory of the IOC and base binaries,linux-x86_64, and--timeoutsets the seconds to wait for each expected event,30.The script prints one line per case and the evidence directory:
[ PASS ] defaults: observed expected behavior [ PASS ] all_puts: observed expected behavior [ PASS ] unfiltered: observed expected behavior [ PASS ] disabled: observed expected behavior [ PASS ] invalid_option: observed expected behavior [ PASS ] missing_host: observed expected behavior Evidence: <evidence_dir>For each case, the script starts
iocLogServerfrom EPICS base and the example IOC, which loadsiocsh/caPutLog.iocshbelow--iocsh-top. It then writes the test record withcaputfrom EPICS base and reads what the log server received. It removes every inheritedEPICS_CA_*,EPICS_CAS_*, andEPICS_IOC_LOG_*variable and gives each case its own Channel Access (CA) port on127.0.0.1. The cases are:Case Macros passed to caPutLog.iocshExpected behavior defaultsLOG_INET=127.0.0.1Port 7004, option 0: puts of 17, 17, and 29 give new=17 old=0andnew=29 old=17, and the repeated 17 adds no lineall_putsLOG_INET, a freeLOG_INET_PORT,OPTION=1The repeated 17 adds a line unfilteredLOG_INET, a freeLOG_INET_PORT,OPTION=2The repeated 17 adds a line disabledLOG_INET, a freeLOG_INET_PORT,OPTION=-1The IOC prints caPutLogInit config: Disabled, and the log server receives no lineinvalid_optionLOG_INET, a freeLOG_INET_PORT,OPTION=9The IOC prints caPutLogInit config: Unknown (must be -1, 0, 1, or 2), and the log server receives no linemissing_hostnone The IOC prints macLib: macro LOG_INET is undefined, and the log server receives no lineIn the cases that log, the script also checks that
caPutLogInitruns afteriocRun: All initialization complete. A case that waits for a result fails after 30 seconds; a case that expects no line watches for 12 seconds.The evidence directory holds
summary.jsonand one directory per case.summary.jsonnames the base, the IOC binary, the fragment path, the Secure Hash Algorithm 256-bit (SHA-256) digest of the fragment, and each case result. Each case directory holdsinputs.json,ioc.log,server.log,received.log, andclients.log. The script exits with 0 when every case passes and 1 when a case fails. -
Optional: to check every fragment through the tc32sim test IOC, run
run_all.shfrom the top of the EPICS-env clone whose example IOC steps 1 and 2 built:export DIST_TOP=<installed_tree> TC32SIM=<tc32sim_dir> export COMMONIOCSH=<installed_tree>/modules/commonIocsh bash examples/commonIocsh/tests/run_all.shDIST_TOPnames the installed tree that providesbase, the modules,iocLogServer, andcaput.<tc32sim_dir>is the tc32sim checkout.COMMONIOCSHnames thecommonIocshdirectory that holds theiocshdirectory of the fragments. The scripts setIOCSH_TOPto it and load$(IOCSH_TOP)/iocsh/<fragment>.iocsh.
The defaults of these three variables are paths on the developer’s host, so set all three. The scripts read them, and these optional variables, through
tests/common.sh:Variable Default Meaning ARCHlinux-x86_64Architecture directory of the binaries SKIP_REBUILD01leavesconfigure/RELEASE.localof tc32sim unchanged and uses its built binaryKEEP_WORKSPACE01keeps the temporary directory ofverify_caputlog.shandverify_integrated.shThe scripts use the tc32sim checkout as follows:
- They run
<tc32sim_dir>/bin/<ARCH>/tc32simfrom<tc32sim_dir>/iocBoot/ioctestlab-tc32sim, whoseenvPathssetsIOCtoioctestlab-tc32sim. - Unless
SKIP_REBUILD=1, each script exceptverify_caputlog.shoverwrites<tc32sim_dir>/configure/RELEASE.localwithEPICS_BASEand the module macros it needs, then runsmake cleanandmakein the checkout. - The tc32sim IOC must include
system.dbdand asyn serial support, andverify_autosave.shandverify_integrated.shload itsiocsh/tc32sim.iocshdevice setup. verify_caputlog.shuses the example IOC of steps 1 and 2 instead of tc32sim.
run_all.shruns eight scripts in turn. Each script prints itsPASS:andFAIL:lines and aPASS=<n> FAIL=<m>line, andrun_all.shprints aRESULTline after each script and anOVERALLline at the end:==== verify_linstat.sh ==== linStat: enabling module and rebuilding PASS: linStat host records present (ioctestlab-tc32sim:SYS_*) PASS: linStat host-net records present (ioctestlab-tc32sim:NET:HOST*) PASS: linStat proc records present (ioctestlab-tc32sim:IOC_*) PASS: linStat nic records present (ioctestlab-tc32sim:NET:lo*) PASS: linStat fs records present (ioctestlab-tc32sim:ROOT:*) -------------------- PASS=5 FAIL=0 RESULT verify_linstat.sh: PASS ==== verify_reccaster.sh ==== reccaster: enabling module and rebuilding PASS: reccaster record present (ioctestlab-tc32sim:State-Sts) PASS: reccaster record present (ioctestlab-tc32sim:Msg-I) -------------------- PASS=2 FAIL=0 RESULT verify_reccaster.sh: PASS ==== verify_iocstatsadmin.sh ==== iocStatsAdmin: enabling devIocStats and rebuilding PASS: iocStatsAdmin record present (ioctestlab-tc32sim:ACCESS) PASS: iocStatsAdmin record present (ioctestlab-tc32sim:HEARTBEAT) PASS: iocStatsAdmin record present (ioctestlab-tc32sim:STARTTOD) PASS: iocStatsAdmin record present (ioctestlab-tc32sim:UPTIME) -------------------- PASS=4 FAIL=0 RESULT verify_iocstatsadmin.sh: PASS ==== verify_autosave.sh ==== autosave: enabling module and rebuilding PASS: autosave pass1 retained across restart (all lines identical) PASS: autosave settings retained across restart (all lines identical) -------------------- PASS=2 FAIL=0 RESULT verify_autosave.sh: PASS ==== verify_ioclog.sh ==== iocLog: rebuilding (Base feature, no module macro) PASS: iocLog boot errlog received at server (proc=ioctestlab-tc32sim) -------------------- PASS=1 FAIL=0 RESULT verify_ioclog.sh: PASS ==== verify_serial.sh ==== serial: rebuilding and starting virtual PTYs PASS: serial params applied via config (baud 19200 on S1) PASS: serial skipped when SERIAL_ENABLE unset PASS: serial unreadable config reports error PASS: serial multiple ports get independent settings (S1 19200, S2 115200) -------------------- PASS=4 FAIL=0 RESULT verify_serial.sh: PASS ==== verify_caputlog.sh ==== caPutLog: orchestrating example IOC on isolated CA port PASS: caPutLog logged value change 0 -> 17 (new=17 old=0) PASS: caPutLog logged value change 17 -> 29 (new=29 old=17) PASS: caPutLog OPTION 0 suppressed the unchanged put (only the 29 change logged) -------------------- PASS=3 FAIL=0 RESULT verify_caputlog.sh: PASS ==== verify_integrated.sh ==== integrated: enabling all service modules and rebuilding Case A: aggregate boot of all services PASS: aggregate linStat host records present (:SYS_*) PASS: aggregate linStat proc records present (:IOC_*) PASS: aggregate linStat nic records present (:NET:lo*) PASS: aggregate linStat fs records present (:ROOT:*) PASS: aggregate reccaster records present (:State-Sts*) PASS: aggregate iocInit completed with all services loaded PASS: aggregate record names fully resolved (no macro cross-talk) PASS: aggregate loaded with no duplicate record collisions across services PASS: iocLog boot errlog reached server alongside other services PASS: caPutLog initialized in aggregate (coexists with autosave afterIocRunning) PASS: autosave afterIocRunning fired in aggregate (values_pass1.sav written) Case B: restart with autosave restore PASS: restart restored autosave values_pass1 set and reloaded all services Case C: minimal boot with optional services omitted PASS: minimal boot completed with optional NIC/FS/serial omitted -------------------- PASS=13 FAIL=0 RESULT verify_integrated.sh: PASS -------------------- OVERALL: PASSverify_integrated.shloads iocLog, serial, caPutLog, autosave, reccaster, and linStat in one IOC on port 7013 and leaves out iocStatsAdmin.run_all.shexits with 0 only when every script passes.
Verification
-
Count the passing cases in the summary file of step 4:
grep -c '"result": "Pass"' <evidence_dir>/summary.jsonAll six cases pass:
6