Restructured the test setup
General test configurations are now separated from specific axis test definitions.
This commit is contained in:
37
README.md
37
README.md
@@ -7,23 +7,28 @@ the tests.
|
||||
|
||||
The general architecture of the framework is as follows:
|
||||
- `ioc` contains all files used to create the IOC used in the tests.
|
||||
- `tests` contains the tests itself in a hierarchical order:
|
||||
- `tests/.` contains tests and configuration applicable for any motor record-based
|
||||
- `setup` contains the motor classes, the EPICS communication interface and generalized tests (which are not tied to one specific axis). These tests are arranged in a hierarchical order:
|
||||
- `tests/.` contains tests and utility functions applicable for any motor record-based
|
||||
driver.
|
||||
- `tests/sinqMotor/.` contains tests and configuration applicable for drivers
|
||||
- `tests/sinqMotor/.` contains tests and utility functions applicable for drivers
|
||||
based on https://gitea.psi.ch/lin-epics-modules/sinqMotor
|
||||
- `tests/sinqMotor/turboPmac/.` contains tests and configuration applicable for the
|
||||
- `tests/sinqMotor/turboPmac/.` contains tests and utility functions applicable for the
|
||||
sinqMotor-based Turbo PMAC driver https://gitea.psi.ch/lin-epics-modules/turboPmac
|
||||
- `tests/sinqMotor/masterMacs/.` contains tests and configuration applicable for the
|
||||
- `tests/sinqMotor/masterMacs/.` contains tests and utility functions applicable for the
|
||||
sinqMotor-based MasterMACS driver https://gitea.psi.ch/lin-epics-modules/mastermacs
|
||||
Individual motors at the test instrument are then set up as subfolders of their
|
||||
respective driver type.
|
||||
- `setup` contains classes representing the motors and the EPICS communication interface.
|
||||
- `tests` contains the tests for the individual axes within subfolders of their respective controller folders. For example, the tests for axis "ax1" of the controller "turboPmac1" configured in `ioc/motors/turboPmac1` should be in `tests/turboPmac1/ax1`, the tests for axis "ax2" of the same controller should be in `tests/turboPmac1/ax2` and so on. If an axis folder has a prepended underscore, it is ignored by `runtests` (e.g. the tests in `tests/turboPmac1/_ax3` would be ignored). This can be used to disable tests when e.g. the axis is not available temporarily.
|
||||
The classes are used to initialize the individual motors within the `tests` directory.
|
||||
- `config.yaml` is the test configuration (see [Configuration](#configuration))
|
||||
- `maketestenv` can be used to create a Python virtual environment for running the tests.
|
||||
- `runtests` is a parallelizing `pytest` wrapper. See section for more information [Parallelizing tests over motors](#parallelizing-tests-over-motors).
|
||||
|
||||
## Installation
|
||||
|
||||
The following prerequisites need to be fulfilled:
|
||||
1) EPICS 7 and the IOC shell must be installed.
|
||||
2) The PSI EPICS drive `/sq_epics/ioc` must be mounted as `/ioc`.
|
||||
The repository can then be simply cloned anywhere. Depending on the available hardware, the [configuration](#configuration) needs to be adjusted.
|
||||
|
||||
## Configuration
|
||||
|
||||
The test setup is defined in `config.yaml`. This file contains information which
|
||||
@@ -33,6 +38,22 @@ identifier of the records created by the motor drivers.
|
||||
- `versions`: Driver versions used in the IOC
|
||||
- `controllers`: Configuration of the different motor controllers (IP + port and poll periods)
|
||||
|
||||
### Adding / removing a controller to the IOC
|
||||
|
||||
The controller name and its configuration needs to added under `controllers` in the following format:
|
||||
|
||||
```yaml
|
||||
turboPmac1:
|
||||
ip: "172.28.101.24" # Controller IP adress
|
||||
port: 1025 # Controller port
|
||||
busypoll: 0.05 # Time in seconds
|
||||
idlepoll: 1 # Time in seconds
|
||||
```
|
||||
|
||||
Additionally, two files need to be added under `ioc/motors`: `ioc/motors/turboPmac1.cmd` and `ioc/motors/turboPmac1.substitutions`.
|
||||
These files need to be configured according to the corresponding motor driver documentation (e.g. according to https://gitea.psi.ch/lin-epics-modules/turboPmac for a TurboPMAC driver).
|
||||
Lastly, `ioc/st.cmd` needs to run the `.cmd` file under motors and to import the driver. See the documentation of [sinqMotor](https://gitea.psi.ch/lin-epics-modules/sinqMotor) for details.
|
||||
|
||||
## Starting the IOC
|
||||
|
||||
It is recommended to start the IOC via `ioc/startioc`:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pvprefix: DRVTESTS
|
||||
versions:
|
||||
turboPmac: "mathis_s"
|
||||
turboPmac: "1.3.1"
|
||||
masterMacs: "1.1"
|
||||
controllers:
|
||||
turboPmac1:
|
||||
|
||||
@@ -1,28 +1,3 @@
|
||||
# Configuration for the Turbo PMAC motor controller
|
||||
#
|
||||
# Important functions:
|
||||
#
|
||||
# turboPmacController:
|
||||
# Creates the controller object and specifies busy poll period, idle poll period and communication timeout.
|
||||
# A typical call looks like this:
|
||||
# turboPmacController("$(NAME)","$(ASYN_PORT)",8,0.05,1,0.05);
|
||||
# with
|
||||
# 8 = Total number of axes
|
||||
# 0.05 = Busy poll period in seconds
|
||||
# 1 = Idle poll period in seconds
|
||||
# 0.05 = Communication timeout in seconds
|
||||
#
|
||||
# setMaxSubsequentTimeouts:
|
||||
# Set the number of subsequent timeouts which may occur before the user is informed in NICOS.
|
||||
#
|
||||
# setThresholdComTimeout:
|
||||
# Set the maximum number of timeouts which may happen in a given timespan before the user is informed in NICOS.
|
||||
# A typical call looks like this:
|
||||
# setThresholdComTimeout("$(NAME)", 3600, 60);
|
||||
# with
|
||||
# 3600 = Timespan in seconds
|
||||
# 60 = Maximum number of timeout events which may occur before the user is informed
|
||||
|
||||
epicsEnvSet("NAME","turboPmac1")
|
||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||
|
||||
|
||||
19
runtests
19
runtests
@@ -22,9 +22,6 @@ import time
|
||||
from tests.conftest import check_ioc_running
|
||||
from setup.classes import IocNotRunning
|
||||
|
||||
# Define the test folders you want to run in parallel
|
||||
FOLDERS = ["tests/sinqMotor/turboPmac/ax1", "tests/sinqMotor/turboPmac/ax5"]
|
||||
|
||||
# Time we excpect the IOC needs to start up
|
||||
TIMEOUT_IOC_STARTUP = 10
|
||||
|
||||
@@ -38,12 +35,22 @@ for arg in sys.argv[1:]:
|
||||
else:
|
||||
extra_args.append(arg)
|
||||
|
||||
# Find all axes paths (pa) within all controller paths (pc)
|
||||
folders =[]
|
||||
for pc in Path("tests").glob("*"):
|
||||
if pc.is_dir() and "__pycache__" not in pc.parts:
|
||||
for pa in Path(pc).glob("*"):
|
||||
if pa.is_dir() and "__pycache__" not in pa.parts:
|
||||
# Ignore all axis paths which start with an underscore
|
||||
if not pa.parts[-1].startswith("_"):
|
||||
folders.append(pa)
|
||||
|
||||
# Filter folders to run based on path_args
|
||||
enabled_folders = []
|
||||
if not path_args:
|
||||
enabled_folders = FOLDERS
|
||||
enabled_folders = folders
|
||||
else:
|
||||
for folder in FOLDERS:
|
||||
for folder in folders:
|
||||
if any(Path(arg).resolve().as_posix().startswith(Path(folder).resolve().as_posix()) for arg in path_args):
|
||||
enabled_folders.append(folder)
|
||||
|
||||
@@ -72,7 +79,7 @@ processes = []
|
||||
for folder in enabled_folders:
|
||||
folder_path_args = (
|
||||
[arg for arg in path_args if Path(arg).resolve().as_posix().startswith(Path(folder).resolve().as_posix())]
|
||||
if path_args else [folder]
|
||||
if path_args else [folder.as_posix()]
|
||||
)
|
||||
|
||||
command = ["pytest"] + folder_path_args + extra_args
|
||||
|
||||
@@ -240,11 +240,11 @@ class SinqMotor(Motor):
|
||||
def error_message(self):
|
||||
return self.get_pv('errormsgpv', as_string=True)
|
||||
|
||||
def enable_and_wait(self, timeout=10):
|
||||
def enable_and_wait(self, timeout=20):
|
||||
self.put_pv('enable', 1)
|
||||
self.wait_enabled(timeout)
|
||||
|
||||
def disable_and_wait(self, timeout=10):
|
||||
def disable_and_wait(self, timeout=20):
|
||||
self.put_pv('enable', 0)
|
||||
self.wait_disabled(timeout)
|
||||
|
||||
@@ -254,7 +254,7 @@ class SinqMotor(Motor):
|
||||
"""
|
||||
return self._wait_enabled_disabled(True, timeout)
|
||||
|
||||
def wait_disabled(self, timeout=10):
|
||||
def wait_disabled(self, timeout=20):
|
||||
"""
|
||||
Wait until the motor is enabled or a timeout has been reached.
|
||||
"""
|
||||
@@ -276,7 +276,7 @@ class SinqMotor(Motor):
|
||||
else:
|
||||
pytest.fail(
|
||||
f'Motor {self.pv} could not be disabled in {timeout} seconds')
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
class TurboPMAC(SinqMotor):
|
||||
|
||||
@@ -6,4 +6,4 @@ from setup.classes import MasterMACS
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def motor():
|
||||
return MasterMACS('masterMacs1', 'lin1')
|
||||
return MasterMACS('masterMacs1', 'ax1')
|
||||
@@ -1,9 +1,9 @@
|
||||
# Run a selection of common tests
|
||||
|
||||
from tests.move import *
|
||||
from tests.sinqMotor.limits import *
|
||||
from tests.home import *
|
||||
from tests.sinqMotor.masterMacs.reset import reset
|
||||
from setup.move import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.masterMacs.reset import reset
|
||||
|
||||
|
||||
def test_reset(motor):
|
||||
0
tests/turboPmac1/ax1/__init__.py
Executable file
0
tests/turboPmac1/ax1/__init__.py
Executable file
@@ -2,11 +2,11 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.move import *
|
||||
from tests.home import *
|
||||
from tests.sinqMotor.limits import *
|
||||
from tests.sinqMotor.speed import *
|
||||
from tests.sinqMotor.turboPmac.reset import reset
|
||||
from setup.move import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.sinqMotor.speed import *
|
||||
from setup.sinqMotor.turboPmac.reset import reset
|
||||
|
||||
|
||||
def test_reset(motor):
|
||||
0
tests/turboPmac1/ax5/__init__.py
Executable file
0
tests/turboPmac1/ax5/__init__.py
Executable file
@@ -1,11 +1,11 @@
|
||||
# Run a selection of common tests
|
||||
import pytest
|
||||
|
||||
from tests.move import *
|
||||
from tests.sinqMotor.limits import *
|
||||
from tests.sinqMotor.speed import *
|
||||
from tests.home import *
|
||||
from tests.sinqMotor.turboPmac.reset import reset
|
||||
from setup.move import *
|
||||
from setup.sinqMotor.limits import *
|
||||
from setup.sinqMotor.speed import *
|
||||
from setup.home import *
|
||||
from setup.sinqMotor.turboPmac.reset import reset
|
||||
|
||||
|
||||
def test_reset(motor):
|
||||
Reference in New Issue
Block a user