TSK-1972: Task.dueDate is inclusive.

This commit is contained in:
Mustapha Zorgati 2023-03-10 15:25:20 +01:00
parent d33c16e790
commit fb11ff97b3
11 changed files with 338 additions and 130 deletions

View File

@ -619,7 +619,9 @@ class UpdateClassificationAccTest {
Task task = taskService.getTask(taskId);
Instant expDue =
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(serviceLevel));
workingTimeCalculator
.addWorkingTime(task.getPlanned(), Duration.ofDays(serviceLevel))
.minusMillis(1);
assertThat(task.getModified())
.describedAs("Task " + task.getId() + " has not been refreshed.")
.isAfter(before);

View File

@ -135,7 +135,7 @@ class ServiceLevelOfAllTasksAccTest {
assertThat(bulkLog.containsErrors()).isFalse();
List<TaskSummary> result =
taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list();
Instant expectedDue = Instant.parse("2020-05-06T07:00:00.000Z");
Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z");
assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue);
}
@ -162,7 +162,7 @@ class ServiceLevelOfAllTasksAccTest {
assertThat(bulkLog.containsErrors()).isFalse();
List<TaskSummary> result =
taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list();
Instant expectedDue = Instant.parse("2020-05-06T07:00:00.000Z");
Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z");
assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue);
}
@ -193,8 +193,8 @@ class ServiceLevelOfAllTasksAccTest {
assertThat(bulkLog.containsErrors()).isFalse();
List<TaskSummary> result =
taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list();
Instant expectedDueSmallServiceLevel = Instant.parse("2020-05-06T07:00:00.000Z");
Instant expectedDueGreatServiceLevel = Instant.parse("2020-05-13T07:00:00.000Z");
Instant expectedDueSmallServiceLevel = Instant.parse("2020-05-06T06:59:59.999Z");
Instant expectedDueGreatServiceLevel = Instant.parse("2020-05-13T06:59:59.999Z");
assertThat(result)
.extracting(TaskSummary::getDue)
.containsOnly(expectedDueSmallServiceLevel, expectedDueGreatServiceLevel);

View File

@ -0,0 +1,217 @@
package acceptance.task.servicelevel;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
import java.time.Instant;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.ObjectReference;
import pro.taskana.task.api.models.Task;
import pro.taskana.testapi.DefaultTestEntities;
import pro.taskana.testapi.TaskanaInject;
import pro.taskana.testapi.TaskanaIntegrationTest;
import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder;
import pro.taskana.testapi.security.WithAccessId;
import pro.taskana.workbasket.api.WorkbasketPermission;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.api.models.Workbasket;
@TaskanaIntegrationTest
class ServiceLevelCalculationAccTest {
private static final String TWO_HOURS = "PT2H";
private static final String ZERO_SECONDS = "PT0S";
@TaskanaInject TaskService taskService;
@TaskanaInject ClassificationService classificationService;
Workbasket workbasket;
ObjectReference primaryObjRef;
@WithAccessId(user = "businessadmin")
@BeforeEach
void before(WorkbasketService workbasketService) throws Exception {
workbasket = DefaultTestEntities.defaultTestWorkbasket().buildAndStore(workbasketService);
primaryObjRef = DefaultTestEntities.defaultTestObjectReference().build();
WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
.workbasketId(workbasket.getId())
.accessId("user-1-1")
.permission(WorkbasketPermission.OPEN)
.permission(WorkbasketPermission.READ)
.permission(WorkbasketPermission.APPEND)
.buildAndStore(workbasketService);
}
@WithAccessId(user = "user-1-1")
@Test
void should_CalculateDueInclusive_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
Task createdTask = createTaskWithPlanned("2023-03-02T16:00:00.000Z", classificationSummary);
// then
assertThat(createdTask.getDue()).isEqualTo(Instant.parse("2023-03-02T17:59:59.999Z"));
}
@WithAccessId(user = "user-1-1")
@Test
void should_CalculateDueInclusiveButNotLowerThanPlanned_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(ZERO_SECONDS);
// when
Task createdTask = createTaskWithPlanned("2023-03-02T16:00:00.000Z", classificationSummary);
// then
assertThat(createdTask.getDue()).isEqualTo(Instant.parse("2023-03-02T16:00:00.000Z"));
}
@WithAccessId(user = "user-1-1")
@Test
void should_NormalizeDueInclusiveIfNotOnWorkingDay_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
Task createdTask = createTaskWithDue("2023-03-04T16:00:00.000Z", classificationSummary);
// then
assertThat(createdTask.getDue())
.isEqualTo(Instant.parse("2023-03-03T22:59:59.999Z")); // Friday end of business day
}
@WithAccessId(user = "user-1-1")
@Test
void should_NormalizeDueInclusiveWithoutChangeIfDueOnEndOfBusinessDay_When_CreatingTask()
throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
Task createdTask = createTaskWithDue("2023-03-03T22:59:59.999Z", classificationSummary);
// then
assertThat(createdTask.getDue())
.isEqualTo(Instant.parse("2023-03-03T22:59:59.999Z")); // Friday end of business day
}
@WithAccessId(user = "user-1-1")
@Test
void should_NormalizeDueInclusiveOnStartOfWeekend_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
String startOfWeekend = "2023-03-03T23:00:00Z";
Task createdTask = createTaskWithDue(startOfWeekend, classificationSummary);
// then
Instant fridayEndOfBusinessDay = Instant.parse("2023-03-03T22:59:59.999Z");
assertThat(createdTask.getDue()).isEqualTo(fridayEndOfBusinessDay);
}
@WithAccessId(user = "user-1-1")
@Test
void should_CalculatePlannedInclusive_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
Task createdTask = createTaskWithDue("2023-03-02T16:59:59.999Z", classificationSummary);
// then
assertThat(createdTask.getPlanned()).isEqualTo(Instant.parse("2023-03-02T15:00:00.000Z"));
}
@WithAccessId(user = "user-1-1")
@Test
void should_CalculatePlannedInclusiveForServiceLevelZero_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(ZERO_SECONDS);
// when
Task createdTask = createTaskWithDue("2023-03-02T16:00:00Z", classificationSummary);
// then
assertThat(createdTask.getPlanned()).isEqualTo(Instant.parse("2023-03-02T16:00:00Z"));
}
@WithAccessId(user = "user-1-1")
@Test
void should_NormalizePlannedInclusiveIfNotOnWorkingDay_When_CreatingTask() throws Exception {
// given
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
// when
Task createdTask = createTaskWithPlanned("2023-03-04T16:00:00.000Z", classificationSummary);
// then
Instant mondayStartOfBusinessDay = Instant.parse("2023-03-05T23:00:00.000Z");
assertThat(createdTask.getPlanned()).isEqualTo(mondayStartOfBusinessDay);
}
@WithAccessId(user = "user-1-1")
@Test
void should_NotFailDueToServiceLevelMismatchForNonZeroServiceLevel_When_CreatingTask()
throws Exception {
ClassificationSummary classificationSummary = classificationWithServiceLevel(TWO_HOURS);
assertThatCode(
() ->
createTaskWithPlannedAndDue(
"2023-03-02T16:00:00.000Z", "2023-03-02T17:59:59.999Z", classificationSummary))
.doesNotThrowAnyException();
}
@WithAccessId(user = "user-1-1")
@Test
void should_NotFailDueToServiceLevelMismatchForZeroServiceLevel_When_CreatingTask()
throws Exception {
ClassificationSummary classificationSummary = classificationWithServiceLevel(ZERO_SECONDS);
assertThatCode(
() ->
createTaskWithPlannedAndDue(
"2023-03-03T16:00:00.000Z", "2023-03-03T16:00:00.000Z", classificationSummary))
.doesNotThrowAnyException();
}
private Task createTaskWithPlannedAndDue(
String planned, String due, ClassificationSummary classificationSummary) throws Exception {
Task task = taskService.newTask(workbasket.getId());
task.setPrimaryObjRef(primaryObjRef);
task.setClassificationKey(classificationSummary.getKey());
if (planned != null) {
task.setPlanned(Instant.parse(planned));
}
if (due != null) {
task.setDue(Instant.parse(due));
}
return taskService.createTask(task);
}
private Task createTaskWithDue(String due, ClassificationSummary classificationSummary)
throws Exception {
return createTaskWithPlannedAndDue(null, due, classificationSummary);
}
private Task createTaskWithPlanned(String planned, ClassificationSummary classificationSummary)
throws Exception {
return createTaskWithPlannedAndDue(planned, null, classificationSummary);
}
private ClassificationSummary classificationWithServiceLevel(String serviceLevel)
throws Exception {
return DefaultTestEntities.defaultTestClassification()
.serviceLevel(serviceLevel)
.buildAndStoreAsSummary(classificationService, "businessadmin");
}
}

