TSK-1705: Add a job to update priority for unfinished tasks

This commit is contained in:
Benjamin Eckstein 2021-08-17 14:34:05 +02:00 committed by Benjamin Eckstein
parent 167d47f951
commit e9540d04e4
12 changed files with 706 additions and 2 deletions

View File

@ -58,6 +58,10 @@ public class TaskanaEngineConfiguration {
private static final String TASKANA_JOB_CLEANUP_MINIMUM_AGE = "taskana.jobs.cleanup.minimumAge";
private static final String TASKANA_JOB_TASK_CLEANUP_ALL_COMPLETED_SAME_PARENT_BUSINESS =
"taskana.jobs.cleanup.allCompletedSameParentBusiness";
private static final String TASKANA_JOB_PRIORITY_BATCHSIZE = "taskana.jobs.priority.batchSize";
private static final String TASKANA_JOB_PRIORITY_RUN_EVERY = "taskana.jobs.priority.runEvery";
private static final String TASKANA_JOB_PRIORITY_FIRST_RUN = "taskana.jobs.priority.firstRunAt";
private static final String TASKANA_JOB_PRIORITY_ACTIVE = "taskana.jobs.priority.active";
private static final String TASKANA_DOMAINS_PROPERTY = "taskana.domains";
private static final String TASKANA_CLASSIFICATION_TYPES_PROPERTY =
"taskana.classification.types";
@ -104,6 +108,11 @@ public class TaskanaEngineConfiguration {
private Duration cleanupJobMinimumAge = Duration.parse("P14D");
private boolean taskCleanupJobAllCompletedSameParentBusiness = true;
private int priorityJobBatchSize = 100;
private Instant priorityJobFirstRun = Instant.parse("2018-01-01T00:00:00Z");
private Duration priorityJobRunEvery = Duration.parse("P1D");
private boolean priorityJobActive = false;
public TaskanaEngineConfiguration(
DataSource dataSource, boolean useManagedTransactions, String schemaName) {
this(dataSource, useManagedTransactions, true, schemaName);
@ -349,6 +358,38 @@ public class TaskanaEngineConfiguration {
taskCleanupJobAllCompletedSameParentBusiness;
}
public int getPriorityJobBatchSize() {
return priorityJobBatchSize;
}
public void setPriorityJobBatchSize(int priorityJobBatchSize) {
this.priorityJobBatchSize = priorityJobBatchSize;
}
public Instant getPriorityJobFirstRun() {
return priorityJobFirstRun;
}
public void setPriorityJobFirstRun(Instant priorityJobFirstRun) {
this.priorityJobFirstRun = priorityJobFirstRun;
}
public Duration getPriorityJobRunEvery() {
return priorityJobRunEvery;
}
public void setPriorityJobRunEvery(Duration priorityJobRunEvery) {
this.priorityJobRunEvery = priorityJobRunEvery;
}
public boolean isPriorityJobActive() {
return priorityJobActive;
}
public void setPriorityJobActive(boolean priorityJobActive) {
this.priorityJobActive = priorityJobActive;
}
public String getSchemaName() {
return schemaName;
}
@ -405,6 +446,18 @@ public class TaskanaEngineConfiguration {
parseProperty(props, TASKANA_JOB_CLEANUP_MINIMUM_AGE, Duration::parse)
.ifPresent(this::setCleanupJobMinimumAge);
parseProperty(props, TASKANA_JOB_PRIORITY_BATCHSIZE, Integer::parseInt)
.ifPresent(this::setPriorityJobBatchSize);
parseProperty(props, TASKANA_JOB_PRIORITY_RUN_EVERY, Duration::parse)
.ifPresent(this::setPriorityJobRunEvery);
parseProperty(props, TASKANA_JOB_PRIORITY_FIRST_RUN, Instant::parse)
.ifPresent(this::setPriorityJobFirstRun);
parseProperty(props, TASKANA_JOB_PRIORITY_ACTIVE, Boolean::parseBoolean)
.ifPresent(this::setPriorityJobActive);
parseProperty(
props,
TASKANA_JOB_TASK_CLEANUP_ALL_COMPLETED_SAME_PARENT_BUSINESS,

View File

@ -8,6 +8,7 @@ import java.util.Objects;
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
import pro.taskana.task.internal.jobs.TaskCleanupJob;
import pro.taskana.task.internal.jobs.TaskRefreshJob;
import pro.taskana.task.internal.jobs.TaskUpdatePriorityJob;
import pro.taskana.workbasket.internal.jobs.WorkbasketCleanupJob;
/** This class holds all data that go into the Job table. */
@ -173,6 +174,7 @@ public class ScheduledJob {
CLASSIFICATION_CHANGED_JOB(ClassificationChangedJob.class.getName()),
TASK_REFRESH_JOB(TaskRefreshJob.class.getName()),
TASK_CLEANUP_JOB(TaskCleanupJob.class.getName()),
TASK_UPDATE_PRIORITY_JOB(TaskUpdatePriorityJob.class.getName()),
WORKBASKET_CLEANUP_JOB(WorkbasketCleanupJob.class.getName()),
HISTORY_CLEANUP_JOB("pro.taskana.simplehistory.impl.jobs.HistoryCleanupJob");

View File

@ -13,8 +13,8 @@ import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
/** Abstract base for all background jobs of TASKANA. */
public abstract class AbstractTaskanaJob implements TaskanaJob {
protected final Instant firstRun;
protected final Duration runEvery;
protected Instant firstRun;
protected Duration runEvery;
protected final TaskanaEngineImpl taskanaEngineImpl;
protected final TaskanaTransactionProvider txProvider;
protected final ScheduledJob scheduledJob;

View File

@ -43,6 +43,10 @@ public class PriorityServiceManager {
return Objects.nonNull(singleton) && singleton.enabled;
}
public long countRegisteredServices() {
return StreamSupport.stream(serviceLoader.spliterator(), false).count();
}
public Optional<Integer> calculatePriorityOfTask(TaskSummary task) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending task to PriorityServiceProviders: {}", task);

View File

@ -0,0 +1,99 @@
package pro.taskana.task.internal.jobs;
import static pro.taskana.common.internal.util.CollectionUtil.partitionBasedOnSize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.common.api.ScheduledJob;
import pro.taskana.common.api.ScheduledJob.Type;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.common.internal.JobServiceImpl;
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityWorker;
/** Job to recalculate the priority of each task that is not in an endstate. */
public class TaskUpdatePriorityJob extends AbstractTaskanaJob {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskUpdatePriorityJob.class);
private final int batchSize;
private final boolean isJobActive;
public TaskUpdatePriorityJob(TaskanaEngine taskanaEngine) {
this(taskanaEngine, null, null);
}
public TaskUpdatePriorityJob(
TaskanaEngine taskanaEngine,
TaskanaTransactionProvider txProvider,
ScheduledJob scheduledJob) {
super(taskanaEngine, txProvider, scheduledJob, true);
batchSize = taskanaEngine.getConfiguration().getPriorityJobBatchSize();
isJobActive = taskanaEngine.getConfiguration().isPriorityJobActive();
runEvery = taskanaEngine.getConfiguration().getPriorityJobRunEvery();
firstRun = taskanaEngine.getConfiguration().getPriorityJobFirstRun();
}
@Override
public void execute() {
if (!isJobActive()) {
LOGGER.debug("Job to update task priority is not active.");
return;
}
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngineImpl);
LOGGER.info("Running job to calculate all non finished task priorities");
try {
partitionBasedOnSize(worker.getAllRelevantTaskIds(), getBatchSize())
.forEach(worker::executeBatch);
LOGGER.info("Job to update priority of tasks has finished.");
} catch (Exception e) {
throw new SystemException("Error while processing TaskUpdatePriorityJob.", e);
}
}
public boolean isJobActive() {
return isJobActive;
}
public int getBatchSize() {
return batchSize;
}
/**
* Initializes the TaskUpdatePriorityJob schedule. <br>
* All scheduled jobs are cancelled/deleted and a new one is scheduled.
*
* @param taskanaEngine the TASKANA engine.
*/
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
jobService.deleteJobs(job.getType());
job.scheduleNextJob();
}
@Override
protected Type getType() {
return Type.TASK_UPDATE_PRIORITY_JOB;
}
@Override
public String toString() {
return "TaskUpdatePriorityJob [firstRun="
+ firstRun
+ ", runEvery="
+ runEvery
+ ", taskanaEngineImpl="
+ taskanaEngineImpl
+ ", txProvider="
+ txProvider
+ ", scheduledJob="
+ scheduledJob
+ ", batchSize="
+ batchSize
+ "]";
}
}

View File

@ -0,0 +1,45 @@
package pro.taskana.task.internal.jobs.helper;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
import javax.sql.DataSource;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.common.internal.util.CheckedConsumer;
/** Run low level SQL Statements reusing the taskana datasource. */
public class SqlConnectionRunner {
private final DataSource dataSource;
public SqlConnectionRunner(TaskanaEngine taskanaEngine) {
this(
Objects.requireNonNull(taskanaEngine, "Taskana engine may not be null")
.getConfiguration()
.getDatasource());
}
public SqlConnectionRunner(DataSource dataSource) {
this.dataSource = Objects.requireNonNull(dataSource, "Datasource may not be null.");
}
/**
* Run custom queries on a given connection. Please check for committing changes.
*
* @param consumer consumes a connection.
* @throws SystemException will pass on any checked SQLException as a runtime SystemException
*/
public void runWithConnection(CheckedConsumer<Connection, SQLException> consumer) {
try (Connection connection = getConnection()) {
consumer.accept(connection);
} catch (SQLException e) {
throw new SystemException("SQL error while running low level SQL", e);
}
}
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}

View File

@ -0,0 +1,30 @@
package pro.taskana.task.internal.jobs.helper;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Update a lot of priorities for tasks in a performant way without the need to write SQL. */
public class TaskUpdatePriorityBatchStatement {
private static final Logger LOGGER =
LoggerFactory.getLogger(TaskUpdatePriorityBatchStatement.class);
private final PreparedStatement preparedStatement;
public TaskUpdatePriorityBatchStatement(Connection connection) throws SQLException {
preparedStatement = connection.prepareStatement("update TASK set PRIORITY = ? where ID = ?");
}
public void addPriorityUpdate(String taskId, Integer priority) throws SQLException {
preparedStatement.setInt(1, priority);
preparedStatement.setString(2, taskId);
LOGGER.debug("Job update priority to {} for task {}.", priority, taskId);
preparedStatement.addBatch();
}
public void executeBatch() throws SQLException {
preparedStatement.executeBatch();
}
}

View File

@ -0,0 +1,83 @@
package pro.taskana.task.internal.jobs.helper;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import pro.taskana.common.api.BaseQuery.SortDirection;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.spi.priority.internal.PriorityServiceManager;
import pro.taskana.task.api.TaskQueryColumnName;
import pro.taskana.task.api.TaskState;
import pro.taskana.task.api.models.TaskSummary;
public class TaskUpdatePriorityWorker {
private final SqlConnectionRunner sqlConnectionRunner;
private final TaskanaEngine taskanaEngine;
public TaskUpdatePriorityWorker(TaskanaEngine taskanaEngine) {
this.taskanaEngine = taskanaEngine;
this.sqlConnectionRunner = new SqlConnectionRunner(taskanaEngine);
}
public List<String> executeBatch(List<String> taskIds) {
List<String> updatedTaskIds = new ArrayList<>();
sqlConnectionRunner.runWithConnection(
connection -> {
TaskUpdatePriorityBatchStatement taskUpdateBatch =
new TaskUpdatePriorityBatchStatement(connection);
List<TaskSummary> list = getTaskSummariesByIds(taskIds);
for (TaskSummary taskSummary : list) {
Optional<Integer> calculatedPriority = getCalculatedPriority(taskSummary);
if (calculatedPriority.isPresent()) {
final String taskId = taskSummary.getId();
updatedTaskIds.add(taskId);
taskUpdateBatch.addPriorityUpdate(taskId, calculatedPriority.get());
}
}
taskUpdateBatch.executeBatch();
// don't forget to save changes
if (!connection.getAutoCommit()) {
connection.commit();
}
});
return updatedTaskIds;
}
/**
* This will return all relevant task ids. This may result in a LOT! of ids
*
* @return list of task ids.
*/
public List<String> getAllRelevantTaskIds() {
return taskanaEngine
.getTaskService()
.createTaskQuery()
.stateNotIn(TaskState.END_STATES)
.listValues(TaskQueryColumnName.ID, SortDirection.ASCENDING);
}
public List<TaskSummary> getTaskSummariesByIds(List<String> taskIds) {
return taskanaEngine
.getTaskService()
.createTaskQuery()
.idIn(taskIds.toArray(new String[0]))
.list();
}
public Optional<Integer> getCalculatedPriority(TaskSummary taskSummary) {
return PriorityServiceManager.getInstance()
.calculatePriorityOfTask(taskSummary)
.filter(hasDifferentPriority(taskSummary));
}
public static Predicate<Integer> hasDifferentPriority(TaskSummary taskSummary) {
return prio -> taskSummary != null && prio != taskSummary.getPriority();
}
}

View File

@ -0,0 +1,141 @@
package acceptance.jobs;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.common.api.BaseQuery.SortDirection;
import pro.taskana.common.api.ScheduledJob;
import pro.taskana.common.api.ScheduledJob.Type;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.task.api.TaskQueryColumnName;
import pro.taskana.task.internal.jobs.TaskUpdatePriorityJob;
/** Acceptance test for all "jobs tasks runner" scenarios. */
@ExtendWith(JaasExtension.class)
class TaskUpdatePriorityJobAccTest 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(true);
taskanaEngineConfiguration.setPriorityJobActive(true);
taskanaEngineConfiguration.setPriorityJobBatchSize(20);
taskanaEngineConfiguration.setPriorityJobRunEvery(Duration.ofMinutes(30));
taskanaEngineConfiguration.setPriorityJobFirstRun(Instant.parse("2007-12-03T10:15:30.00Z"));
}
@Test
@WithAccessId(user = "admin")
void should_workWithoutException() {
// given
TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
// then
assertThatCode(job::execute).doesNotThrowAnyException();
}
@Test
@WithAccessId(user = "admin")
void should_catchException_When_executedWithWrongSettings() {
// given
taskanaEngineConfiguration.setPriorityJobBatchSize(0);
TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
// then
assertThatThrownBy(job::execute).isInstanceOf(SystemException.class);
}
@Test
@WithAccessId(user = "admin")
void should_doNothing_When_NotActive() {
// given
taskanaEngineConfiguration.setPriorityJobActive(false);
TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
List<String> priorities =
taskanaEngine
.getTaskService()
.createTaskQuery()
.listValues(TaskQueryColumnName.PRIORITY, SortDirection.ASCENDING);
// when
job.execute();
// then
List<String> prioritiesUnchanged =
taskanaEngine
.getTaskService()
.createTaskQuery()
.listValues(TaskQueryColumnName.PRIORITY, SortDirection.ASCENDING);
assertThat(priorities).isEqualTo(prioritiesUnchanged);
}
@Test
@WithAccessId(user = "admin")
void should_ScheduleNextJob() throws NoSuchFieldException, IllegalAccessException {
// given
final Instant someTimeInTheFuture = Instant.now().plus(10, ChronoUnit.DAYS);
// when
TaskUpdatePriorityJob.initializeSchedule(taskanaEngine);
// then
assertThat(getJobMapper().findJobsToRun(someTimeInTheFuture))
.hasSizeGreaterThanOrEqualTo(1)
.extracting(ScheduledJob::getType)
.contains(Type.TASK_UPDATE_PRIORITY_JOB);
}
@Test
@WithAccessId(user = "admin")
void should_readConfigurationForBatchSize() {
// given
taskanaEngineConfiguration.setPriorityJobBatchSize(20);
// when
final TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
// then
assertThat(job.getBatchSize()).isEqualTo(20);
}
@Test
@WithAccessId(user = "admin")
void should_readConfigurationForIsActive() {
// given
taskanaEngineConfiguration.setPriorityJobActive(false);
// when
final TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
// then
assertThat(job.isJobActive()).isFalse();
}
@Test
void should_containInformation_When_convertedToString() {
// given
taskanaEngineConfiguration.setPriorityJobBatchSize(543);
taskanaEngineConfiguration.setPriorityJobRunEvery(Duration.ofMinutes(30));
// when
final TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
// then
assertThat(job).asString().contains("543").contains(Duration.ofMinutes(30).toString());
}
}

View File

@ -0,0 +1,62 @@
package acceptance.jobs.helper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.task.internal.jobs.helper.SqlConnectionRunner;
/** Acceptance test for all "jobs tasks runner" scenarios. */
@ExtendWith(JaasExtension.class)
class SqlConnectionRunnerAccTest 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);
}
@Test
void should_executeSimpleQuery() {
// given
SqlConnectionRunner runner = new SqlConnectionRunner(taskanaEngine);
String taskId = "TKI:000000000000000000000000000000000050";
// when
runner.runWithConnection(
connection -> {
PreparedStatement preparedStatement =
connection.prepareStatement("select * from TASK where ID = ?");
preparedStatement.setString(1, taskId);
final ResultSet resultSet = preparedStatement.executeQuery();
// then
assertThat(resultSet.next()).isTrue();
});
}
@Test
void should_catchSqlExceptionAndThrowSystemException() {
// given
SqlConnectionRunner runner = new SqlConnectionRunner(taskanaEngine);
// when
assertThatThrownBy(
() ->
runner.runWithConnection(
connection -> {
throw new SQLException("test");
}))
.isInstanceOf(SystemException.class);
}
}

