async def test_subscribe_ticking(engine: Engine, ioc: Popen): query = (""" subscription { subscribeChannel(id: "ca://%sticking") { value { string(units: true) } display { precision units } } } """ % PV_PREFIX) results = [] wait_for_ioc(ioc) start = time.time() async for result in engine.subscribe(query, context=make_context()): results.append(result) if time.time() - start > 0.9: break for i, x in enumerate(range(3)): display = None if i == 0: display = dict(precision=5, units="mm") assert results[i] == dict(data=dict(subscribeChannel=dict( value=dict(string="%.5f mm" % x), display=display))) assert len(results) == 3
async def test_put_long_and_enum(engine: Engine, ioc: Popen): query = """ mutation { putChannels(ids: ["ca://%slongout", "ca://%senum"], values: ["55", "1"]) { value { string } time { datetime } } } """ % ( PV_PREFIX, PV_PREFIX, ) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict(putChannels=[ dict(value=dict(string="55"), time=ANY), dict(value=dict(string="mm"), time=ANY), ])) thens = [ datetime.fromisoformat(r["time"]["datetime"]) for r in result["data"]["putChannels"] ] now = datetime.now() for then in thens: diff = now - then # Shouldn't take more than this time to get the result of a put out assert diff.total_seconds() < 0.2
async def test_subscribe_ramp_wave(engine: Engine): query = """ subscription { subscribeChannel(id: "ssim://rampwave(3, 0.2)") { value { stringArray } } } """ context = make_context() results = [] start = time.time() async for result in engine.subscribe(query, context=context): results.append(result) if len(results) == 4: break # First result immediate, then takes 3x 0.2s assert time.time() - start - 0.6 < 0.2 expected = [ ["0.00000", "1.00000", "2.00000"], ["1.00000", "2.00000", "3.00000"], ["2.00000", "3.00000", "4.00000"], ["3.00000", "4.00000", "5.00000"], ] for i, x in enumerate(expected): assert results[i] == dict(data=dict(subscribeChannel=dict(value=dict( stringArray=x))))
async def test_get_sim_sine(engine: Engine): query = """ query { getChannel(id: "ssim://sine(-5,5,10,1,60)") { value { float string base64Array { numberType } stringArray } display { widget } } } """ context = make_context() for i, x in enumerate(EXPECTED_SIM_SINE): if i != 0: await asyncio.sleep(1.0) result = await engine.execute(query, context=context) assert result == dict(data=dict(getChannel=dict( value=dict( float=x, string="%.5f" % x, base64Array=None, stringArray=None), display=dict(widget="TEXTUPDATE"), ), ))
async def test_get_str_pv(engine: Engine, ioc: Popen): query = (""" query { getChannel(id: "ca://%slongout.RTYP") { value { string } } } """ % PV_PREFIX) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict(getChannel=dict(value=dict( string="longout"))))
async def test_get_int_pv(engine: Engine, ioc: Popen): query = (""" query { getChannel(id: "ca://%slongout") { value { float string } display { widget controlRange { min max } displayRange { min max } alarmRange { min max } warningRange { min max } units precision form } status { quality } } } """ % PV_PREFIX) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict(getChannel=dict( value=dict(float=42.0, string="42"), display=dict( widget="TEXTINPUT", controlRange=dict(min=10.0, max=90.0), displayRange=dict(min=0.0, max=100.0), alarmRange=dict(min=2.0, max=98.0), warningRange=dict(min=5.0, max=96.0), units="", precision=None, form=None, ), status=dict(quality="VALID"), ), ))
async def test_put_base64(engine: Engine, ioc: Popen): # first dump gives {"key": "value"}, a json string # second dump gives \{\"key\": \"value\"\}, an escaped json string value = json.dumps(json.dumps(BASE64_0_1688_2)) query = r""" mutation { putChannels(ids: ["ca://%swaveform"], values: [%s]) { value { stringArray } } } """ % ( PV_PREFIX, value, ) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict( putChannels=[dict(value=dict(stringArray=["0.0", "1.7", "2.0"]))]))
async def test_put_list(engine: Engine, ioc: Popen): query = (r""" mutation { putChannels(ids: ["ca://%swaveform"], values: ["[0, 1.688, \"2\"]"]) { value { stringArray base64Array { numberType base64 } } } } """ % PV_PREFIX) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict(putChannels=[ dict(value=dict(stringArray=["0.0", "1.7", "2.0"], base64Array=BASE64_0_1688_2)) ]))
async def test_get_enum_pv(engine: Engine, ioc: Popen): query = (""" query { getChannel(id: "ca://%senum") { value { string float } display { choices } } } """ % PV_PREFIX) result = await engine.execute(query, context=make_context()) assert result == dict(data=dict(getChannel=dict( value=dict(string="nm", float=3.0), display=dict(choices=["m", "mm", "um", "nm"]), )))
async def test_get_channel_config(engine: Engine): query = """ query { getChannelConfig(id:"ssim://sine") { readPv writePv description displayForm widget } } """ context = make_context(TEST_DIR / "simdevices.coniql.yaml") result = await engine.execute(query, context=context) assert result == dict(data=dict(getChannelConfig=dict( readPv="ssim://sine", writePv=None, description="A slow updating sine scalar value", displayForm=None, widget=None, )))
async def test_subscribe_sim_sine(engine: Engine): query = """ subscription { subscribeChannel(id: "ssim://sine") { value { float } } } """ context = make_context() results = [] start = time.time() async for result in engine.subscribe(query, context=context): results.append(result) if time.time() - start > 2: break for i, x in enumerate(EXPECTED_SIM_SINE): assert results[i] == dict(data=dict(subscribeChannel=dict(value=dict( float=x)))) assert len(results) == 3
async def test_get_channels(engine: Engine): query = """ query { getChannels(filter:"ssim://sinewave(5*") { id display { description } value { stringArray(length:2) } } } """ context = make_context(TEST_DIR / "simdevices.coniql.yaml") result = await engine.execute(query, context=context) assert result == dict(data=dict(getChannels=[ dict( id="ssim://sinewave(5.0, 1000)", display=dict(description="A low frequency sine wave"), value=dict(stringArray=["0.00000", "0.00000"]), ), ]))
async def test_put_sim_sine_fails(engine: Engine): query = """ mutation { putChannels(ids: ["ssim://sine"], values: ["32"]) { value { float } } } """ context = make_context() result = await engine.execute(query, context=context) assert result == dict( data=None, errors=[ dict( locations=[dict(column=5, line=3)], message= "Cannot put ['32'] to ['sine'], as they aren't writeable", path=["putChannels"], ) ], )
async def test_get_sim_sinewave(engine: Engine): query = """ query { getChannel(id: "ssim://sinewave") { value { string stringArray(length: 10) base64Array(length: 100) { numberType base64 } } } } """ context = make_context() result = await engine.execute(query, context=context) assert result == dict(data=dict(getChannel=dict(value=dict( string=str(np.zeros(50)), stringArray=["%.5f" % x for x in np.zeros(10)], base64Array=dict( numberType="FLOAT64", base64=base64.b64encode(np.zeros(50)).decode(), ), )))) await asyncio.sleep(1.0) result = await engine.execute(query, context=context) b64s = result["data"]["getChannel"]["value"]["base64Array"]["base64"] value = np.frombuffer(base64.b64decode(b64s), dtype=np.float64) assert result == dict(data=dict(getChannel=dict(value=dict( string=str(value), stringArray=["%.5f" % x for x in value[:10]], base64Array=dict( numberType="FLOAT64", base64=base64.b64encode(value).decode(), ), ))))
async def test_get_device(engine: Engine): query = """ query { getDevice(id:"Xspress3") { id children { name label child { ... on Channel { id value { float } } ... on Group { layout } ... on Device { id } } } } } """ context = make_context(TEST_DIR / "simdevices.coniql.yaml") result = await engine.execute(query, context=context) assert result == { "data": { "getDevice": { "id": "Xspress3", "children": [ { "name": "Temperature", "label": "Temperature", "child": { "id": "ssim://sine(40, 50)", "value": { "float": 0 } }, }, { "name": "Channel1", "label": "Channel1", "child": { "id": "Xspress3.Channel1" }, }, { "name": "Channel2", "label": "Channel2", "child": { "id": "Xspress3.Channel2" }, }, { "name": "Channel3", "label": "Channel3", "child": { "id": "Xspress3.Channel3" }, }, { "name": "Channel4", "label": "Channel4", "child": { "id": "Xspress3.Channel4" }, }, ], } } }
async def test_get_devices(engine: Engine): query = """ query { getDevices(filter:"Sine*") { id children(flatten:true) { name child { ... on Channel { id value { float } } ... on Group { layout children { name } } ... on Device { id } } } } } """ context = make_context(TEST_DIR / "simdevices.coniql.yaml") result = await engine.execute(query, context=context) assert result == { "data": { "getDevices": [ { "id": "Sine1", "children": [ { "name": "FastSine", "child": { "id": "ssim://sine(-10, 10, 100, 0.1)", "value": { "float": 0.0 }, }, }, { "name": "SlowSine", "child": { "id": "ssim://sine", "value": { "float": 0.0 } }, }, { "name": "Waves", "child": { "layout": "PLOT", "children": [ { "name": "HighFrequency" }, { "name": "LowFrequency" }, ], }, }, { "name": "HighFrequency", "child": { "id": "ssim://sinewave(0.1, 1000)", "value": { "float": None }, }, }, { "name": "LowFrequency", "child": { "id": "ssim://sinewave(5.0, 1000)", "value": { "float": None }, }, }, ], }, { "children": [ { "name": "FastSine", "child": { "id": "ssim://sine(-10, 10, 100, 0.1)", "value": { "float": 0.0 }, }, }, { "name": "SlowSine", "child": { "id": "ssim://sine", "value": { "float": 0.0 } }, }, { "name": "Waves", "child": { "layout": "PLOT", "children": [ { "name": "HighFrequency" }, { "name": "LowFrequency" }, ], }, }, { "name": "HighFrequency", "child": { "id": "ssim://sinewave(0.1, 1000)", "value": { "float": None }, }, }, { "name": "LowFrequency", "child": { "id": "ssim://sinewave(5.0, 1000)", "value": { "float": None }, }, }, ], "id": "Sine2", }, ] } }