async def test_exception_raising_monitor_callback(ioc: subprocess.Popen, capsys) -> None: wait_for_ioc(ioc) m = camonitor(LONGOUT, boom) assert m.state == m.OPENING captured = capsys.readouterr() assert captured.out == "" assert captured.err == "" # Wait for first update to come in and close the subscription await asyncio.sleep(0.5) assert m.state == m.CLOSED captured = capsys.readouterr() assert captured.out == "" assert "ValueError: Boom" in captured.err # Check no more updates values: List[str] = [] m.callback = values.append await caput(LONGOUT, 32) assert m.state == m.CLOSED captured = capsys.readouterr() assert captured.out == "" assert captured.err == "" assert len(values) == 0
async def test_monitor_two_pvs(ioc: subprocess.Popen) -> None: values: List[Tuple[AugmentedValue, int]] = [] await caput(WAVEFORM, [1, 2], wait=True) ms = camonitor([WAVEFORM, LONGOUT], lambda v, n: values.append((v, n)), count=-1) # Wait for connection await poll_length(values, gt=1) assert values == [(pytest.approx([1, 2, 0, 0, 0]), 0), (42, 1)] values.clear() await caput(LONGOUT, 11, wait=True) await asyncio.sleep(0.1) await caput(LONGOUT, 12, wait=True) await asyncio.sleep(0.1) assert values == [(11, 1), (12, 1)] values.clear() for m in ms: m.close() ioc.communicate("exit") await asyncio.sleep(1.0) assert values == []
async def test_monitor_with_failing_dbr(ioc: subprocess.Popen, capsys) -> None: values: List[AugmentedValue] = [] m = camonitor(LONGOUT, values.append, notify_disconnect=True) # Wait for connection await poll_length(values) assert values == [42] values.clear() m.dbr_to_value = boom assert m.state == m.OPEN await caput(LONGOUT, 43, wait=True) await asyncio.sleep(0.1) assert m.state == m.CLOSED assert values == [] captured = capsys.readouterr() assert captured.out == "" assert "ValueError: Boom" in captured.err ioc.communicate("exit") await asyncio.sleep(0.1) m.close() await asyncio.sleep(0.1) assert values == []
async def do_stuff(): # Using caput: write into pv. Raises exception on failure pv = 'chris:amplitude' await caput(pv, 1.0) # Print out the value reported by pv. print(f"{pv} = {await caget(pv)}") # Monitor pv, printing out each update as it is received. def callback(value): print(f'callback: {pv} = {value}') camonitor(pv, callback) await caput(pv, 2.0) await caput(pv, 3.0) await caput(pv, 4.0)
async def test_camonitor_non_existent() -> None: values: List[AugmentedValue] = [] m = camonitor(NE, values.append, connect_timeout=0.2) try: assert len(values) == 0 await asyncio.sleep(0.5) assert len(values) == 1 assert not values[0].ok finally: m.close()
async def test_monitor_gc(ioc: subprocess.Popen) -> None: values: List[AugmentedValue] = [] camonitor(LONGOUT, values.append, notify_disconnect=True) # Wait for connection await poll_length(values) assert len(values) == 1 await caput(LONGOUT, 43, wait=True) # Check the monitor survives a garbage collect await asyncio.sleep(0.1) gc.collect() await asyncio.sleep(0.1) await caput(LONGOUT, 44, wait=True) await asyncio.sleep(0.1) ioc.communicate("exit") await asyncio.sleep(0.2) # Check everything is there assert [42, 43, 44] == values[:3] assert [True, True, True, False] == [v.ok for v in values]
async def test_monitor(ioc: subprocess.Popen) -> None: values: List[AugmentedValue] = [] m = camonitor(LONGOUT, values.append, notify_disconnect=True) # Wait for connection await poll_length(values) await asyncio.sleep(0.1) await caput(LONGOUT, 43, wait=True) await asyncio.sleep(0.1) await caput(LONGOUT, 44, wait=True) await asyncio.sleep(0.1) ioc.communicate("exit") await asyncio.sleep(0.1) m.close() assert [42, 43, 44] == values[:3] assert [True, True, True, False] == [v.ok for v in values]
async def subscribe_channel( self, pv: str, config: ChannelConfig) -> AsyncIterator[Channel]: q: asyncio.Queue[AugmentedValue] = asyncio.Queue() info, meta_value = await asyncio.gather( cainfo(pv), caget(pv, format=FORMAT_CTRL), ) m = camonitor(pv, q.put, format=FORMAT_TIME) try: # Hold last channel for squashing identical alarms last_channel = None while True: value = await q.get() channel = CAChannel(value, config, meta_value, info.write, last_channel) yield channel last_channel = channel finally: m.close()
async def test_long_monitor_callback(ioc: subprocess.Popen) -> None: values = [] wait_for_ioc(ioc) async def cb(value): values.append(value) await asyncio.sleep(0.4) m = camonitor(LONGOUT, cb, connect_timeout=(time.time() + 0.5, )) # Wait for connection, calling first cb await poll_length(values) assert values == [42] assert m.dropped_callbacks == 0 # These two caputs happen during the sleep of the first cb, and are # squashed together for the second cb await caput(LONGOUT, 43) await caput(LONGOUT, 44) # Wait until the second cb has finished await asyncio.sleep(0.6) assert [42, 44] == values assert m.dropped_callbacks == 0 # Wait until the third cb (which is dropped) has finished await asyncio.sleep(0.6) assert [42, 44] == values assert m.dropped_callbacks == 1 values.clear() # Add another one and close before the cb can fire await caput(LONGOUT, 45) # Block the event loop to make sure the caput has triggered updates # without the callback running time.sleep(0.4) # Now close so that the callback finds the connection closed and doesn't fire m.close() await asyncio.sleep(0.4) assert [] == values assert m.dropped_callbacks == 1
async def monitor_for_a_bit(callback: Callable, ioc) -> Subscription: wait_for_ioc(ioc) m = camonitor(TICKING, callback, notify_disconnect=True) await asyncio.sleep(1.1) return m
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 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