66import unittest
77from contextlib import contextmanager
88from datetime import timedelta
9- from threading import Thread
9+
10+ # from threading import Thread
1011from time import sleep
1112from typing import Any , Callable
1213
3637
3738
3839def 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