Skip to content

Commit

Permalink
fix reassign tests
Browse files Browse the repository at this point in the history
  • Loading branch information
elguardian committed Nov 12, 2024
1 parent e44417c commit ef7de4b
Show file tree
Hide file tree
Showing 8 changed files with 469 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ default String startTransition() {

UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskInstance userTaskInstance, Map<String, Object> data);

UserTaskTransitionToken newCompleteTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> emptyMap);
default Optional<UserTaskTransitionToken> newReassignmentTransitionToken(UserTaskInstance defaultUserTaskInstance, Map<String, Object> data) {
return Optional.empty();
}

UserTaskTransitionToken newCompleteTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data);

UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> emptyMap);
UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data);

List<UserTaskTransition> allowedTransitions(UserTaskInstance ut);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,12 @@ public SignalUserTaskInstanceOnExpiredTimer(JobsService jobService, InMemoryJobC
this.limit = limit;
this.jobsConfiguration = jobsConfiguration;
this.jobService = jobService;

String jobId = userTaskInstanceJobDescription.id();
String userTaskInstanceId = userTaskInstanceJobDescription.getUserTaskInstanceId();
LOGGER.info("building Job {}. There is no user task instance of id {} ", jobId, userTaskInstanceId);
}

@Override
public void run() {
String jobId = userTaskInstanceJobDescription.id();
String userTaskInstanceId = userTaskInstanceJobDescription.getUserTaskInstanceId();
LOGGER.info("Running Job {}. There is no user task instance of id {} ", jobId, userTaskInstanceId);
try {
Optional<UserTaskInstance> userTaskInstance = jobsConfiguration.userTasks().instances().findById(userTaskInstanceId);
if (userTaskInstance.isEmpty()) {
Expand All @@ -119,8 +114,6 @@ public void run() {
LOGGER.info("Retrying Job {} due to: {}", jobId, ex.getMessage());
limit++;
run();
} catch(Exception e) {
e.printStackTrace();
} finally {
if (removeAtExecution) {
jobService.cancelJob(jobId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.function.Consumer;

import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.auth.IdentityProviders;
import org.kie.kogito.internal.usertask.event.KogitoUserTaskEventSupport;
import org.kie.kogito.internal.usertask.event.KogitoUserTaskEventSupport.AssignmentType;
import org.kie.kogito.jobs.ExpirationTime;
Expand All @@ -56,7 +57,9 @@

import com.fasterxml.jackson.annotation.JsonIgnore;

import static java.util.Collections.emptyMap;
import static org.kie.kogito.jobs.descriptors.UserTaskInstanceJobDescription.newUserTaskInstanceJobDescriptionBuilder;
import static org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle.WORKFLOW_ENGINE_USER;

public class DefaultUserTaskInstance implements UserTaskInstance {

Expand Down Expand Up @@ -721,7 +724,7 @@ public void stopNotCompletedReassigments() {
}

public void trigger(UserTaskInstanceJobDescription jobDescription) {
LOG.info("trigger timer in user tasks {} and job {}", this, jobDescription);
LOG.trace("trigger timer in user tasks {} and job {}", this, jobDescription);
checkAndSendNotitication(jobDescription, notStartedDeadlinesTimers, this::startNotification);
checkAndSendNotitication(jobDescription, notCompletedDeadlinesTimers, this::endNotification);
checkAndReassign(jobDescription, notStartedReassignmentsTimers);
Expand Down Expand Up @@ -764,18 +767,16 @@ private void checkAndReassign(UserTaskInstanceJobDescription timerInstance, Map<
}

private void reassign(Reassignment reassignment) {
boolean modified = false;
if (!reassignment.getPotentialUsers().isEmpty()) {
setPotentialUsers(reassignment.getPotentialUsers());
modified = true;
}
if (!reassignment.getPotentialGroups().isEmpty()) {
setPotentialGroups(reassignment.getPotentialGroups());
modified = true;
}
if (modified && this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
}

this.userTaskLifeCycle.newReassignmentTransitionToken(this, emptyMap()).ifPresent(token -> {
this.userTaskLifeCycle.transition(this, token, IdentityProviders.of(WORKFLOW_ENGINE_USER));
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class DefaultUserTaskLifeCycle implements UserTaskLifeCycle {
public static final String COMPLETE = "complete";
public static final String SKIP = "skip";
public static final String FAIL = "fail";
public static final String REASSIGN = "reassign";

public static final UserTaskState INACTIVE = UserTaskState.initalized();
public static final UserTaskState ACTIVE = UserTaskState.of("Ready");
Expand All @@ -66,6 +67,9 @@ public class DefaultUserTaskLifeCycle implements UserTaskLifeCycle {
private final UserTaskTransition T_RESERVED_SKIPPED = new DefaultUserTransition(SKIP, RESERVED, OBSOLETE, this::skip);
private final UserTaskTransition T_RESERVED_ERROR = new DefaultUserTransition(FAIL, RESERVED, ERROR, this::fail);

private final UserTaskTransition T_RESERVED_ACTIVE_R = new DefaultUserTransition(REASSIGN, RESERVED, ACTIVE, this::reassign);
private final UserTaskTransition T_ACTIVE_ACTIVE_R = new DefaultUserTransition(REASSIGN, ACTIVE, ACTIVE, this::reassign);

private List<UserTaskTransition> transitions;

public DefaultUserTaskLifeCycle() {
Expand All @@ -77,7 +81,9 @@ public DefaultUserTaskLifeCycle() {
T_RESERVED_ACTIVE,
T_RESERVED_COMPLETED,
T_RESERVED_SKIPPED,
T_RESERVED_ERROR);
T_RESERVED_ERROR,
T_RESERVED_ACTIVE_R,
T_ACTIVE_ACTIVE_R);
}

@Override
Expand All @@ -95,6 +101,15 @@ public Optional<UserTaskTransitionToken> transition(UserTaskInstance userTaskIns
return transition.executor().execute(userTaskInstance, userTaskTransitionToken, identityProvider);
}

@Override
public Optional<UserTaskTransitionToken> newReassignmentTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
try {
return Optional.of(newTransitionToken(REASSIGN, userTaskInstance.getStatus(), data));
} catch (UserTaskTransitionException e) {
return Optional.empty();
}
}

@Override
public UserTaskTransitionToken newCompleteTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
return newTransitionToken(COMPLETE, userTaskInstance.getStatus(), data);
Expand All @@ -116,17 +131,35 @@ public UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskS
return new DefaultUserTaskTransitionToken(transition.id(), transition.source(), transition.target(), data);
}

public Optional<UserTaskTransitionToken> activate(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
public Optional<UserTaskTransitionToken> reassign(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
userTaskInstance.stopNotStartedDeadlines();
userTaskInstance.stopNotStartedReassignments();
userTaskInstance.stopNotCompletedDeadlines();
userTaskInstance.stopNotCompletedReassigments();

// restart the timers
userTaskInstance.startNotCompletedDeadlines();
userTaskInstance.startNotCompletedReassigments();

String user = assignStrategy(userTaskInstance, identityProvider);
if (user != null) {
return Optional.of(newTransitionToken(CLAIM, ACTIVE, Map.of(PARAMETER_USER, user)));
}
userTaskInstance.startNotStartedDeadlines();
userTaskInstance.startNotStartedReassignments();
return Optional.empty();
}

public Optional<UserTaskTransitionToken> activate(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
userTaskInstance.startNotCompletedDeadlines();
userTaskInstance.startNotCompletedReassigments();

String user = assignStrategy(userTaskInstance, identityProvider);
if (user != null) {
return Optional.of(newTransitionToken(CLAIM, ACTIVE, Map.of(PARAMETER_USER, user)));
}
userTaskInstance.startNotStartedDeadlines();
userTaskInstance.startNotStartedReassignments();
return Optional.empty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -54,6 +55,7 @@
import org.kie.kogito.usertask.UserTaskInstance;
import org.kie.kogito.usertask.UserTaskInstanceNotAuthorizedException;
import org.kie.kogito.usertask.UserTasks;
import org.kie.kogito.usertask.events.UserTaskAssignmentEvent;
import org.kie.kogito.usertask.events.UserTaskDeadlineEvent;
import org.kie.kogito.usertask.events.UserTaskDeadlineEvent.DeadlineType;
import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
Expand Down Expand Up @@ -1054,6 +1056,88 @@ public void onUserTaskDeadline(UserTaskDeadlineEvent event) {

}

@Test
public void testUserTaskNotStartedReassign() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Application app = generateCodeProcessesOnly("usertask/UserTasksNotStartedReasssign.bpmn2");
assertThat(app).isNotNull();

app.config().get(UserTaskConfig.class).userTaskEventListeners().listeners().add(new UserTaskEventListener() {
@Override
public void onUserTaskAssignment(UserTaskAssignmentEvent event) {
List<String> users = Arrays.asList(event.getNewUsersId());
if (users.size() == 1 && users.contains("mike")) {
latch.countDown();
}
}
});
Process<? extends Model> p = app.get(Processes.class).processById("UserTasksDeadline");

Model m = p.createModel();
Map<String, Object> parameters = new HashMap<>();
parameters.put("subject", "this is my subject");
parameters.put("body", "this is my body");
m.fromMap(parameters);

// assign custom business key for process instance
String businessKey = "business key";
ProcessInstance<?> processInstance = p.createInstance(businessKey, m);
processInstance.start();

assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE);
// verify that custom business key is assigned properly
assertThat(processInstance.businessKey()).isEqualTo(businessKey);

// start another process instance with assigned duplicated business key of already active instance
ProcessInstance<? extends Model> otherProcessInstance = p.createInstance(businessKey, m);
assertThat(otherProcessInstance.id()).isNotEqualTo(processInstance.id());
assertThat(otherProcessInstance.businessKey()).isEqualTo(processInstance.businessKey()).isEqualTo(businessKey);
assertThat(latch.await(5L, TimeUnit.SECONDS)).isTrue();
}

@Test
public void testUserTaskNotStartedReassignStopTimers() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Application app = generateCodeProcessesOnly("usertask/UserTasksNotStartedReasssign.bpmn2");
assertThat(app).isNotNull();

app.config().get(UserTaskConfig.class).userTaskEventListeners().listeners().add(new UserTaskEventListener() {
@Override
public void onUserTaskAssignment(UserTaskAssignmentEvent event) {
List<String> users = Arrays.asList(event.getNewUsersId());
if (users.size() == 1 && users.contains("mike")) {
latch.countDown();
}
}
});
Process<? extends Model> p = app.get(Processes.class).processById("UserTasksDeadline");

Model m = p.createModel();
Map<String, Object> parameters = new HashMap<>();
parameters.put("subject", "this is my subject");
parameters.put("body", "this is my body");
m.fromMap(parameters);

// assign custom business key for process instance
String businessKey = "business key";
ProcessInstance<?> processInstance = p.createInstance(businessKey, m);
processInstance.start();

assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE);

// verify that custom business key is assigned properly
assertThat(processInstance.businessKey()).isEqualTo(businessKey);
IdentityProvider mary = IdentityProviders.of("mary");
List<UserTaskInstance> userTaskInstances = app.get(UserTasks.class).instances().findByIdentity(mary);
userTaskInstances.forEach(e -> e.transition(DefaultUserTaskLifeCycle.CLAIM, Collections.emptyMap(), mary));

// start another process instance with assigned duplicated business key of already active instance
ProcessInstance<? extends Model> otherProcessInstance = p.createInstance(businessKey, m);
assertThat(otherProcessInstance.id()).isNotEqualTo(processInstance.id());
assertThat(otherProcessInstance.businessKey()).isEqualTo(processInstance.businessKey()).isEqualTo(businessKey);
assertThat(latch.await(2L, TimeUnit.SECONDS)).isFalse();
}

@Test
public void testUserTaskNotCompletedDeadlineWithReplacement() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Expand Down Expand Up @@ -1144,4 +1228,90 @@ public void onUserTaskDeadline(UserTaskDeadlineEvent event) {
assertThat(latch.await(5L, TimeUnit.SECONDS)).isFalse();

}

@Test
public void testUserTaskNotCompletedReassign() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Application app = generateCodeProcessesOnly("usertask/UserTasksNotCompletedReassign.bpmn2");
assertThat(app).isNotNull();

app.config().get(UserTaskConfig.class).userTaskEventListeners().listeners().add(new UserTaskEventListener() {
@Override
public void onUserTaskAssignment(UserTaskAssignmentEvent event) {
List<String> users = Arrays.asList(event.getNewUsersId());
if (users.size() == 1 && users.contains("mike")) {
latch.countDown();
}
}
});
Process<? extends Model> p = app.get(Processes.class).processById("UserTasksDeadline");

Model m = p.createModel();
Map<String, Object> parameters = new HashMap<>();
parameters.put("body", "my body!!!");
m.fromMap(parameters);

// assign custom business key for process instance
String businessKey = "business key";
ProcessInstance<?> processInstance = p.createInstance(businessKey, m);
processInstance.start();

assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE);
// verify that custom business key is assigned properly
assertThat(processInstance.businessKey()).isEqualTo(businessKey);

// start another process instance with assigned duplicated business key of already active instance
ProcessInstance<? extends Model> otherProcessInstance = p.createInstance(businessKey, m);
assertThat(otherProcessInstance.id()).isNotEqualTo(processInstance.id());
assertThat(otherProcessInstance.businessKey()).isEqualTo(processInstance.businessKey()).isEqualTo(businessKey);
assertTrue(latch.await(5L, TimeUnit.SECONDS));

}

@Test
public void testUserTaskNotCompletedReassignStopTimer() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Application app = generateCodeProcessesOnly("usertask/UserTasksNotCompletedReassign.bpmn2");
assertThat(app).isNotNull();

app.config().get(UserTaskConfig.class).userTaskEventListeners().listeners().add(new UserTaskEventListener() {
@Override
public void onUserTaskAssignment(UserTaskAssignmentEvent event) {
List<String> users = Arrays.asList(event.getNewUsersId());
if (users.size() == 1 && users.contains("mike")) {
latch.countDown();
}
}

});
Process<? extends Model> p = app.get(Processes.class).processById("UserTasksDeadline");

Model m = p.createModel();
Map<String, Object> parameters = new HashMap<>();
parameters.put("subject", "this is my subject");
parameters.put("body", "this is my body");
m.fromMap(parameters);

// assign custom business key for process instance
String businessKey = "business key";
ProcessInstance<?> processInstance = p.createInstance(businessKey, m);
processInstance.start();

assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE);
// verify that custom business key is assigned properly
assertThat(processInstance.businessKey()).isEqualTo(businessKey);
IdentityProvider mary = IdentityProviders.of("mary");
List<UserTaskInstance> userTaskInstances = app.get(UserTasks.class).instances().findByIdentity(mary);
userTaskInstances.forEach(e -> {
e.transition(DefaultUserTaskLifeCycle.CLAIM, emptyMap(), mary);
e.transition(DefaultUserTaskLifeCycle.COMPLETE, emptyMap(), mary);
});

// start another process instance with assigned duplicated business key of already active instance
ProcessInstance<? extends Model> otherProcessInstance = p.createInstance(businessKey, m);
assertThat(otherProcessInstance.id()).isNotEqualTo(processInstance.id());
assertThat(otherProcessInstance.businessKey()).isEqualTo(processInstance.businessKey()).isEqualTo(businessKey);
assertThat(latch.await(2L, TimeUnit.SECONDS)).isFalse();

}
}
Loading

0 comments on commit ef7de4b

Please sign in to comment.