From d058dcc326beee59b59e786d6448d9207eedd00e Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 29 Aug 2018 12:33:15 +0200 Subject: [PATCH] AutoTest: Filter out interfering environment variables If there are environment variables that might interfere with the test process filter them out before setting the environment for the test process as they can - in the worst case - even lead to being not able to execute the test application at all. Task-number: QTCREATORBUG-21012 Change-Id: I4a2059cf527395498824a0914fd6c3203eca9bcf Reviewed-by: David Schulz --- .../autotest/gtest/gtestconfiguration.cpp | 12 ++++++ .../autotest/gtest/gtestconfiguration.h | 1 + src/plugins/autotest/qtest/qttest_utils.cpp | 13 ++++++ src/plugins/autotest/qtest/qttest_utils.h | 2 + .../autotest/qtest/qttestconfiguration.cpp | 5 +++ .../autotest/qtest/qttestconfiguration.h | 1 + .../autotest/quick/quicktestconfiguration.cpp | 5 +++ .../autotest/quick/quicktestconfiguration.h | 2 +- src/plugins/autotest/testconfiguration.h | 2 +- src/plugins/autotest/testrunner.cpp | 40 +++++++++++++++---- 10 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp index 7754a854939..dacd84c4324 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.cpp +++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp @@ -107,5 +107,17 @@ QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) con return arguments; } +Utils::Environment GTestConfiguration::filteredEnvironment(const Utils::Environment &original) const +{ + const QStringList interfering{"GTEST_FILTER", "GTEST_COLOR", "GTEST_ALSO_RUN_DISABLED_TESTS", + "GTEST_REPEAT", "GTEST_SHUFFLE", "GTEST_RANDOM_SEED", + "GTEST_OUTPUT", "GTEST_BREAK_ON_FAILURE", "GTEST_PRINT_TIME", + "GTEST_CATCH_EXCEPTIONS"}; + Utils::Environment result = original; + for (const QString &key : interfering) + result.unset(key); + return result; +} + } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/gtest/gtestconfiguration.h b/src/plugins/autotest/gtest/gtestconfiguration.h index 9e2d63b1e97..51f88293ec2 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.h +++ b/src/plugins/autotest/gtest/gtestconfiguration.h @@ -37,6 +37,7 @@ public: TestOutputReader *outputReader(const QFutureInterface &fi, QProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; + Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; } // namespace Internal diff --git a/src/plugins/autotest/qtest/qttest_utils.cpp b/src/plugins/autotest/qtest/qttest_utils.cpp index 47019270486..ff49155a989 100644 --- a/src/plugins/autotest/qtest/qttest_utils.cpp +++ b/src/plugins/autotest/qtest/qttest_utils.cpp @@ -25,7 +25,9 @@ #include "qttest_utils.h" #include "qttesttreeitem.h" +#include "../autotestplugin.h" #include "../testframeworkmanager.h" +#include "../testsettings.h" #include #include @@ -140,6 +142,17 @@ QStringList filterInterfering(const QStringList &provided, QStringList *omitted, return allowed; } +Utils::Environment prepareBasicEnvironment(const Utils::Environment &env) +{ + Utils::Environment result(env); + if (Utils::HostOsInfo::isWindowsHost()) + result.set("QT_LOGGING_TO_CONSOLE", "1"); + const int timeout = AutotestPlugin::settings()->timeout; + if (timeout > 5 * 60 * 1000) // Qt5.5 introduced hard limit, Qt5.6.1 added env var to raise this + result.set("QTEST_FUNCTION_TIMEOUT", QString::number(timeout)); + return result; +} + } // namespace QTestUtils } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/qtest/qttest_utils.h b/src/plugins/autotest/qtest/qttest_utils.h index 30dfa85055d..23820c05d9b 100644 --- a/src/plugins/autotest/qtest/qttest_utils.h +++ b/src/plugins/autotest/qtest/qttest_utils.h @@ -28,6 +28,7 @@ #include namespace Core { class Id; } +namespace Utils { class Environment; } namespace Autotest { namespace Internal { @@ -37,6 +38,7 @@ bool isQTestMacro(const QByteArray ¯o); QHash testCaseNamesForFiles(const Core::Id &id, const QStringList &files); QMultiHash alternativeFiles(const Core::Id &id, const QStringList &files); QStringList filterInterfering(const QStringList &provided, QStringList *omitted, bool isQuickTest); +Utils::Environment prepareBasicEnvironment(const Utils::Environment &env); } // namespace QTestUtils } // namespace Internal diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index a593fded5b5..86fce62f806 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -84,5 +84,10 @@ QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) co return arguments; } +Utils::Environment QtTestConfiguration::filteredEnvironment(const Utils::Environment &original) const +{ + return QTestUtils::prepareBasicEnvironment(original); +} + } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/qtest/qttestconfiguration.h b/src/plugins/autotest/qtest/qttestconfiguration.h index 1dbc73be20f..f38ad7f847b 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.h +++ b/src/plugins/autotest/qtest/qttestconfiguration.h @@ -37,6 +37,7 @@ public: TestOutputReader *outputReader(const QFutureInterface &fi, QProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; + Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; } // namespace Internal diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp index 47b77480396..024b2223c26 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.cpp +++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp @@ -86,6 +86,11 @@ QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted) return arguments; } +Utils::Environment QuickTestConfiguration::filteredEnvironment(const Utils::Environment &original) const +{ + return QTestUtils::prepareBasicEnvironment(original); +} + void QuickTestConfiguration::setUnnamedOnly(bool unnamedOnly) { m_unnamedOnly = unnamedOnly; diff --git a/src/plugins/autotest/quick/quicktestconfiguration.h b/src/plugins/autotest/quick/quicktestconfiguration.h index 7eca4cc1f01..286b891741c 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.h +++ b/src/plugins/autotest/quick/quicktestconfiguration.h @@ -37,7 +37,7 @@ public: TestOutputReader *outputReader(const QFutureInterface &fi, QProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; - + Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; void setUnnamedOnly(bool unnamedOnly); bool unnamedOnly() const { return m_unnamedOnly; } diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h index a2a06d95c3c..52241f5f10d 100644 --- a/src/plugins/autotest/testconfiguration.h +++ b/src/plugins/autotest/testconfiguration.h @@ -92,7 +92,7 @@ public: virtual TestOutputReader *outputReader(const QFutureInterface &fi, QProcess *app) const = 0; virtual QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const = 0; - + virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const = 0; private: QStringList m_testCases; int m_testCaseCount = 0; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 57574012ec4..8e7f95172da 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -148,6 +148,15 @@ static QString constructOmittedDetailsString(const QStringList &omitted) "configuration page for \"%1\":") + '\n' + omitted.join('\n'); } +static QString constructOmittedVariablesDetailsString(const QList &diff) +{ + auto removedVars = Utils::transform(diff, [](const Utils::EnvironmentItem &it) { + return it.name; + }); + return TestRunner::tr("Omitted the following environment variables for \"%1\":") + + '\n' + removedVars.join('\n'); +} + void TestRunner::scheduleNext() { QTC_ASSERT(!m_selectedTests.isEmpty(), onFinished(); return); @@ -192,17 +201,23 @@ void TestRunner::scheduleNext() details.arg(m_currentConfig->displayName())))); } m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory()); - QProcessEnvironment environment = m_currentConfig->environment().toProcessEnvironment(); - if (Utils::HostOsInfo::isWindowsHost()) - environment.insert("QT_LOGGING_TO_CONSOLE", "1"); - const int timeout = AutotestPlugin::settings()->timeout; - if (timeout > 5 * 60 * 1000) // Qt5.5 introduced hard limit, Qt5.6.1 added env var to raise this - environment.insert("QTEST_FUNCTION_TIMEOUT", QString::number(timeout)); - m_currentProcess->setProcessEnvironment(environment); + const Utils::Environment &original = m_currentConfig->environment(); + Utils::Environment environment = m_currentConfig->filteredEnvironment(original); + const QList removedVariables + = Utils::filtered(original.diff(environment), [](const Utils::EnvironmentItem &it) { + return it.operation == Utils::EnvironmentItem::Unset; + }); + if (!removedVariables.isEmpty()) { + const QString &details = constructOmittedVariablesDetailsString(removedVariables) + .arg(m_currentConfig->displayName()); + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, details))); + } + m_currentProcess->setProcessEnvironment(environment.toProcessEnvironment()); connect(m_currentProcess, static_cast(&QProcess::finished), this, &TestRunner::onProcessFinished); + const int timeout = AutotestPlugin::settings()->timeout; QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); }); m_currentProcess->start(); @@ -521,6 +536,17 @@ void TestRunner::debugTests() emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, details.arg(config->displayName())))); } + Utils::Environment original(inferior.environment); + inferior.environment = config->filteredEnvironment(original); + const QList removedVariables + = Utils::filtered(original.diff(inferior.environment), [](const Utils::EnvironmentItem &it) { + return it.operation == Utils::EnvironmentItem::Unset; + }); + if (!removedVariables.isEmpty()) { + const QString &details = constructOmittedVariablesDetailsString(removedVariables) + .arg(config->displayName()); + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, details))); + } auto debugger = new Debugger::DebuggerRunTool(runControl); debugger->setInferior(inferior); debugger->setRunControlName(config->displayName());