TaskTree: Rewrite tests to use AsyncTask

Instead of using QtcProcess. In this way the tests may be
executed much faster, since there is no need to start
qtcreator_processlauncher.

This should limit the CI failures caused by timeout when
executing these tests.

Remove testapp, unneeded now.

Change-Id: I80775276c2aaec7c2d463b1ac25010efa942b258
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Jarek Kobus
2023-04-28 14:41:02 +02:00
parent 341ade96fb
commit 0b3a0dce88
5 changed files with 220 additions and 309 deletions

View File

@@ -1,11 +1,4 @@
add_subdirectory(testapp)
file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}")
add_qtc_test(tst_utils_tasktree add_qtc_test(tst_utils_tasktree
DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" DEPENDS Utils
"TESTAPP_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/testapp\""
DEPENDS Utils app_version
SOURCES tst_tasktree.cpp SOURCES tst_tasktree.cpp
) )

View File

@@ -1,12 +0,0 @@
add_qtc_executable(testapp
DEPENDS Utils app_version
SOURCES main.cpp
SKIP_INSTALL
INTERNAL_ONLY
)
set_target_properties(testapp PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)

View File

@@ -1,63 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <app/app_version.h>
#include <QString>
#include <QThread>
#ifdef Q_OS_WIN
#include <crtdbg.h>
#include <cstdlib>
#endif
const char CRASH_OPTION[] = "-crash";
const char RETURN_OPTION[] = "-return";
const char SLEEP_OPTION[] = "-sleep";
int main(int argc, char **argv)
{
#ifdef Q_OS_WIN
// avoid crash reporter dialog
_set_error_mode(_OUT_TO_STDERR);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
#endif
if (argc > 1) {
const auto arg = QString::fromLocal8Bit(argv[1]);
if (arg == CRASH_OPTION) {
qFatal("The application has crashed purposefully!");
return 1;
}
if (arg == RETURN_OPTION) {
if (argc > 2) {
const auto retString = QString::fromLocal8Bit(argv[2]);
bool ok = false;
const int retVal = retString.toInt(&ok);
if (ok)
return retVal;
// not an int return value
return 1;
}
// lacking return value
return 1;
}
if (arg == SLEEP_OPTION) {
if (argc > 2) {
const auto msecsString = QString::fromLocal8Bit(argv[2]);
bool ok = false;
const int msecsVal = msecsString.toInt(&ok);
if (ok) {
QThread::msleep(msecsVal);
return 0;
}
// not an int return value
return 1;
}
// lacking return value
return 1;
}
}
// not recognized option
return 1;
}

View File

@@ -1,20 +0,0 @@
import qbs.FileInfo
QtApplication {
name: "testapp"
Depends { name: "qtc" }
Depends { name: "Utils" }
Depends { name: "app_version_header" }
consoleApplication: true
cpp.cxxLanguageVersion: "c++17"
cpp.rpaths: project.buildDirectory + '/' + qtc.ide_library_path
install: false
destinationDirectory: project.buildDirectory + '/'
+ FileInfo.relativePath(project.ide_source_tree, sourceDirectory)
files: [
"main.cpp",
]
}

View File

@@ -1,18 +1,20 @@
// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <app/app_version.h> #include <utils/asynctask.h>
#include <utils/launcherinterface.h>
#include <utils/qtcprocess.h>
#include <utils/singleton.h>
#include <utils/temporarydirectory.h>
#include <QtTest> #include <QtTest>
#include <QDeadlineTimer>
using namespace std::literals::chrono_literals;
using namespace Utils; using namespace Utils;
using namespace Utils::Tasking; using namespace Utils::Tasking;
using TestTask = AsyncTask<void>;
using Test = Async<void>;
enum class Handler { enum class Handler {
Setup, Setup,
Done, Done,
@@ -37,7 +39,9 @@ private:
}; };
int CustomStorage::s_count = 0; int CustomStorage::s_count = 0;
static const char s_processIdProperty[] = "__processId"; static const char s_taskIdProperty[] = "__taskId";
static FutureSynchronizer *s_futureSynchronizer = nullptr;
enum class OnStart { Running, NotRunning }; enum class OnStart { Running, NotRunning };
enum class OnDone { Success, Failure }; enum class OnDone { Success, Failure };
@@ -59,66 +63,58 @@ private slots:
void initTestCase(); void initTestCase();
void validConstructs(); // compile test void validConstructs(); // compile test
void processTree_data(); void testTree_data();
void processTree(); void testTree();
void storageOperators(); void storageOperators();
void storageDestructor(); void storageDestructor();
void cleanupTestCase(); void cleanupTestCase();
private:
FilePath m_testAppPath;
}; };
void tst_TaskTree::initTestCase() void tst_TaskTree::initTestCase()
{ {
TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" s_futureSynchronizer = new FutureSynchronizer;
+ Core::Constants::IDE_CASED_ID + "-XXXXXX");
const QString libExecPath(qApp->applicationDirPath() + '/'
+ QLatin1String(TEST_RELATIVE_LIBEXEC_PATH));
LauncherInterface::setPathToLauncher(libExecPath);
m_testAppPath = FilePath::fromString(QLatin1String(TESTAPP_PATH)
+ QLatin1String("/testapp")).withExecutableSuffix();
} }
void tst_TaskTree::cleanupTestCase() void tst_TaskTree::cleanupTestCase()
{ {
Singleton::deleteAll(); delete s_futureSynchronizer;
s_futureSynchronizer = nullptr;
} }
void tst_TaskTree::validConstructs() void tst_TaskTree::validConstructs()
{ {
const Group process { const Group task {
parallel, parallel,
Process([](QtcProcess &) {}, [](const QtcProcess &) {}), Test([](TestTask &) {}, [](const TestTask &) {}),
Process([](QtcProcess &) {}, [](const QtcProcess &) {}), Test([](TestTask &) {}, [](const TestTask &) {}),
Process([](QtcProcess &) {}, [](const QtcProcess &) {}) Test([](TestTask &) {}, [](const TestTask &) {})
}; };
const Group group1 { const Group group1 {
process task
}; };
const Group group2 { const Group group2 {
parallel, parallel,
Group { Group {
parallel, parallel,
Process([](QtcProcess &) {}, [](const QtcProcess &) {}), Test([](TestTask &) {}, [](const TestTask &) {}),
Group { Group {
parallel, parallel,
Process([](QtcProcess &) {}, [](const QtcProcess &) {}), Test([](TestTask &) {}, [](const TestTask &) {}),
Group { Group {
parallel, parallel,
Process([](QtcProcess &) {}, [](const QtcProcess &) {}) Test([](TestTask &) {}, [](const TestTask &) {})
} }
}, },
Group { Group {
parallel, parallel,
Process([](QtcProcess &) {}, [](const QtcProcess &) {}), Test([](TestTask &) {}, [](const TestTask &) {}),
OnGroupDone([] {}) OnGroupDone([] {})
} }
}, },
process, task,
OnGroupDone([] {}), OnGroupDone([] {}),
OnGroupError([] {}) OnGroupError([] {})
}; };
@@ -150,70 +146,75 @@ void tst_TaskTree::validConstructs()
#endif #endif
} }
void tst_TaskTree::processTree_data() static void runTask(QPromise<void> &promise, bool success, std::chrono::milliseconds sleep)
{
QDeadlineTimer deadline(sleep);
while (!deadline.hasExpired()) {
QThread::msleep(1);
if (promise.isCanceled())
return;
}
if (!success)
promise.future().cancel();
}
void tst_TaskTree::testTree_data()
{ {
QTest::addColumn<TestData>("testData"); QTest::addColumn<TestData>("testData");
TreeStorage<CustomStorage> storage; TreeStorage<CustomStorage> storage;
const auto setupProcessHelper = [storage, testAppPath = m_testAppPath] const auto setupTaskHelper = [storage](TestTask &task, int taskId, bool success = true,
(QtcProcess &process, const QStringList &args, int processId) { std::chrono::milliseconds sleep = 0ms) {
process.setCommand(CommandLine(testAppPath, args)); task.setFutureSynchronizer(s_futureSynchronizer);
process.setProperty(s_processIdProperty, processId); task.setConcurrentCallData(runTask, success, sleep);
storage->m_log.append({processId, Handler::Setup}); task.setProperty(s_taskIdProperty, taskId);
storage->m_log.append({taskId, Handler::Setup});
}; };
const auto setupProcess = [setupProcessHelper](int processId) { const auto setupTask = [setupTaskHelper](int taskId) {
return [=](QtcProcess &process) { return [=](TestTask &task) { setupTaskHelper(task, taskId); };
setupProcessHelper(process, {"-return", "0"}, processId);
}; };
const auto setupFailingTask = [setupTaskHelper](int taskId) {
return [=](TestTask &task) { setupTaskHelper(task, taskId, false); };
}; };
const auto setupCrashProcess = [setupProcessHelper](int processId) { const auto setupSleepingTask = [setupTaskHelper](int taskId, std::chrono::milliseconds sleep) {
return [=](QtcProcess &process) { return [=](TestTask &task) { setupTaskHelper(task, taskId, true, sleep); };
setupProcessHelper(process, {"-crash"}, processId);
}; };
}; const auto setupDynamicTask = [setupTaskHelper](int taskId, TaskAction action) {
const auto setupSleepProcess = [setupProcessHelper](int processId, int msecs) { return [=](TestTask &task) {
return [=](QtcProcess &process) { setupTaskHelper(task, taskId);
setupProcessHelper(process, {"-sleep", QString::number(msecs)}, processId);
};
};
const auto setupDynamicProcess = [setupProcessHelper](int processId, TaskAction action) {
return [=](QtcProcess &process) {
setupProcessHelper(process, {"-return", "0"}, processId);
return action; return action;
}; };
}; };
const auto readResult = [storage](const QtcProcess &process) { const auto logDone = [storage](const TestTask &task) {
const int processId = process.property(s_processIdProperty).toInt(); storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Done});
storage->m_log.append({processId, Handler::Done});
}; };
const auto readError = [storage](const QtcProcess &process) { const auto logError = [storage](const TestTask &task) {
const int processId = process.property(s_processIdProperty).toInt(); storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Error});
storage->m_log.append({processId, Handler::Error});
}; };
const auto groupSetup = [storage](int groupId) { const auto groupSetup = [storage](int taskId) {
return [=] { storage->m_log.append({groupId, Handler::GroupSetup}); }; return [=] { storage->m_log.append({taskId, Handler::GroupSetup}); };
}; };
const auto groupDone = [storage](int groupId) { const auto groupDone = [storage](int taskId) {
return [=] { storage->m_log.append({groupId, Handler::GroupDone}); }; return [=] { storage->m_log.append({taskId, Handler::GroupDone}); };
}; };
const auto groupError = [storage](int groupId) { const auto groupError = [storage](int taskId) {
return [=] { storage->m_log.append({groupId, Handler::GroupError}); }; return [=] { storage->m_log.append({taskId, Handler::GroupError}); };
}; };
const auto setupSync = [storage](int syncId) { const auto setupSync = [storage](int taskId) {
return [=] { storage->m_log.append({syncId, Handler::Sync}); }; return [=] { storage->m_log.append({taskId, Handler::Sync}); };
}; };
const auto setupSyncWithReturn = [storage](int syncId, bool success) { const auto setupSyncWithReturn = [storage](int taskId, bool success) {
return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; }; return [=] { storage->m_log.append({taskId, Handler::Sync}); return success; };
}; };
const auto constructSimpleSequence = [=](const Workflow &policy) { const auto constructSimpleSequence = [=](const Workflow &policy) {
return Group { return Group {
Storage(storage), Storage(storage),
policy, policy,
Process(setupProcess(1), readResult), Test(setupTask(1), logDone),
Process(setupCrashProcess(2), readResult, readError), Test(setupFailingTask(2), logDone, logError),
Process(setupProcess(3), readResult), Test(setupTask(3), logDone),
OnGroupDone(groupDone(0)), OnGroupDone(groupDone(0)),
OnGroupError(groupError(0)) OnGroupError(groupError(0))
}; };
@@ -222,13 +223,13 @@ void tst_TaskTree::processTree_data()
return Group { return Group {
Storage(storage), Storage(storage),
Group { Group {
Process(setupProcess(1), readResult) Test(setupTask(1), logDone)
}, },
Group { Group {
OnGroupSetup([=] { return taskAction; }), OnGroupSetup([=] { return taskAction; }),
Process(setupProcess(2), readResult), Test(setupTask(2), logDone),
Process(setupProcess(3), readResult), Test(setupTask(3), logDone),
Process(setupProcess(4), readResult) Test(setupTask(4), logDone)
}, },
OnGroupDone(groupDone(0)), OnGroupDone(groupDone(0)),
OnGroupError(groupError(0)) OnGroupError(groupError(0))
@@ -274,8 +275,8 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::StopWithDone), readResult, readError), Test(setupDynamicTask(1, TaskAction::StopWithDone), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::StopWithDone), readResult, readError) Test(setupDynamicTask(2, TaskAction::StopWithDone), logDone, logError)
}; };
const Log log {{1, Handler::Setup}, {2, Handler::Setup}}; const Log log {{1, Handler::Setup}, {2, Handler::Setup}};
QTest::newRow("DynamicTaskDone") QTest::newRow("DynamicTaskDone")
@@ -285,8 +286,8 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::StopWithError), readResult, readError), Test(setupDynamicTask(1, TaskAction::StopWithError), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::StopWithError), readResult, readError) Test(setupDynamicTask(2, TaskAction::StopWithError), logDone, logError)
}; };
const Log log {{1, Handler::Setup}}; const Log log {{1, Handler::Setup}};
QTest::newRow("DynamicTaskError") QTest::newRow("DynamicTaskError")
@@ -296,10 +297,10 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError), Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError),
Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError)
}; };
const Log log { const Log log {
{1, Handler::Setup}, {1, Handler::Setup},
@@ -316,10 +317,10 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
parallel, parallel,
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError), Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError),
Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError)
}; };
const Log log { const Log log {
{1, Handler::Setup}, {1, Handler::Setup},
@@ -336,12 +337,12 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
parallel, parallel,
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError),
Group { Group {
Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError) Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError)
}, },
Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError)
}; };
const Log log { const Log log {
{1, Handler::Setup}, {1, Handler::Setup},
@@ -358,16 +359,16 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
parallel, parallel,
Storage(storage), Storage(storage),
Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError),
Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError),
Group { Group {
OnGroupSetup([storage] { OnGroupSetup([storage] {
storage->m_log.append({0, Handler::GroupSetup}); storage->m_log.append({0, Handler::GroupSetup});
return TaskAction::StopWithError; return TaskAction::StopWithError;
}), }),
Process(setupDynamicProcess(3, TaskAction::Continue), readResult, readError) Test(setupDynamicTask(3, TaskAction::Continue), logDone, logError)
}, },
Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError)
}; };
const Log log { const Log log {
{1, Handler::Setup}, {1, Handler::Setup},
@@ -388,7 +389,7 @@ void tst_TaskTree::processTree_data()
Group { Group {
Group { Group {
Group { Group {
Process(setupProcess(5), readResult, readError), Test(setupTask(5), logDone, logError),
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
OnGroupDone(groupDone(5)) OnGroupDone(groupDone(5))
}, },
@@ -426,17 +427,17 @@ void tst_TaskTree::processTree_data()
} }
{ {
const auto readResultAnonymous = [=](const QtcProcess &) { const auto logDoneAnonymously = [=](const TestTask &) {
storage->m_log.append({0, Handler::Done}); storage->m_log.append({0, Handler::Done});
}; };
const Group root { const Group root {
Storage(storage), Storage(storage),
parallel, parallel,
Process(setupProcess(1), readResultAnonymous), Test(setupTask(1), logDoneAnonymously),
Process(setupProcess(2), readResultAnonymous), Test(setupTask(2), logDoneAnonymously),
Process(setupProcess(3), readResultAnonymous), Test(setupTask(3), logDoneAnonymously),
Process(setupProcess(4), readResultAnonymous), Test(setupTask(4), logDoneAnonymously),
Process(setupProcess(5), readResultAnonymous), Test(setupTask(5), logDoneAnonymously),
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
const Log log { const Log log {
@@ -460,9 +461,9 @@ void tst_TaskTree::processTree_data()
auto setupSubTree = [=](TaskTree &taskTree) { auto setupSubTree = [=](TaskTree &taskTree) {
const Group nestedRoot { const Group nestedRoot {
Storage(storage), Storage(storage),
Process(setupProcess(2), readResult), Test(setupTask(2), logDone),
Process(setupProcess(3), readResult), Test(setupTask(3), logDone),
Process(setupProcess(4), readResult) Test(setupTask(4), logDone)
}; };
taskTree.setupRoot(nestedRoot); taskTree.setupRoot(nestedRoot);
CustomStorage *activeStorage = storage.activeStorage(); CustomStorage *activeStorage = storage.activeStorage();
@@ -473,27 +474,27 @@ void tst_TaskTree::processTree_data()
}; };
const Group root1 { const Group root1 {
Storage(storage), Storage(storage),
Process(setupProcess(1), readResult), Test(setupTask(1), logDone),
Process(setupProcess(2), readResult), Test(setupTask(2), logDone),
Process(setupProcess(3), readResult), Test(setupTask(3), logDone),
Process(setupProcess(4), readResult), Test(setupTask(4), logDone),
Process(setupProcess(5), readResult), Test(setupTask(5), logDone),
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
const Group root2 { const Group root2 {
Storage(storage), Storage(storage),
Group { Process(setupProcess(1), readResult) }, Group { Test(setupTask(1), logDone) },
Group { Process(setupProcess(2), readResult) }, Group { Test(setupTask(2), logDone) },
Group { Process(setupProcess(3), readResult) }, Group { Test(setupTask(3), logDone) },
Group { Process(setupProcess(4), readResult) }, Group { Test(setupTask(4), logDone) },
Group { Process(setupProcess(5), readResult) }, Group { Test(setupTask(5), logDone) },
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
const Group root3 { const Group root3 {
Storage(storage), Storage(storage),
Process(setupProcess(1), readResult), Test(setupTask(1), logDone),
Tree(setupSubTree), Tree(setupSubTree),
Process(setupProcess(5), readResult), Test(setupTask(5), logDone),
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
const Log log { const Log log {
@@ -521,15 +522,15 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
Storage(storage), Storage(storage),
Group { Group {
Process(setupProcess(1), readResult), Test(setupTask(1), logDone),
Group { Group {
Process(setupProcess(2), readResult), Test(setupTask(2), logDone),
Group { Group {
Process(setupProcess(3), readResult), Test(setupTask(3), logDone),
Group { Group {
Process(setupProcess(4), readResult), Test(setupTask(4), logDone),
Group { Group {
Process(setupProcess(5), readResult), Test(setupTask(5), logDone),
OnGroupDone(groupDone(5)) OnGroupDone(groupDone(5))
}, },
OnGroupDone(groupDone(4)) OnGroupDone(groupDone(4))
@@ -567,11 +568,11 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Process(setupProcess(1), readResult), Test(setupTask(1), logDone),
Process(setupProcess(2), readResult), Test(setupTask(2), logDone),
Process(setupCrashProcess(3), readResult, readError), Test(setupFailingTask(3), logDone, logError),
Process(setupProcess(4), readResult), Test(setupTask(4), logDone),
Process(setupProcess(5), readResult), Test(setupTask(5), logDone),
OnGroupDone(groupDone(0)), OnGroupDone(groupDone(0)),
OnGroupError(groupError(0)) OnGroupError(groupError(0))
}; };
@@ -646,8 +647,8 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
Storage(storage), Storage(storage),
optional, optional,
Process(setupCrashProcess(1), readResult, readError), Test(setupFailingTask(1), logDone, logError),
Process(setupCrashProcess(2), readResult, readError), Test(setupFailingTask(2), logDone, logError),
OnGroupDone(groupDone(0)), OnGroupDone(groupDone(0)),
OnGroupError(groupError(0)) OnGroupError(groupError(0))
}; };
@@ -707,19 +708,19 @@ void tst_TaskTree::processTree_data()
Storage(storage), Storage(storage),
Group { Group {
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Process(setupProcess(1)) Test(setupTask(1))
}, },
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Process(setupProcess(2)) Test(setupTask(2))
}, },
Group { Group {
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Process(setupProcess(3)) Test(setupTask(3))
}, },
Group { Group {
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Process(setupProcess(4)) Test(setupTask(4))
} }
}; };
const Log log { const Log log {
@@ -742,23 +743,23 @@ void tst_TaskTree::processTree_data()
Storage(storage), Storage(storage),
Group { Group {
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Process(setupProcess(1)) Test(setupTask(1))
}, },
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Process(setupProcess(2)) Test(setupTask(2))
}, },
Group { Group {
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Process(setupDynamicProcess(3, TaskAction::StopWithDone)) Test(setupDynamicTask(3, TaskAction::StopWithDone))
}, },
Group { Group {
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Process(setupProcess(4)) Test(setupTask(4))
}, },
Group { Group {
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Process(setupProcess(5)) Test(setupTask(5))
} }
}; };
const Log log { const Log log {
@@ -783,63 +784,63 @@ void tst_TaskTree::processTree_data()
Storage(storage), Storage(storage),
Group { Group {
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Process(setupProcess(1)) Test(setupTask(1))
}, },
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Process(setupProcess(2)) Test(setupTask(2))
}, },
Group { Group {
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Process(setupDynamicProcess(3, TaskAction::StopWithError)) Test(setupDynamicTask(3, TaskAction::StopWithError))
}, },
Group { Group {
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Process(setupProcess(4)) Test(setupTask(4))
}, },
Group { Group {
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Process(setupProcess(5)) Test(setupTask(5))
} }
}; };
// Inside this test the process 2 should finish first, then synchonously: // Inside this test the task 2 should finish first, then synchonously:
// - process 3 should exit setup with error // - task 3 should exit setup with error
// - process 1 should be stopped as a consequence of error inside the group // - task 1 should be stopped as a consequence of error inside the group
// - processes 4 and 5 should be skipped // - tasks 4 and 5 should be skipped
const Group root2 { const Group root2 {
ParallelLimit(2), ParallelLimit(2),
Storage(storage), Storage(storage),
Group { Group {
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Process(setupSleepProcess(1, 100)) Test(setupSleepingTask(1, 10ms))
}, },
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Process(setupProcess(2)) Test(setupTask(2))
}, },
Group { Group {
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Process(setupDynamicProcess(3, TaskAction::StopWithError)) Test(setupDynamicTask(3, TaskAction::StopWithError))
}, },
Group { Group {
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Process(setupProcess(4)) Test(setupTask(4))
}, },
Group { Group {
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Process(setupProcess(5)) Test(setupTask(5))
} }
}; };
// This test ensures process 1 doesn't invoke its done handler, // This test ensures that the task 1 doesn't invoke its done handler,
// being ready while sleeping in process 2 done handler. // being ready while sleeping in the task's 2 done handler.
// Inside this test the process 2 should finish first, then synchonously: // Inside this test the task 2 should finish first, then synchonously:
// - process 3 should exit setup with error // - task 3 should exit setup with error
// - process 1 should be stopped as a consequence of error inside the group // - task 1 should be stopped as a consequence of error inside the group
// - process 4 should be skipped // - task 4 should be skipped
// - the first child group of root should finish with error // - the first child group of root should finish with error
// - process 5 should be started (because of root's continueOnError policy) // - task 5 should be started (because of root's continueOnError policy)
const Group root3 { const Group root3 {
continueOnError, continueOnError,
Storage(storage), Storage(storage),
@@ -847,24 +848,24 @@ void tst_TaskTree::processTree_data()
ParallelLimit(2), ParallelLimit(2),
Group { Group {
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Process(setupSleepProcess(1, 100)) Test(setupSleepingTask(1, 20ms))
}, },
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Process(setupProcess(2), [](const QtcProcess &) { QThread::msleep(200); }) Test(setupTask(2), [](const TestTask &) { QThread::msleep(10); })
}, },
Group { Group {
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Process(setupDynamicProcess(3, TaskAction::StopWithError)) Test(setupDynamicTask(3, TaskAction::StopWithError))
}, },
Group { Group {
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Process(setupProcess(4)) Test(setupTask(4))
} }
}, },
Group { Group {
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Process(setupProcess(5)) Test(setupTask(5))
} }
}; };
const Log shortLog { const Log shortLog {
@@ -893,7 +894,7 @@ void tst_TaskTree::processTree_data()
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Group { Group {
parallel, parallel,
Process(setupProcess(1)) Test(setupTask(1))
} }
}, },
Group { Group {
@@ -901,7 +902,7 @@ void tst_TaskTree::processTree_data()
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Group { Group {
parallel, parallel,
Process(setupProcess(2)) Test(setupTask(2))
} }
}, },
Group { Group {
@@ -909,7 +910,7 @@ void tst_TaskTree::processTree_data()
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Group { Group {
parallel, parallel,
Process(setupProcess(3)) Test(setupTask(3))
} }
}, },
Group { Group {
@@ -917,7 +918,7 @@ void tst_TaskTree::processTree_data()
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Group { Group {
parallel, parallel,
Process(setupProcess(4)) Test(setupTask(4))
} }
} }
}; };
@@ -942,27 +943,27 @@ void tst_TaskTree::processTree_data()
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Group { Process(setupProcess(1)) } Group { Test(setupTask(1)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Group { Process(setupProcess(2)) } Group { Test(setupTask(2)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Group { Process(setupDynamicProcess(3, TaskAction::StopWithDone)) } Group { Test(setupDynamicTask(3, TaskAction::StopWithDone)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Group { Process(setupProcess(4)) } Group { Test(setupTask(4)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Group { Process(setupProcess(5)) } Group { Test(setupTask(5)) }
} }
}; };
const Log log { const Log log {
@@ -988,27 +989,27 @@ void tst_TaskTree::processTree_data()
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(1)), OnGroupSetup(groupSetup(1)),
Group { Process(setupProcess(1)) } Group { Test(setupTask(1)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
Group { Process(setupProcess(2)) } Group { Test(setupTask(2)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(3)), OnGroupSetup(groupSetup(3)),
Group { Process(setupDynamicProcess(3, TaskAction::StopWithError)) } Group { Test(setupDynamicTask(3, TaskAction::StopWithError)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(4)), OnGroupSetup(groupSetup(4)),
Group { Process(setupProcess(4)) } Group { Test(setupTask(4)) }
}, },
Group { Group {
Storage(TreeStorage<CustomStorage>()), Storage(TreeStorage<CustomStorage>()),
OnGroupSetup(groupSetup(5)), OnGroupSetup(groupSetup(5)),
Group { Process(setupProcess(5)) } Group { Test(setupTask(5)) }
} }
}; };
const Log log { const Log log {
@@ -1107,9 +1108,9 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
Storage(storage), Storage(storage),
Sync(setupSync(1)), Sync(setupSync(1)),
Process(setupProcess(2)), Test(setupTask(2)),
Sync(setupSync(3)), Sync(setupSync(3)),
Process(setupProcess(4)), Test(setupTask(4)),
Sync(setupSync(5)), Sync(setupSync(5)),
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
@@ -1129,9 +1130,9 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
Storage(storage), Storage(storage),
Sync(setupSync(1)), Sync(setupSync(1)),
Process(setupProcess(2)), Test(setupTask(2)),
Sync(setupSyncWithReturn(3, false)), Sync(setupSyncWithReturn(3, false)),
Process(setupProcess(4)), Test(setupTask(4)),
Sync(setupSync(5)), Sync(setupSync(5)),
OnGroupError(groupError(0)) OnGroupError(groupError(0))
}; };
@@ -1148,31 +1149,41 @@ void tst_TaskTree::processTree_data()
{ {
Condition condition; Condition condition;
const auto setupProcessWithCondition const auto reportAndSleep = [](QPromise<bool> &promise) {
= [storage, condition, setupProcessHelper](int processId) { promise.addResult(false);
return [storage, condition, setupProcessHelper, processId](QtcProcess &process) { QThread::msleep(10);
setupProcessHelper(process, {"-return", "0"}, processId); };
const auto setupTaskWithCondition = [storage, condition, reportAndSleep](int taskId) {
return [storage, condition, reportAndSleep, taskId](AsyncTask<bool> &async) {
async.setFutureSynchronizer(s_futureSynchronizer);
async.setConcurrentCallData(reportAndSleep);
async.setProperty(s_taskIdProperty, taskId);
storage->m_log.append({taskId, Handler::Setup});
CustomStorage *currentStorage = storage.activeStorage(); CustomStorage *currentStorage = storage.activeStorage();
ConditionActivator *currentActivator = condition.activator(); ConditionActivator *currentActivator = condition.activator();
connect(&process, &QtcProcess::started, [currentStorage, currentActivator, processId] { connect(&async, &TestTask::resultReadyAt,
currentStorage->m_log.append({processId, Handler::Activator}); [currentStorage, currentActivator, taskId](int index) {
Q_UNUSED(index)
currentStorage->m_log.append({taskId, Handler::Activator});
currentActivator->activate(); currentActivator->activate();
}); });
}; };
}; };
// Test that Activator, triggered from inside the process described by // Test that Activator, triggered from inside the task described by
// setupProcessWithCondition, placed BEFORE the group containing the WaitFor element // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element
// in the tree order, works OK in SEQUENTIAL mode. // in the tree order, works OK in SEQUENTIAL mode.
const Group root1 { const Group root1 {
Storage(storage), Storage(storage),
sequential, sequential,
Process(setupProcessWithCondition(1)), Async<bool>(setupTaskWithCondition(1)),
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
WaitFor(condition), WaitFor(condition),
Process(setupProcess(2)), Test(setupTask(2)),
Process(setupProcess(3)) Test(setupTask(3))
} }
}; };
const Log log1 { const Log log1 {
@@ -1183,18 +1194,18 @@ void tst_TaskTree::processTree_data()
{3, Handler::Setup} {3, Handler::Setup}
}; };
// Test that Activator, triggered from inside the process described by // Test that Activator, triggered from inside the task described by
// setupProcessWithCondition, placed BEFORE the group containing the WaitFor element // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element
// in the tree order, works OK in PARALLEL mode. // in the tree order, works OK in PARALLEL mode.
const Group root2 { const Group root2 {
Storage(storage), Storage(storage),
parallel, parallel,
Process(setupProcessWithCondition(1)), Async<bool>(setupTaskWithCondition(1)),
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
WaitFor(condition), WaitFor(condition),
Process(setupProcess(2)), Test(setupTask(2)),
Process(setupProcess(3)) Test(setupTask(3))
} }
}; };
const Log log2 { const Log log2 {
@@ -1205,8 +1216,8 @@ void tst_TaskTree::processTree_data()
{3, Handler::Setup} {3, Handler::Setup}
}; };
// Test that Activator, triggered from inside the process described by // Test that Activator, triggered from inside the task described by
// setupProcessWithCondition, placed AFTER the group containing the WaitFor element // setupTaskWithCondition, placed AFTER the group containing the WaitFor element
// in the tree order, works OK in PARALLEL mode. // in the tree order, works OK in PARALLEL mode.
// //
// Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the // Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the
@@ -1221,10 +1232,10 @@ void tst_TaskTree::processTree_data()
Group { Group {
OnGroupSetup(groupSetup(2)), OnGroupSetup(groupSetup(2)),
WaitFor(condition), WaitFor(condition),
Process(setupProcess(2)), Test(setupTask(2)),
Process(setupProcess(3)) Test(setupTask(3))
}, },
Process(setupProcessWithCondition(1)) Async<bool>(setupTaskWithCondition(1))
}; };
const Log log3 { const Log log3 {
{2, Handler::GroupSetup}, {2, Handler::GroupSetup},
@@ -1244,7 +1255,7 @@ void tst_TaskTree::processTree_data()
} }
} }
void tst_TaskTree::processTree() void tst_TaskTree::testTree()
{ {
QFETCH(TestData, testData); QFETCH(TestData, testData);
@@ -1324,12 +1335,13 @@ void tst_TaskTree::storageDestructor()
QCOMPARE(CustomStorage::instanceCount(), 0); QCOMPARE(CustomStorage::instanceCount(), 0);
{ {
TreeStorage<CustomStorage> storage; TreeStorage<CustomStorage> storage;
const auto setupProcess = [testAppPath = m_testAppPath](QtcProcess &process) { const auto setupSleepingTask = [](TestTask &task) {
process.setCommand(CommandLine(testAppPath, {"-sleep", "1000"})); task.setFutureSynchronizer(s_futureSynchronizer);
task.setConcurrentCallData(runTask, true, 1000ms);
}; };
const Group root { const Group root {
Storage(storage), Storage(storage),
Process(setupProcess) Test(setupSleepingTask)
}; };
TaskTree taskTree(root); TaskTree taskTree(root);
@@ -1338,6 +1350,7 @@ void tst_TaskTree::storageDestructor()
taskTree.onStorageDone(storage, doneHandler); taskTree.onStorageDone(storage, doneHandler);
taskTree.start(); taskTree.start();
QCOMPARE(CustomStorage::instanceCount(), 1); QCOMPARE(CustomStorage::instanceCount(), 1);
QThread::msleep(5); // Give the sleeping task a change to start
} }
QCOMPARE(CustomStorage::instanceCount(), 0); QCOMPARE(CustomStorage::instanceCount(), 0);
QVERIFY(setupCalled); QVERIFY(setupCalled);