TSK-1257: implementes forceCompleteTasks
This commit is contained in:
parent
496da17b3e
commit
6f12677b74
|
@ -0,0 +1,21 @@
|
|||
package pro.taskana.common.internal.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import pro.taskana.common.api.exceptions.SystemException;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CheckedConsumer<T> {
|
||||
static <T> Consumer<T> wrap(CheckedConsumer<T> checkedConsumer) {
|
||||
return t -> {
|
||||
try {
|
||||
checkedConsumer.accept(t);
|
||||
} catch (Throwable e) {
|
||||
throw new SystemException("Caught exception", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void accept(T t) throws Throwable;
|
||||
}
|
||||
|
|
@ -349,6 +349,7 @@ public interface TaskService {
|
|||
/**
|
||||
* Completes a list of tasks.
|
||||
*
|
||||
* @see TaskService#forceCompleteTask
|
||||
* @param taskIds of the tasks which should be completed.
|
||||
* @return the result of the operations with Id and Exception for each failed task completion.
|
||||
* @throws InvalidArgumentException If the taskId parameter is NULL.
|
||||
|
|
|
@ -158,13 +158,22 @@ public interface TaskMapper {
|
|||
|
||||
@Update(
|
||||
"<script>"
|
||||
+ " UPDATE TASK SET COMPLETED = #{referenceTask.completed}, MODIFIED = #{referenceTask.modified}, STATE = #{referenceTask.state}"
|
||||
+ " UPDATE TASK SET COMPLETED = #{referenceTask.completed}, MODIFIED = #{referenceTask.modified}, STATE = #{referenceTask.state}, OWNER = #{referenceTask.owner}"
|
||||
+ " WHERE ID IN <foreach item='taskId' index='index' separator=',' open='(' close=')' collection='taskIds'>#{taskId}</foreach>"
|
||||
+ "</script>")
|
||||
void updateCompleted(
|
||||
@Param("taskIds") List<String> taskIds,
|
||||
@Param("referenceTask") TaskSummary referenceTask);
|
||||
|
||||
@Update(
|
||||
"<script>"
|
||||
+ " UPDATE TASK SET CLAIMED = #{referenceTask.claimed}, MODIFIED = #{referenceTask.modified}, STATE = #{referenceTask.state}, OWNER = #{referenceTask.owner}, IS_READ = #{referenceTask.isRead}"
|
||||
+ " WHERE ID IN <foreach item='taskId' index='index' separator=',' open='(' close=')' collection='taskIds'>#{taskId}</foreach>"
|
||||
+ "</script>")
|
||||
void updateClaimed(
|
||||
@Param("taskIds") List<String> taskIds,
|
||||
@Param("referenceTask") TaskSummary referenceTask);
|
||||
|
||||
@Select(
|
||||
"<script>SELECT ID, EXTERNAL_ID, STATE, WORKBASKET_ID, OWNER, MODIFIED, CLASSIFICATION_ID, "
|
||||
+ "PLANNED, DUE, CALLBACK_STATE FROM TASK "
|
||||
|
@ -289,4 +298,5 @@ public interface TaskMapper {
|
|||
@Results(value = {@Result(property = "id", column = "ID")})
|
||||
List<String> filterTaskIdsNotAuthorizedFor(
|
||||
@Param("taskIds") List<String> taskIds, @Param("accessIds") List<String> accessIds);
|
||||
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
private static final String ID_PREFIX_TASK = "TKI";
|
||||
private static final String ID_PREFIX_EXT_TASK_ID = "ETI";
|
||||
private static final String ID_PREFIX_BUSINESS_PROCESS = "BPI";
|
||||
private static final Set<String> ALLOWED_KEYS =
|
||||
private static final Set<String> ALLOWED_CUSTOM_KEYS =
|
||||
IntStream.rangeClosed(1, 16).mapToObj(String::valueOf).collect(Collectors.toSet());
|
||||
private static final String TASK_WITH_ID_IS_ALREADY_IN_END_STATE =
|
||||
"Task with Id %s is already in an end state.";
|
||||
|
@ -517,78 +517,13 @@ public class TaskServiceImpl implements TaskService {
|
|||
@Override
|
||||
public BulkOperationResults<String, TaskanaException> completeTasks(List<String> taskIds)
|
||||
throws InvalidArgumentException {
|
||||
try {
|
||||
LOGGER.debug("entry to completeTasks(taskIds = {})", taskIds);
|
||||
taskanaEngine.openConnection();
|
||||
if (taskIds == null) {
|
||||
throw new InvalidArgumentException("TaskIds can't be used as NULL-Parameter.");
|
||||
}
|
||||
BulkOperationResults<String, TaskanaException> bulkLog = new BulkOperationResults<>();
|
||||
Map<String, TaskSummaryImpl> taskSummaryMap =
|
||||
createTaskQuery().idIn(taskIds.toArray(new String[0])).list().stream()
|
||||
.collect(Collectors.toMap(TaskSummary::getId, e -> (TaskSummaryImpl) e));
|
||||
|
||||
Predicate<Pair<String, ? extends TaskSummary>> taskIdNotFound =
|
||||
pair -> {
|
||||
if (pair.getRight() == null) {
|
||||
String taskId = pair.getLeft();
|
||||
bulkLog.addError(
|
||||
taskId,
|
||||
new TaskNotFoundException(
|
||||
taskId, String.format(TASK_WITH_ID_WAS_NOT_FOUND, taskId)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Predicate<TaskSummary> stateIsCorrect =
|
||||
summary -> {
|
||||
if (summary.getClaimed() == null || summary.getState() != TaskState.CLAIMED) {
|
||||
bulkLog.addError(summary.getId(), new InvalidStateException(summary.getId()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Predicate<TaskSummary> userIsCorrect =
|
||||
summary -> {
|
||||
if (!CurrentUserContext.getAccessIds().contains(summary.getOwner())) {
|
||||
bulkLog.addError(
|
||||
summary.getId(),
|
||||
new InvalidOwnerException(
|
||||
String.format(
|
||||
"TaskOwner is %s, but currentUser is %s.",
|
||||
summary.getOwner(), CurrentUserContext.getUserid())));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Stream<TaskSummaryImpl> filteredSummaries =
|
||||
taskIds.stream()
|
||||
.map(id -> Pair.of(id, taskSummaryMap.get(id)))
|
||||
.filter(taskIdNotFound)
|
||||
.map(Pair::getRight)
|
||||
.filter(stateIsCorrect)
|
||||
.filter(userIsCorrect);
|
||||
|
||||
updateTasksToBeCompleted(filteredSummaries);
|
||||
|
||||
return bulkLog;
|
||||
} finally {
|
||||
taskanaEngine.returnConnection();
|
||||
LOGGER.debug("exit from to completeTasks(taskIds = {})", taskIds);
|
||||
}
|
||||
return completeTasks(taskIds, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BulkOperationResults<String, TaskanaException> forceCompleteTasks(List<String> taskIds)
|
||||
throws InvalidArgumentException {
|
||||
|
||||
if (taskIds == null) {
|
||||
throw new InvalidArgumentException("TaskIds can't be used as NULL-Parameter.");
|
||||
}
|
||||
return null;
|
||||
return completeTasks(taskIds, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1074,6 +1009,109 @@ public class TaskServiceImpl implements TaskService {
|
|||
return result;
|
||||
}
|
||||
|
||||
private BulkOperationResults<String, TaskanaException> completeTasks(
|
||||
List<String> taskIds, boolean forced) throws InvalidArgumentException {
|
||||
try {
|
||||
LOGGER.debug("entry to completeTasks(taskIds = {})", taskIds);
|
||||
taskanaEngine.openConnection();
|
||||
if (taskIds == null) {
|
||||
throw new InvalidArgumentException("TaskIds can't be used as NULL-Parameter.");
|
||||
}
|
||||
BulkOperationResults<String, TaskanaException> bulkLog = new BulkOperationResults<>();
|
||||
|
||||
Instant now = Instant.now();
|
||||
Stream<TaskSummaryImpl> filteredSummaries = filterNotExistingTaskIds(taskIds, bulkLog);
|
||||
filteredSummaries = filterInvalidTaskStates(filteredSummaries, bulkLog);
|
||||
|
||||
if (!forced) {
|
||||
filteredSummaries = filterPreConditionForCompleteTasks(filteredSummaries, bulkLog);
|
||||
} else {
|
||||
filteredSummaries = claimNotClaimedTasks(filteredSummaries, forced, now, bulkLog);
|
||||
}
|
||||
|
||||
updateTasksToBeCompleted(filteredSummaries, now);
|
||||
|
||||
return bulkLog;
|
||||
} finally {
|
||||
taskanaEngine.returnConnection();
|
||||
LOGGER.debug("exit from to completeTasks(taskIds = {})", taskIds);
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream<TaskSummaryImpl> filterPreConditionForCompleteTasks(
|
||||
Stream<TaskSummaryImpl> stream, BulkOperationResults<String, TaskanaException> bulkLog) {
|
||||
return stream.filter(
|
||||
summary -> {
|
||||
try {
|
||||
checkPreconditionsForCompleteTask(summary);
|
||||
return true;
|
||||
} catch (TaskanaException e) {
|
||||
bulkLog.addError(summary.getId(), e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Stream<TaskSummaryImpl> claimNotClaimedTasks(
|
||||
Stream<TaskSummaryImpl> stream,
|
||||
boolean forced,
|
||||
Instant now,
|
||||
BulkOperationResults<String, TaskanaException> bulkLog) {
|
||||
String userId = CurrentUserContext.getUserid();
|
||||
return stream.filter(
|
||||
summary -> {
|
||||
try {
|
||||
if (taskIsNotClaimed(summary)) {
|
||||
checkPreconditionsForClaimTask(summary, forced);
|
||||
claimActionsOnTask(summary, userId, now);
|
||||
}
|
||||
return true;
|
||||
} catch (TaskanaException e) {
|
||||
bulkLog.addError(summary.getId(), e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Stream<TaskSummaryImpl> filterNotExistingTaskIds(
|
||||
List<String> taskIds, BulkOperationResults<String, TaskanaException> bulkLog) {
|
||||
|
||||
Map<String, TaskSummaryImpl> taskSummaryMap =
|
||||
getTasksToChange(taskIds).stream()
|
||||
.collect(Collectors.toMap(TaskSummary::getId, e -> (TaskSummaryImpl) e));
|
||||
return taskIds.stream()
|
||||
.map(id -> Pair.of(id, taskSummaryMap.get(id)))
|
||||
.filter(
|
||||
pair -> {
|
||||
if (pair.getRight() == null) {
|
||||
String taskId = pair.getLeft();
|
||||
bulkLog.addError(
|
||||
taskId,
|
||||
new TaskNotFoundException(
|
||||
taskId, String.format(TASK_WITH_ID_WAS_NOT_FOUND, taskId)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(Pair::getRight);
|
||||
}
|
||||
|
||||
private static Stream<TaskSummaryImpl> filterInvalidTaskStates(
|
||||
Stream<TaskSummaryImpl> stream, BulkOperationResults<String, TaskanaException> bulkLog) {
|
||||
return stream
|
||||
.filter(task -> task.getState() != TaskState.COMPLETED)
|
||||
.filter(
|
||||
summary -> {
|
||||
try {
|
||||
checkIfTaskIsTerminatedOrCancelled(summary);
|
||||
return true;
|
||||
} catch (TaskanaException e) {
|
||||
bulkLog.addError(summary.getId(), e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkConcurrencyAndSetModified(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)
|
||||
throws ConcurrencyException {
|
||||
// TODO: not safe to rely only on different timestamps.
|
||||
|
@ -1144,21 +1182,10 @@ public class TaskServiceImpl implements TaskService {
|
|||
try {
|
||||
taskanaEngine.openConnection();
|
||||
task = (TaskImpl) getTask(taskId);
|
||||
TaskState state = task.getState();
|
||||
if (!state.in(TaskState.READY, TaskState.CLAIMED)) {
|
||||
throw new InvalidStateException(
|
||||
String.format(TASK_WITH_ID_IS_ALREADY_IN_END_STATE, taskId));
|
||||
}
|
||||
if (state == TaskState.CLAIMED && !forceClaim && !task.getOwner().equals(userId)) {
|
||||
throw new InvalidOwnerException(
|
||||
String.format(TASK_WITH_ID_IS_ALREADY_CLAIMED_BY, taskId, task.getOwner()));
|
||||
}
|
||||
Instant now = Instant.now();
|
||||
task.setOwner(userId);
|
||||
task.setModified(now);
|
||||
task.setClaimed(now);
|
||||
task.setRead(true);
|
||||
task.setState(TaskState.CLAIMED);
|
||||
|
||||
checkPreconditionsForClaimTask(task, forceClaim);
|
||||
claimActionsOnTask(task, userId, now);
|
||||
taskMapper.update(task);
|
||||
LOGGER.debug("Task '{}' claimed by user '{}'.", taskId, userId);
|
||||
if (HistoryEventProducer.isHistoryEnabled()) {
|
||||
|
@ -1171,6 +1198,62 @@ public class TaskServiceImpl implements TaskService {
|
|||
return task;
|
||||
}
|
||||
|
||||
private static void claimActionsOnTask(TaskSummaryImpl task, String userId, Instant now) {
|
||||
task.setOwner(userId);
|
||||
task.setModified(now);
|
||||
task.setClaimed(now);
|
||||
task.setRead(true);
|
||||
task.setState(TaskState.CLAIMED);
|
||||
}
|
||||
|
||||
private static void completeActionsOnTask(TaskSummaryImpl task, String userId, Instant now) {
|
||||
task.setCompleted(now);
|
||||
task.setModified(now);
|
||||
task.setState(TaskState.COMPLETED);
|
||||
task.setOwner(userId);
|
||||
}
|
||||
|
||||
private static void checkPreconditionsForClaimTask(TaskSummary task, boolean forced)
|
||||
throws InvalidStateException, InvalidOwnerException {
|
||||
TaskState state = task.getState();
|
||||
if (!state.in(TaskState.READY, TaskState.CLAIMED)) {
|
||||
throw new InvalidStateException(
|
||||
String.format(TASK_WITH_ID_IS_ALREADY_IN_END_STATE, task.getId()));
|
||||
}
|
||||
if (!forced
|
||||
&& state == TaskState.CLAIMED
|
||||
&& !task.getOwner().equals(CurrentUserContext.getUserid())) {
|
||||
throw new InvalidOwnerException(
|
||||
String.format(TASK_WITH_ID_IS_ALREADY_CLAIMED_BY, task.getId(), task.getOwner()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean taskIsNotClaimed(TaskSummary task) {
|
||||
return task.getClaimed() == null || task.getState() != TaskState.CLAIMED;
|
||||
}
|
||||
|
||||
private static void checkIfTaskIsTerminatedOrCancelled(TaskSummary task)
|
||||
throws InvalidStateException {
|
||||
if (task.getState().in(TaskState.CANCELLED, TaskState.TERMINATED)) {
|
||||
throw new InvalidStateException(
|
||||
String.format(
|
||||
"Cannot complete task %s because it is in state %s.", task.getId(), task.getState()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkPreconditionsForCompleteTask(TaskSummary task)
|
||||
throws InvalidStateException, InvalidOwnerException {
|
||||
if (taskIsNotClaimed(task)) {
|
||||
throw new InvalidStateException(
|
||||
String.format(TASK_WITH_ID_HAS_TO_BE_CLAIMED_BEFORE, task.getId()));
|
||||
} else if (!CurrentUserContext.getAccessIds().contains(task.getOwner())) {
|
||||
throw new InvalidOwnerException(
|
||||
String.format(
|
||||
"Owner of task %s is %s, but current user is %s ",
|
||||
task.getId(), task.getOwner(), CurrentUserContext.getUserid()));
|
||||
}
|
||||
}
|
||||
|
||||
private Task cancelClaim(String taskId, boolean forceUnclaim)
|
||||
throws TaskNotFoundException, InvalidStateException, InvalidOwnerException,
|
||||
NotAuthorizedException {
|
||||
|
@ -1227,34 +1310,16 @@ public class TaskServiceImpl implements TaskService {
|
|||
return task;
|
||||
}
|
||||
|
||||
if (task.getState().in(TaskState.CANCELLED, TaskState.TERMINATED)) {
|
||||
throw new InvalidStateException(
|
||||
String.format(
|
||||
"Cannot complete task %s because it is in state %s.", taskId, task.getState()));
|
||||
checkIfTaskIsTerminatedOrCancelled(task);
|
||||
|
||||
if (!isForced) {
|
||||
checkPreconditionsForCompleteTask(task);
|
||||
} else if (taskIsNotClaimed(task)) {
|
||||
task = (TaskImpl) this.forceClaim(taskId);
|
||||
}
|
||||
|
||||
// check pre-conditions for non-forced invocation
|
||||
if (!isForced) {
|
||||
if (task.getClaimed() == null || task.getState() != TaskState.CLAIMED) {
|
||||
throw new InvalidStateException(
|
||||
String.format(TASK_WITH_ID_HAS_TO_BE_CLAIMED_BEFORE, taskId));
|
||||
} else if (!CurrentUserContext.getAccessIds().contains(task.getOwner())) {
|
||||
throw new InvalidOwnerException(
|
||||
String.format(
|
||||
"Owner of task %s is %s, but current user is %s ",
|
||||
taskId, task.getOwner(), userId));
|
||||
}
|
||||
} else {
|
||||
// CLAIM-forced, if task was not already claimed before.
|
||||
if (task.getClaimed() == null || task.getState() != TaskState.CLAIMED) {
|
||||
task = (TaskImpl) this.forceClaim(taskId);
|
||||
}
|
||||
}
|
||||
Instant now = Instant.now();
|
||||
task.setCompleted(now);
|
||||
task.setModified(now);
|
||||
task.setState(TaskState.COMPLETED);
|
||||
task.setOwner(userId);
|
||||
completeActionsOnTask(task, userId, now);
|
||||
taskMapper.update(task);
|
||||
LOGGER.debug("Task '{}' completed by user '{}'.", taskId, userId);
|
||||
if (HistoryEventProducer.isHistoryEnabled()) {
|
||||
|
@ -1457,23 +1522,34 @@ public class TaskServiceImpl implements TaskService {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateTasksToBeCompleted(Stream<TaskSummaryImpl> taskSummaries) {
|
||||
private void updateTasksToBeCompleted(Stream<TaskSummaryImpl> taskSummaries, Instant now) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("entry to updateTasksToBeCompleted()");
|
||||
}
|
||||
|
||||
Instant now = Instant.now();
|
||||
List<String> taskIds = new ArrayList<>();
|
||||
List<String> updateClaimedTaskIds = new ArrayList<>();
|
||||
List<TaskSummary> taskSummaryList =
|
||||
taskSummaries
|
||||
.peek(summary -> summary.setModified(now))
|
||||
.peek(summary -> summary.setCompleted(now))
|
||||
.peek(summary -> summary.setState(TaskState.COMPLETED))
|
||||
.peek(summary -> completeActionsOnTask(summary, CurrentUserContext.getUserid(), now))
|
||||
.peek(summary -> taskIds.add(summary.getId()))
|
||||
.peek(
|
||||
summary -> {
|
||||
if (summary.getClaimed().equals(now)) {
|
||||
updateClaimedTaskIds.add(summary.getId());
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
TaskSummary claimedReference =
|
||||
taskSummaryList.stream()
|
||||
.filter(summary -> updateClaimedTaskIds.contains(summary.getId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (!taskSummaryList.isEmpty()) {
|
||||
taskMapper.updateCompleted(taskIds, taskSummaryList.get(0));
|
||||
if (!updateClaimedTaskIds.isEmpty()) {
|
||||
taskMapper.updateClaimed(updateClaimedTaskIds, claimedReference);
|
||||
}
|
||||
if (HistoryEventProducer.isHistoryEnabled()) {
|
||||
createTasksCompletedEvents(taskSummaryList);
|
||||
}
|
||||
|
@ -1741,7 +1817,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
|
||||
for (Map.Entry<String, String> entry : customFieldsToUpdate.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (!ALLOWED_KEYS.contains(key)) {
|
||||
if (!ALLOWED_CUSTOM_KEYS.contains(key)) {
|
||||
throw new InvalidArgumentException(
|
||||
"The customFieldsToUpdate argument to updateTasks contains invalid key " + key);
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ class CompleteTaskAccTest extends AbstractAccTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_BulkUpdateWithNullList() {
|
||||
void should_ThrowException_When_BulkCompleteWithNullList() {
|
||||
assertThatThrownBy(() -> TASK_SERVICE.completeTasks(null))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
}
|
||||
|
@ -320,16 +320,20 @@ class CompleteTaskAccTest extends AbstractAccTest {
|
|||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
|
||||
Task completedTask1 = TASK_SERVICE.getTask(id1);
|
||||
assertThat(completedTask1.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask1.getCompleted())
|
||||
.isEqualTo(completedTask1.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask1.getOwner()).isEqualTo("user-1-2");
|
||||
|
||||
Task completedTask2 = TASK_SERVICE.getTask(id2);
|
||||
assertThat(completedTask2.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask2.getCompleted())
|
||||
.isEqualTo(completedTask2.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask2.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
|
@ -343,11 +347,12 @@ class CompleteTaskAccTest extends AbstractAccTest {
|
|||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
Task completedTask2 = TASK_SERVICE.getTask(validId);
|
||||
assertThat(completedTask2.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask2.getCompleted())
|
||||
.isEqualTo(completedTask2.getModified())
|
||||
Task completedTask = TASK_SERVICE.getTask(validId);
|
||||
assertThat(completedTask.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask.getCompleted())
|
||||
.isEqualTo(completedTask.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
|
@ -370,23 +375,54 @@ class CompleteTaskAccTest extends AbstractAccTest {
|
|||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_AddErrorForTaskWhichIsNotClaimed_When_BulkCompletingTasks() throws Exception {
|
||||
String id1 = "TKI:000000000000000000000000000000000033"; // task is not claimed
|
||||
String id2 = "TKI:000000000000000000000000000000000036"; // task is completed
|
||||
String id3 = "TKI:300000000000000000000000000000000000"; // task is canceled
|
||||
String id4 = "TKI:300000000000000000000000000000000010"; // task is terminated
|
||||
List<String> taskIdList = Arrays.asList(id1, id2, id3, id4);
|
||||
String id = "TKI:000000000000000000000000000000000025"; // task is not claimed
|
||||
List<String> taskIdList = Collections.singletonList(id);
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
assertThat(results.getFailedIds()).containsExactlyInAnyOrder(id1, id2, id3, id4);
|
||||
assertThat(results.getErrorForId(id1)).isInstanceOf(InvalidStateException.class);
|
||||
assertThat(results.getFailedIds()).containsExactlyInAnyOrder(id);
|
||||
assertThat(results.getErrorMap().values()).hasOnlyElementsOfType(InvalidStateException.class);
|
||||
assertThat(results.getErrorForId(id))
|
||||
.hasMessage("Task with Id %s has to be claimed before.", id);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_AddErrorForTasksInEndState_When_BulkCompletingTasks() throws Exception {
|
||||
String id1 = "TKI:300000000000000000000000000000000000"; // task is canceled
|
||||
String id2 = "TKI:300000000000000000000000000000000010"; // task is terminated
|
||||
List<String> taskIdList = Arrays.asList(id1, id2);
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
assertThat(results.getFailedIds()).containsExactlyInAnyOrder(id1, id2);
|
||||
assertThat(results.getErrorMap().values()).hasOnlyElementsOfType(InvalidStateException.class);
|
||||
assertThat(results.getErrorForId(id1))
|
||||
.hasMessage("Cannot complete task %s because it is in state CANCELLED.", id1);
|
||||
assertThat(results.getErrorForId(id2))
|
||||
.hasMessage("Cannot complete task %s because it is in state TERMINATED.", id2);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_DoNothingForCompletedTask_When_BulkCompletingTasks() throws Exception {
|
||||
String id = "TKI:000000000000000000000000000000000036"; // task is completed
|
||||
List<String> taskIdList = Collections.singletonList(id);
|
||||
|
||||
Task before = TASK_SERVICE.getTask(id);
|
||||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
Task after = TASK_SERVICE.getTask(id);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
assertThat(before).isEqualTo(after);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2", groups = "group-1")
|
||||
@Test
|
||||
void should_AddErrorForTaskIfOwnerDoesNotMach_When_BulkCompletingTasks() throws Exception {
|
||||
String id1 = "TKI:000000000000000000000000000000000002";
|
||||
String id1 = "TKI:000000000000000000000000000000000066";
|
||||
List<String> taskIdList = Collections.singletonList(id1);
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results = TASK_SERVICE.completeTasks(taskIdList);
|
||||
|
@ -395,4 +431,152 @@ class CompleteTaskAccTest extends AbstractAccTest {
|
|||
assertThat(results.getFailedIds()).containsExactlyInAnyOrder(id1);
|
||||
assertThat(results.getErrorForId(id1)).isInstanceOf(InvalidOwnerException.class);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_CompleteAllTasks_When_BulkForceCompletingTasks() throws Exception {
|
||||
String id1 = "TKI:000000000000000000000000000000000026";
|
||||
String id2 = "TKI:000000000000000000000000000000000027";
|
||||
List<String> taskIdList = Arrays.asList(id1, id2);
|
||||
|
||||
Instant beforeBulkComplete = Instant.now();
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
|
||||
Task completedTask1 = TASK_SERVICE.getTask(id1);
|
||||
assertThat(completedTask1.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask1.getCompleted())
|
||||
.isEqualTo(completedTask1.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask1.getOwner()).isEqualTo("user-1-2");
|
||||
|
||||
Task completedTask2 = TASK_SERVICE.getTask(id2);
|
||||
assertThat(completedTask2.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask2.getCompleted())
|
||||
.isEqualTo(completedTask2.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask2.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_CompleteValidTasksEvenIfErrorsExist_When_BulkForceCompletingTasks() throws Exception {
|
||||
String invalid = "invalid-id";
|
||||
String validId = "TKI:000000000000000000000000000000000028";
|
||||
List<String> taskIdList = Arrays.asList(invalid, validId);
|
||||
|
||||
Instant beforeBulkComplete = Instant.now();
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
Task completedTask = TASK_SERVICE.getTask(validId);
|
||||
assertThat(completedTask.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(completedTask.getCompleted())
|
||||
.isEqualTo(completedTask.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(completedTask.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_AddErrorsForInvalidTaskIds_When_BulkForceCompletingTasks() throws Exception {
|
||||
String invalid1 = "";
|
||||
String invalid2 = null;
|
||||
String invalid3 = "invalid-id";
|
||||
String notAuthorized = "TKI:000000000000000000000000000000000002";
|
||||
List<String> taskIdList = Arrays.asList(invalid1, invalid2, invalid3, notAuthorized);
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
assertThat(results.getFailedIds())
|
||||
.containsExactlyInAnyOrder(invalid1, invalid2, invalid3, notAuthorized);
|
||||
assertThat(results.getErrorMap().values()).hasOnlyElementsOfType(TaskNotFoundException.class);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_AddErrorForTasksInEndState_When_BulkForceCompletingTasks() throws Exception {
|
||||
String id1 = "TKI:300000000000000000000000000000000000"; // task is canceled
|
||||
String id2 = "TKI:300000000000000000000000000000000010"; // task is terminated
|
||||
List<String> taskIdList = Arrays.asList(id1, id2);
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isTrue();
|
||||
assertThat(results.getFailedIds()).containsExactlyInAnyOrder(id1, id2);
|
||||
assertThat(results.getErrorMap().values()).hasOnlyElementsOfType(InvalidStateException.class);
|
||||
assertThat(results.getErrorForId(id1))
|
||||
.hasMessage("Cannot complete task %s because it is in state CANCELLED.", id1);
|
||||
assertThat(results.getErrorForId(id2))
|
||||
.hasMessage("Cannot complete task %s because it is in state TERMINATED.", id2);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2")
|
||||
@Test
|
||||
void should_DoNothingForCompletedTask_When_BulkForceCompletingTasks() throws Exception {
|
||||
String id = "TKI:000000000000000000000000000000000036"; // task is completed
|
||||
List<String> taskIdList = Collections.singletonList(id);
|
||||
|
||||
Task before = TASK_SERVICE.getTask(id);
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
Task after = TASK_SERVICE.getTask(id);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
assertThat(before).isEqualTo(after);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2", groups = "group-1")
|
||||
@Test
|
||||
void should_CompleteTaskWhenAlreadyClaimedByDifferentUser_When_BulkForceCompletingTasks()
|
||||
throws Exception {
|
||||
String id = "TKI:000000000000000000000000000000000002";
|
||||
List<String> taskIdList = Collections.singletonList(id);
|
||||
|
||||
Task beforeClaim = TASK_SERVICE.getTask(id);
|
||||
assertThat(beforeClaim.getOwner()).isNotEqualTo("user-1-2");
|
||||
final Instant beforeBulkComplete = Instant.now();
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
Task afterClaim = TASK_SERVICE.getTask(id);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
assertThat(afterClaim.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(afterClaim.getClaimed()).isEqualTo(beforeClaim.getClaimed());
|
||||
assertThat(afterClaim.getCompleted())
|
||||
.isEqualTo(afterClaim.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(afterClaim.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-2", groups = "group-1")
|
||||
@Test
|
||||
void should_ClaimTaskWhenNotClaimed_When_BulkForceCompletingTasks() throws Exception {
|
||||
String id = "TKI:000000000000000000000000000000000033";
|
||||
List<String> taskIdList = Collections.singletonList(id);
|
||||
|
||||
Task task = TASK_SERVICE.getTask(id);
|
||||
assertThat(task.getState()).isSameAs(TaskState.READY);
|
||||
assertThat(task.getClaimed()).isNull();
|
||||
|
||||
final Instant beforeBulkComplete = Instant.now();
|
||||
|
||||
BulkOperationResults<String, TaskanaException> results =
|
||||
TASK_SERVICE.forceCompleteTasks(taskIdList);
|
||||
|
||||
assertThat(results.containsErrors()).isFalse();
|
||||
task = TASK_SERVICE.getTask(id);
|
||||
assertThat(task.getState()).isEqualTo(TaskState.COMPLETED);
|
||||
assertThat(task.getCompleted())
|
||||
.isEqualTo(task.getClaimed())
|
||||
.isEqualTo(task.getModified())
|
||||
.isAfter(beforeBulkComplete);
|
||||
assertThat(task.getOwner()).isEqualTo("user-1-2");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue