mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
ctest: Respect test envvars set by CTEST_PRESET
Note the special attention given to support CTest environment variables from inside a test preset's `environment` field. Fixes: #28079
This commit is contained in:
@@ -2,8 +2,10 @@
|
|||||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||||
#include "cmCTestTestCommand.h"
|
#include "cmCTestTestCommand.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <map>
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -105,13 +107,49 @@ cmCTestTestCommand::ResolveTestPreset(cmMakefile& mf,
|
|||||||
return cm::optional<ResolvedTestPreset>(std::move(resolved));
|
return cm::optional<ResolvedTestPreset>(std::move(resolved));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cmCTestTestCommand::ExecuteHandlerCommand(TestArguments& args,
|
||||||
|
cmExecutionStatus& status) const
|
||||||
|
{
|
||||||
|
cmMakefile& mf = status.GetMakefile();
|
||||||
|
|
||||||
|
// Resolve the preset once here (rather than letting InitializeHandler()
|
||||||
|
// resolve it again) so its Environment can be applied for the duration of
|
||||||
|
// the whole test run, without parsing the presets file (and emitting errors,
|
||||||
|
// etc.) more than once.
|
||||||
|
this->CachedPresetResolution.emplace(
|
||||||
|
ResolveTestPreset(mf, args.Preset, args.PresetsFile, status));
|
||||||
|
|
||||||
|
cmSystemTools::SaveRestoreEnvironment restoreEnv;
|
||||||
|
if (*this->CachedPresetResolution &&
|
||||||
|
(*this->CachedPresetResolution)->ExpandedPreset) {
|
||||||
|
for (auto const& var :
|
||||||
|
(*this->CachedPresetResolution)->ExpandedPreset->Environment) {
|
||||||
|
if (var.second) {
|
||||||
|
cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for CTest environment variables specified in a preset, which
|
||||||
|
// are handled by cmCTest much earlier than here, and would otherwise be
|
||||||
|
// ignored.
|
||||||
|
if (!this->CTest->UpdateStateFromEnvironment()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmCTestHandlerCommand::ExecuteHandlerCommand(args, status);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
|
std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
|
||||||
HandlerArguments& arguments, cmExecutionStatus& status) const
|
HandlerArguments& arguments, cmExecutionStatus& status) const
|
||||||
{
|
{
|
||||||
cmMakefile& mf = status.GetMakefile();
|
cmMakefile& mf = status.GetMakefile();
|
||||||
auto& args = static_cast<TestArguments&>(arguments);
|
auto& args = static_cast<TestArguments&>(arguments);
|
||||||
auto resolvedPreset =
|
|
||||||
ResolveTestPreset(mf, args.Preset, args.PresetsFile, status);
|
assert(this->CachedPresetResolution);
|
||||||
|
cm::optional<ResolvedTestPreset> resolvedPreset =
|
||||||
|
std::move(*this->CachedPresetResolution);
|
||||||
|
this->CachedPresetResolution.reset();
|
||||||
if (!resolvedPreset) {
|
if (!resolvedPreset) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,17 @@ class cmCTestTestCommand : public cmCTestHandlerCommand
|
|||||||
public:
|
public:
|
||||||
using cmCTestHandlerCommand::cmCTestHandlerCommand;
|
using cmCTestHandlerCommand::cmCTestHandlerCommand;
|
||||||
|
|
||||||
|
cmCTestTestCommand(cmCTestTestCommand const& other)
|
||||||
|
: cmCTestHandlerCommand(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cmCTestTestCommand& operator=(cmCTestTestCommand const& other)
|
||||||
|
{
|
||||||
|
cmCTestHandlerCommand::operator=(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct TestArguments : HandlerArguments
|
struct TestArguments : HandlerArguments
|
||||||
{
|
{
|
||||||
@@ -54,6 +65,9 @@ protected:
|
|||||||
std::string PresetsFile;
|
std::string PresetsFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool ExecuteHandlerCommand(TestArguments& args,
|
||||||
|
cmExecutionStatus& status) const;
|
||||||
|
|
||||||
template <typename Args>
|
template <typename Args>
|
||||||
static auto MakeTestParser() -> cmArgumentParser<Args>
|
static auto MakeTestParser() -> cmArgumentParser<Args>
|
||||||
{
|
{
|
||||||
@@ -101,6 +115,12 @@ private:
|
|||||||
cmMakefile& mf, std::string const& presetArg,
|
cmMakefile& mf, std::string const& presetArg,
|
||||||
std::string const& presetsFileArg, cmExecutionStatus& status) const;
|
std::string const& presetsFileArg, cmExecutionStatus& status) const;
|
||||||
|
|
||||||
|
// Set by ExecuteHandlerCommand() (resolves the preset once, up
|
||||||
|
// front) and consumed by InitializeHandler() to avoid parsing the presets
|
||||||
|
// file (and emitting error messages, etc.) more than once.
|
||||||
|
mutable cm::optional<cm::optional<ResolvedTestPreset>>
|
||||||
|
CachedPresetResolution;
|
||||||
|
|
||||||
virtual std::unique_ptr<cmCTestTestHandler> InitializeActualHandler(
|
virtual std::unique_ptr<cmCTestTestHandler> InitializeActualHandler(
|
||||||
HandlerArguments& arguments, cmExecutionStatus& status) const;
|
HandlerArguments& arguments, cmExecutionStatus& status) const;
|
||||||
|
|
||||||
|
|||||||
@@ -869,6 +869,84 @@ block()
|
|||||||
-V)
|
-V)
|
||||||
endblock()
|
endblock()
|
||||||
|
|
||||||
|
# Environment variables from a test preset selected by -D CTEST_PRESET are
|
||||||
|
# applied when dashboard mode runs the Test step.
|
||||||
|
block()
|
||||||
|
set(src "${RunCMake_BINARY_DIR}/TestPresetCLIVarEnvironment")
|
||||||
|
set(bin "${RunCMake_BINARY_DIR}/TestPresetCLIVarEnvironment-build")
|
||||||
|
file(REMOVE_RECURSE "${src}" "${bin}")
|
||||||
|
file(MAKE_DIRECTORY "${src}" "${bin}")
|
||||||
|
configure_file("${RunCMake_SOURCE_DIR}/TestPresetCLIVarEnvironment-CMakePresets.json.in"
|
||||||
|
"${src}/CMakePresets.json" @ONLY)
|
||||||
|
file(WRITE "${bin}/DartConfiguration.tcl"
|
||||||
|
"BuildDirectory: ${bin}\n"
|
||||||
|
"SourceDirectory: ${src}\n")
|
||||||
|
file(WRITE "${bin}/CTestTestfile.cmake" "
|
||||||
|
add_test(print-env \"${CMAKE_COMMAND}\" -E environment)
|
||||||
|
set_tests_properties(print-env PROPERTIES PASS_REGULAR_EXPRESSION \"DASHBOARD_PRESET_ENV=from-preset\")
|
||||||
|
")
|
||||||
|
set(RunCMake_TEST_SOURCE_DIR "${src}")
|
||||||
|
set(RunCMake_TEST_BINARY_DIR "${bin}")
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
run_cmake_command(TestPresetCLIVarEnvironment
|
||||||
|
${CMAKE_CTEST_COMMAND}
|
||||||
|
-M Experimental
|
||||||
|
-D "CTEST_PRESET=my-test-preset"
|
||||||
|
-T Test
|
||||||
|
-V)
|
||||||
|
endblock()
|
||||||
|
|
||||||
|
# CTEST_PARALLEL_LEVEL set by a test preset's environment is respected.
|
||||||
|
block()
|
||||||
|
set(src "${RunCMake_BINARY_DIR}/TestPresetParallelLevelEnvironment")
|
||||||
|
set(bin "${RunCMake_BINARY_DIR}/TestPresetParallelLevelEnvironment-build")
|
||||||
|
file(REMOVE_RECURSE "${src}" "${bin}")
|
||||||
|
file(MAKE_DIRECTORY "${src}" "${bin}")
|
||||||
|
configure_file("${RunCMake_SOURCE_DIR}/TestPresetParallelLevelEnvironment-CMakePresets.json.in"
|
||||||
|
"${src}/CMakePresets.json" @ONLY)
|
||||||
|
file(WRITE "${bin}/DartConfiguration.tcl"
|
||||||
|
"BuildDirectory: ${bin}\n"
|
||||||
|
"SourceDirectory: ${src}\n")
|
||||||
|
file(WRITE "${bin}/CTestTestfile.cmake" "
|
||||||
|
foreach(i RANGE 1 6)
|
||||||
|
add_test(test\${i} \"${CMAKE_COMMAND}\" -E true)
|
||||||
|
endforeach()
|
||||||
|
")
|
||||||
|
set(RunCMake_TEST_SOURCE_DIR "${src}")
|
||||||
|
set(RunCMake_TEST_BINARY_DIR "${bin}")
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
# Spoof a number of processors to make these tests predictable.
|
||||||
|
set(ENV{__CTEST_FAKE_PROCESSOR_COUNT_FOR_TESTING} 1)
|
||||||
|
run_cmake_command(TestPresetParallelLevelEnvironment
|
||||||
|
${CMAKE_CTEST_COMMAND}
|
||||||
|
-M Experimental
|
||||||
|
-D "CTEST_PRESET=my-test-preset"
|
||||||
|
-T Test)
|
||||||
|
unset(ENV{__CTEST_FAKE_PROCESSOR_COUNT_FOR_TESTING})
|
||||||
|
endblock()
|
||||||
|
|
||||||
|
# CTEST_NO_TESTS_ACTION set by a test preset's environment is respected.
|
||||||
|
block()
|
||||||
|
set(src "${RunCMake_BINARY_DIR}/TestPresetNoTestsActionEnvironment")
|
||||||
|
set(bin "${RunCMake_BINARY_DIR}/TestPresetNoTestsActionEnvironment-build")
|
||||||
|
file(REMOVE_RECURSE "${src}" "${bin}")
|
||||||
|
file(MAKE_DIRECTORY "${src}" "${bin}")
|
||||||
|
configure_file("${RunCMake_SOURCE_DIR}/TestPresetNoTestsActionEnvironment-CMakePresets.json.in"
|
||||||
|
"${src}/CMakePresets.json" @ONLY)
|
||||||
|
file(WRITE "${bin}/DartConfiguration.tcl"
|
||||||
|
"BuildDirectory: ${bin}\n"
|
||||||
|
"SourceDirectory: ${src}\n")
|
||||||
|
file(WRITE "${bin}/CTestTestfile.cmake" "")
|
||||||
|
set(RunCMake_TEST_SOURCE_DIR "${src}")
|
||||||
|
set(RunCMake_TEST_BINARY_DIR "${bin}")
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
run_cmake_command(TestPresetNoTestsActionEnvironment
|
||||||
|
${CMAKE_CTEST_COMMAND}
|
||||||
|
-M Experimental
|
||||||
|
-D "CTEST_PRESET=my-test-preset"
|
||||||
|
-T Test)
|
||||||
|
endblock()
|
||||||
|
|
||||||
# Test --output-junit
|
# Test --output-junit
|
||||||
function(run_output_junit)
|
function(run_output_junit)
|
||||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/output-junit)
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/output-junit)
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 21,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "my-configure-preset",
|
||||||
|
"generator": "@RunCMake_GENERATOR@",
|
||||||
|
"binaryDir": "${sourceDir}/build"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "my-test-preset",
|
||||||
|
"configurePreset": "my-configure-preset",
|
||||||
|
"environment": {
|
||||||
|
"DASHBOARD_PRESET_ENV": "from-preset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DASHBOARD_PRESET_ENV=from-preset
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 21,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "my-configure-preset",
|
||||||
|
"generator": "@RunCMake_GENERATOR@",
|
||||||
|
"binaryDir": "${sourceDir}/build"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "my-test-preset",
|
||||||
|
"configurePreset": "my-configure-preset",
|
||||||
|
"environment": {
|
||||||
|
"CTEST_NO_TESTS_ACTION": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
8
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
No tests were found!!!
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 21,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "my-configure-preset",
|
||||||
|
"generator": "@RunCMake_GENERATOR@",
|
||||||
|
"binaryDir": "${sourceDir}/build"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "my-test-preset",
|
||||||
|
"configurePreset": "my-configure-preset",
|
||||||
|
"environment": {
|
||||||
|
"CTEST_PARALLEL_LEVEL": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
Test project [^
|
||||||
|
]*/Tests/RunCMake/CTestCommandLine/TestPresetParallelLevelEnvironment-build
|
||||||
|
Start [0-9]+: test[0-9]+
|
||||||
|
Start [0-9]+: test[0-9]+
|
||||||
|
Start [0-9]+: test[0-9]+
|
||||||
|
1/6 Test #[0-9]+: test[0-9]+ \.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. Passed +[0-9\.]+ sec
|
||||||
Reference in New Issue
Block a user