summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-10-29 18:45:21 (GMT)
committerBrad King <brad.king@kitware.com>2019-10-29 19:10:12 (GMT)
commit80c2c9d14cf1c1a8f162e119bd00d5f483a94af2 (patch)
tree273a15083c42453ee3265a3ce8263bf7a74a3e3e /Source
parent0187e522448c8fe92c15d4a983afac36950d1d59 (diff)
downloadCMake-80c2c9d14cf1c1a8f162e119bd00d5f483a94af2.zip
CMake-80c2c9d14cf1c1a8f162e119bd00d5f483a94af2.tar.gz
CMake-80c2c9d14cf1c1a8f162e119bd00d5f483a94af2.tar.bz2
ctest: Add --repeat-until-pass option
Add an option to re-run tests if they fail. This will help tolerate sporadic failures. Issue: #17010 Co-Author: Ben Boeckel <ben.boeckel@kitware.com> Co-Author: Chuck Atkins <chuck.atkins@kitware.com>
Diffstat (limited to 'Source')
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx4
-rw-r--r--Source/CTest/cmCTestRunTest.cxx14
-rw-r--r--Source/CTest/cmCTestRunTest.h15
-rw-r--r--Source/cmCTest.cxx35
-rw-r--r--Source/cmCTest.h9
-rw-r--r--Source/ctest.cxx5
6 files changed, 63 insertions, 19 deletions
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 7e8d548..4812f30 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -171,8 +171,8 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test)
this->RunningCount += GetProcessorsUsed(test);
cmCTestRunTest* testRun = new cmCTestRunTest(*this);
- if (this->CTest->GetRepeatUntilFail()) {
- testRun->SetRunUntilFailOn();
+ if (this->CTest->GetRerunMode() != cmCTest::Rerun::Never) {
+ testRun->SetRerunMode(this->CTest->GetRerunMode());
testRun->SetNumberOfRuns(this->CTest->GetTestRepeat());
}
testRun->SetIndex(test);
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 2e7836a..ce9e13b 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -340,10 +340,12 @@ bool cmCTestRunTest::NeedsToRerun()
return false;
}
// if number of runs left is not 0, and we are running until
- // we find a failed test, then return true so the test can be
+ // we find a failed (or passed) test, then return true so the test can be
// restarted
- if (this->RunUntilFail &&
- this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+ if ((this->RerunMode == cmCTest::Rerun::UntilFail &&
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED) ||
+ (this->RerunMode == cmCTest::Rerun::UntilPass &&
+ this->TestResult.Status != cmCTestTestHandler::COMPLETED)) {
this->RunAgain = true;
return true;
}
@@ -743,7 +745,11 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
// then it will never print out the completed / total, same would
// got for run until pass. Trick is when this is called we don't
// yet know if we are passing or failing.
- if (this->NumberOfRunsLeft == 1 || this->CTest->GetTestProgressOutput()) {
+ if ((this->RerunMode != cmCTest::Rerun::UntilPass &&
+ this->NumberOfRunsLeft == 1) ||
+ (this->RerunMode == cmCTest::Rerun::UntilPass &&
+ this->NumberOfRunsLeft == this->NumberOfRunsTotal) ||
+ this->CTest->GetTestProgressOutput()) {
outputStream << std::setw(getNumWidth(total)) << completed << "/";
outputStream << std::setw(getNumWidth(total)) << total << " ";
}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 7b202d1..881cbb6 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -13,13 +13,12 @@
#include <stddef.h>
+#include "cmCTest.h"
#include "cmCTestMultiProcessHandler.h"
#include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmProcess.h"
-class cmCTest;
-
/** \class cmRunTest
* \brief represents a single test to be run
*
@@ -30,8 +29,13 @@ class cmCTestRunTest
public:
explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler);
- void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; }
- void SetRunUntilFailOn() { this->RunUntilFail = true; }
+ void SetNumberOfRuns(int n)
+ {
+ this->NumberOfRunsLeft = n;
+ this->NumberOfRunsTotal = n;
+ }
+
+ void SetRerunMode(cmCTest::Rerun r) { this->RerunMode = r; }
void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop)
{
this->TestProperties = prop;
@@ -129,8 +133,9 @@ private:
std::vector<std::map<
std::string, std::vector<cmCTestMultiProcessHandler::HardwareAllocation>>>
AllocatedHardware;
- bool RunUntilFail = false; // default to run the test once
+ cmCTest::Rerun RerunMode = cmCTest::Rerun::Never;
int NumberOfRunsLeft = 1; // default to 1 run of the test
+ int NumberOfRunsTotal = 1; // default to 1 run of the test
bool RunAgain = false; // default to not having to run again
size_t TotalNumberOfTests;
};
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 10b7646..7276d98 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -84,7 +84,7 @@ struct cmCTest::Private
};
int RepeatTests = 1; // default to run each test once
- bool RepeatUntilFail = false;
+ cmCTest::Rerun RerunMode = cmCTest::Rerun::Never;
std::string ConfigType;
std::string ScheduleType;
std::chrono::system_clock::time_point StopTime;
@@ -1839,11 +1839,16 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
this->SetParallelLevel(plevel);
this->Impl->ParallelLevelSetInCli = true;
}
+
if (this->CheckArgument(arg, "--repeat-until-fail")) {
if (i >= args.size() - 1) {
errormsg = "'--repeat-until-fail' requires an argument";
return false;
}
+ if (this->Impl->RerunMode != cmCTest::Rerun::Never) {
+ errormsg = "At most one '--repeat-*' option may be used.";
+ return false;
+ }
i++;
long repeat = 1;
if (!cmStrToLong(args[i], &repeat)) {
@@ -1853,7 +1858,29 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
this->Impl->RepeatTests = static_cast<int>(repeat);
if (repeat > 1) {
- this->Impl->RepeatUntilFail = true;
+ this->Impl->RerunMode = cmCTest::Rerun::UntilFail;
+ }
+ }
+
+ if (this->CheckArgument(arg, "--repeat-until-pass")) {
+ if (i >= args.size() - 1) {
+ errormsg = "'--repeat-until-pass' requires an argument";
+ return false;
+ }
+ if (this->Impl->RerunMode != cmCTest::Rerun::Never) {
+ errormsg = "At most one '--repeat-*' option may be used.";
+ return false;
+ }
+ i++;
+ long repeat = 1;
+ if (!cmStrToLong(args[i], &repeat)) {
+ errormsg =
+ "'--repeat-until-pass' given non-integer value '" + args[i] + "'";
+ return false;
+ }
+ this->Impl->RepeatTests = static_cast<int>(repeat);
+ if (repeat > 1) {
+ this->Impl->RerunMode = cmCTest::Rerun::UntilPass;
}
}
@@ -2852,9 +2879,9 @@ int cmCTest::GetTestRepeat() const
return this->Impl->RepeatTests;
}
-bool cmCTest::GetRepeatUntilFail() const
+cmCTest::Rerun cmCTest::GetRerunMode() const
{
- return this->Impl->RepeatUntilFail;
+ return this->Impl->RerunMode;
}
void cmCTest::SetBuildID(const std::string& id)
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 82a6f4c..c6b8928 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -433,8 +433,13 @@ public:
/** Return the number of times a test should be run */
int GetTestRepeat() const;
- /** Return true if test should run until fail */
- bool GetRepeatUntilFail() const;
+ enum class Rerun
+ {
+ Never,
+ UntilFail,
+ UntilPass,
+ };
+ Rerun GetRerunMode() const;
void GenerateSubprojectsOutput(cmXMLWriter& xml);
std::vector<std::string> GetLabelsForSubprojects();
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 91ee598..f716d7a 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -99,8 +99,9 @@ static const char* cmDocumentationOptions[][2] = {
{ "-U, --union", "Take the Union of -I and -R" },
{ "--rerun-failed", "Run only the tests that failed previously" },
{ "--repeat-until-fail <n>",
- "Require each test to run <n> "
- "times without failing in order to pass" },
+ "Require each test to run <n> times without failing in order to pass" },
+ { "--repeat-until-pass <n>",
+ "Allow each test to run up to <n> times in order to pass" },
{ "--max-width <width>", "Set the max width for a test name to output" },
{ "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." },
{ "--hardware-spec-file <file>", "Set the hardware spec file to use." },