@@ -273,6 +273,7 @@ const char * const TestInfoKindName[] =
273
273
" env" ,
274
274
" command" ,
275
275
" timeout" ,
276
+ " timeoutRetries" ,
276
277
" sourcepath" ,
277
278
" eol-normalization" ,
278
279
" custom-config-file" ,
@@ -315,34 +316,34 @@ char *CL, *_CL_;
315
316
const char *JCBinary = " jshost.exe" ;
316
317
317
318
BOOL FStatus = TRUE ;
318
- char *StatusPrefix;
319
- const char *StatusFormat;
319
+ char *StatusPrefix = nullptr ;
320
+ const char *StatusFormat = nullptr ;
320
321
321
- BOOL FVerbose;
322
- BOOL FQuiet;
323
- BOOL FNoWarn;
324
- BOOL FTest;
322
+ BOOL FVerbose = FALSE ;
323
+ BOOL FQuiet = FALSE ;
324
+ BOOL FNoWarn = FALSE ;
325
+ BOOL FTest = FALSE ;
325
326
BOOL FStopOnError = FALSE ;
326
327
BOOL GStopDueToError = FALSE ;
327
- BOOL FLow;
328
- BOOL FNoDelete;
329
- BOOL FCopyOnFail;
328
+ BOOL FLow = FALSE ;
329
+ BOOL FNoDelete = FALSE ;
330
+ BOOL FCopyOnFail = FALSE ;
330
331
BOOL FSummary = TRUE ;
331
- BOOL FMoveDiffs;
332
- BOOL FNoMoveDiffsSwitch;
333
- BOOL FRelativeLogPath;
332
+ BOOL FMoveDiffs = FALSE ;
333
+ BOOL FNoMoveDiffsSwitch = FALSE ;
334
+ BOOL FRelativeLogPath = FALSE ;
334
335
BOOL FNoDirName = TRUE ;
335
- BOOL FBaseline;
336
+ BOOL FBaseline = FALSE ;
336
337
BOOL FRebase = FALSE ;
337
- BOOL FDiff;
338
- BOOL FBaseDiff;
339
- BOOL FSyncEnumDirs;
338
+ BOOL FDiff = FALSE ;
339
+ BOOL FBaseDiff = FALSE ;
340
+ BOOL FSyncEnumDirs = FALSE ;
340
341
BOOL FNogpfnt = TRUE ;
341
- BOOL FAppend;
342
+ BOOL FAppend = FALSE ;
342
343
BOOL FAppendTestNameToExtraCCFlags = FALSE ;
343
344
344
345
#ifndef NODEBUG
345
- BOOL FDebug;
346
+ BOOL FDebug = FALSE ;
346
347
#endif
347
348
348
349
// Output synchronization options
@@ -364,7 +365,6 @@ RLMODE Mode = DEFAULT_RLMODE;
364
365
char *DCFGfile = NULL ;
365
366
char const *CFGfile = NULL ;
366
367
char const *CMDfile = NULL ;
367
- int CFGline;
368
368
369
369
#define MAX_ALLOWED_THREADS 10 // must be <= MAXIMUM_WAIT_OBJECTS (64)
370
370
unsigned NumberOfThreads = 0 ;
@@ -376,15 +376,18 @@ BOOL FNoProgramOutput = FALSE;
376
376
BOOL FOnlyAssertOutput = FALSE ;
377
377
BOOL FExcludeDirs = FALSE ;
378
378
BOOL FGenLst = FALSE ;
379
- char *ResumeDir, *MatchDir;
379
+ char *ResumeDir = nullptr ;
380
+ char *MatchDir = nullptr ;
380
381
381
382
TIME_OPTION Timing = TIME_DIR | TIME_TEST; // Default to report times at test and directory level
382
383
383
- static const char *ProgramName;
384
- static const char *LogName;
385
- static const char *FullLogName;
386
- static const char *ResultsLogName;
387
- static const char *TestTimeout; // Stores timeout in seconds for all tests
384
+ static const char *ProgramName = nullptr ;
385
+ static const char *LogName = nullptr ;
386
+ static const char *FullLogName = nullptr ;
387
+ static const char *ResultsLogName = nullptr ;
388
+ static const char *TestTimeout = nullptr ; // Stores timeout in seconds for all tests
389
+ static const char *TestTimeoutRetries = nullptr ; // Number of timeout retries for all tests
390
+ #define MAX_ALLOWED_TIMEOUT_RETRIES 100 // Arbitrary max to avoid accidentally specifying too many retries
388
391
389
392
// NOTE: this might be unused now
390
393
static char TempPath[MAX_PATH] = " " ; // Path for temporary files
@@ -2474,6 +2477,7 @@ WriteEnvLst
2474
2477
NULL ,
2475
2478
NULL ,
2476
2479
NULL ,
2480
+ NULL ,
2477
2481
NULL
2478
2482
};
2479
2483
@@ -2994,6 +2998,11 @@ ParseArg(
2994
2998
break ;
2995
2999
}
2996
3000
3001
+ if (!_stricmp (&arg[1 ], " timeoutRetries" )) {
3002
+ TestTimeoutRetries = ComplainIfNoArg (arg, s);
3003
+ break ;
3004
+ }
3005
+
2997
3006
#ifndef NODEBUG
2998
3007
if (!_stricmp (&arg[1 ], " debug" )) {
2999
3008
FDebug = FVerbose = TRUE ;
@@ -3540,6 +3549,32 @@ IsTimeoutStringValid(const char *strTimeout)
3540
3549
return TRUE ;
3541
3550
}
3542
3551
3552
+ BOOL
3553
+ IsTimeoutRetriesStringValid (const char *strTimeoutRetries)
3554
+ {
3555
+ char *end;
3556
+ _set_errno (0 );
3557
+
3558
+ uint32 numRetries = strtoul (strTimeoutRetries, &end, 10 );
3559
+
3560
+ if (errno != 0 || *end != 0 )
3561
+ {
3562
+ return FALSE ;
3563
+ }
3564
+
3565
+ // We will not be doing any math with this value, so no need to check for overflow.
3566
+ // However, large values will possibly result in an unacceptably long retry loop,
3567
+ // (especially with the default timeout being multiple minutes long),
3568
+ // so limit the number of retries to some arbitrary max.
3569
+
3570
+ if (numRetries > MAX_ALLOWED_TIMEOUT_RETRIES)
3571
+ {
3572
+ return FALSE ;
3573
+ }
3574
+
3575
+ return TRUE ;
3576
+ }
3577
+
3543
3578
uint32 GetTimeoutValue (const char *strTimeout)
3544
3579
{
3545
3580
if (strTimeout == nullptr )
@@ -3606,13 +3641,26 @@ GetTestInfoFromNode
3606
3641
if (i == TIK_TIMEOUT)
3607
3642
{
3608
3643
// Validate the timeout string now to fail early so we don't run any tests when there is an error.
3609
- if (!IsTimeoutStringValid (testInfo->data [i])) {
3644
+ if (!IsTimeoutStringValid (testInfo->data [i]))
3645
+ {
3610
3646
CFG_ERROR_EX (fileName, node->LineNumber ,
3611
3647
" Invalid timeout specified. Cannot parse or too large.\n " , nullptr );
3612
3648
childNode->Dump ();
3613
3649
return FALSE ;
3614
3650
}
3615
3651
}
3652
+
3653
+ if (i == TIK_TIMEOUT_RETRIES)
3654
+ {
3655
+ // Validate the timeoutRetries string now to fail early so we don't run any tests when there is an error.
3656
+ if (!IsTimeoutRetriesStringValid (testInfo->data [i]))
3657
+ {
3658
+ CFG_ERROR_EX (fileName, node->LineNumber ,
3659
+ " Invalid number of timeout retries specified. Value must be numeric and <= %d.\n " , MAX_ALLOWED_TIMEOUT_RETRIES);
3660
+ childNode->Dump ();
3661
+ return FALSE ;
3662
+ }
3663
+ }
3616
3664
}
3617
3665
}
3618
3666
@@ -3626,6 +3674,17 @@ GetTestInfoFromNode
3626
3674
testInfo->data [i] = TestTimeout;
3627
3675
}
3628
3676
}
3677
+
3678
+ if (i == TIK_TIMEOUT_RETRIES && TestTimeoutRetries != nullptr )
3679
+ {
3680
+ // Overriding the timeoutRetries value with the command line value (if the command line value is larger)
3681
+ uint32 xmlTimeoutRetriesValue = GetTimeoutValue (testInfo->data [i]);
3682
+ uint32 testTimeoutRetriesValue = GetTimeoutValue (TestTimeoutRetries);
3683
+ if (xmlTimeoutRetriesValue < testTimeoutRetriesValue)
3684
+ {
3685
+ testInfo->data [i] = TestTimeoutRetries;
3686
+ }
3687
+ }
3629
3688
}
3630
3689
3631
3690
return TRUE ;
0 commit comments