Description, motivation and use case
The test dummy control system currently creates independent DeviceAccess objects for Tango attributes. This makes it difficult to prepare a test context where a Tango attribute has a predefined value before the accelerator configuration is loaded.
For tests, dummy Tango attributes should behave like shared objects identified by their full attribute name. If a test initializes a value for a given attribute, every DeviceAccess object created later for the same attribute should read and update that same shared value.
This is especially useful for BPM tests based on array-valued Tango attributes. A BPM position may be backed by one Tango attribute returning both horizontal and vertical values. Today, there is a test-specific trick in the dummy control system: attach_array() marks the attached attribute as an array, and Attribute.set_array(True) initializes its internal cache to [0.0, 1.0]. This implicit initialization should be removed and replaced by explicit test setup.
This feature should be implemented from main and should not depend on catalog-related changes.
Proposed solution
Add a shared registry in the dummy Tango package, keyed by full Tango attribute name.
Each registry entry should store:
- current value
- readback value, if needed
- unit
- range
- read-only/read-write behavior, if needed
Attribute instances should no longer own their value directly. Instead, they should delegate get(), set(), readback(), unit(), and get_range() to the shared registry entry associated with their full attribute name.
Expose test helper functions such as:
set_attribute(name: str, value, unit: str = "", range=None)
get_attribute(name: str)
clear_attributes()
clear_attributes() should be used between tests to avoid state leakage. Pytest already provides mechanisms for this: a fixture can be added in conftest.py to automatically clear the dummy Tango registry before or after each test, so individual tests do not have to call clear_attributes() manually.
Describe alternatives you've considered
The current alternative is to keep initializing array attributes implicitly from attach_array() through Attribute.set_array(True). This is not ideal because the test data is hidden in the dummy implementation instead of being explicit in the test setup.
Another alternative would be to initialize each Attribute instance independently. This does not model Tango-like behavior correctly when several access objects point to the same attribute, and it does not allow a value prepared before Accelerator.load() to be shared by all objects created afterward.
Example
Example test setup:
dummy_tango.set_attribute("srdiag/bpm/c01-04/Position", [0.0, 1.0], unit="mm")
Then any dummy Attribute created later for srdiag/bpm/c01-04/Position should read the initialized array value.
This would allow the indexed BPM control-system test to prepare the expected array explicitly instead of relying on the current implicit [0.0, 1.0] initialization in Attribute.set_array(True).
Additional context
Expected behavior:
- A test can set the initial value of
srdiag/bpm/c01-04/Position before loading the accelerator.
- Any dummy
DeviceAccess created afterward for srdiag/bpm/c01-04/Position reads that initialized value.
- If one access object writes a new value, all other access objects for the same attribute see the updated value.
- Read-only attributes can still be initialized by the test setup.
- Attributes can be initialized either as scalars or arrays.
Acceptance criteria:
- Two dummy
Attribute instances created with the same Tango attribute name share the same value.
- A value initialized before
Accelerator.load() is visible from the loaded accelerator.
- Array-valued attributes are supported.
- Read-only attributes can be initialized by test setup.
- Tests can reset the dummy Tango registry between runs, preferably through a pytest fixture in
conftest.py.
Checklist
Description, motivation and use case
The test dummy control system currently creates independent
DeviceAccessobjects for Tango attributes. This makes it difficult to prepare a test context where a Tango attribute has a predefined value before the accelerator configuration is loaded.For tests, dummy Tango attributes should behave like shared objects identified by their full attribute name. If a test initializes a value for a given attribute, every
DeviceAccessobject created later for the same attribute should read and update that same shared value.This is especially useful for BPM tests based on array-valued Tango attributes. A BPM position may be backed by one Tango attribute returning both horizontal and vertical values. Today, there is a test-specific trick in the dummy control system:
attach_array()marks the attached attribute as an array, andAttribute.set_array(True)initializes its internal cache to[0.0, 1.0]. This implicit initialization should be removed and replaced by explicit test setup.This feature should be implemented from
mainand should not depend on catalog-related changes.Proposed solution
Add a shared registry in the dummy Tango package, keyed by full Tango attribute name.
Each registry entry should store:
Attributeinstances should no longer own their value directly. Instead, they should delegateget(),set(),readback(),unit(), andget_range()to the shared registry entry associated with their full attribute name.Expose test helper functions such as:
clear_attributes()should be used between tests to avoid state leakage. Pytest already provides mechanisms for this: a fixture can be added inconftest.pyto automatically clear the dummy Tango registry before or after each test, so individual tests do not have to callclear_attributes()manually.Describe alternatives you've considered
The current alternative is to keep initializing array attributes implicitly from
attach_array()throughAttribute.set_array(True). This is not ideal because the test data is hidden in the dummy implementation instead of being explicit in the test setup.Another alternative would be to initialize each
Attributeinstance independently. This does not model Tango-like behavior correctly when several access objects point to the same attribute, and it does not allow a value prepared beforeAccelerator.load()to be shared by all objects created afterward.Example
Example test setup:
Then any dummy
Attributecreated later forsrdiag/bpm/c01-04/Positionshould read the initialized array value.This would allow the indexed BPM control-system test to prepare the expected array explicitly instead of relying on the current implicit
[0.0, 1.0]initialization inAttribute.set_array(True).Additional context
Expected behavior:
srdiag/bpm/c01-04/Positionbefore loading the accelerator.DeviceAccesscreated afterward forsrdiag/bpm/c01-04/Positionreads that initialized value.Acceptance criteria:
Attributeinstances created with the same Tango attribute name share the same value.Accelerator.load()is visible from the loaded accelerator.conftest.py.Checklist