@@ -483,6 +483,8 @@ def run_tests(
483483 ):
484484 print (f"Diff between { name1 } and { name2 } : vimdiff { file1 } { file2 } " )
485485
486+ return (failed == 0 ) and (skipped == 0 ) and (passed > 0 )
487+
486488
487489@app .command (help = f"Convert Context and/or Fixture messages to human-readable format." )
488490def decode_protobufs (
@@ -711,7 +713,7 @@ def debug_mismatches(
711713 ):
712714 os .remove (files [j ])
713715
714- run_tests (
716+ return run_tests (
715717 input = globals .inputs_dir ,
716718 reference_shared_library = reference_shared_library ,
717719 default_harness_ctx = default_harness_ctx ,
@@ -1033,5 +1035,157 @@ def exec_fixtures(
10331035 print (f"Skipped tests: { skipped_tests } " )
10341036
10351037
1038+ @app .command (
1039+ help = f"""
1040+ Set up environment for debugging a mismatch from FuzzCorp
1041+ """
1042+ )
1043+ def create_env (
1044+ reference_shared_library : Path = typer .Option (
1045+ Path (os .getenv ("SOLFUZZ_TARGET" , "impl/lib/libsolfuzz_agave_v2.0.so" )),
1046+ "--solana-target" ,
1047+ "-s" ,
1048+ help = "Solana (or ground truth) shared object (.so) target file path" ,
1049+ ),
1050+ default_harness_ctx : str = typer .Option (
1051+ "InstrHarness" ,
1052+ "--default-harness-type" ,
1053+ "-h" ,
1054+ help = f"Harness type to use for Context protobufs" ,
1055+ ),
1056+ shared_libraries : List [Path ] = typer .Option (
1057+ [Path (os .getenv ("FIREDANCER_TARGET" , "impl/lib/libsolfuzz_firedancer.so" ))],
1058+ "--target" ,
1059+ "-t" ,
1060+ help = "Shared object (.so) target file paths (pairs with --keep-passing)."
1061+ f" Targets must have required function entrypoints defined" ,
1062+ ),
1063+ output_dir : Path = typer .Option (
1064+ Path ("debug_mismatch" ),
1065+ "--output-dir" ,
1066+ "-o" ,
1067+ help = f"Output directory for messages" ,
1068+ ),
1069+ repro_urls : str = typer .Option (
1070+ "" , "--repro-urls" , "-u" , help = "Comma-delimited list of FuzzCorp mismatch links"
1071+ ),
1072+ section_names : str = typer .Option (
1073+ "" ,
1074+ "--section-names" ,
1075+ "-n" ,
1076+ help = "Comma-delimited list of FuzzCorp section names" ,
1077+ ),
1078+ fuzzcorp_url : str = typer .Option (
1079+ os .getenv (
1080+ "FUZZCORP_URL" ,
1081+ "https://api.dev.fuzzcorp.asymmetric.re/uglyweb/firedancer-io/solfuzz/bugs/" ,
1082+ ),
1083+ "--fuzzcorp-url" ,
1084+ "-f" ,
1085+ help = "Comma-delimited list of FuzzCorp section names" ,
1086+ ),
1087+ log_level : int = typer .Option (
1088+ 5 ,
1089+ "--log-level" ,
1090+ "-l" ,
1091+ help = "FD logging level" ,
1092+ ),
1093+ randomize_output_buffer : bool = typer .Option (
1094+ False ,
1095+ "--randomize-output-buffer" ,
1096+ "-r" ,
1097+ help = "Randomizes bytes in output buffer before shared library execution" ,
1098+ ),
1099+ num_processes : int = typer .Option (
1100+ 4 , "--num-processes" , "-p" , help = "Number of processes to use"
1101+ ),
1102+ section_limit : int = typer .Option (
1103+ 0 , "--section-limit" , "-l" , help = "Limit number of fixture per section"
1104+ ),
1105+ firedancer_repo_path : Path = typer .Option (
1106+ os .getenv ("FIREDANCER_DIR" ),
1107+ "--firedancer-repo" ,
1108+ "-fd" ,
1109+ help = "Path to firedancer repository" ,
1110+ ),
1111+ test_vectors_repos_path : Path = typer .Option (
1112+ os .getenv ("TEST_VECTORS_DIR" ),
1113+ "--test-vectors-repo" ,
1114+ "-tv" ,
1115+ help = "Path to test-vectors repository" ,
1116+ ),
1117+ ):
1118+ lists = [
1119+ f"{ file .parent .name } /{ file .name } "
1120+ for file in firedancer_repo_path .glob (
1121+ "contrib/test/test-vectors-fixtures/*fixtures*/*list"
1122+ )
1123+ ]
1124+
1125+ max_width = max (len (option ) for option in lists ) + 2
1126+
1127+ print ("Select correct list for mismatch:" )
1128+ for i , option in enumerate (lists , start = 1 ):
1129+ print (f"{ i } . { option } " .ljust (max_width ), end = "\t " )
1130+ if i % 4 == 0 :
1131+ print ()
1132+
1133+ if len (lists ) % 4 != 0 :
1134+ print ()
1135+
1136+ while True :
1137+ try :
1138+ choice = int (input ("Enter the list of your choice: " ))
1139+ if 1 <= choice <= len (lists ):
1140+ selected_option = lists [choice - 1 ]
1141+ break
1142+ else :
1143+ print (f"Please enter a number between 1 and { len (lists )} ." )
1144+ except ValueError :
1145+ print ("Invalid input. Please enter a number." )
1146+
1147+ print (f"Adding fixture to: { selected_option } " )
1148+ list_path = glob (
1149+ str (firedancer_repo_path )
1150+ + f"/contrib/test/test-vectors-fixtures/{ selected_option } "
1151+ )[0 ]
1152+
1153+ passed = debug_mismatches (
1154+ reference_shared_library = reference_shared_library ,
1155+ default_harness_ctx = default_harness_ctx ,
1156+ shared_libraries = shared_libraries ,
1157+ output_dir = output_dir ,
1158+ repro_urls = repro_urls ,
1159+ section_names = section_names ,
1160+ fuzzcorp_url = fuzzcorp_url ,
1161+ log_level = log_level ,
1162+ randomize_output_buffer = randomize_output_buffer ,
1163+ num_processes = num_processes ,
1164+ section_limit = section_limit ,
1165+ )
1166+
1167+ if passed :
1168+ print ("All fixtures already pass" )
1169+ typer .Exit (code = 1 )
1170+
1171+ failures = glob (str (output_dir ) + "/test_results/failed_protobufs/*" )
1172+
1173+ for failure in failures :
1174+ with open (list_path , "r" ) as file :
1175+ lines = file .readlines ()
1176+
1177+ last_line = lines [- 1 ].strip ()
1178+
1179+ failure_path = os .path .dirname (last_line ) + "/" + os .path .basename (failure )
1180+ with open (list_path , "a" ) as file :
1181+ file .write (failure_path + "\n " )
1182+ print (f"\n Added { os .path .basename (failure )} to { list_path } " )
1183+
1184+ failure_test_vector_path = failure_path .replace (
1185+ "dump/test-vectors" , str (test_vectors_repos_path )
1186+ )
1187+ shutil .copy2 (failure , os .path .dirname (failure_test_vector_path ))
1188+
1189+
10361190if __name__ == "__main__" :
10371191 app ()
0 commit comments