@@ -96,10 +96,11 @@ def get_module(name, path):
96
96
97
97
class ProgressIndicator (object ):
98
98
99
- def __init__ (self , cases , flaky_tests_mode ):
99
+ def __init__ (self , cases , flaky_tests_mode , measure_flakiness ):
100
100
self .cases = cases
101
101
self .serial_id = 0
102
102
self .flaky_tests_mode = flaky_tests_mode
103
+ self .measure_flakiness = measure_flakiness
103
104
self .parallel_queue = Queue (len (cases ))
104
105
self .sequential_queue = Queue (len (cases ))
105
106
for case in cases :
@@ -211,10 +212,20 @@ def RunSingle(self, parallel, thread_id):
211
212
if output .UnexpectedOutput ():
212
213
if FLAKY in output .test .outcomes and self .flaky_tests_mode == DONTCARE :
213
214
self .flaky_failed .append (output )
215
+ elif FLAKY in output .test .outcomes and self .flaky_tests_mode == KEEP_RETRYING :
216
+ for _ in range (99 ):
217
+ if not case .Run ().UnexpectedOutput ():
218
+ self .flaky_failed .append (output )
219
+ break
220
+ # If after 100 tries, the test is not passing, it's not flaky.
221
+ self .failed .append (output )
214
222
else :
215
223
self .failed .append (output )
216
224
if output .HasCrashed ():
217
225
self .crashed += 1
226
+ if self .measure_flakiness :
227
+ outputs = [case .Run () for _ in range (self .measure_flakiness )]
228
+ print (f" failed { len ([i for i in outputs if i .UnexpectedOutput ()])} out of { self .measure_flakiness } " )
218
229
else :
219
230
self .succeeded += 1
220
231
self .remaining -= 1
@@ -436,8 +447,8 @@ def Done(self):
436
447
437
448
class CompactProgressIndicator (ProgressIndicator ):
438
449
439
- def __init__ (self , cases , flaky_tests_mode , templates ):
440
- super (CompactProgressIndicator , self ).__init__ (cases , flaky_tests_mode )
450
+ def __init__ (self , cases , flaky_tests_mode , measure_flakiness , templates ):
451
+ super (CompactProgressIndicator , self ).__init__ (cases , flaky_tests_mode , measure_flakiness )
441
452
self .templates = templates
442
453
self .last_status_length = 0
443
454
self .start_time = time .time ()
@@ -492,29 +503,29 @@ def PrintProgress(self, name):
492
503
493
504
class ColorProgressIndicator (CompactProgressIndicator ):
494
505
495
- def __init__ (self , cases , flaky_tests_mode ):
506
+ def __init__ (self , cases , flaky_tests_mode , measure_flakiness ):
496
507
templates = {
497
508
'status_line' : "[%(mins)02i:%(secs)02i|\033 [34m%%%(remaining) 4d\033 [0m|\033 [32m+%(passed) 4d\033 [0m|\033 [31m-%(failed) 4d\033 [0m]: %(test)s" ,
498
509
'stdout' : "\033 [1m%s\033 [0m" ,
499
510
'stderr' : "\033 [31m%s\033 [0m" ,
500
511
}
501
- super (ColorProgressIndicator , self ).__init__ (cases , flaky_tests_mode , templates )
512
+ super (ColorProgressIndicator , self ).__init__ (cases , flaky_tests_mode , measure_flakiness , templates )
502
513
503
514
def ClearLine (self , last_line_length ):
504
515
print ("\033 [1K\r " , end = '' )
505
516
506
517
507
518
class MonochromeProgressIndicator (CompactProgressIndicator ):
508
519
509
- def __init__ (self , cases , flaky_tests_mode ):
520
+ def __init__ (self , cases , flaky_tests_mode , measure_flakiness ):
510
521
templates = {
511
522
'status_line' : "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%(failed) 4d]: %(test)s" ,
512
523
'stdout' : '%s' ,
513
524
'stderr' : '%s' ,
514
525
'clear' : lambda last_line_length : ("\r " + (" " * last_line_length ) + "\r " ),
515
526
'max_length' : 78
516
527
}
517
- super (MonochromeProgressIndicator , self ).__init__ (cases , flaky_tests_mode , templates )
528
+ super (MonochromeProgressIndicator , self ).__init__ (cases , flaky_tests_mode , measure_flakiness , templates )
518
529
519
530
def ClearLine (self , last_line_length ):
520
531
print (("\r " + (" " * last_line_length ) + "\r " ), end = '' )
@@ -948,8 +959,8 @@ def GetTimeout(self, mode, section=''):
948
959
timeout = timeout * 6
949
960
return timeout
950
961
951
- def RunTestCases (cases_to_run , progress , tasks , flaky_tests_mode ):
952
- progress = PROGRESS_INDICATORS [progress ](cases_to_run , flaky_tests_mode )
962
+ def RunTestCases (cases_to_run , progress , tasks , flaky_tests_mode , measure_flakiness ):
963
+ progress = PROGRESS_INDICATORS [progress ](cases_to_run , flaky_tests_mode , measure_flakiness )
953
964
return progress .Run (tasks )
954
965
955
966
# -------------------------------------------
@@ -967,6 +978,7 @@ def RunTestCases(cases_to_run, progress, tasks, flaky_tests_mode):
967
978
SLOW = 'slow'
968
979
FLAKY = 'flaky'
969
980
DONTCARE = 'dontcare'
981
+ KEEP_RETRYING = 'keep_retrying'
970
982
971
983
class Expression (object ):
972
984
pass
@@ -1357,6 +1369,9 @@ def BuildOptions():
1357
1369
result .add_option ("--flaky-tests" ,
1358
1370
help = "Regard tests marked as flaky (run|skip|dontcare)" ,
1359
1371
default = "run" )
1372
+ result .add_option ("--measure-flakiness" ,
1373
+ help = "When a test fails, re-run it x number of times" ,
1374
+ default = 0 , type = "int" )
1360
1375
result .add_option ("--skip-tests" ,
1361
1376
help = "Tests that should not be executed (comma-separated)" ,
1362
1377
default = "" )
@@ -1733,7 +1748,7 @@ def should_keep(case):
1733
1748
else :
1734
1749
try :
1735
1750
start = time .time ()
1736
- if RunTestCases (cases_to_run , options .progress , options .j , options .flaky_tests ):
1751
+ if RunTestCases (cases_to_run , options .progress , options .j , options .flaky_tests , options . measure_flakiness ):
1737
1752
result = 0
1738
1753
else :
1739
1754
result = 1
0 commit comments