From 0f60f120d2e24b9912b43b5ba4859adcd5a1a803 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 17 Mar 2020 09:23:55 +0100 Subject: [PATCH] AutoTest: Handle async updates of executable information When opening or creating a project for the first time the executable path of the application targets may be empty until the build system has updated this after the first successful build. This update happens asynchronously, so we might need to postpone the test execution a bit and wait for the respective update. Change-Id: I63b5c45f6ecb194020ea36bbb5c9486a4dcc004c Reviewed-by: Christian Kandeler --- src/plugins/autotest/testrunner.cpp | 38 +++++++++++++++++++++++++++++ src/plugins/autotest/testrunner.h | 3 +++ 2 files changed, 41 insertions(+) diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index ec3c1e2f490..059f6ac1e06 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -317,6 +319,7 @@ void TestRunner::resetInternalPointers() void TestRunner::prepareToRunTests(TestRunMode mode) { QTC_ASSERT(!m_executingTests, return); + m_skipTargetsCheck = false; m_runMode = mode; ProjectExplorer::Internal::ProjectExplorerSettings projectExplorerSettings = ProjectExplorerPlugin::projectExplorerSettings(); @@ -448,6 +451,15 @@ int TestRunner::precheckTestConfigurations() return testCaseCount; } +void TestRunner::onBuildSystemUpdated() +{ + Target *target = SessionManager::startupTarget(); + if (QTC_GUARD(target)) + disconnect(target, &Target::buildSystemUpdated, this, &TestRunner::onBuildSystemUpdated); + m_skipTargetsCheck = true; + runOrDebugTests(); +} + void TestRunner::runTests() { QList toBeRemoved; @@ -619,8 +631,34 @@ void TestRunner::debugTests() AutotestPlugin::popupResultsPane(); } +static bool executablesEmpty() +{ + Target *target = SessionManager::startupTarget(); + const QList configs = target->runConfigurations(); + QTC_ASSERT(!configs.isEmpty(), return false); + if (auto execAspect = configs.first()->aspect()) + return execAspect->executable().isEmpty(); + return false; +} + void TestRunner::runOrDebugTests() { + if (!m_skipTargetsCheck) { + if (executablesEmpty()) { + m_skipTargetsCheck = true; + Target * target = SessionManager::startupTarget(); + QTimer::singleShot(5000, this, [this, target = QPointer(target)]() { + if (target) { + disconnect(target, &Target::buildSystemUpdated, + this, &TestRunner::onBuildSystemUpdated); + } + runOrDebugTests(); + }); + connect(target, &Target::buildSystemUpdated, this, &TestRunner::onBuildSystemUpdated); + return; + } + } + switch (m_runMode) { case TestRunMode::Run: case TestRunMode::RunWithoutDeploy: diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index 4dfb744a256..a33f6248e1a 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -93,6 +93,8 @@ private: void runOrDebugTests(); void reportResult(ResultType type, const QString &description); explicit TestRunner(QObject *parent = nullptr); + bool postponeTestRunWithEmptyExecutable(ProjectExplorer::Project *project); + void onBuildSystemUpdated(); QFutureWatcher m_futureWatcher; QFutureInterface *m_fakeFutureInterface = nullptr; @@ -111,6 +113,7 @@ private: QMetaObject::Connection m_finishDebugConnect; // temporarily used for handling of switching the current target QMetaObject::Connection m_targetConnect; + bool m_skipTargetsCheck = false; }; class RunConfigurationSelectionDialog : public QDialog