@@ -44,8 +44,8 @@ class DemoConfig(BaseModel):
4444
4545class TestConfigModels :
4646 def test_beamline_state_config_valid_name (self ):
47- config = bl_states .BeamlineStateConfig (name = "shutter_open " )
48- assert config .name == "shutter_open "
47+ config = bl_states .BeamlineStateConfig (name = "sample_x_limits " )
48+ assert config .name == "sample_x_limits "
4949
5050 @pytest .mark .parametrize ("invalid_name" , ["state-name" , "class" , "add" , "remove" , "show_all" ])
5151 def test_beamline_state_config_invalid_name (self , invalid_name ):
@@ -91,18 +91,25 @@ def evaluate(self, *args, **kwargs):
9191
9292class TestDeviceBeamlineState :
9393 def test_start_requires_connector (self , dm_with_devices ):
94- state = bl_states .ShutterState (
95- name = "shutter_open" , device = "samy" , signal = "samy" , device_manager = dm_with_devices
94+ state = bl_states .DeviceWithinLimitsState (
95+ name = "sample_y_limits" ,
96+ device = "samy" ,
97+ signal = "samy" ,
98+ low_limit = 0.0 ,
99+ high_limit = 10.0 ,
100+ device_manager = dm_with_devices ,
96101 )
97102
98103 with pytest .raises (RuntimeError , match = "Redis connector is not set" ):
99104 state .start ()
100105
101106 def test_start_registers_device_callback (self , connected_connector , dm_with_devices ):
102- state = bl_states .ShutterState (
103- name = "shutter_open " ,
107+ state = bl_states .DeviceWithinLimitsState (
108+ name = "sample_x_limits " ,
104109 device = "samx" ,
105110 signal = "samx" ,
111+ low_limit = 0.0 ,
112+ high_limit = 10.0 ,
106113 redis_connector = connected_connector ,
107114 device_manager = dm_with_devices ,
108115 )
@@ -115,10 +122,12 @@ def test_start_registers_device_callback(self, connected_connector, dm_with_devi
115122 )
116123
117124 def test_stop_unregisters_device_callback (self , connected_connector , dm_with_devices ):
118- state = bl_states .ShutterState (
119- name = "shutter_open " ,
125+ state = bl_states .DeviceWithinLimitsState (
126+ name = "sample_x_limits " ,
120127 device = "samx" ,
121128 signal = "samx" ,
129+ low_limit = 0.0 ,
130+ high_limit = 10.0 ,
122131 redis_connector = connected_connector ,
123132 device_manager = dm_with_devices ,
124133 )
@@ -134,50 +143,55 @@ def test_stop_unregisters_device_callback(self, connected_connector, dm_with_dev
134143 def test_update_device_state_publishes_when_state_changes (
135144 self , connected_connector , dm_with_devices
136145 ):
137- state = bl_states .ShutterState (
138- name = "shutter_open " ,
146+ state = bl_states .DeviceWithinLimitsState (
147+ name = "sample_x_limits " ,
139148 device = "samx" ,
140149 signal = "samx" ,
150+ low_limit = 0.0 ,
151+ high_limit = 10.0 ,
141152 redis_connector = connected_connector ,
142153 device_manager = dm_with_devices ,
143154 )
144155
145156 msg = messages .DeviceMessage (
146- signals = {"samx" : {"value" : "open" , "timestamp" : 1.0 }}, metadata = {"stream" : "primary" }
157+ signals = {"samx" : {"value" : 5.0 , "timestamp" : 1.0 }}, metadata = {"stream" : "primary" }
147158 )
148- msg_obj = MessageObject (value = msg , topic = "test" )
149159
150160 state ._update_device_state (MessageObject (value = msg , topic = "test" ))
151161
152162 assert state ._last_state is not None
153163 assert state ._last_state .status == "valid"
154164 out = connected_connector .xread (
155- MessageEndpoints .beamline_state ("shutter_open " ), from_start = True
165+ MessageEndpoints .beamline_state ("sample_x_limits " ), from_start = True
156166 )
157167 assert out is not None
158168 assert out [0 ]["data" ].status == "valid"
159169
160170
161171class TestConcreteStates :
162- def test_shutter_state_open_and_closed (self , connected_connector , dm_with_devices ):
163- state = bl_states .ShutterState (
164- name = "shutter_open" ,
172+ def test_device_within_limits_state_valid_and_invalid (
173+ self , connected_connector , dm_with_devices
174+ ):
175+ state = bl_states .DeviceWithinLimitsState (
176+ name = "sample_x_limits" ,
165177 device = "samx" ,
166178 signal = "samx" ,
179+ low_limit = 0.0 ,
180+ high_limit = 10.0 ,
167181 redis_connector = connected_connector ,
168182 device_manager = dm_with_devices ,
169183 )
170184 state .start ()
171185
172- open_msg = messages .DeviceMessage (
173- signals = {"samx" : {"value" : "OPEN" , "timestamp" : 1.0 }}, metadata = {"stream" : "primary" }
186+ valid_msg = messages .DeviceMessage (
187+ signals = {"samx" : {"value" : 5.0 , "timestamp" : 1.0 }}, metadata = {"stream" : "primary" }
174188 )
175- closed_msg = messages .DeviceMessage (
176- signals = {"samx" : {"value" : "closed" , "timestamp" : 2.0 }}, metadata = {"stream" : "primary" }
189+ invalid_msg = messages .DeviceMessage (
190+ signals = {"samx" : {"value" : 11.0 , "timestamp" : 2.0 }}, metadata = {"stream" : "primary" }
177191 )
178192
179- assert state .evaluate (open_msg ).status == "valid"
180- assert state .evaluate (closed_msg ).status == "invalid"
193+ assert state .evaluate (valid_msg ).status == "valid"
194+ assert state .evaluate (invalid_msg ).status == "invalid"
181195
182196 def test_device_within_limits_state (self , connected_connector , dm_with_devices ):
183197 state = bl_states .DeviceWithinLimitsState (
@@ -253,9 +267,14 @@ def test_manager_is_ready_when_no_state_update_exists(self, connected_connector)
253267
254268 def test_manager_loads_existing_state_update_on_init (self , connected_connector ):
255269 config = messages .BeamlineStateConfig (
256- name = "shutter_open" ,
257- state_type = "ShutterState" ,
258- parameters = {"name" : "shutter_open" , "device" : "samy" },
270+ name = "sample_y_limits" ,
271+ state_type = "DeviceWithinLimitsState" ,
272+ parameters = {
273+ "name" : "sample_y_limits" ,
274+ "device" : "samy" ,
275+ "low_limit" : 0.0 ,
276+ "high_limit" : 10.0 ,
277+ },
259278 )
260279 connected_connector .xadd (
261280 MessageEndpoints .available_beamline_states (),
@@ -268,14 +287,14 @@ def test_manager_loads_existing_state_update_on_init(self, connected_connector):
268287 manager = BeamlineStateManager (client )
269288
270289 assert manager .ready is True
271- assert "shutter_open " in manager ._states
272- assert isinstance (getattr (manager , "shutter_open " ), BeamlineStateClientBase )
290+ assert "sample_y_limits " in manager ._states
291+ assert isinstance (getattr (manager , "sample_y_limits " ), BeamlineStateClientBase )
273292
274293 def test_manager_rejects_abstract_state_type_on_init (self , connected_connector ):
275294 config = messages .BeamlineStateConfig (
276- name = "shutter_open " ,
295+ name = "generic_device_state " ,
277296 state_type = "DeviceBeamlineState" ,
278- parameters = {"name" : "shutter_open " , "device" : "samy" },
297+ parameters = {"name" : "generic_device_state " , "device" : "samy" },
279298 )
280299 connected_connector .xadd (
281300 MessageEndpoints .available_beamline_states (),
@@ -290,17 +309,24 @@ def test_manager_rejects_abstract_state_type_on_init(self, connected_connector):
290309
291310 def test_on_state_update_creates_client_attribute (self , state_manager ):
292311 config = messages .BeamlineStateConfig (
293- name = "shutter_open" ,
294- state_type = "ShutterState" ,
295- parameters = {"name" : "shutter_open" , "device" : "samy" },
312+ name = "sample_y_limits" ,
313+ state_type = "DeviceWithinLimitsState" ,
314+ parameters = {
315+ "name" : "sample_y_limits" ,
316+ "device" : "samy" ,
317+ "low_limit" : 0.0 ,
318+ "high_limit" : 10.0 ,
319+ },
296320 )
297321 update = messages .AvailableBeamlineStatesMessage (states = [config ])
298322
299323 state_manager ._on_state_update ({"data" : update }, parent = state_manager )
300324
301- assert "shutter_open" in state_manager ._states
302- assert isinstance (state_manager ._states ["shutter_open" ], bl_states .ShutterStateConfig )
303- assert isinstance (getattr (state_manager , "shutter_open" ), BeamlineStateClientBase )
325+ assert "sample_y_limits" in state_manager ._states
326+ assert isinstance (
327+ state_manager ._states ["sample_y_limits" ], bl_states .DeviceWithinLimitsStateConfig
328+ )
329+ assert isinstance (getattr (state_manager , "sample_y_limits" ), BeamlineStateClientBase )
304330
305331 def test_update_parameters_from_client_updates_state_and_publishes (self , state_manager ):
306332 config = messages .BeamlineStateConfig (
@@ -355,48 +381,60 @@ def test_external_parameter_update_refreshes_existing_client_state(self, state_m
355381
356382 def test_client_get_returns_unknown_without_status_message (self , state_manager ):
357383 config = messages .BeamlineStateConfig (
358- name = "shutter_open" ,
359- state_type = "ShutterState" ,
360- parameters = {"name" : "shutter_open" , "device" : "samy" },
384+ name = "sample_y_limits" ,
385+ state_type = "DeviceWithinLimitsState" ,
386+ parameters = {
387+ "name" : "sample_y_limits" ,
388+ "device" : "samy" ,
389+ "low_limit" : 0.0 ,
390+ "high_limit" : 10.0 ,
391+ },
361392 )
362393 update = messages .AvailableBeamlineStatesMessage (states = [config ])
363394 state_manager ._on_state_update ({"data" : update }, parent = state_manager )
364395
365- result = state_manager .shutter_open .get ()
396+ result = state_manager .sample_y_limits .get ()
366397 assert result == {"status" : "unknown" , "label" : "No state information available." }
367398
368399 def test_client_get_returns_latest_status_message (self , state_manager ):
369400 config = messages .BeamlineStateConfig (
370- name = "shutter_open" ,
371- state_type = "ShutterState" ,
372- parameters = {"name" : "shutter_open" , "device" : "samy" },
401+ name = "sample_y_limits" ,
402+ state_type = "DeviceWithinLimitsState" ,
403+ parameters = {
404+ "name" : "sample_y_limits" ,
405+ "device" : "samy" ,
406+ "low_limit" : 0.0 ,
407+ "high_limit" : 10.0 ,
408+ },
373409 )
374410 update = messages .AvailableBeamlineStatesMessage (states = [config ])
375411 state_manager ._on_state_update ({"data" : update }, parent = state_manager )
376412
377413 state_manager ._connector .xadd (
378- MessageEndpoints .beamline_state ("shutter_open " ),
414+ MessageEndpoints .beamline_state ("sample_y_limits " ),
379415 {
380416 "data" : messages .BeamlineStateMessage (
381- name = "shutter_open " , status = "valid" , label = "ok"
417+ name = "sample_y_limits " , status = "valid" , label = "ok"
382418 )
383419 },
384420 max_size = 1 ,
385421 )
386422
387- result = state_manager .shutter_open .get ()
423+ result = state_manager .sample_y_limits .get ()
388424 assert result == {"status" : "valid" , "label" : "ok" }
389425
390426 def test_add_waits_for_initial_state_message (self , state_manager ):
391- state = bl_states .ShutterStateConfig (name = "shutter_open" , device = "samy" )
427+ state = bl_states .DeviceWithinLimitsStateConfig (
428+ name = "sample_y_limits" , device = "samy" , low_limit = 0.0 , high_limit = 10.0
429+ )
392430
393431 def publish_initial_state ():
394432 time .sleep (0.05 )
395433 state_manager ._connector .xadd (
396- MessageEndpoints .beamline_state ("shutter_open " ),
434+ MessageEndpoints .beamline_state ("sample_y_limits " ),
397435 {
398436 "data" : messages .BeamlineStateMessage (
399- name = "shutter_open " , status = "valid" , label = "ok"
437+ name = "sample_y_limits " , status = "valid" , label = "ok"
400438 )
401439 },
402440 max_size = 1 ,
@@ -409,43 +447,52 @@ def publish_initial_state():
409447 finally :
410448 publisher .join ()
411449
412- assert state_manager .shutter_open .get () == {"status" : "valid" , "label" : "ok" }
450+ assert state_manager .sample_y_limits .get () == {"status" : "valid" , "label" : "ok" }
413451
414452 def test_add_rejects_abstract_device_state_config (self , state_manager ):
415- state = bl_states .DeviceStateConfig (name = "shutter_open " , device = "samy" )
453+ state = bl_states .DeviceStateConfig (name = "generic_device_state " , device = "samy" )
416454
417455 with pytest .raises (ValueError , match = "not a concrete beamline state" ):
418456 state_manager .add (state )
419457
420458 def test_add_and_delete_publish_updates (self , state_manager ):
421- state = bl_states .ShutterStateConfig (name = "shutter_open" , device = "samy" )
459+ state = bl_states .DeviceWithinLimitsStateConfig (
460+ name = "sample_y_limits" , device = "samy" , low_limit = 0.0 , high_limit = 10.0
461+ )
422462
423463 with mock .patch .object (state_manager , "_wait_for_initial_state" ):
424464 state_manager .add (state )
425- assert "shutter_open " in state_manager ._states
465+ assert "sample_y_limits " in state_manager ._states
426466
427- state_manager .delete ("shutter_open " )
428- assert "shutter_open " not in state_manager ._states
467+ state_manager .delete ("sample_y_limits " )
468+ assert "sample_y_limits " not in state_manager ._states
429469
430470 def test_client_remove_state (self , state_manager ):
431471 config = messages .BeamlineStateConfig (
432- name = "shutter_open" ,
433- state_type = "ShutterState" ,
434- parameters = {"name" : "shutter_open" , "device" : "samy" },
472+ name = "sample_y_limits" ,
473+ state_type = "DeviceWithinLimitsState" ,
474+ parameters = {
475+ "name" : "sample_y_limits" ,
476+ "device" : "samy" ,
477+ "low_limit" : 0.0 ,
478+ "high_limit" : 10.0 ,
479+ },
435480 )
436481 update = messages .AvailableBeamlineStatesMessage (states = [config ])
437482 state_manager ._on_state_update ({"data" : update }, parent = state_manager )
438483
439- state_manager .shutter_open .remove ()
484+ state_manager .sample_y_limits .remove ()
440485
441- assert "shutter_open " not in state_manager ._states
486+ assert "sample_y_limits " not in state_manager ._states
442487
443488 def test_show_all_prints_table (self , state_manager , capsys ):
444- state = bl_states .ShutterStateConfig (name = "shutter_open" , device = "samy" )
489+ state = bl_states .DeviceWithinLimitsStateConfig (
490+ name = "sample_y_limits" , device = "samy" , low_limit = 0.0 , high_limit = 10.0
491+ )
445492 with mock .patch .object (state_manager , "_wait_for_initial_state" ):
446493 state_manager .add (state )
447494
448495 state_manager .show_all ()
449496
450497 captured = capsys .readouterr ()
451- assert "shutter_open " in (captured .out + captured .err )
498+ assert "sample_y_limits " in (captured .out + captured .err )
0 commit comments