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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to