View File

@ -316,11 +316,6 @@ public class ClassificationServiceImpl implements ClassificationService {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
// check that the duration is based on format PnD, i.e. it must start with a P, end with a D
if (!serviceLevel.toLowerCase().startsWith("p") || !serviceLevel.toLowerCase().endsWith("d")) {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
}
private void validateAndPopulateParentInformation(ClassificationImpl classificationImpl)

View File

@ -49,6 +49,9 @@ public interface Task extends TaskSummary {
/**
* Sets the time when the work on this Task should be finished.
*
* <p><code>due</code> denotes the last point in the allowed work time has ended or in short it is
* inclusive.
*
* @param due as exact {@linkplain Instant}
*/
void setDue(Instant due);

View File

@ -84,6 +84,9 @@ public interface TaskSummary {
/**
* Returns the time when the {@linkplain Task} is due.
*
* <p>This instant denotes the last point in the allowed work time has ended or in short it is
* inclusive.
*
* @return the due Instant
*/
Instant getDue();

View File

@ -283,8 +283,8 @@ class ServiceLevelHandler {
private void recalcPlannedBasedOnDue(
TaskImpl newTaskImpl, TaskImpl oldTaskImpl, Duration duration)
throws InvalidArgumentException {
Instant calcDue = instantOrEndOfPreviousWorkSlot(newTaskImpl.getDue());
Instant calcPlanned = subtractWorkingTime(calcDue, duration);
Instant calcDue = normalizeDue(newTaskImpl.getDue());
Instant calcPlanned = calculatePlanned(calcDue, duration);
if (plannedHasChanged(newTaskImpl, oldTaskImpl)) {
ensureServiceLevelIsNotViolated(newTaskImpl, duration, calcPlanned);
}
@ -293,28 +293,49 @@ class ServiceLevelHandler {
}
private void recalcDueBasedPlanned(TaskImpl newTaskImpl, Duration duration) {
newTaskImpl.setPlanned(instantOrStartOfNextWorkSlot(newTaskImpl.getPlanned()));
newTaskImpl.setDue(addWorkingTime(newTaskImpl.getPlanned(), duration));
Instant planned = normalizePlanned(newTaskImpl.getPlanned());
newTaskImpl.setPlanned(planned);
newTaskImpl.setDue(calculateDue(planned, duration));
}
private boolean plannedHasChanged(Task newTask, Task oldTask) {
return newTask.getPlanned() != null && !oldTask.getPlanned().equals(newTask.getPlanned());
}
private Instant instantOrEndOfPreviousWorkSlot(Instant instant) {
return subtractWorkingTime(instant, Duration.ZERO);
private Instant calculateDue(Instant planned, Duration duration) {
Instant dueExclusive = workingTimeCalculator.addWorkingTime(planned, duration);
if (!planned.equals(dueExclusive)) {
// Calculation is exclusive, but we want due date to be inclusive. Hence, we subtract a
// millisecond
// If planned and dueExclusive are the same values, we don't want due to be before planned.
// To compensate for that we allow a delta of one millisecond in
// ensureServiceLevelIsNotViolated
dueExclusive = dueExclusive.minusMillis(1);
}
return dueExclusive;
}
private Instant subtractWorkingTime(Instant instant, Duration workingTime) {
return workingTimeCalculator.subtractWorkingTime(instant, workingTime);
private Instant calculatePlanned(Instant due, Duration duration) {
if (Duration.ZERO.equals(duration)) {
// Since calculation happens on due, that is already inclusive we do not calculate at all
return due;
} else {
// due is inclusive, but calculation happens exclusive.
return workingTimeCalculator.subtractWorkingTime(due.plusMillis(1), duration);
}
}
private Instant instantOrStartOfNextWorkSlot(Instant instant) {
return addWorkingTime(instant, Duration.ZERO);
private Instant normalizeDue(Instant due) {
// plusMillis since due is inclusive, but calculation happens exclusive.
// minusMillis since we calculated a due date
// Without that some edge case fail (e.g. due is exactly the start of weekend)
return workingTimeCalculator
.subtractWorkingTime(due.plusMillis(1), Duration.ZERO)
.minusMillis(1);
}
private Instant addWorkingTime(Instant instant, Duration workingTime) {
return workingTimeCalculator.addWorkingTime(instant, workingTime);
private Instant normalizePlanned(Instant instant) {
return workingTimeCalculator.addWorkingTime(instant, Duration.ZERO);
}
/**
@ -340,12 +361,15 @@ class ServiceLevelHandler {
*/
private void ensureServiceLevelIsNotViolated(
TaskImpl task, Duration duration, Instant calcPlanned) throws InvalidArgumentException {
// TODO tests mit coverage. falls die Exception nie auftritt weg mit der Methode
if (task.getPlanned() != null
&& !task.getPlanned().equals(calcPlanned)
// manual entered planned date is a different working day than computed value
&& (workingTimeCalculator.isWorkingDay(task.getPlanned())
|| workingTimeCalculator.isWorkingTimeBetween(task.getPlanned(), calcPlanned))) {
// We allow a diff of at most one millisecond, because calcPlanned is based on due date
// which is inclusive and not exclusive. This handles standard cases and edge cases
// (planned und due on weekends, e.g.)
&& (workingTimeCalculator
.workingTimeBetween(task.getPlanned(), calcPlanned)
.compareTo(Duration.ofMillis(1))
> 0)) {
throw new InvalidArgumentException(
String.format(
"Cannot update a task with given planned %s "
@ -363,8 +387,8 @@ class ServiceLevelHandler {
}
if (newTask.getDue() != null) {
// due is specified: calculate back and check correctness
Instant calcDue = instantOrEndOfPreviousWorkSlot(newTask.getDue());
Instant calcPlanned = subtractWorkingTime(calcDue, duration);
Instant calcDue = normalizeDue(newTask.getDue());
Instant calcPlanned = calculatePlanned(calcDue, duration);
ensureServiceLevelIsNotViolated(newTask, duration, calcPlanned);
newTask.setDue(calcDue);
newTask.setPlanned(calcPlanned);
@ -392,7 +416,7 @@ class ServiceLevelHandler {
TaskImpl referenceTask = new TaskImpl();
referenceTask.setPlanned(durationHolder.getPlanned());
referenceTask.setModified(Instant.now());
referenceTask.setDue(addWorkingTime(referenceTask.getPlanned(), durationHolder.getDuration()));
referenceTask.setDue(calculateDue(referenceTask.getPlanned(), durationHolder.getDuration()));
List<String> taskIdsToUpdate =
taskDurationList.stream().map(TaskDuration::getTaskId).collect(Collectors.toList());
Pair<List<MinimalTaskSummary>, BulkLog> existingAndAuthorizedTasks =
@ -412,7 +436,7 @@ class ServiceLevelHandler {
taskIdsByDueDuration.forEach(
(duration, taskIds) -> {
referenceTask.setDue(addWorkingTime(planned, duration));
referenceTask.setDue(calculateDue(planned, duration));
Pair<List<MinimalTaskSummary>, BulkLog> existingAndAuthorizedTasks =
taskServiceImpl.getMinimalTaskSummaries(taskIds);
bulkLog.addAllErrors(existingAndAuthorizedTasks.getRight());

View File

@ -45,7 +45,8 @@ class UpdateObjectsUseUtcTimeStampsAccTest extends AbstractAccTest {
task.setPlanned(now.plus(Duration.ofHours(17)));
// associated Classification has ServiceLevel 'P1D'
task.setDue(workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1)));
task.setDue(
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1)).minusMillis(1));
TaskImpl ti = (TaskImpl) task;
ti.setCompleted(now.plus(Duration.ofHours(27)));

View File

@ -56,8 +56,8 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
Instant due =
moveBackToWorkingDay(
Instant.now().truncatedTo(ChronoUnit.MILLIS).plus(40, ChronoUnit.DAYS));
moveBackToWorkingDay(Instant.now().truncatedTo(ChronoUnit.MILLIS).plus(40, ChronoUnit.DAYS))
.minusMillis(1);
newTask.setDue(due);
Task createdTask = taskService.createTask(newTask);
assertThat(createdTask.getId()).isNotNull();
@ -67,7 +67,8 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
assertThat(readTask.getDue()).isEqualTo(due);
Instant expectedPlanned =
workingTimeCalculator.subtractWorkingTime(due, Duration.ofDays(serviceLevelDays));
workingTimeCalculator.subtractWorkingTime(
due.plusMillis(1), Duration.ofDays(serviceLevelDays));
assertThat(readTask.getPlanned()).isEqualTo(expectedPlanned);
}
@ -85,7 +86,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
newTask.setPrimaryObjRef(
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
Instant planned = moveForwardToWorkingDay(Instant.now().truncatedTo(ChronoUnit.MILLIS));
Instant planned = Instant.parse("2023-03-03T10:37:16.456Z");
newTask.setPlanned(planned);
Task createdTask = taskService.createTask(newTask);
assertThat(createdTask.getId()).isNotNull();
@ -93,33 +94,22 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
Task readTask = taskService.getTask(createdTask.getId());
assertThat(readTask).isNotNull();
assertThat(readTask.getPlanned()).isEqualTo(planned);
Instant expectedDue =
workingTimeCalculator.addWorkingTime(
readTask.getPlanned(), Duration.ofDays(serviceLevelDays));
assertThat(readTask.getDue()).isEqualTo(expectedDue);
assertThat(readTask.getDue()).isEqualTo(Instant.parse("2023-03-27T10:37:16.455Z"));
}
@WithAccessId(user = "user-1-1")
@Test
void should_NotThrowException_When_DueAndPlannedAreConsistent() throws Exception {
Classification classification = classificationService.getClassification("T2100", "DOMAIN_A");
long duration = Duration.parse(classification.getServiceLevel()).toDays();
Task newTask = taskService.newTask("USER-1-1", "DOMAIN_A");
newTask.setPlanned(moveForwardToWorkingDay(Instant.now()));
newTask.setPlanned(Instant.parse("2023-03-01T14:52:13.879Z"));
newTask.setClassificationKey(classification.getKey());
newTask.setPrimaryObjRef(
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
newTask.setOwner("user-1-1");
// due date according to service level
Instant expectedDue =
workingTimeCalculator.addWorkingTime(newTask.getPlanned(), Duration.ofDays(duration));
newTask.setDue(expectedDue);
newTask.setDue(Instant.parse("2023-03-03T14:52:13.878Z"));
ThrowingCallable call = () -> taskService.createTask(newTask);
assertThatCode(call).doesNotThrowAnyException();
}
@ -212,7 +202,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
BulkOperationResults<String, TaskanaException> results =
taskService.setPlannedPropertyOfTasks(planned, taskIds);
assertThat(results.containsErrors()).isFalse();
Instant dueExpected = getInstant("2020-02-12T07:00:00");
Instant dueExpected = getInstant("2020-02-12T06:59:59.999");
Instant due1 = taskService.getTask(tkId1).getDue();
assertThat(due1).isEqualTo(dueExpected);
@ -241,7 +231,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
assertThat(results.getErrorMap()).hasSize(1);
assertThat(results.getErrorForId("TKI:000000000000000000000000000047110059"))
.isInstanceOf(TaskNotFoundException.class);
Instant dueExpected = getInstant("2020-04-21T07:00:00");
Instant dueExpected = getInstant("2020-04-21T06:59:59.999");
Instant due1 = taskService.getTask(tkId1).getDue();
assertThat(due1).isEqualTo(dueExpected);
Instant due3 = taskService.getTask(tkId3).getDue();
@ -303,9 +293,9 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
Instant dueBulk1 = taskService.getTask(tkId1).getDue();
Instant dueBulk2 = taskService.getTask(tkId2).getDue();
assertThat(dueBulk0).isEqualTo(planned.plus(1, ChronoUnit.DAYS));
assertThat(dueBulk1).isEqualTo(planned.plus(2, ChronoUnit.DAYS));
assertThat(dueBulk2).isEqualTo(planned.plus(1, ChronoUnit.DAYS));
assertThat(dueBulk0).isEqualTo(getInstant("2020-04-22T12:59:59.999"));
assertThat(dueBulk1).isEqualTo(getInstant("2020-04-23T12:59:59.999"));
assertThat(dueBulk2).isEqualTo(getInstant("2020-04-22T12:59:59.999"));
assertThat(results.containsErrors()).isFalse();
assertThat(dueBulk0).isEqualTo(due0);
@ -363,10 +353,10 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
Instant dueBulk2 = taskService.getTask(tkId2).getDue();
Instant dueBulk3 = taskService.getTask(tkId3).getDue();
Instant dueBulk4 = taskService.getTask(tkId4).getDue();
assertThat(dueBulk1).isEqualTo(getInstant("2020-05-14T00:00:00"));
assertThat(dueBulk2).isEqualTo(getInstant("2020-05-21T00:00:00"));
assertThat(dueBulk3).isEqualTo(getInstant("2020-05-14T00:00:00"));
assertThat(dueBulk4).isEqualTo(getInstant("2020-05-21T00:00:00"));
assertThat(dueBulk1).isEqualTo(getInstant("2020-05-13T23:59:59.999"));
assertThat(dueBulk2).isEqualTo(getInstant("2020-05-20T23:59:59.999"));
assertThat(dueBulk3).isEqualTo(getInstant("2020-05-13T23:59:59.999"));
assertThat(dueBulk4).isEqualTo(getInstant("2020-05-20T23:59:59.999"));
}
@WithAccessId(user = "admin")
@ -397,9 +387,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
taskService.setPlannedPropertyOfTasks(planned, List.of(taskId));
Task task = taskService.getTask(taskId);
assertThat(results.containsErrors()).isFalse();
Instant expectedDue =
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expectedDue);
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-04T23:59:59.999"));
}
@WithAccessId(user = "admin")
@ -410,16 +398,15 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
// test update of planned date via updateTask()
task.setPlanned(task.getPlanned().plus(Duration.ofDays(3)));
task = taskService.updateTask(task);
Instant expectedDue =
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expectedDue);
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-02-02T15:54:59.999Z"));
}
@WithAccessId(user = "admin")
@Test
void should_SetPlanned_When_OnlyDueWasChanged() throws Exception {
String taskId = "TKI:000000000000000000000000000000000002"; // P1D
Instant planned = getInstant("2020-05-03T07:00:00");
Instant planned = getInstant("2020-05-03T06:59:59.999");
Task task = taskService.getTask(taskId);
// test update of due with unchanged planned
@ -432,32 +419,25 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
@Test
void should_SetDue_When_OnlyPlannedWasChanged() throws Exception {
String taskId = "TKI:000000000000000000000000000000000002";
Instant planned = getInstant("2020-05-03T07:00:00"); // Sunday
Instant expectedPlanned = getInstant("2020-05-04T00:00:00");
Instant planned = getInstant("2020-05-06T07:00:00");
Task task = taskService.getTask(taskId);
task.setPlanned(planned);
task = taskService.updateTask(task);
String serviceLevel = task.getClassificationSummary().getServiceLevel();
Instant expDue =
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.parse(serviceLevel));
assertThat(task.getPlanned()).isEqualTo(expectedPlanned);
assertThat(task.getDue()).isEqualTo(expDue);
assertThat(task.getPlanned()).isEqualTo(planned);
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-07T06:59:59.999"));
}
@WithAccessId(user = "admin")
@Test
void should_SetPlanned_When_DueIsChangedAndPlannedIsNulled() throws Exception {
String taskId = "TKI:000000000000000000000000000000000002";
Instant due = getInstant("2020-05-06T07:00:00");
Instant due = getInstant("2020-05-06T06:59:59.999");
Task task = taskService.getTask(taskId);
task.setDue(due);
task.setPlanned(null);
task = taskService.updateTask(task);
String serviceLevel = task.getClassificationSummary().getServiceLevel();
Instant expPlanned =
workingTimeCalculator.subtractWorkingTime(task.getDue(), Duration.parse(serviceLevel));
assertThat(task.getPlanned()).isEqualTo(expPlanned);
assertThat(task.getPlanned()).isEqualTo("2020-05-05T07:00:00.000Z");
assertThat(task.getDue()).isEqualTo(due);
}
@ -470,27 +450,23 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
task.setPlanned(null);
task = taskService.updateTask(task);
Instant expectedDue =
workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expectedDue);
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-07T06:59:59.999"));
task.setDue(null);
task = taskService.updateTask(task);
expectedDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expectedDue);
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-07T06:59:59.999"));
task.setPlanned(planned.plus(Duration.ofDays(13))); // Saturday
task.setDue(null);
task = taskService.updateTask(task);
expectedDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expectedDue);
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-18T23:59:59.999"));
task.setDue(planned.plus(Duration.ofDays(13))); // Saturday
task.setPlanned(null);
task = taskService.updateTask(task);
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-05-15T00:00:00"));
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-16T00:00:00"));
assertThat(task.getDue()).isEqualTo(getInstant("2020-05-15T23:59:59.999"));
}
@WithAccessId(user = "user-1-2")
@ -500,7 +476,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
Task task = taskService.getTask("TKI:000000000000000000000000000000000030"); // SL=P13D
task.setPlanned(getInstant("2020-03-23T07:00:00")); // planned = saturday
task = taskService.updateTask(task);
assertThat(task.getDue()).isEqualTo(getInstant("2020-04-09T07:00:00"));
assertThat(task.getDue()).isEqualTo(getInstant("2020-04-09T06:59:59.999"));
task.setDue(getInstant("2020-04-11T07:00:00")); // due = saturday
task.setPlanned(null);
@ -512,14 +488,14 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-03-24T00:00:00"));
task.setPlanned(getInstant("2020-03-21T07:00:00")); // planned = saturday
task.setDue(getInstant("2020-04-09T00:00:00")); // thursday
task.setDue(getInstant("2020-04-09T23:59:59.999")); // thursday
task = taskService.updateTask(task);
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-03-23T00:00:00"));
task.setPlanned(getInstant("2020-03-04T00:00:00")); // planned on tuesday
task.setDue(getInstant("2020-03-22T07:00:00")); // due = sunday
task = taskService.updateTask(task);
assertThat(task.getDue()).isEqualTo(getInstant("2020-03-21T00:00:00")); // friday, EOB
assertThat(task.getDue()).isEqualTo(getInstant("2020-03-20T23:59:59.999")); // friday, EOB
}
@WithAccessId(user = "user-1-1")
@ -542,7 +518,7 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
// due changed, planned did not change
task.setDue(getInstant("2020-04-12T07:00:00")); // Sunday
task = taskService.updateTask(task);
Instant endOfHolyThursday = getInstant("2020-04-10T00:00:00");
Instant endOfHolyThursday = getInstant("2020-04-09T23:59:59.999");
assertThat(task.getPlanned()).isEqualTo(endOfHolyThursday); // Thursday (skip Good Friday)
assertThat(task.getDue()).isEqualTo(endOfHolyThursday);
@ -561,11 +537,12 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-03-23T00:00:00")); // Monday
// both changed, not null (due at weekend)
task.setPlanned(getInstant("2020-03-21T00:00:00")); // Friday
Instant fridayEndOfBusinessDay = getInstant("2020-03-20T23:59:59.999");
task.setPlanned(fridayEndOfBusinessDay);
task.setDue(getInstant("2020-03-22T07:00:00")); // Sunday
task = taskService.updateTask(task);
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-03-21T00:00:00")); // Friday
assertThat(task.getDue()).isEqualTo(getInstant("2020-03-21T00:00:00")); // Friday
assertThat(task.getPlanned()).isEqualTo(fridayEndOfBusinessDay);
assertThat(task.getDue()).isEqualTo(fridayEndOfBusinessDay);
// both changed, not null (planned at weekend)
task.setPlanned(getInstant("2020-03-22T07:00:00")); // Sunday
@ -578,8 +555,8 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
task.setPlanned(getInstant("2020-03-22T07:00:00")); // Sunday
task.setDue(getInstant("2020-03-22T07:00:00")); // Sunday
task = taskService.updateTask(task);
assertThat(task.getDue()).isEqualTo(getInstant("2020-03-21T00:00:00")); // Friday
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-03-21T00:00:00")); // Friday
assertThat(task.getDue()).isEqualTo(fridayEndOfBusinessDay);
assertThat(task.getPlanned()).isEqualTo(fridayEndOfBusinessDay);
// both changed, not null (planned > due)
task.setPlanned(getInstant("2020-03-24T07:00:00")); // Tuesday
@ -598,10 +575,10 @@ class ServiceLevelPriorityAccTest extends AbstractAccTest {
Task task = taskService.getTask("TKI:000000000000000000000000000000000002"); // P1D
// SLA is broken but only with holidays in between
task.setDue(getInstant("2020-04-14T07:00:00")); // Tuesday after Easter
task.setDue(getInstant("2020-04-14T06:59:59.999")); // Tuesday after Easter
task.setPlanned(getInstant("2020-04-09T07:00:00")); // Thursday before Easter
task = taskService.updateTask(task);
assertThat(task.getDue()).isEqualTo(getInstant("2020-04-14T07:00:00")); // Tuesday
assertThat(task.getDue()).isEqualTo(getInstant("2020-04-14T06:59:59.999")); // Tuesday
assertThat(task.getPlanned()).isEqualTo(getInstant("2020-04-09T07:00:00")); // Thursday
}
}

View File

@ -6,7 +6,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import acceptance.TaskTestMapper;
import acceptance.TaskanaEngineProxy;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.Set;
@ -545,8 +544,7 @@ class CreateTaskAccTest extends AbstractAccTest {
assertThat(readTask).isNotNull();
assertThat(createdTask.getCreator())
.isEqualTo(taskanaEngine.getCurrentUserContext().getUserid());
assertThat(readTask.getAttachments()).isNotNull();
assertThat(readTask.getAttachments()).hasSize(2);
assertThat(readTask.getAttachments()).isNotNull().hasSize(2);
assertThat(readTask.getAttachments().get(1).getCreated()).isNotNull();
assertThat(readTask.getAttachments().get(1).getModified()).isNotNull();
assertThat(readTask.getAttachments().get(1).getModified())
@ -556,10 +554,7 @@ class CreateTaskAccTest extends AbstractAccTest {
assertThat(readTask.getPriority()).isEqualTo(99);
Instant expDue =
workingTimeCalculator.addWorkingTime(readTask.getPlanned(), Duration.ofDays(1));
assertThat(readTask.getDue()).isEqualTo(expDue);
assertThat(readTask.getDue()).isNotNull();
}
@WithAccessId(user = "user-1-1")

View File

@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import org.assertj.core.api.Condition;
@ -71,8 +70,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
@Test
void should_UpdateTaskCorrectlyInDatabase_When_AddingAnAttachment() throws Exception {
final int attachmentCount = task.getAttachments().size();
assertThat(task.getPriority()).isEqualTo(1);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
assertThat(task.getPriority()).isOne();
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
task.addAttachment(attachment);
task = taskService.updateTask(task);
@ -155,11 +154,10 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
@Test
void should_ThrowAttachmentPersistenceException_When_UpdatingTaskWithTwoIdenticalAttachments()
throws Exception {
final int attachmentCount = 0;
task.getAttachments().clear();
task = taskService.updateTask(task);
task = taskService.getTask(task.getId());
assertThat(task.getAttachments()).hasSize(attachmentCount);
assertThat(task.getAttachments()).isEmpty();
AttachmentImpl attachment = (AttachmentImpl) this.attachment;
attachment.setId("TAI:000017");
@ -198,8 +196,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertThat(task.getAttachments().get(0).getChannel()).isEqualTo(newChannel);
assertThat(task.getPriority()).isEqualTo(99);
Instant expDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expDue);
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
}
@WithAccessId(user = "user-1-1")
@ -250,8 +247,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertThat(task.getAttachments()).hasSize(attachmentCount2); // locally, not inserted
task = taskService.getTask(task.getId());
assertThat(task.getAttachments()).hasSize(attachmentCount2); // inserted values not changed
assertThat(task.getPriority()).isEqualTo(1);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
assertThat(task.getPriority()).isOne();
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
}
@WithAccessId(user = "user-1-1")
@ -260,7 +257,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
task.addAttachment(attachment);
task = taskService.updateTask(task);
assertThat(task.getPriority()).isEqualTo(99);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
Instant expectedDue = Instant.parse("2018-01-30T15:54:59.999Z");
assertThat(task.getDue()).isEqualTo(expectedDue);
int attachmentCount = task.getAttachments().size();
Attachment attachmentToRemove = task.getAttachments().get(0);
task.removeAttachment(attachmentToRemove.getId());
@ -269,8 +267,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
.hasSize(attachmentCount - 1); // locally, removed and not inserted
task = taskService.getTask(task.getId());
assertThat(task.getAttachments()).hasSize(attachmentCount - 1); // inserted, values removed
assertThat(task.getPriority()).isEqualTo(1);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
assertThat(task.getPriority()).isOne();
assertThat(task.getDue()).isEqualTo(expectedDue);
}
@WithAccessId(user = "user-1-1")
@ -298,14 +296,14 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
void testUpdateAttachment() throws Exception {
((TaskImpl) task).setAttachments(new ArrayList<>());
task = taskService.updateTask(task);
assertThat(task.getPriority()).isEqualTo(1);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
assertThat(task.getPriority()).isOne();
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
Attachment attachment = this.attachment;
task.addAttachment(attachment);
task = taskService.updateTask(task);
assertThat(task.getPriority()).isEqualTo(99);
assertThat(task.getPlanned().plus(Duration.ofDays(1))).isEqualTo(task.getDue());
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
final int attachmentCount = task.getAttachments().size();
@ -321,9 +319,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertThat(task.getAttachments()).hasSize(attachmentCount);
assertThat(task.getAttachments().get(0).getChannel()).isEqualTo(newChannel);
assertThat(task.getPriority()).isEqualTo(99);
Instant expDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
assertThat(task.getDue()).isEqualTo(expDue);
assertThat(task.getDue()).isEqualTo(Instant.parse("2018-01-30T15:54:59.999Z"));
}
@WithAccessId(user = "user-1-1")
@ -350,7 +346,7 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
task = taskService.getTask(task.getId());
assertThat(task.getPriority()).isEqualTo(101);
Instant expDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(1));
Instant expDue = Instant.parse("2018-01-30T15:54:59.999Z");
assertThat(task.getDue()).isEqualTo(expDue);
assertThat(task.getAttachments())
.hasSize(2)
@ -383,7 +379,8 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
task = taskService.getTask(task.getId());
assertThat(task.getPriority()).isEqualTo(99);
expDue = workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(16));
expDue = Instant.parse("2018-02-20T15:54:59.999Z");
assertThat(task.getDue()).isEqualTo(expDue);
assertThat(task.getAttachments())
.hasSize(2)
@ -503,20 +500,14 @@ class UpdateTaskAttachmentsAccTest extends AbstractAccTest {
assertThat(readTask).isNotNull();
assertThat(createdTask.getCreator())
.isEqualTo(taskanaEngine.getCurrentUserContext().getUserid());
assertThat(readTask.getAttachments()).isNotNull();
assertThat(readTask.getAttachments()).hasSize(2);
assertThat(readTask.getAttachments().get(1).getCreated()).isNotNull();
assertThat(readTask.getAttachments().get(1).getModified()).isNotNull();
assertThat(readTask.getAttachments().get(0).getCreated())
.isEqualTo(readTask.getAttachments().get(1).getModified());
assertThat(readTask.getAttachments().get(0).getObjectReference()).isNotNull();
assertThat(readTask.getPriority()).isEqualTo(99);
Instant expDue =
workingTimeCalculator.addWorkingTime(readTask.getPlanned(), Duration.ofDays(1));
assertThat(readTask.getDue()).isEqualTo(expDue);
assertThat(readTask.getDue()).isNotNull();
}
@WithAccessId(user = "user-1-1")