TSK-1143 UpdateTask planned - comments from Holger

This commit is contained in:
BerndBreier 2020-03-09 12:02:52 +01:00 committed by Holger Hagen
parent 1291287419
commit 7deb925411
10 changed files with 272 additions and 147 deletions

View File

@ -479,8 +479,8 @@ public interface TaskService {
/**
* Sets the planned property on a list of tasks. Only tasks in state READY and CLAIMED will be
* affected by this method. On each task, the corresponding due date is set according to the due
* dates in the classification() of the task and the task's attachments.
* affected by this method. On each task, the corresponding due date is set according to the
* shortest service level in the classifications of the task and the task's attachments.
*
* @param planned the new 'PLANNED" property of the tasks
* @param taskIds the IDs of the tasks on which the new planned property is to be set.

View File

@ -1,10 +1,14 @@
package pro.taskana.task.api.models;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
/** ObjectReference entity. */
public class ObjectReference {
private static final Logger LOGGER = LoggerFactory.getLogger(ObjectReference.class);
private String id;
private String company;
private String system;
@ -60,6 +64,33 @@ public class ObjectReference {
this.value = value;
}
public static void validate(ObjectReference objectReference, String objRefType, String objName)
throws InvalidArgumentException {
LOGGER.debug("entry to validateObjectReference()");
// check that all values in the ObjectReference are set correctly
if (objectReference == null) {
throw new InvalidArgumentException(
String.format("ObectReferenc %s of %s must not be null.", objRefType, objName));
} else if (objectReference.getCompany() == null || objectReference.getCompany().length() == 0) {
throw new InvalidArgumentException(
String.format("Company of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getSystem() == null || objectReference.getSystem().length() == 0) {
throw new InvalidArgumentException(
String.format("System of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getSystemInstance() == null
|| objectReference.getSystemInstance().length() == 0) {
throw new InvalidArgumentException(
String.format("SystemInstance of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getType() == null || objectReference.getType().length() == 0) {
throw new InvalidArgumentException(
String.format("Type of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getValue() == null || objectReference.getValue().length() == 0) {
throw new InvalidArgumentException(
String.format("Value of %s of %s must not be empty", objRefType, objName));
}
LOGGER.debug("exit from validateObjectReference()");
}
@Override
public int hashCode() {
return Objects.hash(id, company, system, systemInstance, type, value);

View File

@ -1,6 +1,5 @@
package pro.taskana.task.internal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -37,9 +36,8 @@ public class AttachmentHandler {
this.classificationService = classificationService;
}
public List<Attachment> augmentAttachmentsByClassification(
List<AttachmentImpl> attachmentImpls,
BulkOperationResults<String, Exception> bulkLog) {
List<Attachment> augmentAttachmentsByClassification(
List<AttachmentImpl> attachmentImpls, BulkOperationResults<String, Exception> bulkLog) {
LOGGER.debug("entry to augmentAttachmentsByClassification()");
List<Attachment> result = new ArrayList<>();
if (attachmentImpls == null || attachmentImpls.isEmpty()) {
@ -148,18 +146,15 @@ public class AttachmentHandler {
}
}
void insertNewAttachmentsOnTaskCreation(TaskImpl task, Instant now)
void insertNewAttachmentsOnTaskCreation(TaskImpl task)
throws InvalidArgumentException {
List<Attachment> attachments = task.getAttachments();
if (attachments != null) {
for (Attachment attachment : attachments) {
AttachmentImpl attachmentImpl = (AttachmentImpl) attachment;
attachmentImpl.setId(IdGenerator.generateWithPrefix(ID_PREFIX_ATTACHMENT));
attachmentImpl.setTaskId(task.getId());
attachmentImpl.setCreated(now);
attachmentImpl.setModified(now);
initAttachment(attachmentImpl, task);
ObjectReference objRef = attachmentImpl.getObjectReference();
validateObjectReference(objRef, "ObjectReference", "Attachment");
ObjectReference.validate(objRef, "ObjectReference", "Attachment");
attachmentMapper.insert(attachmentImpl);
}
}
@ -210,11 +205,9 @@ public class AttachmentHandler {
attachmentImpl);
} catch (PersistenceException e) {
throw new AttachmentPersistenceException(
"Cannot insert the Attachement "
+ attachmentImpl.getId()
+ " for Task "
+ newTaskImpl.getId()
+ " because it already exists.",
String.format(
"Cannot insert the Attachement %s for Task %s because it already exists.",
attachmentImpl.getId(), newTaskImpl.getId()),
e.getCause());
}
LOGGER.debug("exit from insertNewAttachmentOnTaskUpdate(), returning");
@ -226,7 +219,7 @@ public class AttachmentHandler {
attachment.setId(IdGenerator.generateWithPrefix(ID_PREFIX_ATTACHMENT));
}
if (attachment.getCreated() == null) {
attachment.setCreated(Instant.now());
attachment.setCreated(newTask.getModified());
}
if (attachment.getModified() == null) {
attachment.setModified(attachment.getCreated());
@ -237,28 +230,4 @@ public class AttachmentHandler {
LOGGER.debug("exit from initAttachment()");
}
void validateObjectReference(ObjectReference objRef, String objRefType, String objName)
throws InvalidArgumentException {
LOGGER.debug("entry to validateObjectReference()");
// check that all values in the ObjectReference are set correctly
if (objRef == null) {
throw new InvalidArgumentException(objRefType + " of " + objName + " must not be null");
} else if (objRef.getCompany() == null || objRef.getCompany().length() == 0) {
throw new InvalidArgumentException(
String.format("Company of %s of %s must not be empty", objRefType, objName));
} else if (objRef.getSystem() == null || objRef.getSystem().length() == 0) {
throw new InvalidArgumentException(
String.format("System of %s of %s must not be empty", objRefType, objName));
} else if (objRef.getSystemInstance() == null || objRef.getSystemInstance().length() == 0) {
throw new InvalidArgumentException(
String.format("SystemInstance of %s of %s must not be empty", objRefType, objName));
} else if (objRef.getType() == null || objRef.getType().length() == 0) {
throw new InvalidArgumentException(
String.format("Type of %s of %s must not be empty", objRefType, objName));
} else if (objRef.getValue() == null || objRef.getValue().length() == 0) {
throw new InvalidArgumentException(
String.format("Value of %s of %s must not be empty", objRefType, objName));
}
LOGGER.debug("exit from validateObjectReference()");
}
}

View File

@ -85,7 +85,7 @@ public interface AttachmentMapper {
@Result(property = "channel", column = "CHANNEL"),
@Result(property = "received", column = "RECEIVED")
})
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(@Param("taskIds") String[] taskIds);
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(@Param("taskIds") List<String> taskIds);
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
void deleteAttachment(@Param("attachmentId") String attachmentId);

View File

@ -83,10 +83,10 @@ class ServiceLevelHandler {
findAllInvolvedClassifications(existingTasksAuthorizedFor, attachments);
List<ClassificationWithServiceLevelResolved> allInvolvedClassificationsWithDuration =
resolveDurationsInClassifications(allInvolvedClassifications);
Map<Duration, List<TaskDuration>> tasksPerDuration =
getTasksPerDuration(
Map<Duration, List<String>> durationToTaskIdsMap =
getDurationToTaskIdsMap(
existingTasksAuthorizedFor, attachments, allInvolvedClassificationsWithDuration);
BulkLog updateResult = updatePlannedPropertyOfAffectedTasks(planned, tasksPerDuration);
BulkLog updateResult = updatePlannedPropertyOfAffectedTasks(planned, durationToTaskIdsMap);
bulkLog.addAllErrors(updateResult);
return bulkLog;
@ -214,21 +214,31 @@ class ServiceLevelHandler {
private TaskImpl updatePlannedDueOnTaskUpdate(
TaskImpl newTaskImpl, TaskImpl oldTaskImpl, DurationPrioHolder durationPrioHolder)
throws InvalidArgumentException {
// case 1: no change of planned / due, but change of an attachment or classification
if (newTaskImpl.getDue().equals(oldTaskImpl.getDue())
&& newTaskImpl.getPlanned().equals(oldTaskImpl.getPlanned())) {
if (newTaskImpl.getPlanned() == null && newTaskImpl.getDue() == null) {
newTaskImpl.setPlanned(oldTaskImpl.getPlanned());
}
// case 1: no change of planned / due, but potentially change of an attachment or classification
if (oldTaskImpl.getDue().equals(newTaskImpl.getDue())
&& oldTaskImpl.getPlanned().equals(newTaskImpl.getPlanned())) {
newTaskImpl.setDue(newPlannedDueInstant(newTaskImpl, durationPrioHolder.getDuration(), true));
} else if ((newTaskImpl.getDue().equals(oldTaskImpl.getDue()))) {
} else if (oldTaskImpl.getDue().equals(newTaskImpl.getDue())
&& newTaskImpl.getPlanned() != null) {
// case 2: planned was changed
newTaskImpl.setDue(newPlannedDueInstant(newTaskImpl, durationPrioHolder.getDuration(), true));
} else { // case 3: due was changed
Instant planned = newPlannedDueInstant(newTaskImpl, durationPrioHolder.getDuration(), false);
if (newTaskImpl.getPlanned() != null && !planned.equals(newTaskImpl.getPlanned())) {
throw new InvalidArgumentException(
"Cannot update a task with given planned "
+ "and due date not matching the service level");
if (newTaskImpl.getDue() == null) {
newTaskImpl.setDue(
newPlannedDueInstant(newTaskImpl, durationPrioHolder.getDuration(), true));
} else {
Instant planned =
newPlannedDueInstant(newTaskImpl, durationPrioHolder.getDuration(), false);
if (newTaskImpl.getPlanned() != null && !planned.equals(newTaskImpl.getPlanned())) {
throw new InvalidArgumentException(
"Cannot update a task with given planned "
+ "and due date not matching the service level");
}
newTaskImpl.setPlanned(planned);
}
newTaskImpl.setPlanned(planned);
}
return newTaskImpl;
}
@ -250,17 +260,16 @@ class ServiceLevelHandler {
}
private BulkLog updatePlannedPropertyOfAffectedTasks(
Instant planned, Map<Duration, List<TaskDuration>> tasksPerDuration) {
Instant planned, Map<Duration, List<String>> durationToTaskIdsMap) {
BulkLog bulkLog = new BulkLog();
TaskImpl referenceTask = new TaskImpl();
referenceTask.setPlanned(planned);
for (Map.Entry<Duration, List<TaskDuration>> entry : tasksPerDuration.entrySet()) {
List<String> taskIdsToUpdate =
entry.getValue().stream().map(TaskDuration::getTaskId).collect(Collectors.toList());
referenceTask.setModified(Instant.now());
for (Map.Entry<Duration, List<String>> entry : durationToTaskIdsMap.entrySet()) {
List<String> taskIdsToUpdate = entry.getValue();
long days = converter.convertWorkingDaysToDays(planned, entry.getKey().toDays());
Instant due = planned.plus(Duration.ofDays(days));
referenceTask.setDue(due);
referenceTask.setModified(Instant.now());
long numTasksUpdated = taskMapper.updateTaskDueDates(taskIdsToUpdate, referenceTask);
if (numTasksUpdated != taskIdsToUpdate.size()) {
BulkLog checkResult =
@ -300,17 +309,17 @@ class ServiceLevelHandler {
return bulkLog;
}
private Map<Duration, List<TaskDuration>> getTasksPerDuration(
private Map<Duration, List<String>> getDurationToTaskIdsMap(
List<MinimalTaskSummary> minimalTaskSummariesAuthorizedFor,
List<AttachmentSummaryImpl> attachments,
List<ClassificationWithServiceLevelResolved>
allInvolvedClassificationsWithServiceLevelResolved) {
List<TaskDuration> resultingTaskDurations = new ArrayList<>();
// Map taskId -> Set Of involved classification Ids
Map<String, Set<String>> classificationIdsPerTaskId =
Map<String, Set<String>> taskIdToClassificationIdsMap =
findAllClassificationIdsPerTask(minimalTaskSummariesAuthorizedFor, attachments);
// Map classificationId -> Duration
Map<String, Duration> durationPerClassificationId =
Map<String, Duration> classificationIdToDurationMap =
allInvolvedClassificationsWithServiceLevelResolved.stream()
.collect(
Collectors.toMap(
@ -318,15 +327,19 @@ class ServiceLevelHandler {
ClassificationWithServiceLevelResolved::getDurationFromClassification));
for (MinimalTaskSummary task : minimalTaskSummariesAuthorizedFor) {
Duration duration =
determineMinimalDurationForTasks(
classificationIdsPerTaskId.get(task.getTaskId()), durationPerClassificationId);
determineMinimalDurationForATask(
taskIdToClassificationIdsMap.get(task.getTaskId()), classificationIdToDurationMap);
TaskDuration taskDuration = new TaskDuration(task.getTaskId(), duration);
resultingTaskDurations.add(taskDuration);
}
return resultingTaskDurations.stream().collect(groupingBy(TaskDuration::getDuration));
return resultingTaskDurations.stream()
.collect(
groupingBy(
TaskDuration::getDuration,
Collectors.mapping(TaskDuration::getTaskId, Collectors.toList())));
}
private Duration determineMinimalDurationForTasks(
private Duration determineMinimalDurationForATask(
Set<String> classificationIds, Map<String, Duration> durationPerClassificationId) {
Duration result = MAX_DURATION;
for (String classificationId : classificationIds) {
@ -341,7 +354,7 @@ class ServiceLevelHandler {
// returns a map <taskId -> Set of ClassificationIds>
private Map<String, Set<String>> findAllClassificationIdsPerTask(
List<MinimalTaskSummary> minimalTaskSummaries, List<AttachmentSummaryImpl> attachments) {
Map<String, Set<String>> result = new HashMap<>();
Map<String, Set<String>> resultingTaskIdToClassificationIdsMap = new HashMap<>();
for (MinimalTaskSummary task : minimalTaskSummaries) {
Set<String> classificationIds =
attachments.stream()
@ -350,9 +363,9 @@ class ServiceLevelHandler {
.map(ClassificationSummary::getId)
.collect(Collectors.toSet());
classificationIds.add(task.getClassificationId());
result.put(task.getTaskId(), classificationIds);
resultingTaskIdToClassificationIdsMap.put(task.getTaskId(), classificationIds);
}
return result;
return resultingTaskIdToClassificationIdsMap;
}
private List<ClassificationWithServiceLevelResolved> resolveDurationsInClassifications(
@ -374,12 +387,9 @@ class ServiceLevelHandler {
.map(MinimalTaskSummary::getTaskId)
.collect(Collectors.toList());
String[] taskIdsAuthorizedForArray = new String[existingTaskIdsAuthorizedFor.size()];
taskIdsAuthorizedForArray = existingTaskIdsAuthorizedFor.toArray(taskIdsAuthorizedForArray);
return existingTaskIdsAuthorizedFor.isEmpty()
? new ArrayList<>()
: attachmentMapper.findAttachmentSummariesByTaskIds(taskIdsAuthorizedForArray);
: attachmentMapper.findAttachmentSummariesByTaskIds(existingTaskIdsAuthorizedFor);
}
private List<ClassificationSummary> findAllInvolvedClassifications(

View File

@ -215,8 +215,7 @@ public class TaskServiceImpl implements TaskService {
Classification classification =
this.classificationService.getClassification(classificationKey, workbasket.getDomain());
task.setClassificationSummary(classification.asSummary());
attachmentHandler.validateObjectReference(
task.getPrimaryObjRef(), "primary ObjectReference", TASK);
ObjectReference.validate(task.getPrimaryObjRef(), "primary ObjectReference", TASK);
standardSettings(task, classification);
setCallbackStateOnTaskCreation(task);
try {
@ -410,6 +409,10 @@ public class TaskServiceImpl implements TaskService {
try {
taskanaEngine.openConnection();
oldTaskImpl = (TaskImpl) getTask(newTaskImpl.getId());
newTaskImpl = checkConcurrencyAndSetModified(newTaskImpl, oldTaskImpl);
attachmentHandler.insertAndDeleteAttachmentsOnTaskUpdate(newTaskImpl, oldTaskImpl);
standardUpdateActions(oldTaskImpl, newTaskImpl);
taskMapper.update(newTaskImpl);
@ -522,8 +525,7 @@ public class TaskServiceImpl implements TaskService {
selectionCriteria,
customFieldsToUpdate);
}
attachmentHandler.validateObjectReference(
selectionCriteria, "ObjectReference", "updateTasks call");
ObjectReference.validate(selectionCriteria, "ObjectReference", "updateTasks call");
validateCustomFields(customFieldsToUpdate);
CustomPropertySelector fieldSelector = new CustomPropertySelector();
TaskImpl updated = initUpdatedTask(customFieldsToUpdate, fieldSelector);
@ -840,16 +842,16 @@ public class TaskServiceImpl implements TaskService {
return result;
}
String[] taskIdArray =
taskSummaries.stream().map(TaskSummaryImpl::getId).distinct().toArray(String[]::new);
List<String> taskIds =
taskSummaries.stream().map(TaskSummaryImpl::getId).distinct().collect(Collectors.toList());
if (taskIdArray.length == 0) {
taskIdArray = null;
if (taskIds.isEmpty()) {
taskIds = null;
}
LOGGER.debug(
"augmentTaskSummariesByContainedSummaries() about to query for attachmentSummaries ");
List<AttachmentSummaryImpl> attachmentSummaries =
attachmentMapper.findAttachmentSummariesByTaskIds(taskIdArray);
attachmentMapper.findAttachmentSummariesByTaskIds(taskIds);
List<ClassificationSummary> classifications =
findClassificationsForTasksAndAttachments(taskSummaries, attachmentSummaries);
@ -862,23 +864,22 @@ public class TaskServiceImpl implements TaskService {
return result;
}
private Duration calculateDuration(
PrioDurationHolder prioDurationFromAttachments,
ClassificationSummary newClassificationSummary) {
if (newClassificationSummary.getServiceLevel() == null) {
return null;
private TaskImpl checkConcurrencyAndSetModified(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)
throws ConcurrencyException {
// TODO: not safe to rely only on different timestamps.
// With fast execution below 1ms there will be no concurrencyException
if (oldTaskImpl.getModified() != null
&& !oldTaskImpl.getModified().equals(newTaskImpl.getModified())
|| oldTaskImpl.getClaimed() != null
&& !oldTaskImpl.getClaimed().equals(newTaskImpl.getClaimed())
|| oldTaskImpl.getState() != null
&& !oldTaskImpl.getState().equals(newTaskImpl.getState())) {
throw new ConcurrencyException("The task has already been updated by another user");
}
Duration minDuration = prioDurationFromAttachments.getLeft();
Duration durationFromClassification =
Duration.parse(newClassificationSummary.getServiceLevel());
if (minDuration != null) {
if (minDuration.compareTo(durationFromClassification) > 0) {
minDuration = durationFromClassification;
}
} else {
minDuration = durationFromClassification;
}
return minDuration;
newTaskImpl.setModified(Instant.now());
return newTaskImpl;
}
private BulkOperationResults<String, TaskanaException> addExceptionsForTasksWhoseOwnerWasNotSet(
@ -1190,7 +1191,7 @@ public class TaskServiceImpl implements TaskService {
if (task.getDescription() == null && classification != null) {
task.setDescription(classification.getDescription());
}
attachmentHandler.insertNewAttachmentsOnTaskCreation(task, now);
attachmentHandler.insertNewAttachmentsOnTaskCreation(task);
LOGGER.debug("exit from standardSettings()");
}
@ -1205,8 +1206,9 @@ public class TaskServiceImpl implements TaskService {
} catch (Exception e) {
LOGGER.warn(
"Attempted to determine callback state from {} and caught exception", value, e);
throw new InvalidArgumentException(
"Attempted to set callback state for task " + task.getId(), e);
String.format("Attempted to set callback state for task %s.", task.getId()), e);
}
}
}
@ -1562,20 +1564,8 @@ public class TaskServiceImpl implements TaskService {
}
private void standardUpdateActions(TaskImpl oldTaskImpl, TaskImpl newTaskImpl)
throws InvalidArgumentException, ConcurrencyException, InvalidStateException,
AttachmentPersistenceException, ClassificationNotFoundException {
attachmentHandler.validateObjectReference(
newTaskImpl.getPrimaryObjRef(), "primary ObjectReference", TASK);
// TODO: not safe to rely only on different timestamps.
// With fast execution below 1ms there will be no concurrencyException
if (oldTaskImpl.getModified() != null
&& !oldTaskImpl.getModified().equals(newTaskImpl.getModified())
|| oldTaskImpl.getClaimed() != null
&& !oldTaskImpl.getClaimed().equals(newTaskImpl.getClaimed())
|| oldTaskImpl.getState() != null
&& !oldTaskImpl.getState().equals(newTaskImpl.getState())) {
throw new ConcurrencyException("The task has already been updated by another user");
}
throws InvalidArgumentException, InvalidStateException, ClassificationNotFoundException {
ObjectReference.validate(newTaskImpl.getPrimaryObjRef(), "primary ObjectReference", TASK);
if (oldTaskImpl.getExternalId() == null
|| !(oldTaskImpl.getExternalId().equals(newTaskImpl.getExternalId()))) {
@ -1589,16 +1579,6 @@ public class TaskServiceImpl implements TaskService {
"A task's Workbasket cannot be changed via update of the task");
}
if (newTaskImpl.getPlanned() == null) {
newTaskImpl.setPlanned(oldTaskImpl.getPlanned());
}
if (newTaskImpl.getClassificationSummary() == null) {
newTaskImpl.setClassificationSummary(oldTaskImpl.getClassificationSummary());
}
attachmentHandler.insertAndDeleteAttachmentsOnTaskUpdate(newTaskImpl, oldTaskImpl);
updateClassificationSummary(newTaskImpl, oldTaskImpl);
newTaskImpl = serviceLevelHandler.updatePrioPlannedDueOfTask(newTaskImpl, oldTaskImpl, false);
@ -1614,8 +1594,6 @@ public class TaskServiceImpl implements TaskService {
throw new InvalidStateException(
String.format(TASK_WITH_ID_IS_NOT_READY, oldTaskImpl.getId(), oldTaskImpl.getState()));
}
newTaskImpl.setModified(Instant.now());
}
private void updateClassificationSummary(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)

View File

@ -57,10 +57,11 @@ public class UpdateObjectsUseUtcTimeStampsAccTest extends AbstractAccTest {
InvalidStateException {
TaskService taskService = taskanaEngine.getTaskService();
Task task = taskService.getTask("TKI:000000000000000000000000000000000000");
Instant now = Instant.now();
TaskImpl ti = (TaskImpl) task;
task.setPlanned(Instant.now().plus(Duration.ofHours(17)));
task.setDue(Instant.now().plus(Duration.ofHours(41)));
ti.setCompleted(Instant.now().plus(Duration.ofHours(40)));
task.setPlanned(now.plus(Duration.ofHours(17)));
task.setDue(now.plus(Duration.ofHours(41))); // SL = 1D -> Due must be planned + 24 h
ti.setCompleted(now.plus(Duration.ofHours(27)));
TimeZone originalZone = TimeZone.getDefault();
Task updatedTask = taskService.updateTask(task);

View File

@ -1,6 +1,7 @@
package acceptance.task;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import java.sql.SQLException;
@ -35,7 +36,7 @@ import pro.taskana.task.api.models.TaskSummary;
/** Acceptance test for all "create task" scenarios. */
@ExtendWith(JaasExtension.class)
@SuppressWarnings({"checkstyle:LineLength"})
public class SetPlannedAccTest extends AbstractAccTest {
public class ServiceLevelPriorityAccTest extends AbstractAccTest {
private TaskService taskService;
@BeforeEach
@ -260,6 +261,130 @@ public class SetPlannedAccTest extends AbstractAccTest {
assertThat(results.containsErrors()).isFalse();
}
// +-----------------------------------------+------------------------------------------+------+
// |TKI:000000000000000000000000000000000002 | CLI:100000000000000000000000000000000016 | P1D |
// |TAI:000000000000000000000000000000000003 | CLI:000000000000000000000000000000000004 | P4D |
// |TAI:000000000000000000000000000000000004 | CLI:000000000000000000000000000000000005 | P5D |
// |TAI:000000000000000000000000000000000005 | CLI:000000000000000000000000000000000006 | P5D |
// |TAI:000000000000000000000000000000000006 | CLI:000000000000000000000000000000000007 | P6D |
// |TAI:000000000000000000000000000000000007 | CLI:100000000000000000000000000000000008 | P1D |
// +-----------------------------------------+------------------------------------------+------+
@WithAccessId(
userName = "admin",
groupNames = {"group_2"})
@Test
void testSetPlannedPropertyOnSingleTaskWithBulkUpdate()
throws NotAuthorizedException, TaskNotFoundException, InvalidArgumentException,
ConcurrencyException, InvalidStateException, ClassificationNotFoundException,
AttachmentPersistenceException {
String taskId = "TKI:000000000000000000000000000000000002";
Instant planned = getInstant("2020-05-03T07:00:00");
// test bulk operation setPlanned...
BulkOperationResults<String, TaskanaException> results =
taskanaEngine.getTaskService().setPlannedPropertyOfTasks(planned, Arrays.asList(taskId));
Task task = taskService.getTask(taskId);
assertThat(results.containsErrors()).isFalse();
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize();
long days = converter.convertWorkingDaysToDays(task.getPlanned(), 1);
assertThat(task.getDue()).isEqualTo(planned.plus(Duration.ofDays(days)));
}
@WithAccessId(
userName = "admin",
groupNames = {"group_2"})
@Test
void testSetPlannedPropertyOnSingleTaskWitHTaskUpdate()
throws NotAuthorizedException, TaskNotFoundException, InvalidArgumentException,
ConcurrencyException, InvalidStateException, ClassificationNotFoundException,
AttachmentPersistenceException {
String taskId = "TKI:000000000000000000000000000000000002";
Instant planned = getInstant("2020-05-03T07:00:00");
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize();
Task task = taskService.getTask(taskId);
// test update of planned date via updateTask()
task.setPlanned(task.getPlanned().plus(Duration.ofDays(3)));
task = taskService.updateTask(task);
long days = converter.convertWorkingDaysToDays(task.getPlanned(), 1);
assertThat(task.getDue()).isEqualTo(task.getPlanned().plus(Duration.ofDays(days)));
}
@WithAccessId(
userName = "admin",
groupNames = {"group_2"})
@Test
void testSetDuePropertyOnSingleTask()
throws NotAuthorizedException, TaskNotFoundException, InvalidArgumentException,
ConcurrencyException, InvalidStateException, ClassificationNotFoundException,
AttachmentPersistenceException {
String taskId = "TKI:000000000000000000000000000000000002";
Instant planned = getInstant("2020-05-03T07:00:00");
Task task = taskService.getTask(taskId);
// test update of due that fails
task.setDue(planned.plus(Duration.ofDays(8)));
Task finalTask = task;
assertThatThrownBy(
() -> {
taskService.updateTask(finalTask);
})
.isInstanceOf(InvalidArgumentException.class);
// update due and planned as expected.
task = taskService.getTask(taskId);
task.setDue(planned.plus(Duration.ofDays(3)));
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize();
long days = converter.convertWorkingDaysToDays(task.getDue(), -1);
task.setPlanned(task.getDue().plus(Duration.ofDays(-1)));
task = taskService.updateTask(task);
days = converter.convertWorkingDaysToDays(task.getDue(), -1);
assertThat(task.getPlanned()).isEqualTo(task.getDue().plus(Duration.ofDays(days)));
// update due and planned as expected.
task = taskService.getTask(taskId);
task.setDue(planned.plus(Duration.ofDays(3)));
task.setPlanned(null);
task = taskService.updateTask(task);
days = converter.convertWorkingDaysToDays(task.getDue(), -1);
assertThat(task.getPlanned()).isEqualTo(task.getDue().plus(Duration.ofDays(days)));
}
@WithAccessId(
userName = "admin",
groupNames = {"group_2"})
@Test
void testSetPlannedPropertyOnSingleTaskUpdateWithNulls()
throws NotAuthorizedException, TaskNotFoundException, InvalidArgumentException,
ConcurrencyException, InvalidStateException, ClassificationNotFoundException,
AttachmentPersistenceException {
String taskId = "TKI:000000000000000000000000000000000002";
final Instant planned = getInstant("2020-05-03T07:00:00");
Task task = taskService.getTask(taskId);
task.setPlanned(null);
task = taskService.updateTask(task);
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize();
long days = converter.convertWorkingDaysToDays(task.getPlanned(), 1);
assertThat(task.getDue()).isEqualTo(task.getPlanned().plus(Duration.ofDays(days)));
task.setDue(null);
task = taskService.updateTask(task);
days = converter.convertWorkingDaysToDays(task.getPlanned(), 1);
assertThat(task.getDue()).isEqualTo(task.getPlanned().plus(Duration.ofDays(days)));
task.setPlanned(planned.plus(Duration.ofDays(13)));
task.setDue(null);
task = taskService.updateTask(task);
days = converter.convertWorkingDaysToDays(task.getPlanned(), 1);
assertThat(task.getDue()).isEqualTo(task.getPlanned().plus(Duration.ofDays(days)));
task.setDue(planned.plus(Duration.ofDays(13)));
task.setPlanned(null);
task = taskService.updateTask(task);
days = converter.convertWorkingDaysToDays(task.getDue(), -1);
assertThat(task.getDue()).isEqualTo(planned.plus(Duration.ofDays(13)));
assertThat(task.getPlanned()).isEqualTo(task.getDue().plus(Duration.ofDays(days)));
}
@WithAccessId(
userName = "admin",
groupNames = {"group_2"})

View File

@ -83,26 +83,32 @@ class UpdateTaskAccTest extends AbstractAccTest {
assertThatThrownBy(() -> taskService.updateTask(task))
.isInstanceOf(InvalidArgumentException.class);
task.setPrimaryObjRef(
Task task1 = taskService.getTask("TKI:000000000000000000000000000000000000");
task1.setPrimaryObjRef(
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", null));
assertThatThrownBy(() -> taskService.updateTask(task))
assertThatThrownBy(() -> taskService.updateTask(task1))
.isInstanceOf(InvalidArgumentException.class);
task.setPrimaryObjRef(
Task task2 = taskService.getTask("TKI:000000000000000000000000000000000000");
task2.setPrimaryObjRef(
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", null, "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task))
assertThatThrownBy(() -> taskService.updateTask(task2))
.isInstanceOf(InvalidArgumentException.class);
task.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", null, "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task))
Task task3 = taskService.getTask("TKI:000000000000000000000000000000000000");
task3.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", null, "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task3))
.isInstanceOf(InvalidArgumentException.class);
task.setPrimaryObjRef(createObjectReference("COMPANY_A", null, "INSTANCE_A", "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task))
Task task4 = taskService.getTask("TKI:000000000000000000000000000000000000");
task4.setPrimaryObjRef(
createObjectReference("COMPANY_A", null, "INSTANCE_A", "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task4))
.isInstanceOf(InvalidArgumentException.class);
task.setPrimaryObjRef(createObjectReference(null, "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task))
Task task5 = taskService.getTask("TKI:000000000000000000000000000000000000");
task5.setPrimaryObjRef(createObjectReference(null, "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
assertThatThrownBy(() -> taskService.updateTask(task5))
.isInstanceOf(InvalidArgumentException.class);
}
@ -347,7 +353,6 @@ class UpdateTaskAccTest extends AbstractAccTest {
AttachmentPersistenceException {
TaskService taskService = taskanaEngine.getTaskService();
Task task = taskService.getTask("TKI:000000000000000000000000000000000030");
task.setPlanned(Instant.now());
task.setPlanned(getInstant("2020-04-21T07:00:00"));
task.setDue(getInstant("2020-04-21T10:00:00"));
assertThatThrownBy(() -> taskService.updateTask(task))

View File

@ -86,6 +86,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
equalTo("12345678901234567890123456789012345678901234567890"));
assertEquals(99, task.getPriority());
assertEquals(task.getDue(), task.getPlanned().plus(Duration.ofDays(1)));
task.getAttachments().forEach(at -> assertEquals(at.getModified(), task.getModified()));
}
@WithAccessId(
@ -109,6 +111,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
task = taskService.updateTask(task);
assertEquals(1, task.getAttachments().size());
task.getAttachments().forEach(at -> assertEquals(at.getModified(), task.getModified()));
}
@WithAccessId(
@ -327,7 +330,6 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertThat(task.getAttachments().size(), equalTo(attachmentCount));
assertThat(task.getAttachments().get(0).getChannel(), equalTo(newChannel));
assertEquals(999, task.getPriority());
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(Instant.now());
long calendarDays = converter.convertWorkingDaysToDays(task.getDue(), 1);
@ -377,6 +379,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
int custAttSize = att.getCustomAttributes().size();
if ("ROHRPOST".equals(channel)) {
rohrpostFound = true;
assertEquals(att.getModified(), task.getModified());
} else if ("E-MAIL".equals(channel)) {
emailFound = true;
} else {
@ -482,7 +485,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
task = taskService.updateTask(task);
assertThat(task.getAttachments().size(), equalTo(1));
assertThat(task.getAttachments().get(0).getChannel(), equalTo("DHL"));
task.getAttachments().forEach(at -> assertEquals(at.getModified(), task.getModified()));
// setup environment for 2nd version of replacement (list.add call)
task.getAttachments().add(attachment2);
task = taskService.updateTask(task);
@ -540,7 +543,9 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertNotNull(createdTask.getId());
assertThat(createdTask.getCreator(), equalTo(CurrentUserContext.getUserid()));
createdTask
.getAttachments()
.forEach(at -> assertEquals(at.getModified(), createdTask.getModified()));
Task readTask = taskService.getTask(createdTask.getId());
assertNotNull(readTask);
assertThat(readTask.getCreator(), equalTo(CurrentUserContext.getUserid()));
@ -597,6 +602,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
.findFirst()
.orElse(null);
assertNotNull(updatedAttachment);
assertEquals(updatedAttachment.getModified(),updatedTask.getModified());
assertEquals("TEST_VALUE", updatedAttachment.getCustomAttributes().get("TEST_KEY"));
}