From 52badc2fa6cc22f9f02b0cb66b1a67cf6769537f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Jun 2023 16:37:50 +0200 Subject: [PATCH] TaskTree: Fix calling the right group end handler Make non-Continue TaskAction returned by group's start handler take precedence over group's workflow policy. Call the group's done handler when group's setup returns StopWithDone and the workflow policy is FinishAddAndError. Call the group's error handler when group's setup returns StopWithError and the workflow policy is FinishAddAndDone. Add tests for these cases. Change-Id: I98210a5d522daabc0986200e65b25986a8c0c440 Reviewed-by: Qt CI Bot Reviewed-by: hjk Reviewed-by: --- src/libs/solutions/tasking/tasktree.cpp | 9 ++++- tests/auto/solutions/tasking/tst_tasking.cpp | 39 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 985343ab517..83b586deef5 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -242,19 +242,21 @@ private: It instructs the running task tree on how to proceed after the setup handler's execution finished. \value Continue - Default. The group's or task's execution continues nomally. + Default. The group's or task's execution continues normally. When a group's or task's setup handler returns void, it's assumed that it returned Continue. \value StopWithDone The group's or task's execution stops immediately with success. When returned from the group's setup handler, all child tasks are skipped, and the group's onGroupDone() handler is invoked (if provided). + The group reports success to its parent. The group's workflow policy is ignored. When returned from the task's setup handler, the task isn't started, its done handler isn't invoked, and the task reports success to its parent. \value StopWithError The group's or task's execution stops immediately with an error. When returned from the group's setup handler, all child tasks are skipped, and the group's onGroupError() handler is invoked (if provided). + The group reports an error to its parent. The group's workflow policy is ignored. When returned from the task's setup handler, the task isn't started, its error handler isn't invoked, and the task reports an error to its parent. */ @@ -953,8 +955,11 @@ TaskAction TaskContainer::start() TaskAction startAction = TaskAction::Continue; if (m_constData.m_groupHandler.m_setupHandler) { startAction = invokeHandler(this, m_constData.m_groupHandler.m_setupHandler); - if (startAction != TaskAction::Continue) + if (startAction != TaskAction::Continue) { m_constData.m_taskTreePrivate->advanceProgress(m_constData.m_taskCount); + // Non-Continue TaskAction takes precedence over the workflow policy. + m_runtimeData->m_successBit = startAction == TaskAction::StopWithDone; + } } if (startAction == TaskAction::Continue) { if (m_constData.m_children.isEmpty()) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 64442529b49..fabf6d5c242 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -318,14 +318,53 @@ void tst_Tasking::testTree_data() groupDone(0), groupError(0) }; + const Log logDone {{0, Handler::GroupDone}}; const Log logError {{0, Handler::GroupError}}; + QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, OnDone::Success}; QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, OnDone::Success}; QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, OnDone::Success}; QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, OnDone::Failure}; } + { + const auto setupGroup = [=](TaskAction taskAction, WorkflowPolicy policy) { + return Group { + Storage(storage), + workflowPolicy(policy), + onGroupSetup([taskAction] { return taskAction; }), + groupDone(0), + groupError(0) + }; + }; + + const auto doneData = [storage, setupGroup](WorkflowPolicy policy) { + return TestData{storage, setupGroup(TaskAction::StopWithDone, policy), + Log{{0, Handler::GroupDone}}, 0, OnDone::Success}; + }; + const auto errorData = [storage, setupGroup](WorkflowPolicy policy) { + return TestData{storage, setupGroup(TaskAction::StopWithError, policy), + Log{{0, Handler::GroupError}}, 0, OnDone::Failure}; + }; + + QTest::newRow("DoneAndStopOnError") << doneData(WorkflowPolicy::StopOnError); + QTest::newRow("DoneAndContinueOnError") << doneData(WorkflowPolicy::ContinueOnError); + QTest::newRow("DoneAndStopOnDone") << doneData(WorkflowPolicy::StopOnDone); + QTest::newRow("DoneAndContinueOnDone") << doneData(WorkflowPolicy::ContinueOnDone); + QTest::newRow("DoneAndStopOnFinished") << doneData(WorkflowPolicy::StopOnFinished); + QTest::newRow("DoneAndFinishAllAndDone") << doneData(WorkflowPolicy::FinishAllAndDone); + QTest::newRow("DoneAndFinishAllAndError") << doneData(WorkflowPolicy::FinishAllAndError); + + QTest::newRow("ErrorAndStopOnError") << errorData(WorkflowPolicy::StopOnError); + QTest::newRow("ErrorAndContinueOnError") << errorData(WorkflowPolicy::ContinueOnError); + QTest::newRow("ErrorAndStopOnDone") << errorData(WorkflowPolicy::StopOnDone); + QTest::newRow("ErrorAndContinueOnDone") << errorData(WorkflowPolicy::ContinueOnDone); + QTest::newRow("ErrorAndStopOnFinished") << errorData(WorkflowPolicy::StopOnFinished); + QTest::newRow("ErrorAndFinishAllAndDone") << errorData(WorkflowPolicy::FinishAllAndDone); + QTest::newRow("ErrorAndFinishAllAndError") << errorData(WorkflowPolicy::FinishAllAndError); + } + { const Group root { Storage(storage),