-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #34 from shilorigins/devagr/test-ioc
TST: Implement test IOC
- Loading branch information
Showing
9 changed files
with
151 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
docs/source/upcoming_release_notes/34-ioc_infrastructure.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
34 ioc infrastructure | ||
################# | ||
|
||
API Breaks | ||
---------- | ||
- N/A | ||
|
||
Features | ||
-------- | ||
- implement fixture for running IOCs that can be queried for integration tests | ||
- implement module that can run IOCs for demos | ||
|
||
Bugfixes | ||
-------- | ||
- don't change control_layer/core.py:SHIMS when creating dummy CLs | ||
|
||
Maintenance | ||
----------- | ||
- define linac testing structure outside of fixture | ||
|
||
Contributors | ||
------------ | ||
- shilorigins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .ioc_factory import IOCFactory # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
from multiprocessing import Process | ||
from typing import Iterable, Mapping, Union | ||
|
||
from caproto.server import PVGroup, pvproperty | ||
from caproto.server import run as run_ioc | ||
from epicscorelibs.ca import dbr | ||
|
||
from superscore.model import Entry, Nestable, Parameter, Readback, Setpoint | ||
|
||
|
||
class TempIOC(PVGroup): | ||
""" | ||
Makes PVs accessible via EPICS when running. Instances automatically start | ||
and stop running when used as a context manager, and are thus suitable for | ||
use in tests. | ||
""" | ||
def __enter__(self): | ||
self.running_process = Process( | ||
target=run_ioc, | ||
args=(self.pvdb,), | ||
daemon=True, | ||
) | ||
self.running_process.start() | ||
return self | ||
|
||
def __exit__(self, exc_type, exc_value, traceback): | ||
pass | ||
|
||
|
||
class IOCFactory: | ||
""" | ||
Generates TempIOC subclasses bound to a set of PVs. | ||
""" | ||
@staticmethod | ||
def from_entries(entries: Iterable[Entry], **ioc_options) -> PVGroup: | ||
""" | ||
Defines and instantiates a TempIOC subclass containing all PVs reachable | ||
from entries. | ||
""" | ||
attrs = IOCFactory.prepare_attrs(entries) | ||
IOC = type("IOC", (TempIOC,), attrs) | ||
return IOC | ||
|
||
@staticmethod | ||
def collect_pvs(entries: Iterable[Entry]) -> Iterable[Union[Parameter, Setpoint, Readback]]: | ||
"""Returns a collection of all PVs reachable from entries""" | ||
pvs = [] | ||
q = entries.copy() | ||
while len(q) > 0: | ||
entry = q.pop() | ||
if isinstance(entry, Nestable): | ||
q.extend(entry.children) | ||
else: | ||
pvs.append(entry) | ||
return pvs | ||
|
||
@staticmethod | ||
def prepare_attrs(entries: Iterable[Entry]) -> Mapping[str, pvproperty]: | ||
""" | ||
Turns a collecton of PVs into a Mapping from attribute names to | ||
caproto.pvproperties. The mapping is suitable for passing into a type() | ||
call as the dict arg. | ||
""" | ||
pvs = IOCFactory.collect_pvs(entries) | ||
attrs = {} | ||
for entry in pvs: | ||
value = entry.data if isinstance(entry, (Setpoint, Readback)) else None | ||
pv = pvproperty(name=entry.pv_name, doc=entry.description, value=value, dtype=dbr.DBR_STRING if isinstance(entry.data, str) else None) | ||
attr = "".join([c.lower() for c in entry.pv_name if c != ':']) | ||
attrs[attr] = pv | ||
return attrs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from caproto.server import ioc_arg_parser, run | ||
|
||
from superscore.tests.conftest import linac_data | ||
from superscore.tests.ioc import IOCFactory | ||
|
||
if __name__ == '__main__': | ||
_, snapshot = linac_data() | ||
LinacIOC = IOCFactory.from_entries(snapshot.children) | ||
|
||
ioc_options, run_options = ioc_arg_parser( | ||
default_prefix='SCORETEST:', | ||
desc="IOC evoking the structure of a linac", | ||
) | ||
ioc = LinacIOC(**ioc_options) | ||
run(ioc.pvdb, **run_options) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from superscore.control_layers.core import ControlLayer | ||
|
||
|
||
def test_ioc(linac_ioc): | ||
cl = ControlLayer() | ||
assert cl.get("SCORETEST:MGNT:GUNB:TEST0").data == 1 | ||
cl.put("SCORETEST:MGNT:GUNB:TEST0", 0) | ||
assert cl.get("SCORETEST:MGNT:GUNB:TEST0").data == 0 | ||
|
||
assert cl.get("SCORETEST:VAC:GUNB:TEST1").data == "Ion Pump" | ||
cl.put("SCORETEST:VAC:GUNB:TEST1", "new value") | ||
assert cl.get("SCORETEST:VAC:GUNB:TEST1").data == "new value" | ||
|
||
assert cl.get("SCORETEST:LASR:GUNB:TEST2").data == 5 | ||
cl.put("SCORETEST:LASR:GUNB:TEST2", 10) | ||
assert cl.get("SCORETEST:LASR:GUNB:TEST2").data == 10 | ||
|
||
assert cl.get("SCORETEST:LASR:IN10:TEST0").data == 645.26 | ||
cl.put("SCORETEST:LASR:IN10:TEST0", 600.0) | ||
assert cl.get("SCORETEST:LASR:IN10:TEST0").data == 600.0 |