diff --git a/lib/taskana-core-test/src/test/java/acceptance/jobs/AbstractTaskanaJobAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/jobs/AbstractTaskanaJobAccTest.java new file mode 100644 index 000000000..6aff25626 --- /dev/null +++ b/lib/taskana-core-test/src/test/java/acceptance/jobs/AbstractTaskanaJobAccTest.java @@ -0,0 +1,129 @@ +package acceptance.jobs; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import pro.taskana.TaskanaConfiguration; +import pro.taskana.TaskanaConfiguration.Builder; +import pro.taskana.classification.internal.jobs.ClassificationChangedJob; +import pro.taskana.common.api.JobService; +import pro.taskana.common.api.ScheduledJob; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.internal.JobMapper; +import pro.taskana.common.internal.jobs.AbstractTaskanaJob; +import pro.taskana.common.internal.jobs.JobRunner; +import pro.taskana.task.internal.jobs.TaskCleanupJob; +import pro.taskana.task.internal.jobs.TaskRefreshJob; +import pro.taskana.testapi.TaskanaConfigurationModifier; +import pro.taskana.testapi.TaskanaInject; +import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.security.WithAccessId; + +@TaskanaIntegrationTest +class AbstractTaskanaJobAccTest { + + @TaskanaInject JobMapper jobMapper; + + @TaskanaInject JobService jobService; + + @TaskanaInject TaskanaEngine taskanaEngine; + + @TaskanaInject TaskanaConfiguration taskanaConfiguration; + + @AfterEach + void cleanupJobs() { + // Dirty Hack, please refactor me with ticket https://github.com/Taskana/taskana/issues/2238 + jobMapper.deleteMultiple(TaskCleanupJob.class.getName()); + jobMapper.deleteMultiple(TaskRefreshJob.class.getName()); + jobMapper.deleteMultiple(ClassificationChangedJob.class.getName()); + } + + @WithAccessId(user = "admin") + @Test + void should_SetNextScheduledJobBasedOnDueDateOfPredecessor_When_RunningTaskCleanupJob() { + List jobsToRun = jobMapper.findJobsToRun(Instant.now()); + assertThat(jobsToRun).isEmpty(); + + Instant firstDue = Instant.now().truncatedTo(ChronoUnit.MILLIS); + ScheduledJob scheduledJob = new ScheduledJob(); + scheduledJob.setType(TaskCleanupJob.class.getName()); + scheduledJob.setDue(firstDue); + + jobService.createJob(scheduledJob); + jobsToRun = jobMapper.findJobsToRun(Instant.now()); + + assertThat(jobsToRun).extracting(ScheduledJob::getDue).containsExactly(firstDue); + + JobRunner runner = new JobRunner(taskanaEngine); + runner.runJobs(); + Duration runEvery = taskanaConfiguration.getJobRunEvery(); + jobsToRun = jobMapper.findJobsToRun(Instant.now().plus(runEvery)); + + assertThat(jobsToRun).extracting(ScheduledJob::getDue).containsExactly(firstDue.plus(runEvery)); + } + + @WithAccessId(user = "admin") + @Test + void should_DeleteOldTaskCleanupJobs_When_InitializingSchedule() { + + for (int i = 0; i < 10; i++) { + ScheduledJob job = new ScheduledJob(); + job.setType(TaskCleanupJob.class.getName()); + taskanaEngine.getJobService().createJob(job); + job.setType(TaskRefreshJob.class.getName()); + taskanaEngine.getJobService().createJob(job); + job.setType(ClassificationChangedJob.class.getName()); + taskanaEngine.getJobService().createJob(job); + } + + List jobsToRun = jobMapper.findJobsToRun(Instant.now()); + + assertThat(jobsToRun).hasSize(30); + + List taskCleanupJobs = + jobsToRun.stream() + .filter(scheduledJob -> scheduledJob.getType().equals(TaskCleanupJob.class.getName())) + .collect(Collectors.toList()); + + AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class); + + jobsToRun = jobMapper.findJobsToRun(Instant.now()); + + assertThat(jobsToRun).doesNotContainAnyElementsOf(taskCleanupJobs); + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CleanCompletedTasks implements TaskanaConfigurationModifier { + @TaskanaInject TaskanaEngine taskanaEngine; + + @TaskanaInject JobMapper jobMapper; + + @Override + public Builder modify(Builder builder) { + return builder + .taskCleanupJobEnabled(true) + .jobRunEvery(Duration.ofMillis(1)) + .jobFirstRun(Instant.now().plus(5, ChronoUnit.MINUTES)); + } + + @WithAccessId(user = "admin") + @Test + void should_FindNoJobsToRunUntilFirstRunIsReached_When_CleanupScheduleIsInitialized() + throws Exception { + AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class); + + List nextJobs = jobMapper.findJobsToRun(Instant.now()); + assertThat(nextJobs).isEmpty(); + } + } +} diff --git a/lib/taskana-core-test/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java new file mode 100644 index 000000000..a65477420 --- /dev/null +++ b/lib/taskana-core-test/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java @@ -0,0 +1,290 @@ +package acceptance.jobs; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.function.ThrowingConsumer; +import pro.taskana.TaskanaConfiguration.Builder; +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.TaskSummary; +import pro.taskana.task.internal.jobs.TaskCleanupJob; +import pro.taskana.testapi.DefaultTestEntities; +import pro.taskana.testapi.TaskanaConfigurationModifier; +import pro.taskana.testapi.TaskanaInject; +import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.builder.TaskBuilder; +import pro.taskana.testapi.security.WithAccessId; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; + +// All tests are executed as admin, because the jobrunner needs admin rights. +@TaskanaIntegrationTest +class TaskCleanupJobAccTest { + + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + + ClassificationSummary classification; + ObjectReference primaryObjRef; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + classification = + DefaultTestEntities.defaultTestClassification() + .buildAndStoreAsSummary(classificationService); + primaryObjRef = DefaultTestEntities.defaultTestObjectReference().build(); + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CleanCompletedTasks implements TaskanaConfigurationModifier { + + WorkbasketSummary workbasket; + + @TaskanaInject TaskanaEngine taskanaEngine; + + @Override + public Builder modify(Builder builder) { + return builder + .taskCleanupJobEnabled(true) + .jobFirstRun(Instant.now().minus(10, ChronoUnit.MILLIS)) + .jobRunEvery(Duration.ofMillis(1)) + .taskCleanupJobMinimumAge(Duration.ofDays(5)); + } + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + workbasket = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + } + + @WithAccessId(user = "admin") + @Test + void should_CleanCompletedTasks_When_CompletedTimestampIsOlderThenTaskCleanupJobMinimumAge() + throws Exception { + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(6, ChronoUnit.DAYS)) + .buildAndStoreAsSummary(taskService); + + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .isEmpty(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class NotCleanCompletedTasksWhereDateIsNotReached implements TaskanaConfigurationModifier { + + @TaskanaInject TaskanaEngine taskanaEngine; + + @Override + public Builder modify(Builder builder) { + return builder + .taskCleanupJobEnabled(true) + .jobFirstRun(Instant.now().minus(10, ChronoUnit.MILLIS)) + .jobRunEvery(Duration.ofMillis(1)) + .taskCleanupJobMinimumAge(Duration.ofDays(5)); + } + + @WithAccessId(user = "admin") + @Test + void should_NotCleanCompletedTasksAfterDefinedDay() throws Exception { + WorkbasketSummary workbasket = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + TaskSummary taskSummary = + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(3, ChronoUnit.DAYS)) + .buildAndStoreAsSummary(taskService); + + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .containsExactlyInAnyOrder(taskSummary); + } + + @WithAccessId(user = "admin") + @Test + void should_OnlyCleanCompletedTasks_When_DefinedCompletedExceedThreshold() throws Exception { + WorkbasketSummary workbasket = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + TaskBuilder taskBuilder = + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(3, ChronoUnit.DAYS)); + TaskSummary taskSummary1 = taskBuilder.buildAndStoreAsSummary(taskService); + TaskSummary taskSummary2 = + taskBuilder + .completed(Instant.now().minus(10, ChronoUnit.DAYS)) + .buildAndStoreAsSummary(taskService); + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .containsExactlyInAnyOrder(taskSummary1) + .doesNotContain(taskSummary2); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CleanCompletedTasksWithBusinessProcessId implements TaskanaConfigurationModifier { + + @TaskanaInject TaskanaEngine taskanaEngine; + + @Override + public Builder modify(Builder builder) { + return builder + .taskCleanupJobEnabled(true) + .jobFirstRun(Instant.now().minus(10, ChronoUnit.MILLIS)) + .jobRunEvery(Duration.ofMillis(1)) + .taskCleanupJobMinimumAge(Duration.ofDays(5)) + .taskCleanupJobAllCompletedSameParentBusiness(true); + } + + @WithAccessId(user = "admin") + @Test + void should_CleanCompletedTasksWithSameParentBusiness() throws Exception { + WorkbasketSummary workbasket = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + TaskBuilder taskBuilder = + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(10, ChronoUnit.DAYS)) + .parentBusinessProcessId("ParentProcessId_1"); + taskBuilder.buildAndStoreAsSummary(taskService); + taskBuilder.buildAndStoreAsSummary(taskService); + + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .isEmpty(); + } + + @WithAccessId(user = "admin") + @Test + void should_NotCleanCompletedTasksWithSameParentBusiness_When_OneSubTaskIsIncomplete() + throws Exception { + WorkbasketSummary workbasket = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + TaskBuilder taskBuilder = + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(10, ChronoUnit.DAYS)) + .parentBusinessProcessId("ParentProcessId_3"); + + TaskSummary taskSummaryCompleted1 = taskBuilder.buildAndStoreAsSummary(taskService); + TaskSummary taskSummaryCompleted2 = taskBuilder.buildAndStoreAsSummary(taskService); + + TaskSummary taskSummaryCompleted = + taskBuilder + .parentBusinessProcessId("ParentProcessId_4") + .buildAndStoreAsSummary(taskService); + TaskSummary taskSummaryClaimed = + taskBuilder + .parentBusinessProcessId("ParentProcessId_4") + .state(TaskState.CLAIMED) + .completed(null) + .buildAndStoreAsSummary(taskService); + + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .containsExactlyInAnyOrder(taskSummaryCompleted, taskSummaryClaimed) + .doesNotContain(taskSummaryCompleted1, taskSummaryCompleted2); + } + + @WithAccessId(user = "admin") + @TestFactory + Stream + should_DeleteCompletedTaskWithParentBusinessEmptyOrNull_When_RunningCleanupJob() + throws Exception { + Iterator iterator = Arrays.asList("", null).iterator(); + + ThrowingConsumer test = + parentBusinessId -> { + WorkbasketSummary workbasket = + DefaultTestEntities.defaultTestWorkbasket() + .buildAndStoreAsSummary(workbasketService); + TaskBuilder taskBuilder = + TaskBuilder.newTask() + .workbasketSummary(workbasket) + .classificationSummary(classification) + .primaryObjRef(primaryObjRef) + .state(TaskState.COMPLETED) + .completed(Instant.now().minus(10, ChronoUnit.DAYS)) + .parentBusinessProcessId(parentBusinessId); + + TaskSummary taskSummaryCompleted = taskBuilder.buildAndStoreAsSummary(taskService); + TaskSummary taskSummaryClaimed = + taskBuilder + .state(TaskState.CLAIMED) + .completed(null) + .buildAndStoreAsSummary(taskService); + + TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); + job.run(); + + List taskSummaries = taskService.createTaskQuery().list(); + assertThat(taskSummaries) + .filteredOn(t -> t.getWorkbasketSummary().equals(workbasket)) + .containsExactlyInAnyOrder(taskSummaryClaimed) + .doesNotContain(taskSummaryCompleted); + }; + return DynamicTest.stream(iterator, c -> "for parentBusinessProcessId = '" + c + "'", test); + } + } +} diff --git a/lib/taskana-core/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java b/lib/taskana-core/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java deleted file mode 100644 index aedba9eef..000000000 --- a/lib/taskana-core/src/test/java/acceptance/jobs/TaskCleanupJobAccTest.java +++ /dev/null @@ -1,265 +0,0 @@ -package acceptance.jobs; - -import static org.assertj.core.api.Assertions.assertThat; - -import acceptance.AbstractAccTest; -import java.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestFactory; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.function.ThrowingConsumer; -import pro.taskana.TaskanaConfiguration; -import pro.taskana.classification.internal.jobs.ClassificationChangedJob; -import pro.taskana.common.api.ScheduledJob; -import pro.taskana.common.api.TaskanaEngine; -import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode; -import pro.taskana.common.internal.JobMapper; -import pro.taskana.common.internal.JobServiceImpl; -import pro.taskana.common.internal.jobs.AbstractTaskanaJob; -import pro.taskana.common.internal.jobs.JobRunner; -import pro.taskana.common.test.security.JaasExtension; -import pro.taskana.common.test.security.WithAccessId; -import pro.taskana.task.api.TaskService; -import pro.taskana.task.api.models.Task; -import pro.taskana.task.api.models.TaskSummary; -import pro.taskana.task.internal.jobs.TaskCleanupJob; -import pro.taskana.task.internal.jobs.TaskRefreshJob; - -/** Acceptance test for all "jobs tasks runner" scenarios. */ -@ExtendWith(JaasExtension.class) -class TaskCleanupJobAccTest extends AbstractAccTest { - - @BeforeEach - void before() throws Exception { - // required if single tests modify database - // TODO split test class into readOnly & modifying tests to improve performance - resetDb(false); - } - - @WithAccessId(user = "admin") - @Test - void should_CleanCompletedTasksUntilDate() throws Exception { - TaskanaConfiguration taskanaConfiguration = - new TaskanaConfiguration.Builder(AbstractAccTest.taskanaConfiguration) - .taskCleanupJobAllCompletedSameParentBusiness(false) - .build(); - TaskanaEngine taskanaEngine = - TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.AUTOCOMMIT); - TaskService taskService = taskanaEngine.getTaskService(); - String taskId = createAndInsertTask(taskService, null); - taskService.claim(taskId); - taskService.completeTask(taskId); - - long totalTasksCount = taskService.createTaskQuery().count(); - assertThat(totalTasksCount).isEqualTo(100); - - TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); - job.run(); - - totalTasksCount = taskService.createTaskQuery().count(); - assertThat(totalTasksCount).isEqualTo(81); - } - - @WithAccessId(user = "admin") - @Test - void shouldCleanCompletedTasksUntilDateWithSameParentBusiness() throws Exception { - long totalTasksCount = taskService.createTaskQuery().count(); - assertThat(totalTasksCount).isEqualTo(99); - - TaskanaConfiguration taskanaConfiguration = - new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngine.getConfiguration()) - .taskCleanupJobAllCompletedSameParentBusiness(true) - .build(); - - TaskanaEngine taskanaEngine = - TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.AUTOCOMMIT); - List tasks = - taskanaEngine - .getTaskService() - .createTaskQuery() - .parentBusinessProcessIdIn("DOC_0000000000000000006") - .list(); - List ids = new ArrayList<>(); - tasks.forEach( - item -> { - if (item.getCompleted() == null) { - ids.add(item.getId()); - } - }); - taskanaEngine.getTaskService().deleteTasks(ids); - - TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); - job.run(); - - totalTasksCount = taskanaEngine.getTaskService().createTaskQuery().count(); - assertThat(totalTasksCount).isEqualTo(79); - } - - @WithAccessId(user = "admin") - @Test - void shouldNotCleanCompleteTasksAfterDefinedDay() throws Exception { - String taskId = createAndInsertTask(taskService, null); - taskService.claim(taskId); - taskService.completeTask(taskId); - - TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); - job.run(); - - Task completedCreatedTask = taskService.getTask(taskId); - assertThat(completedCreatedTask).isNotNull(); - } - - @WithAccessId(user = "admin") - @Test - void should_DeleteOldTaskCleanupJobs_When_InitializingSchedule() throws Exception { - - for (int i = 0; i < 10; i++) { - ScheduledJob job = new ScheduledJob(); - job.setType(TaskCleanupJob.class.getName()); - taskanaEngine.getJobService().createJob(job); - job.setType(TaskRefreshJob.class.getName()); - taskanaEngine.getJobService().createJob(job); - job.setType(ClassificationChangedJob.class.getName()); - taskanaEngine.getJobService().createJob(job); - } - - List jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now()); - - assertThat(jobsToRun).hasSize(30); - - List taskCleanupJobs = - jobsToRun.stream() - .filter(scheduledJob -> scheduledJob.getType().equals(TaskCleanupJob.class.getName())) - .collect(Collectors.toList()); - - AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class); - - jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now()); - - assertThat(jobsToRun).doesNotContainAnyElementsOf(taskCleanupJobs); - } - - @WithAccessId(user = "admin") - @TestFactory - Stream - should_DeleteCompletedTaskWithParentBusinessEmptyOrNull_When_RunningCleanupJob() - throws Exception { - Iterator iterator = Arrays.asList("", null).iterator(); - - TaskanaConfiguration taskanaConfiguration = - new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngine.getConfiguration()) - .taskCleanupJobAllCompletedSameParentBusiness(true) - .taskCleanupJobMinimumAge(Duration.ofMillis(1)) - .build(); - TaskanaEngine taskanaEngine = - TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.AUTOCOMMIT); - TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null); - - TaskService taskService = taskanaEngine.getTaskService(); - ThrowingConsumer test = - parentBusinessId -> { - String taskId1 = createAndInsertTask(taskService, parentBusinessId); - taskService.claim(taskId1); - taskService.completeTask(taskId1); - String taskId2 = createAndInsertTask(taskService, parentBusinessId); - taskService.claim(taskId2); - - job.run(); - List tasksAfterCleaning = - taskService.createTaskQuery().idIn(taskId1, taskId2).list(); - - assertThat(tasksAfterCleaning).extracting(TaskSummary::getId).containsExactly(taskId2); - }; - - return DynamicTest.stream(iterator, c -> "for parentBusinessProcessId = '" + c + "'", test); - } - - @WithAccessId(user = "admin") - @Test - void should_SetNextScheduledJobBasedOnDueDateOfPredecessor_When_RunningTaskCleanupJob() - throws Exception { - JobMapper jobMapper = getJobMapper(AbstractAccTest.taskanaEngine); - List jobsToRun = jobMapper.findJobsToRun(Instant.now()); - assertThat(jobsToRun).isEmpty(); - - Instant firstDue = Instant.now().truncatedTo(ChronoUnit.MILLIS); - ScheduledJob scheduledJob = new ScheduledJob(); - scheduledJob.setType(TaskCleanupJob.class.getName()); - scheduledJob.setDue(firstDue); - - JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService(); - jobService.createJob(scheduledJob); - jobsToRun = jobMapper.findJobsToRun(Instant.now()); - - assertThat(jobsToRun).extracting(ScheduledJob::getDue).containsExactly(firstDue); - - JobRunner runner = new JobRunner(taskanaEngine); - runner.runJobs(); - Duration runEvery = taskanaConfiguration.getJobRunEvery(); - jobsToRun = jobMapper.findJobsToRun(Instant.now().plus(runEvery)); - - assertThat(jobsToRun).extracting(ScheduledJob::getDue).containsExactly(firstDue.plus(runEvery)); - } - - @WithAccessId(user = "admin") - @Test - void should_ScheduleNextJobAccordingToFirstRun_When_PreviousJobNotExisting() throws Exception { - Instant firstRun = Instant.now().minus(2, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.MILLIS); - Duration runEvery = Duration.ofMinutes(5); - TaskanaConfiguration taskanaConfiguration = - new TaskanaConfiguration.Builder(AbstractAccTest.taskanaConfiguration) - .jobRunEvery(runEvery) - .jobFirstRun(firstRun) - .jobSchedulerEnabled(true) - .jobSchedulerInitialStartDelay(1) - .jobSchedulerPeriod(1) - .jobSchedulerPeriodTimeUnit(TimeUnit.SECONDS) - .taskCleanupJobEnabled(true) - .build(); - - TaskanaEngine taskanaEngine = - TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.AUTOCOMMIT); - - List nextJobs = - getJobMapper(taskanaEngine).findJobsToRun(Instant.now().plus(runEvery)); - assertThat(nextJobs).extracting(ScheduledJob::getDue).containsExactly(firstRun.plus(runEvery)); - } - - @WithAccessId(user = "admin") - @Test - void should_FindNoJobsToRunUntilFirstRunIsReached_When_CleanupScheduleIsInitialized() - throws Exception { - TaskanaConfiguration taskanaConfiguration = - new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngine.getConfiguration()) - .jobRunEvery(Duration.ofMillis(1)) - .jobFirstRun(Instant.now().plus(5, ChronoUnit.MINUTES)) - .build(); - - TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaConfiguration); - AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class); - - List nextJobs = getJobMapper(taskanaEngine).findJobsToRun(Instant.now()); - assertThat(nextJobs).isEmpty(); - } - - private String createAndInsertTask(TaskService taskService, String parentBusinessProcessId) - throws Exception { - Task newTask = taskService.newTask("user-1-1", "DOMAIN_A"); - newTask.setClassificationKey("T2100"); - newTask.setPrimaryObjRef( - createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567")); - newTask.setParentBusinessProcessId(parentBusinessProcessId); - return taskService.createTask(newTask).getId(); - } -}