1
1
"""
2
2
System tests for starting or stopping iocs through Proc server
3
3
"""
4
+
4
5
import os
5
6
import unittest
6
7
import xml .etree .ElementTree as ET
10
11
from hamcrest import assert_that , less_than
11
12
from six .moves import range
12
13
13
- from utilities .utilities import g , as_seconds , start_ioc , stop_ioc , wait_for_ioc_start_stop , \
14
- load_config_if_not_already_loaded , bulk_start_ioc , bulk_stop_ioc
14
+ from utilities .utilities import (
15
+ as_seconds ,
16
+ bulk_start_ioc ,
17
+ bulk_stop_ioc ,
18
+ g ,
19
+ load_config_if_not_already_loaded ,
20
+ start_ioc ,
21
+ stop_ioc ,
22
+ wait_for_ioc_start_stop ,
23
+ )
15
24
16
25
# The following iocs are ignored in the test which starts/stops all iocs
17
26
# This is usually because they don't build by default, or have some complex dependency,
18
27
# or are special in some way (e.g. psctrl).
19
28
# we also ignore ISISDAE, INSTETC and RUNCTRL as testing them here messed up subsequent tests
20
29
# by leaving these IOCs permanently stopped. We could re-enable testing them if this test was either
21
- # always ran last or could re-enabel autostart on these ioc afterwards
30
+ # always ran last or could re-enabel autostart on these ioc afterwards
22
31
IOCS_TO_IGNORE_START_STOP = [
23
- ' ASTRIUM_01' ,
24
- ' ASTRIUM_02' ,
25
- ' BGRSCRPT_01' , # Won't keep running unless it has a config file
26
- ' BGRSCRPT_02' ,
27
- ' CHOPPERSIM' , # Simulation ioc
28
- ' CAENMCA' , # currently fails to start, and is not used so skip
29
- ' DELFTDCMAG_01' , # Delft iocs have a weird build/run process?
30
- ' DELFTDCMAG_02' ,
31
- ' DELFTSHEAR_01' ,
32
- ' ECLAB_01' ,
33
- ' INSTETC' ,
34
- ' ISISDAE' ,
35
- ' LSICORR_01' , # Needs vendor library in correct place to keep running
36
- ' LSICORR_02' ,
37
- ' MOTORSIM' , # Simulation ioc
38
- ' MOXA12XX_01' ,
39
- ' MOXA12XX_02' ,
40
- ' MOXA12XX_03' ,
41
- ' MK3CHOPR_01' ,
42
- ' NANODAC_01' ,
43
- ' OERCONE_02' ,
44
- ' PIXELMAN' ,
45
- ' PSCTRL' , # Special, controls other IOCs
46
- ' REFL_01' , # Won't run correctly without a config
47
- ' RUNCTRL' ,
48
- ' SECI2IBEX' , # requires labview
49
- ' SEPRTR' , # relies on daqMX
50
- ' TC_01' , # relies on twincat
51
- ' ZFMAGFLD' # relies on daqMX
32
+ " ASTRIUM_01" ,
33
+ " ASTRIUM_02" ,
34
+ " BGRSCRPT_01" , # Won't keep running unless it has a config file
35
+ " BGRSCRPT_02" ,
36
+ " CHOPPERSIM" , # Simulation ioc
37
+ " CAENMCA" , # currently fails to start, and is not used so skip
38
+ " DELFTDCMAG_01" , # Delft iocs have a weird build/run process?
39
+ " DELFTDCMAG_02" ,
40
+ " DELFTSHEAR_01" ,
41
+ " ECLAB_01" ,
42
+ " INSTETC" ,
43
+ " ISISDAE" ,
44
+ " LSICORR_01" , # Needs vendor library in correct place to keep running
45
+ " LSICORR_02" ,
46
+ " MOTORSIM" , # Simulation ioc
47
+ " MOXA12XX_01" ,
48
+ " MOXA12XX_02" ,
49
+ " MOXA12XX_03" ,
50
+ " MK3CHOPR_01" ,
51
+ " NANODAC_01" ,
52
+ " OERCONE_02" ,
53
+ " PIXELMAN" ,
54
+ " PSCTRL" , # Special, controls other IOCs
55
+ " REFL_01" , # Won't run correctly without a config
56
+ " RUNCTRL" ,
57
+ " SECI2IBEX" , # requires labview
58
+ " SEPRTR" , # relies on daqMX
59
+ " TC_01" , # relies on twincat
60
+ " ZFMAGFLD" , # relies on daqMX
52
61
]
53
62
54
- GLOBALS_FILENAME = os .path .join (os .environ [' ICPCONFIGROOT' ], "globals.txt" )
63
+ GLOBALS_FILENAME = os .path .join (os .environ [" ICPCONFIGROOT" ], "globals.txt" )
55
64
56
65
57
66
class TestProcControl (unittest .TestCase ):
@@ -104,20 +113,29 @@ def test_GIVEN_ioc_is_stopped_WHEN_call_start_multiple_times_quickly_THEN_ioc_is
104
113
g .waitfor_time (seconds = 5 ) # wait just in case it is starting
105
114
wait_for_ioc_start_stop (timeout = 30 , is_start = True , ioc_name = "SIMPLE" )
106
115
107
- def test_GIVEN_ioc_is_running_WHEN_call_restart_multiple_times_quickly_THEN_ioc_is_restarted (self ):
116
+ def test_GIVEN_ioc_is_running_WHEN_call_restart_multiple_times_quickly_THEN_ioc_is_restarted (
117
+ self ,
118
+ ):
108
119
time_to_restart_and_read_uptime = 10
109
120
start_ioc (ioc_name = "SIMPLE" )
110
- while as_seconds (g .get_pv ("CS:IOC:SIMPLE:DEVIOS:UPTIME" , is_local = True )) < time_to_restart_and_read_uptime :
121
+ while (
122
+ as_seconds (g .get_pv ("CS:IOC:SIMPLE:DEVIOS:UPTIME" , is_local = True ))
123
+ < time_to_restart_and_read_uptime
124
+ ):
111
125
g .waitfor_time (seconds = 1 )
112
126
for _ in range (20 ):
113
127
g .set_pv ("CS:PS:SIMPLE:RESTART" , 1 , is_local = True , wait = False )
114
128
115
129
wait_for_ioc_start_stop (timeout = 30 , is_start = True , ioc_name = "SIMPLE" )
116
- assert_that (as_seconds (g .get_pv ("CS:IOC:SIMPLE:DEVIOS:UPTIME" , is_local = True )),
117
- less_than (time_to_restart_and_read_uptime ), "Uptime" )
118
-
119
- def test_GIVEN_ioc_is_off_WHEN_call_restart_multiple_times_quickly_THEN_ioc_is_still_stopped (self ):
130
+ assert_that (
131
+ as_seconds (g .get_pv ("CS:IOC:SIMPLE:DEVIOS:UPTIME" , is_local = True )),
132
+ less_than (time_to_restart_and_read_uptime ),
133
+ "Uptime" ,
134
+ )
120
135
136
+ def test_GIVEN_ioc_is_off_WHEN_call_restart_multiple_times_quickly_THEN_ioc_is_still_stopped (
137
+ self ,
138
+ ):
121
139
stop_ioc (ioc_name = "SIMPLE" )
122
140
123
141
for _ in range (20 ):
@@ -126,7 +144,6 @@ def test_GIVEN_ioc_is_off_WHEN_call_restart_multiple_times_quickly_THEN_ioc_is_s
126
144
wait_for_ioc_start_stop (timeout = 30 , is_start = False , ioc_name = "SIMPLE" )
127
145
128
146
def test_WHEN_start_iocs_THEN_iocs_started_WHEN_stop_iocs_THEN_iocs_stopped (self ):
129
-
130
147
# A test to check all IOCs start and stop correctly
131
148
# Implemented to test for the error we encountered where we met our procserv limit and some iocs didn't start
132
149
@@ -137,16 +154,17 @@ def test_WHEN_start_iocs_THEN_iocs_started_WHEN_stop_iocs_THEN_iocs_stopped(self
137
154
number_to_run = 40
138
155
139
156
## disable for moment
140
- #iocs_to_test = self._prepare_ioc_list()
157
+ # iocs_to_test = self._prepare_ioc_list()
141
158
iocs_to_test = []
142
159
143
160
# Test handles Channel access exceptions, so set us to handle it to reduce prints.
144
161
g .toggle .exceptions_raised (True )
145
162
for chunk in self ._chunk_iocs (iocs_to_test , number_to_run ):
146
163
start_time = time ()
147
164
failed_to_start , not_in_proc_serv = bulk_start_ioc (chunk )
148
- failed_to_stop = bulk_stop_ioc ([ioc for ioc in chunk if ioc not in failed_to_start
149
- and ioc not in not_in_proc_serv ])
165
+ failed_to_stop = bulk_stop_ioc (
166
+ [ioc for ioc in chunk if ioc not in failed_to_start and ioc not in not_in_proc_serv ]
167
+ )
150
168
for ioc in failed_to_start + failed_to_stop :
151
169
if not self ._retry_in_recsim (ioc ):
152
170
error_iocs .append (ioc )
@@ -167,25 +185,36 @@ def _prepare_ioc_list(self):
167
185
:return: The list of IOCs to test, sorted alphanumerically.
168
186
"""
169
187
iocs_to_test = []
170
- tree = ET .parse (os .path .join ("C:\\ " , "Instrument" , "Apps" , "EPICS" , "iocstartup" , "config.xml" ))
188
+ tree = ET .parse (
189
+ os .path .join ("C:\\ " , "Instrument" , "Apps" , "EPICS" , "iocstartup" , "config.xml" )
190
+ )
171
191
root = tree .getroot ()
172
192
173
193
# IOCs are listed in the above XML file under two different schemas, we need both
174
194
schemas = (
175
195
"{http://epics.isis.rl.ac.uk/schema/ioc_config/1.0}" ,
176
- "{http://epics.isis.rl.ac.uk/schema/ioc_configs/1.0}"
196
+ "{http://epics.isis.rl.ac.uk/schema/ioc_configs/1.0}" ,
177
197
)
178
198
179
199
for schema in schemas :
180
- iocs_to_test .extend ([ioc_config .attrib ["name" ] for ioc_config in root .iter (f"{ schema } ioc_config" )])
200
+ iocs_to_test .extend (
201
+ [ioc_config .attrib ["name" ] for ioc_config in root .iter (f"{ schema } ioc_config" )]
202
+ )
181
203
182
204
# Check parsed IOCs are a sensible length check there's at least one known ioc in the list
183
205
if not len (iocs_to_test ) > 100 :
184
- if not any (item in iocs_to_test for item in ["SIMPLE" , "AMINT2L_01" , "EUROTHRM_01" , "INSTETC_01" ]):
206
+ if not any (
207
+ item in iocs_to_test
208
+ for item in ["SIMPLE" , "AMINT2L_01" , "EUROTHRM_01" , "INSTETC_01" ]
209
+ ):
185
210
# Fairly long test so error out early if IOCs aren't in a sensible state
186
211
raise ValueError ("List of IOCs not in a sensible state. Have you run IOC startups?" )
187
212
# Check IOC 1 and IOC2, but not other IOCs as they should follow the same format as IOC 2.
188
- iocs_to_test = [ioc for ioc in iocs_to_test if self ._skip_high_ioc_nums (ioc ) and not self ._ignore_ioc (ioc )]
213
+ iocs_to_test = [
214
+ ioc
215
+ for ioc in iocs_to_test
216
+ if self ._skip_high_ioc_nums (ioc ) and not self ._ignore_ioc (ioc )
217
+ ]
189
218
iocs_to_test .sort ()
190
219
return iocs_to_test
191
220
@@ -216,7 +245,7 @@ def _chunk_iocs(ioc_list: List[str], chunk_size: int):
216
245
:return: an iterator that gives the next chunk of the list.
217
246
"""
218
247
for i in range (0 , len (ioc_list ), chunk_size ):
219
- yield ioc_list [i : i + chunk_size ]
248
+ yield ioc_list [i : i + chunk_size ]
220
249
221
250
@staticmethod
222
251
def _retry_in_recsim (ioc : str ):
0 commit comments