View File

@ -0,0 +1,51 @@
package acceptance.jobs.helper;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
import pro.taskana.task.api.models.Task;
import pro.taskana.task.internal.jobs.helper.SqlConnectionRunner;
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityBatchStatement;
/** Acceptance test for all "jobs tasks runner" scenarios. */
@ExtendWith(JaasExtension.class)
class TaskUpdatePriorityBatchStatementAccTest 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(true);
}
@Test
@WithAccessId(user = "admin")
void should_updatePriority() throws TaskNotFoundException, NotAuthorizedException {
// given
SqlConnectionRunner runner = new SqlConnectionRunner(taskanaEngine);
String taskId = "TKI:000000000000000000000000000000000050";
final int priorityUpdate = 25;
// when
runner.runWithConnection(
connection -> {
final TaskUpdatePriorityBatchStatement batchStatement =
new TaskUpdatePriorityBatchStatement(connection);
batchStatement.addPriorityUpdate(taskId, priorityUpdate);
batchStatement.executeBatch();
connection.commit();
});
// then
final Task actual = taskanaEngine.getTaskService().getTask(taskId);
assertThat(actual).extracting(Task::getPriority).isEqualTo(priorityUpdate);
}
}

View File

@ -0,0 +1,134 @@
package acceptance.jobs.helper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import acceptance.AbstractAccTest;
import java.util.List;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.spi.priority.internal.PriorityServiceManager;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
import pro.taskana.task.api.models.Task;
import pro.taskana.task.api.models.TaskSummary;
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityWorker;
import pro.taskana.task.internal.models.TaskImpl;
/** Acceptance test for all "jobs tasks runner" scenarios. */
@ExtendWith(JaasExtension.class)
class TaskUpdatePriorityWorkerAccTest 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(true);
}
@Test
@WithAccessId(user = "admin")
void should_loadAnyRelevantTaskId() {
// given
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
// when
final List<String> allRelevantTaskIds = worker.getAllRelevantTaskIds();
// then
assertThat(allRelevantTaskIds).hasSizeGreaterThan(0);
}
@Test
@WithAccessId(user = "admin")
void should_loadExistingTaskIds() {
// given
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
final List<String> allRelevantTaskIds = worker.getAllRelevantTaskIds();
final String foundTaskId = allRelevantTaskIds.get(0);
// when
final List<TaskSummary> taskSummariesByIds = worker.getTaskSummariesByIds(List.of(foundTaskId));
// then
assertThat(taskSummariesByIds)
.hasSize(1)
.extracting(TaskSummary::getId)
.containsExactly(foundTaskId);
}
@Test
@WithAccessId(user = "admin")
void should_notLoadAnyIrrelevantTaskIds() {
// given
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
String completedTaskId = "TKI:000000000000000000000000000000000038";
// when
final List<String> allRelevantTaskIds = worker.getAllRelevantTaskIds();
// then
assertThat(allRelevantTaskIds).isNotEmpty().doesNotContain(completedTaskId);
}
@Test
@WithAccessId(user = "admin")
void should_loadExistingTaskSummariesById() {
// given
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
String taskId1 = "TKI:000000000000000000000000000000000050";
String taskId2 = "TKI:000000000000000000000000000000000051";
// when
final List<TaskSummary> taskSummariesByIds =
worker.getTaskSummariesByIds(List.of(taskId1, taskId2));
// then
assertThat(taskSummariesByIds)
.hasSizeGreaterThan(0)
.extracting(TaskSummary::getId)
.containsExactlyInAnyOrder(taskId1, taskId2);
}
@Test
@WithAccessId(user = "admin")
void should_executeBatch() throws TaskNotFoundException, NotAuthorizedException {
// given
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
final List<String> allRelevantTaskIds = worker.getAllRelevantTaskIds();
String taskId = "TKI:000000000000000000000000000000000050";
Task taskOld = taskanaEngine.getTaskService().getTask(taskId);
// when
final List<String> updatedTaskIds = worker.executeBatch(allRelevantTaskIds);
// then
final Task taskUpdated = taskanaEngine.getTaskService().getTask(taskId);
assumeThat(PriorityServiceManager.getInstance().countRegisteredServices())
.describedAs("SPI should be provided in order to check for modified priorities.")
.isPositive();
assertThat(updatedTaskIds).contains(taskId);
assertThat(taskUpdated.getPriority()).isNotEqualTo(taskOld.getPriority());
}
@Test
void should_noticeDifferentPriority_When_PriorityHasChanged() {
// given
final TaskImpl task = (TaskImpl) taskanaEngine.getTaskService().newTask();
task.setPriority(232);
// when
final Predicate<Integer> differentPriority =
TaskUpdatePriorityWorker.hasDifferentPriority(task);
// then
assertThat(differentPriority).rejects(232).accepts(2, 3, 4, 5);
}
}