Skip to content

Commit 9e48632

Browse files
authored
Merge pull request #129 from ISISComputingGroup/archiver_fast_restart
Archiver fast restart
2 parents dad0daf + bc1558d commit 9e48632

File tree

1 file changed

+66
-16
lines changed

1 file changed

+66
-16
lines changed

test_genie_python_dae.py

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import unittest
77
from contextlib import contextmanager
88
from datetime import timedelta
9-
from threading import Thread
9+
10+
# from threading import Thread
1011
from time import sleep
1112
from typing import Any, Callable
1213

@@ -36,7 +37,7 @@
3637

3738

3839
def nexus_file_with_retry(
39-
instrument: str, run_number: int, test_func: Callable[[h5py.File], None]
40+
instrument: str, run_number: int, test_func: Callable[[h5py.File, int], None]
4041
) -> None:
4142
# isisicp writes files asynchronously, so need to retry file read
4243
# in case file not completed and still locked
@@ -46,7 +47,8 @@ def nexus_file_with_retry(
4647
for i in range(num_of_tries):
4748
try:
4849
with h5py.File(nexus_file, "r") as f:
49-
test_func(f)
50+
test_func(f, run_number)
51+
break
5052
except IOError:
5153
if i == num_of_tries - 1:
5254
print("{} not found, giving up".format(nexus_file))
@@ -153,6 +155,54 @@ def test_GIVEN_running_instrument_WHEN_pars_changed_THEN_pars_saved_in_file(self
153155
else:
154156
self.assertEqual(0, saved_beamstop)
155157

158+
def test_GIVEN_running_instrument_WHEN_block_logging_but_not_changing_THEN_block_value_saved_in_file(
159+
self,
160+
):
161+
load_config_if_not_already_loaded("rcptt_simple")
162+
self.fail_if_not_in_setup()
163+
set_genie_python_raises_exceptions(True)
164+
test_block_name = "FLOAT_BLOCK"
165+
# number of planned restarts due to a begin/end
166+
r_cnt_start = g.get_pv("DAE:_RESTART_ARCHIVER_CNT", is_local=True)
167+
# number of forced restarts due to background check
168+
fr_cnt_start = g.get_pv("DAE:_FR_ARCHIVER_CNT", is_local=True)
169+
ncheck = 10
170+
# block is not changing but check we get at least one value logged
171+
# test quick begin/end and some with delays
172+
# there is a 5 second flush time in archiver -> mysql hence
173+
# trying shorter and longer delays
174+
delays = [(10, 10), (2, 10), (10, 2), (2, 2), (2, 0), (0, 2), (0, 0)]
175+
for delay in delays:
176+
print(f"Testing (pre, post) delay {delay}")
177+
for _ in range(ncheck):
178+
sleep(delay[0])
179+
g.begin()
180+
sleep(delay[1])
181+
run_number = g.get_runnumber()
182+
g.end()
183+
g.waitfor_runstate("SETUP", maxwaitsecs=self.TIMEOUT)
184+
nexus_path = r"/raw_data_1/selog/{}/value_log".format(test_block_name)
185+
186+
def test_function(f: Any, run_number: int) -> None:
187+
# if no values are logged this will fail with a
188+
# "Unable to synchronously open object (component not found)" exception
189+
values = [val for val in f[nexus_path + r"/value"][:]]
190+
print(
191+
f"Found {len(values)} value(s) for block {test_block_name} run {run_number}"
192+
)
193+
self.assertTrue(
194+
len(values) > 0,
195+
"Not enough values logged to file",
196+
)
197+
198+
nexus_file_with_retry(g.adv.get_instrument(), run_number, test_function)
199+
# check archiver has restarted expected number of times and no forced restarts
200+
# ARBLOCK restarted on begin and end hence factor 2
201+
r_cnt = g.get_pv("DAE:_RESTART_ARCHIVER_CNT", is_local=True)
202+
fr_cnt = g.get_pv("DAE:_FR_ARCHIVER_CNT", is_local=True)
203+
self.assertEqual(r_cnt, r_cnt_start + 2 * ncheck * len(delays))
204+
self.assertEqual(fr_cnt, fr_cnt_start)
205+
156206
def test_GIVEN_running_instrument_WHEN_block_logging_THEN_block_saved_in_file(self):
157207
load_config_if_not_already_loaded("rcptt_simple")
158208
self.fail_if_not_in_setup()
@@ -195,7 +245,7 @@ def test_GIVEN_running_instrument_WHEN_block_logging_THEN_block_saved_in_file(se
195245

196246
nexus_path = r"/raw_data_1/selog/{}/value_log".format(test_block_name)
197247

198-
def test_function(f: Any) -> None:
248+
def test_function(f: h5py.File, run_number: int) -> None:
199249
value_valid = f[nexus_path + r"/value_valid"][:]
200250
is_valid = [sample == 1 for sample in value_valid]
201251
values = [int(val) for val in f[nexus_path + r"/value"][:]]
@@ -270,7 +320,7 @@ def _assert_title_correct(self, test_title, expected_title):
270320

271321
g.waitfor_runstate("SETUP", maxwaitsecs=self.TIMEOUT)
272322

273-
def test_func(f):
323+
def test_func(f: Any, run_number: int) -> None:
274324
saved_title = f["/raw_data_1/title"][0].decode()
275325
self.assertEqual(expected_title, saved_title)
276326

@@ -567,7 +617,10 @@ def _adjust_icp_begin_delay(self, delay_seconds):
567617

568618
begindelay_property = "isisicp.begindelay"
569619
config_line = "{} = {}\r\n".format(begindelay_property, delay_seconds)
570-
if g.get_runstate() != "SETUP":
620+
g.waitfor_runstate("PROCESSING", maxwaitsecs=30, onexit=True)
621+
runstate = g.get_runstate()
622+
if runstate != "SETUP":
623+
print(f"Aborting run as currently {runstate}")
571624
g.abort() # make sure not left in a funny state from e.g. previous aborted test
572625

573626
with g._genie_api.dae.temporarily_kill_icp():
@@ -720,12 +773,13 @@ def get_time_thread(return_value):
720773
return_value.append(g.get_time_since_begin(True))
721774

722775
time_taken = []
723-
thread = Thread(target=get_time_thread, args=(time_taken,))
724-
thread.start()
776+
# thread = Thread(target=get_time_thread, args=(time_taken,))
777+
# thread.start()
725778

726779
g.begin()
780+
get_time_thread(time_taken)
727781

728-
thread.join()
782+
# thread.join()
729783

730784
# Taking the fluctuation of actual runtime into account and tolerating up to 1 sec difference
731785
self.assertAlmostEqual(
@@ -813,9 +867,7 @@ def test_GIVEN_change_title_called_WHEN_valid_argument_THEN_get_title_correct_im
813867
g.change_title(title)
814868
self.assertEqual(g.get_title(), title)
815869

816-
def test_GIVEN_dae_setup_WHEN_read_x_and_xe_THEN_centre_and_edges_correct(
817-
self
818-
) -> None:
870+
def test_GIVEN_dae_setup_WHEN_read_x_and_xe_THEN_centre_and_edges_correct(self) -> None:
819871
set_genie_python_raises_exceptions(True)
820872
# check x and xe are correct length
821873
ntc = g.get_number_timechannels()
@@ -826,12 +878,10 @@ def test_GIVEN_dae_setup_WHEN_read_x_and_xe_THEN_centre_and_edges_correct(
826878
# check x is a bin centre of xe edges
827879
x = g.get_pv("DAE:SPEC:1:1:X", is_local=True)
828880
xe = g.get_pv("DAE:SPEC:1:1:XE", is_local=True)
829-
self.assertAlmostEqual(x[0], (xe[0] + xe[1]) / 2.0, delta=.001)
881+
self.assertAlmostEqual(x[0], (xe[0] + xe[1]) / 2.0, delta=0.001)
830882
set_genie_python_raises_exceptions(False)
831883

832-
def test_GIVEN_dae_setup_WHEN_paused_THEN_period_values_correct(
833-
self
834-
) -> None:
884+
def test_GIVEN_dae_setup_WHEN_paused_THEN_period_values_correct(self) -> None:
835885
set_genie_python_raises_exceptions(True)
836886
sleep_time = 5
837887
num_periods = 2

0 commit comments

Comments
 (0)