You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# 6. Handle devices shared between multiple endstations
2
+
3
+
Date: 2025-08-27
4
+
5
+
## Status
6
+
7
+
Proposed
8
+
9
+
## Context
10
+
11
+
Some beamlines have multiple endstations with shared hardware in the optics or experiment hutch, and could potentially be trying to control it at the same time. Any device in the common hutch should only be fully controlled by one endstation at a time - the one that is taking data - but still be readable from the other endstations.
12
+
13
+
## Decision
14
+
15
+
The current solution is to have a separate blueapi instance for the shared hutch in order to be able to control the access to all the devices defined there.
16
+
For all hardware in the shared optics hutch, the architecture should follow this structure:
17
+
18
+
- There is a base device in dodal that sends a REST call to the shared blueapi with plan and devices names, as well as the name of the endstation performing the call.
19
+
- There are read-only versions of the shared devices in the endstation blueapi which inherit from the base device above and set up the request parameters.
20
+
- The real settable devices are only defined in the shared blueapi and should never be called directly from a plan.
21
+
- The shared blueapi instance also has an ``AccessControl`` device that reads the endstation in use for beamtime from a PV.
22
+
- Every plan should then be wrapped in a decorator that reads the ``AccessControl`` device, check which endstation is making the request and only allows the plan to run if the two values match.
23
+
24
+
25
+
:::{seealso}
26
+
[Optics hutch implementation on I19](https://diamondlightsource.github.io/i19-bluesky/main/explanations/decisions/0004-optics-blueapi-architecture.html) for an example.
In the process of writing code in other DLS repos you may come to realise that it makes more sense to be in ``dodal``. It is a good idea to keep the history for this code, you can do this by doing the following (we will be using moving devices from https://github.com/DiamondLightSource/hyperion as an example):
* Add a note to every commit message to mention it's been moved::
36
+
37
+
```bash
38
+
git filter-branch --msg-filter 'sed "$ a \
39
+
NOTE: Commit originally came from https://github.com/DiamondLightSource/hyperion"' -f -- --all
40
+
```
41
+
42
+
* If you have been using Github [issue references](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/autolinked-references-and-urls#issues-and-pull-requests) in the old repository modify these to point to be more explicit (Note that this assumes the old repo uses ``#123`` notation and only ever references issues from it's own repo)::
* Tidy up the code so that it fits into the ``dodal`` repo e.g. in the Hyperion case we had to change the tests to import from ``hyperion`` to import from ``dodal`` and add some more dependencies.
Copy file name to clipboardExpand all lines: docs/how-to/write-tests.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,9 @@ Testing is essential to maintain the integrity and reliability of the codebase.
7
7
-**Unit Tests**: Place unit tests for individual components in the `tests` directory, but take care to mirror the file structure of the `src` folder with the corresponding code files. Use the `test_*.py` naming convention for test files.
8
8
-**System Tests**: Tests that interact with DLS infrastructure, network, and filesystem should be placed in the top-level `systems_test` folder. This separation ensures that these tests are easily identifiable and can be run independently from unit tests.
9
9
10
+
Useful functions for testing that can be reused across multiple tests for common devices and for external plan repositories belong in the `dodal/testing` directory. For example, when mocking a `Motor` device, all of the signals will default to zero, which will cause errors when trying to move. The `patch_motor` and `patch_all_motors` functions, found in `dodal.testing`, will populate the mocked motor with useful default values for the signals so that it can still be used in tests.
11
+
12
+
10
13
## Writing a test for a device
11
14
We aim for high test coverage in dodal with small, modular test functions. To achieve this, we need to test the relevant methods by writing tests for the class/method we are creating or changing, checking for the expected behaviour. We shouldn't need to write tests for parent classes unless we alter their behaviour.
If you look at the recipe json, Zocalo then runs Per-Image-Analysis on each frame and then assembles the results in
68
+
the [DLS X-Ray Centring service](https://github.com/DiamondLightSource/python-dlstbx/blob/a8fcbd30335bf13f5e35df78badfc60397500535/src/dlstbx/services/xray_centering.py).
0 commit comments