@@ -964,6 +964,34 @@ class Ztest(Test):
964964
965965class Bsim (Harness ):
966966
967+ DEFAULT_VERBOSITY = 2
968+ DEFAULT_SIM_LENGTH = 60e6
969+
970+ def __init__ (self ):
971+ super ().__init__ ()
972+ self ._bsim_out_path = os .getenv ('BSIM_OUT_PATH' , '' )
973+ self ._exe_path = None
974+ self ._tc_output = []
975+
976+ @property
977+ def exe_path (self ):
978+ if self ._exe_path :
979+ return self ._exe_path
980+
981+ if not self ._bsim_out_path :
982+ logger .warning ('Cannot copy bsim exe - BSIM_OUT_PATH not provided.' )
983+ return self ._exe_path
984+
985+ new_exe_name : str = self .instance .testsuite .harness_config .get ('bsim_exe_name' , '' )
986+ if new_exe_name :
987+ new_exe_name = f'bs_{ self .instance .platform .name } _{ new_exe_name } '
988+ else :
989+ new_exe_name = f'bs_{ self .instance .name } '
990+
991+ new_exe_name = new_exe_name .replace (os .path .sep , '_' ).replace ('.' , '_' ).replace ('@' , '_' )
992+ self ._exe_path = os .path .join (self ._bsim_out_path , 'bin' , new_exe_name )
993+ return self ._exe_path
994+
967995 def build (self ):
968996 """
969997 Copying the application executable to BabbleSim's bin directory enables
@@ -978,23 +1006,91 @@ def build(self):
9781006 logger .warning ('Cannot copy bsim exe - cannot find original executable.' )
9791007 return
9801008
981- bsim_out_path : str = os .getenv ('BSIM_OUT_PATH' , '' )
982- if not bsim_out_path :
983- logger .warning ('Cannot copy bsim exe - BSIM_OUT_PATH not provided.' )
984- return
1009+ logger .debug (f'Copying executable from { original_exe_path } to { self .exe_path } ' )
1010+ shutil .copy (original_exe_path , self .exe_path )
9851011
986- new_exe_name : str = self .instance .testsuite .harness_config .get ('bsim_exe_name' , '' )
987- if new_exe_name :
988- new_exe_name = f'bs_{ self .instance .platform .name } _{ new_exe_name } '
1012+ def _run_cmd (self , cmd , timeout ):
1013+ with subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE ,
1014+ cwd = os .path .join (self ._bsim_out_path , 'bin' )) as proc :
1015+ try :
1016+ reader_t = threading .Thread (target = self ._output_reader , args = (proc ,), daemon = True )
1017+ reader_t .start ()
1018+ reader_t .join (timeout )
1019+ if reader_t .is_alive ():
1020+ terminate_process (proc )
1021+ logger .warning ('Timeout has occurred. Can be extended in testspec file. '
1022+ f'Currently set to { timeout } seconds.' )
1023+ self .status = TwisterStatus .FAIL
1024+ proc .wait (timeout )
1025+ except subprocess .TimeoutExpired :
1026+ self .status = TwisterStatus .FAIL
1027+ proc .kill ()
1028+
1029+ if self .status == TwisterStatus .NONE :
1030+ self .status = TwisterStatus .FAIL if proc .returncode != 0 else TwisterStatus .PASS
9891031 else :
990- new_exe_name = self .instance .name
991- new_exe_name = f'bs_{ new_exe_name } '
1032+ self .status = TwisterStatus .FAIL \
1033+ if proc .returncode != 0 or self .status in [TwisterStatus .ERROR , TwisterStatus .FAIL ] \
1034+ else TwisterStatus .PASS
9921035
993- new_exe_name = new_exe_name .replace (os .path .sep , '_' ).replace ('.' , '_' ).replace ('@' , '_' )
1036+ def _output_reader (self , proc ):
1037+ while proc .stdout .readable () and proc .poll () is None :
1038+ line = proc .stdout .readline ().decode ().strip ()
1039+ if not line :
1040+ continue
1041+ logger .debug (line )
1042+ self ._tc_output .append (line )
1043+ proc .communicate ()
1044+
1045+ def _generate_commands (self ):
1046+ bsim_phy_path = os .path .join (self ._bsim_out_path , 'bin' , 'bs_2G4_phy_v1' )
1047+ suite_id = f'-s={ self .instance .name .split (os .path .sep )[- 1 ].replace ("." , "_" )} '
1048+
1049+ cfg = self .instance .testsuite .harness_config
1050+ verbosity = f'-v={ cfg .get ("bsim_verbosity" , self .DEFAULT_VERBOSITY )} '
1051+ sim_length = f'-sim_length={ cfg .get ("bsim_sim_length" , self .DEFAULT_SIM_LENGTH )} '
1052+ extra_args = cfg .get ('bsim_options' , [])
1053+ test_ids = cfg .get ('bsim_test_ids' , [])
1054+ if not test_ids :
1055+ logger .error ('No test ids specified for bsim test' )
1056+ self .status = TwisterStatus .ERROR
1057+ return
1058+
1059+ cmds = [[self .exe_path , verbosity , suite_id , f'-d={ i } ' , f'-testid={ t_id } ' ] + extra_args
1060+ for i , t_id in enumerate (test_ids )]
1061+ cmds .append ([bsim_phy_path , verbosity , suite_id , f'-D={ len (test_ids )} ' , sim_length ])
1062+
1063+ return cmds
1064+
1065+ def bsim_run (self , timeout ):
1066+ try :
1067+ threads = []
1068+ start_time = time .time ()
1069+ for cmd in self ._generate_commands ():
1070+ t = threading .Thread (target = lambda c = cmd : self ._run_cmd (c , timeout ))
1071+ threads .append (t )
1072+ t .start ()
1073+
1074+ for t in threads :
1075+ t .join (timeout = timeout )
1076+
1077+ self .instance .execution_time = time .time () - start_time
1078+ finally :
1079+ self ._update_test_status ()
1080+
1081+ def _update_test_status (self ):
1082+ if not self .instance .testcases :
1083+ self .instance .init_cases ()
1084+
1085+ # currently there is alays one testcase per bsim suite
1086+ self .instance .testcases [0 ].status = self .status if self .status != TwisterStatus .NONE else \
1087+ TwisterStatus .FAIL
1088+ self .instance .status = self .instance .testcases [0 ].status
1089+ if self .instance .status in [TwisterStatus .ERROR , TwisterStatus .FAIL ]:
1090+ logger .warning (f'BSIM test failed: { self .instance .reason } ' )
1091+ self .instance .reason = self .instance .reason or 'Bsim test failed'
1092+ self .instance .testcases [0 ].output = '\n ' .join (self ._tc_output )
9941093
995- new_exe_path : str = os .path .join (bsim_out_path , 'bin' , new_exe_name )
996- logger .debug (f'Copying executable from { original_exe_path } to { new_exe_path } ' )
997- shutil .copy (original_exe_path , new_exe_path )
9981094
9991095class Ctest (Harness ):
10001096 def configure (self , instance : TestInstance ):
0 commit comments