Skip to content

Commit 5f63e8d

Browse files
Add tests for caput using invalid values
Note we have to skip mbbOut record testing, as for some reason cothread caput succeeds for this record type but not for the others
1 parent c555837 commit 5f63e8d

File tree

1 file changed

+136
-1
lines changed

1 file changed

+136
-1
lines changed

tests/test_record_values.py

+136-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
log,
1313
select_and_recv,
1414
TIMEOUT,
15-
get_multiprocessing_context
15+
get_multiprocessing_context,
16+
create_random_prefix
1617
)
1718

1819
from softioc import asyncio_dispatcher, builder, softioc
20+
from softioc.fields import DBR_STRING
1921
from softioc.pythonSoftIoc import RecordWrapper
2022

2123
# Test file for anything related to valid record values getting/setting
@@ -966,3 +968,136 @@ def test_mbb_rejects_invalid_values(self):
966968
builder.mbbIn("MBB_IN_3", initial_value=16)
967969
with pytest.raises(AssertionError):
968970
builder.mbbOut("MBB_OUT_3", initial_value=16)
971+
972+
def invalid_value_test_func(self, device_name, conn, creation_func):
973+
974+
builder.SetDeviceName(device_name)
975+
976+
creation_func("INVALID_VAL_REC")
977+
978+
dispatcher = asyncio_dispatcher.AsyncioDispatcher()
979+
builder.LoadDatabase()
980+
softioc.iocInit(dispatcher)
981+
982+
conn.send("R") # "Ready"
983+
984+
log("CHILD: Sent R over Connection to Parent")
985+
986+
# Keep process alive while main thread runs CAGET
987+
if conn.poll(TIMEOUT):
988+
val = conn.recv()
989+
assert val == "D", "Did not receive expected Done character"
990+
991+
log("CHILD: Received exit command, child exiting")
992+
993+
@requires_cothread
994+
@pytest.mark.parametrize(
995+
"creation_func, invalid_min, invalid_max, expected_val",
996+
[
997+
(
998+
builder.longOut,
999+
numpy.iinfo(numpy.int32).min - 1,
1000+
numpy.iinfo(numpy.int32).max + 1,
1001+
0,
1002+
),
1003+
(
1004+
builder.boolOut,
1005+
-1,
1006+
2,
1007+
0,
1008+
),
1009+
(
1010+
builder.mbbOut,
1011+
-1,
1012+
16,
1013+
0,
1014+
),
1015+
],
1016+
1017+
)
1018+
def test_invalid_values_caput(
1019+
self, creation_func, invalid_min, invalid_max, expected_val
1020+
):
1021+
"""Test that attempting to set invalid values causes caput to return
1022+
an error, and the record's value remains unchanged."""
1023+
if creation_func == builder.mbbOut:
1024+
pytest.skip(
1025+
"Bug somewhere, possibly Cothread, means that errors are not "
1026+
"reported for mbbOut records")
1027+
1028+
ctx = get_multiprocessing_context()
1029+
1030+
parent_conn, child_conn = ctx.Pipe()
1031+
1032+
device_name = create_random_prefix()
1033+
1034+
process = ctx.Process(
1035+
target=self.invalid_value_test_func,
1036+
args=(device_name, child_conn, creation_func),
1037+
)
1038+
1039+
process.start()
1040+
1041+
log("PARENT: Child started, waiting for R command")
1042+
1043+
from cothread.catools import caget, caput, _channel_cache
1044+
1045+
try:
1046+
# Wait for message that IOC has started
1047+
select_and_recv(parent_conn, "R")
1048+
1049+
log("PARENT: received R command")
1050+
1051+
# Suppress potential spurious warnings
1052+
_channel_cache.purge()
1053+
1054+
record_name = device_name + ":INVALID_VAL_REC"
1055+
1056+
log(f"PARENT: Putting invalid min value {invalid_min} to record")
1057+
# Send as string data, otherwise catools will automatically convert
1058+
# it to a valid int32
1059+
put_ret = caput(
1060+
record_name,
1061+
invalid_min,
1062+
wait=True,
1063+
datatype=DBR_STRING,
1064+
throw=False,
1065+
)
1066+
assert not put_ret.ok, \
1067+
"caput for invalid minimum value unexpectedly succeeded"
1068+
1069+
log(f"PARENT: Putting invalid max value {invalid_max} to record")
1070+
put_ret = caput(
1071+
record_name,
1072+
invalid_max,
1073+
wait=True,
1074+
datatype=DBR_STRING,
1075+
throw=False,
1076+
)
1077+
assert not put_ret.ok, \
1078+
"caput for invalid maximum value unexpectedly succeeded"
1079+
1080+
1081+
log("PARENT: Getting value from record")
1082+
1083+
ret_val = caget(
1084+
record_name,
1085+
timeout=TIMEOUT,
1086+
)
1087+
assert ret_val.ok, \
1088+
f"caget did not succeed: {ret_val.errorcode}, {ret_val}"
1089+
1090+
log(f"PARENT: Received val from record: {ret_val}")
1091+
1092+
assert ret_val == expected_val
1093+
1094+
finally:
1095+
# Suppress potential spurious warnings
1096+
_channel_cache.purge()
1097+
1098+
log("PARENT: Sending Done command to child")
1099+
parent_conn.send("D") # "Done"
1100+
process.join(timeout=TIMEOUT)
1101+
log(f"PARENT: Join completed with exitcode {process.exitcode}")
1102+
if process.exitcode is None:
1103+
pytest.fail("Process did not terminate")

0 commit comments

Comments
 (0)