-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathtest_asyncio.py
More file actions
211 lines (167 loc) · 6.56 KB
/
Copy pathtest_asyncio.py
File metadata and controls
211 lines (167 loc) · 6.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import asyncio
import pytest
import sys
from multiprocessing.connection import Listener
from conftest import (
ADDRESS, select_and_recv,
log, get_multiprocessing_context, TIMEOUT,
create_random_prefix
)
from softioc.asyncio_dispatcher import AsyncioDispatcher
from softioc import builder, softioc
@pytest.mark.asyncio
async def test_asyncio_ioc(asyncio_ioc):
import asyncio
from aioca import caget, caput, camonitor, CANothing, FORMAT_TIME
pre = asyncio_ioc.pv_prefix
with Listener(ADDRESS) as listener, listener.accept() as conn:
select_and_recv(conn, "R") # "Ready"
# Start
assert (await caget(pre + ":UPTIME")).startswith("00:00:0")
# WAVEFORM
await caput(pre + ":SINN", 4, wait=True)
q = asyncio.Queue()
m = camonitor(pre + ":SIN", q.put, notify_disconnect=True)
assert len(await asyncio.wait_for(q.get(), 1)) == 4
# AO
ao_val = await caget(pre + ":ALARM", format=FORMAT_TIME)
assert ao_val == 0
assert ao_val.severity == 3 # INVALID
assert ao_val.status == 17 # UDF
ai_val = await caget(pre + ":AI", format=FORMAT_TIME)
assert ai_val == 23.45
assert ai_val.severity == 0
assert ai_val.status == 0
await caput(pre + ":ALARM", 3, wait=True)
await caput(pre + ":NAME-CALLBACK", 12, wait=True)
# Confirm the ALARM callback has completed
select_and_recv(conn, "C") # "Complete"
ai_val = await caget(pre + ":AI", format=FORMAT_TIME)
assert ai_val == 23.45
assert ai_val.severity == 3
assert ai_val.status == 7 # STATE_ALARM
# Check pvaccess works
from p4p.client.asyncio import Context
with Context("pva") as ctx:
assert await ctx.get(pre + ":AI") == 23.45
long_pv = pre + ":AVERYLONGRECORDSUFFIXTOMAKELONGPV"
long_str = "A long string that is more than 40 characters long"
assert await ctx.get(long_pv) == long_str
assert await ctx.get(long_pv + ".NAME") == long_pv
await ctx.put(pre + ":LONGSTRING", long_str)
assert await ctx.get(pre + ":LONGSTRING") == long_str
conn.send("D") # "Done"
select_and_recv(conn, "D") # "Done"
# Stop
out, err = asyncio_ioc.proc.communicate(b"exit\n", timeout=5)
out = out.decode()
err = err.decode()
# Disconnect
assert isinstance(await asyncio.wait_for(q.get(), 10), CANothing)
m.close()
# check closed and output
try:
assert "%s:SINN.VAL 1024 -> 4" % pre in out
assert 'update_sin_wf 4' in out
assert "%s:ALARM.VAL 0 -> 3" % pre in out
assert 'on_update %s:AO : 3.0' % pre in out
assert 'async update 3.0 (23.45)' in out
assert "%s:NAME-CALLBACK value 12" % pre in out
assert 'Starting iocInit' in err
assert 'iocRun: All initialization complete' in err
except Exception:
# Useful printing for when things go wrong!
print("Out:", out)
print("Err:", err)
raise
@pytest.mark.asyncio
@pytest.mark.skipif(
sys.platform.startswith("darwin"),
reason="devIocStats reboot doesn't work on MacOS")
async def test_asyncio_ioc_override(asyncio_ioc_override):
from aioca import caget, caput
with Listener(ADDRESS) as listener, listener.accept() as conn:
select_and_recv(conn, "R") # "Ready"
# Gain bo
pre = asyncio_ioc_override.pv_prefix
assert (await caget(pre + ":GAIN")) == 0
await caput(pre + ":GAIN", "On", wait=True)
assert (await caget(pre + ":GAIN")) == 1
# Stop
await caput(pre + ":SYSRESET", 1)
conn.send("D") # "Done"
select_and_recv(conn, "D") # "Done"
# check closed and output
out, err = asyncio_ioc_override.proc.communicate(timeout=5)
out = out.decode()
err = err.decode()
# check closed and output
try:
assert '1' in out
assert 'Starting iocInit' in err
assert 'iocRun: All initialization complete' in err
assert 'IOC reboot started' in err
except Exception:
# Useful printing for when things go wrong!
print("Out:", out)
print("Err:", err)
raise
def test_asyncio_dispatcher_event_loop():
"""Test that passing a non-running event loop to the AsyncioDispatcher
raises an exception"""
try:
event_loop = asyncio.get_event_loop()
except RuntimeError:
event_loop = asyncio.new_event_loop()
with pytest.raises(ValueError):
AsyncioDispatcher(loop=event_loop)
def asyncio_dispatcher_test_func(device_name, child_conn):
log("CHILD: Child started")
builder.SetDeviceName(device_name)
with AsyncioDispatcher() as dispatcher:
# Create some records
ai = builder.aIn('AI', initial_value=5)
builder.aOut('AO', initial_value=12.45, always_update=True,
on_update=lambda v: ai.set(v))
# Boilerplate get the IOC started
builder.LoadDatabase()
softioc.iocInit(dispatcher)
# Start processes required to be run after iocInit
async def update():
while True:
ai.set(ai.get() + 1)
await asyncio.sleep(0.01)
dispatcher(update)
log("CHILD: Sending Ready")
child_conn.send("R")
# Keep process alive while main thread runs CAGET
if child_conn.poll(TIMEOUT):
val = child_conn.recv()
assert val == "D", "Did not receive expected Done character"
async def test_asyncio_dispatcher_as_context_manager():
"""Test that the asyncio dispatcher can be used as a context manager"""
ctx = get_multiprocessing_context()
parent_conn, child_conn = ctx.Pipe()
device_name = create_random_prefix()
process = ctx.Process(
target=asyncio_dispatcher_test_func,
args=(device_name, child_conn),
)
process.start()
log("PARENT: Child started, waiting for R command")
from aioca import caget
try:
# Wait for message that IOC has started
select_and_recv(parent_conn, "R")
# ao_val = await caget(device_name + ":AO")
ao_val = await caget(device_name + ":AO")
assert ao_val == 12.45
# Confirm the value of the AI record is increasing
ai_val_1 = await caget(device_name + ":AI")
await asyncio.sleep(1)
ai_val_2 = await caget(device_name + ":AI")
assert ai_val_2 > ai_val_1
finally:
parent_conn.send("D") # "Done"
process.join(timeout=TIMEOUT)
assert process.exitcode == 0 # clean exit