Merge topic 'ctest-schedule-random-seed'

d3455f38de ctest: Add option to specify the --schedule-random seed
3dc8e59bdc ctest: Record --schedule-random seed in test log

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Acked-by: Nadav Tenenbaum <tnadav@gmail.com>
Acked-by: Hagai Cohen <hagai.co@gmail.com>
Acked-by: Toplica Tanasković <toplicius@gmail.com>
Acked-by: Itay Bookstein <itay.bookstein@nextsilicon.com>
Acked-by: Ilan Tayari <ilan@nextsilicon.com>
Acked-by: Adnan Hodzic <adnan.hodzic@nextsilicon.com>
Merge-request: !10488
This commit is contained in:
Brad King 2025-03-20 13:10:49 +00:00 committed by Kitware Robot
commit 97246b2083
11 changed files with 75 additions and 1 deletions

View File

@ -445,6 +445,15 @@ Run Tests
This option will run the tests in a random order. It is commonly
used to detect implicit dependencies in a test suite.
.. option:: --schedule-random-seed
.. versionadded:: 4.1
Override the random order seed
This option is used to allow recreating failures owing to
random order of execution by ``--schedule-random``.
.. option:: --submit-index
Legacy option for old Dart2 dashboard server feature.

View File

@ -0,0 +1,7 @@
ctest-schedule-random-seed
--------------------------
* :manual:`ctest(1)` gained a
:option:`--schedule-random-seed <ctest --schedule-random-seed>`
option to specify a numeric random seed to make
:option:`ctest --schedule-random` deterministic for reproduction.

View File

@ -43,6 +43,7 @@ protected:
cm::optional<ArgumentParser::Maybe<std::string>> ParallelLevel;
std::string Repeat;
std::string ScheduleRandom;
std::string ScheduleRandomSeed;
std::string StopTime;
std::string TestLoad;
std::string ResourceSpecFile;
@ -70,6 +71,7 @@ protected:
.Bind("PARALLEL_LEVEL"_s, &TestArguments::ParallelLevel)
.Bind("REPEAT"_s, &TestArguments::Repeat)
.Bind("SCHEDULE_RANDOM"_s, &TestArguments::ScheduleRandom)
.Bind("SCHEDULE_RANDOM_SEED"_s, &TestArguments::ScheduleRandomSeed)
.Bind("STOP_TIME"_s, &TestArguments::StopTime)
.Bind("TEST_LOAD"_s, &TestArguments::TestLoad)
.Bind("RESOURCE_SPEC_FILE"_s, &TestArguments::ResourceSpecFile)

View File

@ -1324,7 +1324,14 @@ bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
bool randomSchedule = this->CTest->GetScheduleType() == "Random";
if (randomSchedule) {
srand(static_cast<unsigned>(time(nullptr)));
cm::optional<unsigned int> scheduleRandomSeed =
this->CTest->GetRandomSeed();
if (!scheduleRandomSeed.has_value()) {
scheduleRandomSeed = static_cast<unsigned int>(time(nullptr));
}
srand(*scheduleRandomSeed);
*this->LogFile << "Test order random seed: " << *scheduleRandomSeed
<< std::endl;
}
for (cmCTestTestProperties& p : this->TestList) {

View File

@ -34,6 +34,7 @@ struct cmCTestTestOptions
bool ScheduleRandom = false;
bool StopOnFailure = false;
bool UseUnion = false;
cm::optional<unsigned int> ScheduleRandomSeed;
int OutputSizePassed = 1 * 1024;
int OutputSizeFailed = 300 * 1024;

View File

@ -2527,6 +2527,20 @@ int cmCTest::Run(std::vector<std::string> const& args)
this->Impl->TestOptions.ScheduleRandom = true;
return true;
} },
CommandArgument{
"--schedule-random-seed", CommandArgument::Values::One,
[this](std::string const& sz) -> bool {
unsigned long seed_value;
if (cmStrToULong(sz, &seed_value)) {
this->Impl->TestOptions.ScheduleRandomSeed =
static_cast<unsigned int>(seed_value);
} else {
cmCTestLog(this, WARNING,
"Invalid value for '--schedule-random-seed': " << sz
<< "\n");
}
return true;
} },
CommandArgument{ "--rerun-failed", CommandArgument::Values::Zero,
[this](std::string const&) -> bool {
this->Impl->TestOptions.RerunFailed = true;
@ -2795,6 +2809,11 @@ void cmCTest::SetStopTime(std::string const& time_str)
}
}
cm::optional<unsigned int> cmCTest::GetRandomSeed() const
{
return this->Impl->TestOptions.ScheduleRandomSeed;
}
std::string cmCTest::GetScheduleType() const
{
return this->Impl->ScheduleType;

View File

@ -198,6 +198,8 @@ public:
std::string GetScheduleType() const;
void SetScheduleType(std::string const& type);
cm::optional<unsigned int> GetRandomSeed() const;
/** The max output width */
int GetMaxTestNameWidth() const;
void SetMaxTestNameWidth(int w);

View File

@ -149,6 +149,7 @@ cmDocumentationEntry const cmDocumentationOptions[] = {
{ "--extra-submit <file>[;<file>]", "Submit extra files to the dashboard." },
{ "--http-header <header>", "Append HTTP header when submitting" },
{ "--schedule-random", "Use a random order for scheduling tests" },
{ "--schedule-random-seed", "Override seed for random order of tests" },
{ "--submit-index",
"Submit individual dashboard tests with specific index" },
{ "--timeout <seconds>", "Set the default test timeout." },

View File

@ -656,3 +656,17 @@ set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 1000)
run_cmake_command(TimeoutSignalBad ${CMAKE_CTEST_COMMAND})
endblock()
endif()
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ScheduleRandomSeed)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
foreach(i RANGE 1 5)
add_test(test\${i} \"${CMAKE_COMMAND}\" -E true)
endforeach()
")
run_cmake_command(ScheduleRandomSeed1 ${CMAKE_CTEST_COMMAND} --schedule-random --schedule-random-seed 42)
run_cmake_command(ScheduleRandomSeed2 ${CMAKE_CTEST_COMMAND} --schedule-random --schedule-random-seed 42)
endblock()

View File

@ -0,0 +1,2 @@
string(REGEX MATCHALL "Start [1-5]" ScheduleRandomSeed1_ORDER "${actual_stdout}")
set_property(DIRECTORY PROPERTY ScheduleRandomSeed1_ORDER "${ScheduleRandomSeed1_ORDER}")

View File

@ -0,0 +1,10 @@
string(REGEX MATCHALL "Start [1-5]" ScheduleRandomSeed2_ORDER "${actual_stdout}")
get_property(ScheduleRandomSeed1_ORDER DIRECTORY PROPERTY ScheduleRandomSeed1_ORDER)
if(NOT "${ScheduleRandomSeed1_ORDER}" STREQUAL "${ScheduleRandomSeed2_ORDER}")
string(CONCAT RunCMake_TEST_FAILED
"ScheduleRandomSeed1 order:\n"
" ${ScheduleRandomSeed1_ORDER}\n"
"does not match ScheduleRandomSeed2 order:\n"
" ${ScheduleRandomSeed2_ORDER}\n"
)
endif()