Skip to content

Commit

Permalink
TST: add tests that revealed some minor bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
ZLLentz committed Nov 14, 2024
1 parent ce4587f commit 2f2ea07
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 0 deletions.
45 changes: 45 additions & 0 deletions beams/tests/mock_iocs/various_types_ioc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
from textwrap import dedent

from caproto import ChannelType
from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run


class VariousTypesIOC(PVGroup):
"""
An IOC with three uncoupled read/writable PVs.
Scalar PVs
----------
COMP (int)
"""

INT = pvproperty(
value=3,
dtype=ChannelType.INT,
)

FLOAT = pvproperty(
value=3.14,
dtype=ChannelType.FLOAT,
precision=3,
)

STRING = pvproperty(
value="pi",
dtype=ChannelType.STRING,
)

ENUM = pvproperty(
value=2,
dtype=ChannelType.ENUM,
enum_strings=["e", "i", "pi"]
)


if __name__ == "__main__":
ioc_options, run_options = ioc_arg_parser(
default_prefix="VAR:TYPES:", desc=dedent(VariousTypesIOC.__doc__)
)
ioc = VariousTypesIOC(**ioc_options)
run(ioc.pvdb, **run_options)
105 changes: 105 additions & 0 deletions beams/tests/test_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@
import caproto.server
import caproto.server.server
import pytest
from caproto import ChannelType
from caproto.server import PVGroup, pvproperty
from caproto.tests.conftest import run_example_ioc

from beams.bin.gen_test_ioc_main import collect_pv_info
from beams.bin.main import main
from beams.tests.conftest import cli_args, restore_logging
from beams.tree_config import save_tree_item_to_path
from beams.tree_config.base import EPICSValue
from beams.tree_config.composite import SequenceItem
from beams.tree_config.condition import BinaryConditionItem

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -94,6 +101,104 @@ def mock_run(*args, **kwargs):
assert not run_called


def test_collect_pvinfo(
request: pytest.FixtureRequest,
):
run_example_ioc(
"beams.tests.mock_iocs.various_types_ioc",
request=request,
pv_to_check="VAR:TYPES:INT",
)
pv_info = collect_pv_info([
"VAR:TYPES:INT",
"VAR:TYPES:FLOAT",
"VAR:TYPES:STRING",
"VAR:TYPES:ENUM",
])
for info in pv_info:
if info.pvname == "VAR:TYPES:INT":
assert info.python_name == "var_types_int"
assert info.dtype == "INT"
assert info.value == 3
elif info.pvname == "VAR:TYPES:FLOAT":
assert info.python_name == "var_types_float"
assert info.dtype == "FLOAT"
assert info.value == pytest.approx(3.14)
assert info.precision == 3
elif info.pvname == "VAR:TYPES:STRING":
assert info.python_name == "var_types_string"
assert info.dtype == "STRING"
assert info.value == "pi"
elif info.pvname == "VAR:TYPES:ENUM":
assert info.python_name == "var_types_enum"
assert info.dtype == "ENUM"
assert info.value == 2
assert info.enum_strings == ["e", "i", "pi"]
else:
raise RuntimeError(f"Unexpected pvname {info.pvname}")


def test_gen_test_ioc_online(
request: pytest.FixtureRequest,
capsys: pytest.CaptureFixture,
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
):
run_example_ioc(
"beams.tests.mock_iocs.various_types_ioc",
request=request,
pv_to_check="VAR:TYPES:INT",
)
check_int = BinaryConditionItem(left_value=EPICSValue("VAR:TYPES:INT"))
check_float = BinaryConditionItem(left_value=EPICSValue("VAR:TYPES:FLOAT"))
check_string = BinaryConditionItem(left_value=EPICSValue("VAR:TYPES:STRING"))
check_enum = BinaryConditionItem(left_value=EPICSValue("VAR:TYPES:ENUM"))
seq = SequenceItem(children=[check_int, check_float, check_string, check_enum])
temp_file = str(tmp_path / "temp.json")
save_tree_item_to_path(path=temp_file, root=seq)
args = ["beams", "gen_test_ioc", temp_file]
with cli_args(args), restore_logging():
main()
result = capsys.readouterr()
code = result.out
assert isinstance(code, str)
logger.debug(f"Generated file:\n{code}")
inner_globals = {}
run_called = 0

def mock_run(*args, **kwargs):
nonlocal run_called
run_called += 1

# Paranoia: stop run from running if the generated file tries to run
monkeypatch.setattr(caproto.server, "run", mock_run)
monkeypatch.setattr(caproto.server.server, "run", mock_run)
exec(code, inner_globals)
BTSimIOC = inner_globals["BTSimIOC"]
assert issubclass(BTSimIOC, PVGroup)
assert isinstance(BTSimIOC.var_types_int, pvproperty)
assert isinstance(BTSimIOC.var_types_float, pvproperty)
assert isinstance(BTSimIOC.var_types_string, pvproperty)
assert isinstance(BTSimIOC.var_types_enum, pvproperty)
assert BTSimIOC.var_types_int.pvspec.name == "VAR:TYPES:INT"
assert BTSimIOC.var_types_float.pvspec.name == "VAR:TYPES:FLOAT"
assert BTSimIOC.var_types_string.pvspec.name == "VAR:TYPES:STRING"
assert BTSimIOC.var_types_enum.pvspec.name == "VAR:TYPES:ENUM"
assert BTSimIOC.var_types_int.pvspec.dtype == ChannelType.INT
assert BTSimIOC.var_types_float.pvspec.dtype == ChannelType.FLOAT
assert BTSimIOC.var_types_string.pvspec.dtype == ChannelType.STRING
assert BTSimIOC.var_types_enum.pvspec.dtype == ChannelType.ENUM

ioc = BTSimIOC(prefix="")
assert "VAR:TYPES:INT" in ioc.pvdb
assert "VAR:TYPES:FLOAT" in ioc.pvdb
assert "VAR:TYPES:STRING" in ioc.pvdb
assert "VAR:TYPES:ENUM" in ioc.pvdb

# We essentially did an import, no run should have happened
assert not run_called


artifact_validation_codes = [
# Standard test eggs should work
("eggs.json", 0),
Expand Down

0 comments on commit 2f2ea07

Please sign in to comment.