You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by dj...@apache.org on 2026/06/25 09:40:22 UTC
(incubator-kie-kogito-runtimes) branch main updated: [incubator-kie-issues-2354] Resume transition permission fix for Suspended Tasks (#4324)
This is an automated email from the ASF dual-hosted git repository.
josedee pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git
The following commit(s) were added to refs/heads/main by this push:
new e847f353db [incubator-kie-issues-2354] Resume transition permission fix for Suspended Tasks (#4324)
e847f353db is described below
commit e847f353dbe6aed60d8b4c9a9cad5585cde6a779
Author: Deepak Joseph <15...@users.noreply.github.com>
AuthorDate: Thu Jun 25 15:10:17 2026 +0530
[incubator-kie-issues-2354] Resume transition permission fix for Suspended Tasks (#4324)
* Resume transition permission fix for Suspended Tasks
* More tests
* update
* update
---
.../impl/lifecycle/WsHumanTaskLifeCycle.java | 9 +-
.../resources/manager_admin_multiple_users.bpmn | 156 +++++++++++++++++++++
.../usertask/jpa/it/WsHumanTaskLifeCycleIT.java | 139 ++++++++++++++++++
.../resources/manager_admin_multiple_users.bpmn | 156 +++++++++++++++++++++
.../usertask/jpa/it/WsHumanTaskLifeCycleIT.java | 137 ++++++++++++++++++
5 files changed, 594 insertions(+), 3 deletions(-)
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
index 8159446834..128ca419d4 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
@@ -443,7 +443,7 @@ public class WsHumanTaskLifeCycle implements UserTaskLifeCycle {
private static ZonedDateTime parseSimpleDuration(String input) {
try {
- var millis = parseTimeString(input);
+ long millis = parseTimeString(input);
if (millis <= 0) {
throw new IllegalArgumentException("Invalid suspendUntil duration: " + input);
}
@@ -522,8 +522,11 @@ public class WsHumanTaskLifeCycle implements UserTaskLifeCycle {
throw new UserTaskInstanceNotAuthorizedException(message);
}
- if (List.of(CREATED, READY, SUSPENDED).contains(userTaskInstance.getStatus())) {
- // there is no user
+ if (CREATED.equals(userTaskInstance.getStatus())
+ || READY.equals(userTaskInstance.getStatus())
+ || (SUSPENDED.equals(userTaskInstance.getStatus())
+ && READY.getName().equals(userTaskInstance.getMetadata().get(PREVIOUS_STATUS)))) {
+
Set<String> users = new HashSet<>(userTaskInstance.getPotentialUsers());
users.removeAll(userTaskInstance.getExcludedUsers());
if (users.contains(user)) {
diff --git a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn
new file mode 100644
index 0000000000..ebced58b76
--- /dev/null
+++ b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpsim="http://www.bpsim.org/schemas/1.0" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:drools="http://www.jboss.org/drools" id="_he0oAFJzED-wgK5wjEdlLQ" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www. [...]
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_PriorityInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_CommentInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_DescriptionInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_CreatedByInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_GroupIdInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_ContentInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedReassignInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedReassignInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedNotifyInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedNotifyInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem" structureRef="String"/>
+ <bpmn2:collaboration id="_3778CA92-9FE5-4681-907A-076773F7B8A1" name="Default Collaboration">
+ <bpmn2:participant id="_872C19AB-BF7E-4B86-B5F6-A8773B235325" name="Pool Participant" processRef="manager_admin_multiple_users"/>
+ </bpmn2:collaboration>
+ <bpmn2:process id="manager_admin_multiple_users" drools:packageName="com.example" drools:version="1.0" drools:adHoc="false" name="manager_admin_multiple_users" isExecutable="true" processType="Public">
+ <bpmn2:sequenceFlow id="_E9728BB4-C7C1-4613-8506-61F6E8D54928" sourceRef="_60F9AB18-9065-48B1-9667-791889027BF8" targetRef="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717"/>
+ <bpmn2:sequenceFlow id="_8FF3949E-26E7-42C7-818E-17C8AAF127F5" sourceRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51" targetRef="_60F9AB18-9065-48B1-9667-791889027BF8"/>
+ <bpmn2:endEvent id="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <bpmn2:incoming>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:userTask id="_60F9AB18-9065-48B1-9667-791889027BF8" name="Manager Approval">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Manager Approval]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:incoming>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:incoming>
+ <bpmn2:outgoing>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:outgoing>
+ <bpmn2:ioSpecification>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX" drools:dtype="Object" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem" name="TaskName"/>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX" drools:dtype="String" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem" name="BusinessAdministratorId"/>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX" drools:dtype="Object" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem" name="Skippable"/>
+ <bpmn2:inputSet>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:dataInputRefs>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:dataInputRefs>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:dataInputRefs>
+ </bpmn2:inputSet>
+ </bpmn2:ioSpecification>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[carl]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[true]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:potentialOwner id="_he12IFJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he12IVJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>john</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ <bpmn2:potentialOwner id="_he12IlJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he2dMFJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>dave</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ </bpmn2:userTask>
+ <bpmn2:startEvent id="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpmn2:outgoing>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:outgoing>
+ </bpmn2:startEvent>
+ </bpmn2:process>
+ <bpmndi:BPMNDiagram>
+ <bpmndi:BPMNPlane bpmnElement="manager_admin_multiple_users">
+ <bpmndi:BPMNShape id="shape__F4221219-F8CE-47B1-A637-8452CB0B6A51" bpmnElement="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <dc:Bounds height="56" width="56" x="210" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__60F9AB18-9065-48B1-9667-791889027BF8" bpmnElement="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <dc:Bounds height="102" width="154" x="346" y="190"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717" bpmnElement="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <dc:Bounds height="56" width="56" x="580" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="edge_shape__F4221219-F8CE-47B1-A637-8452CB0B6A51_to_shape__60F9AB18-9065-48B1-9667-791889027BF8" bpmnElement="_8FF3949E-26E7-42C7-818E-17C8AAF127F5">
+ <di:waypoint x="238" y="241"/>
+ <di:waypoint x="423" y="241"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="edge_shape__60F9AB18-9065-48B1-9667-791889027BF8_to_shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717" bpmnElement="_E9728BB4-C7C1-4613-8506-61F6E8D54928">
+ <di:waypoint x="423" y="241"/>
+ <di:waypoint x="608" y="241"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+ <bpmn2:relationship type="BPSimData">
+ <bpmn2:extensionElements>
+ <bpsim:BPSimData>
+ <bpsim:Scenario id="default" name="Simulationscenario">
+ <bpsim:ScenarioParameters/>
+ <bpsim:ElementParameters elementRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ </bpsim:ElementParameters>
+ <bpsim:ElementParameters elementRef="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ <bpsim:ResourceParameters>
+ <bpsim:Availability>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Availability>
+ <bpsim:Quantity>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Quantity>
+ </bpsim:ResourceParameters>
+ <bpsim:CostParameters>
+ <bpsim:UnitCost>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:UnitCost>
+ </bpsim:CostParameters>
+ </bpsim:ElementParameters>
+ </bpsim:Scenario>
+ </bpsim:BPSimData>
+ </bpmn2:extensionElements>
+ <bpmn2:source>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:source>
+ <bpmn2:target>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:target>
+ </bpmn2:relationship>
+</bpmn2:definitions>
\ No newline at end of file
diff --git a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
index 0994d4a692..9e2cc64605 100644
--- a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
+++ b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
@@ -211,6 +211,132 @@ public class WsHumanTaskLifeCycleIT {
isProcessCompleted(processId, pid);
}
+ @Test
+ public void testPotentialUserCanResumeSuspendedToReadyTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, potentialUser, "Ready");
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testBusinessAdminCanResumeSuspendedTask() {
+ var owner = "dave";
+ var admin = "carl";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_admin_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, admin, "Ready");
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "Reserved");
+
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
@Test
public void testSuspendUntilWithDuration() {
var user = "dave";
@@ -626,6 +752,7 @@ public class WsHumanTaskLifeCycleIT {
public void testMultipleGroupsWithVariablesUserTaskLifeCycle() {
// This test verifies the fix for multi-variable expressions in BPMN
// The GroupId is defined as #{group1},#{group2},#{group3} in the BPMN
+ // and we pass the actual group names as process variables
var user = "dave";
var group = "engineering";
var potentialGroups = new String[] { "hr", "engineering", "management" };
@@ -640,6 +767,7 @@ public class WsHumanTaskLifeCycleIT {
var taskId = getTaskId(user, group, pid);
// Verify all three groups are present in potentialGroups
+ // This would fail with the old implementation which only extracted the first variable
given()
.contentType(ContentType.JSON)
.when()
@@ -732,6 +860,17 @@ public class WsHumanTaskLifeCycleIT {
.body("metadata.SuspendedJobId", equalTo(null));
}
+ private void resumeNotAuthorized(String taskId, String user) {
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", user)
+ .body(new TransitionInfo("resume"))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(403);
+ }
+
private void suspend(String taskId, String user) {
given()
.contentType(ContentType.JSON)
diff --git a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn
new file mode 100644
index 0000000000..ebced58b76
--- /dev/null
+++ b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpsim="http://www.bpsim.org/schemas/1.0" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:drools="http://www.jboss.org/drools" id="_he0oAFJzED-wgK5wjEdlLQ" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www. [...]
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_PriorityInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_CommentInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_DescriptionInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_CreatedByInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_GroupIdInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_ContentInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedReassignInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedReassignInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedNotifyInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedNotifyInputXItem" structureRef="Object"/>
+ <bpmn2:itemDefinition id="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem" structureRef="String"/>
+ <bpmn2:collaboration id="_3778CA92-9FE5-4681-907A-076773F7B8A1" name="Default Collaboration">
+ <bpmn2:participant id="_872C19AB-BF7E-4B86-B5F6-A8773B235325" name="Pool Participant" processRef="manager_admin_multiple_users"/>
+ </bpmn2:collaboration>
+ <bpmn2:process id="manager_admin_multiple_users" drools:packageName="com.example" drools:version="1.0" drools:adHoc="false" name="manager_admin_multiple_users" isExecutable="true" processType="Public">
+ <bpmn2:sequenceFlow id="_E9728BB4-C7C1-4613-8506-61F6E8D54928" sourceRef="_60F9AB18-9065-48B1-9667-791889027BF8" targetRef="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717"/>
+ <bpmn2:sequenceFlow id="_8FF3949E-26E7-42C7-818E-17C8AAF127F5" sourceRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51" targetRef="_60F9AB18-9065-48B1-9667-791889027BF8"/>
+ <bpmn2:endEvent id="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <bpmn2:incoming>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:userTask id="_60F9AB18-9065-48B1-9667-791889027BF8" name="Manager Approval">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Manager Approval]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:incoming>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:incoming>
+ <bpmn2:outgoing>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:outgoing>
+ <bpmn2:ioSpecification>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX" drools:dtype="Object" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem" name="TaskName"/>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX" drools:dtype="String" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem" name="BusinessAdministratorId"/>
+ <bpmn2:dataInput id="_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX" drools:dtype="Object" itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem" name="Skippable"/>
+ <bpmn2:inputSet>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:dataInputRefs>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:dataInputRefs>
+ <bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:dataInputRefs>
+ </bpmn2:inputSet>
+ </bpmn2:ioSpecification>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[carl]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+ <bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from xsi:type="bpmn2:tFormalExpression"><![CDATA[true]]></bpmn2:from>
+ <bpmn2:to xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:potentialOwner id="_he12IFJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he12IVJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>john</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ <bpmn2:potentialOwner id="_he12IlJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he2dMFJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>dave</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ </bpmn2:userTask>
+ <bpmn2:startEvent id="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpmn2:outgoing>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:outgoing>
+ </bpmn2:startEvent>
+ </bpmn2:process>
+ <bpmndi:BPMNDiagram>
+ <bpmndi:BPMNPlane bpmnElement="manager_admin_multiple_users">
+ <bpmndi:BPMNShape id="shape__F4221219-F8CE-47B1-A637-8452CB0B6A51" bpmnElement="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <dc:Bounds height="56" width="56" x="210" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__60F9AB18-9065-48B1-9667-791889027BF8" bpmnElement="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <dc:Bounds height="102" width="154" x="346" y="190"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717" bpmnElement="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <dc:Bounds height="56" width="56" x="580" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="edge_shape__F4221219-F8CE-47B1-A637-8452CB0B6A51_to_shape__60F9AB18-9065-48B1-9667-791889027BF8" bpmnElement="_8FF3949E-26E7-42C7-818E-17C8AAF127F5">
+ <di:waypoint x="238" y="241"/>
+ <di:waypoint x="423" y="241"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="edge_shape__60F9AB18-9065-48B1-9667-791889027BF8_to_shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717" bpmnElement="_E9728BB4-C7C1-4613-8506-61F6E8D54928">
+ <di:waypoint x="423" y="241"/>
+ <di:waypoint x="608" y="241"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+ <bpmn2:relationship type="BPSimData">
+ <bpmn2:extensionElements>
+ <bpsim:BPSimData>
+ <bpsim:Scenario id="default" name="Simulationscenario">
+ <bpsim:ScenarioParameters/>
+ <bpsim:ElementParameters elementRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ </bpsim:ElementParameters>
+ <bpsim:ElementParameters elementRef="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ <bpsim:ResourceParameters>
+ <bpsim:Availability>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Availability>
+ <bpsim:Quantity>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Quantity>
+ </bpsim:ResourceParameters>
+ <bpsim:CostParameters>
+ <bpsim:UnitCost>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:UnitCost>
+ </bpsim:CostParameters>
+ </bpsim:ElementParameters>
+ </bpsim:Scenario>
+ </bpsim:BPSimData>
+ </bpmn2:extensionElements>
+ <bpmn2:source>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:source>
+ <bpmn2:target>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:target>
+ </bpmn2:relationship>
+</bpmn2:definitions>
\ No newline at end of file
diff --git a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
index 2f811265a2..e2d069ace2 100644
--- a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
+++ b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
@@ -220,6 +220,132 @@ public class WsHumanTaskLifeCycleIT {
isProcessCompleted(processId, pid);
}
+ @Test
+ public void testPotentialUserCanResumeSuspendedToReadyTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, potentialUser, "Ready");
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testBusinessAdminCanResumeSuspendedTask() {
+ var owner = "dave";
+ var admin = "carl";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_admin_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, admin, "Ready");
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "Reserved");
+
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
@Test
public void testSuspendUntilWithDuration() {
var user = "dave";
@@ -743,6 +869,17 @@ public class WsHumanTaskLifeCycleIT {
.body("metadata.SuspendedJobId", equalTo(null));
}
+ private void resumeNotAuthorized(String taskId, String user) {
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", user)
+ .body(new TransitionInfo("resume"))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(403);
+ }
+
private void suspend(String taskId, String user) {
given()
.contentType(ContentType.JSON)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org