@@ -150,6 +150,7 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
150150 successes = []
151151 failures = []
152152 errors = []
153+ success_testapp_paths = set ()
153154
154155 for test in tests :
155156 results = validate_results (test .logs , platform )
@@ -160,6 +161,7 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
160161 failures .append (test_result_pair )
161162 else :
162163 successes .append (test_result_pair )
164+ success_testapp_paths .add (test .testapp_path )
163165
164166 # First log the successes, then the failures and errors, then the summary.
165167 # This way, debugging will involve checking the summary at the bottom,
@@ -174,6 +176,11 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
174176 for test , _ in errors :
175177 logging .info ("%s didn't finish normally.\n %s" , test .testapp_path , test .logs )
176178
179+ # Testapps that failed first, but succeed after retry. (max 3 retry)
180+ flaky_testapps = []
181+ failures_exclude_flakiness = []
182+ errors_exclude_flakiness = []
183+
177184 # The summary is much more terse, to minimize the time it takes to understand
178185 # what went wrong, without necessarily providing full debugging context.
179186 summary = []
@@ -184,7 +191,12 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
184191 if errors :
185192 summary .append ("\n %d TESTAPPS EXPERIENCED ERRORS:" % len (errors ))
186193 for test , results in errors :
187- summary .append ("%s:" % test .testapp_path )
194+ summary .append ("\n %s:" % test .testapp_path )
195+ if test .testapp_path in success_testapp_paths :
196+ summary .append ("THIS TESTAPP IS FLAKY" )
197+ flaky_testapps .append ((test , results ))
198+ else :
199+ errors_exclude_flakiness .append ((test , results ))
188200 if hasattr (test , "ftl_link" ) and test .ftl_link :
189201 summary .append ("ftl_link: %s" % test .ftl_link )
190202 if hasattr (test , "raw_result_link" ) and test .raw_result_link :
@@ -198,7 +210,12 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
198210 if failures :
199211 summary .append ("\n %d TESTAPPS FAILED:" % len (failures ))
200212 for test , results in failures :
201- summary .append (test .testapp_path )
213+ summary .append ("\n %s:" % test .testapp_path )
214+ if test .testapp_path in success_testapp_paths :
215+ summary .append ("THIS TESTAPP IS FLAKY" )
216+ flaky_testapps .append ((test , results ))
217+ else :
218+ failures_exclude_flakiness .append ((test , results ))
202219 if hasattr (test , "ftl_link" ) and test .ftl_link :
203220 summary .append ("ftl_link: %s" % test .ftl_link )
204221 if hasattr (test , "raw_result_link" ) and test .raw_result_link :
@@ -208,44 +225,72 @@ def summarize_test_results(tests, platform, summary_dir, file_name="summary.log"
208225 "%d TESTAPPS TOTAL: %d PASSES, %d FAILURES, %d ERRORS"
209226 % (len (tests ), len (successes ), len (failures ), len (errors )))
210227
228+ if len (flaky_testapps ) > 0 and len (flaky_testapps ) == len (failures ) + len (errors ):
229+ logging .info ("All failures and errors are due to flakiness." )
230+ summary .append ("ALL THE FOLLOWING FAILURES AND ERRORS ARE DUE TO FLAKINESS:(" )
231+
211232 # summary_json format:
212233 # { "type": "test",
213234 # "testapps": [testapp],
214- # "errors": {testapp:{"log": error_log, "ftl_link": ftl_link, "raw_result_link": raw_result_link}},
215- # "failures": {testapp:{"log": error_log, "ftl_link": ftl_link, "raw_result_link": raw_result_link,
216- # "failed_tests": {falied_test: test_log}}}}}
235+ # "errors": {testapp:{"logs": [error_log], "ftl_links": [ftl_link], "raw_result_links": [raw_result_link]}},
236+ # "failures": {testapp:{"logs": [error_log], "ftl_links": [ftl_link], "raw_result_links": [raw_result_link],
237+ # "failed_tests": {failed_test: test_log}}},
238+ # "flakiness": {testapp:{"logs": [error_log], "ftl_links": [ftl_link], "raw_result_links": [raw_result_link],
239+ # "flaky_tests": {flaky_test: test_log}}}}
217240 summary_json = {}
218241 summary_json ["type" ] = "test"
219242 summary_json ["testapps" ] = [get_name (test .testapp_path ) for test in tests ]
220- summary_json ["errors" ] = {get_name (test .testapp_path ):{"logs" : results . summary } for (test , results ) in errors }
221- for (test , results ) in errors :
243+ summary_json ["errors" ] = {get_name (test .testapp_path ):{"logs" : [], "ftl_links" : [], "raw_result_links" : [] } for (test , _ ) in errors_exclude_flakiness }
244+ for (test , results ) in errors_exclude_flakiness :
222245 testapp = get_name (test .testapp_path )
246+ summary_json ["errors" ][testapp ]["logs" ].append (results .summary )
223247 if hasattr (test , "ftl_link" ) and test .ftl_link :
224- summary_json ["errors" ][testapp ]["ftl_link" ] = test .ftl_link
248+ summary_json ["errors" ][testapp ]["ftl_links" ]. append ( test .ftl_link )
225249 if hasattr (test , "raw_result_link" ) and test .raw_result_link :
226- summary_json ["errors" ][testapp ]["raw_result_link" ] = test .raw_result_link
227- summary_json ["failures" ] = {get_name (test .testapp_path ):{"logs" : results . summary , "failed_tests" : dict ()} for (test , results ) in failures }
228- for (test , results ) in failures :
250+ summary_json ["errors" ][testapp ]["raw_result_links" ]. append ( test .raw_result_link )
251+ summary_json ["failures" ] = {get_name (test .testapp_path ):{"logs" : [] , "ftl_links" : [], "raw_result_links" : [], " failed_tests" : dict ()} for (test , _ ) in failures_exclude_flakiness }
252+ for (test , results ) in failures_exclude_flakiness :
229253 testapp = get_name (test .testapp_path )
254+ summary_json ["failures" ][testapp ]["logs" ].append (results .summary )
230255 if hasattr (test , "ftl_link" ) and test .ftl_link :
231- summary_json ["failures" ][testapp ]["ftl_link" ] = test .ftl_link
256+ summary_json ["failures" ][testapp ]["ftl_links" ]. append ( test .ftl_link )
232257 if hasattr (test , "raw_result_link" ) and test .raw_result_link :
233- summary_json ["failures" ][testapp ]["raw_result_link" ] = test .raw_result_link
258+ summary_json ["failures" ][testapp ]["raw_result_links" ]. append ( test .raw_result_link )
234259 failed_tests = re .findall (r"\[ FAILED \] (.+)[.](.+)" , results .summary )
235260 for failed_test in failed_tests :
236261 failed_test = failed_test [0 ] + "." + failed_test [1 ]
237262 pattern = fr'\[ RUN \] { failed_test } (.*?)\[ FAILED \] { failed_test } '
238263 failure_log = re .search (pattern , test .logs , re .MULTILINE | re .DOTALL )
239264 summary_json ["failures" ][testapp ]["failed_tests" ][failed_test ] = failure_log .group ()
240265 summary .append ("\n %s FAILED:\n %s\n " % (failed_test , failure_log .group ()))
266+ summary_json ["flakiness" ] = {get_name (test .testapp_path ):{"logs" : [], "ftl_links" : [], "raw_result_links" : [], "flaky_tests" : dict ()} for (test , _ ) in flaky_testapps }
267+ for (test , results ) in flaky_testapps :
268+ testapp = get_name (test .testapp_path )
269+ summary_json ["flakiness" ][testapp ]["logs" ].append (results .summary )
270+ if hasattr (test , "ftl_link" ) and test .ftl_link :
271+ summary_json ["flakiness" ][testapp ]["ftl_links" ].append (test .ftl_link )
272+ if hasattr (test , "raw_result_link" ) and test .raw_result_link :
273+ summary_json ["flakiness" ][testapp ]["raw_result_links" ].append (test .raw_result_link )
274+ flaky_tests = re .findall (r"\[ FAILED \] (.+)[.](.+)" , results .summary )
275+ for flaky_test in flaky_tests :
276+ flaky_test = flaky_test [0 ] + "." + flaky_test [1 ]
277+ pattern = fr'\[ RUN \] { flaky_test } (.*?)\[ FAILED \] { flaky_test } '
278+ failure_log = re .search (pattern , test .logs , re .MULTILINE | re .DOTALL )
279+ if failure_log :
280+ summary_json ["flakiness" ][testapp ]["flaky_tests" ][flaky_test ] = failure_log .group ()
281+ summary .append ("\n %s FAILED:\n %s\n " % (flaky_test , failure_log .group ()))
241282
242283 with open (os .path .join (summary_dir , file_name + ".json" ), "a" ) as f :
243284 f .write (json .dumps (summary_json , indent = 2 ))
244285
245286 summary = "\n " .join (summary )
246287 write_summary (summary_dir , summary , file_name )
247288
248- return 0 if len (tests ) == len (successes ) else 1
289+ # success or only flakiness
290+ if len (tests ) == len (successes ) or len (flaky_testapps ) == len (failures ) + len (errors ):
291+ return 0
292+ else :
293+ return 1
249294
250295
251296def write_summary (testapp_dir , summary , file_name = "summary.log" ):
0 commit comments