TSK-1704: test API now restricting service providers to specific test
This commit is contained in:
parent
d61fc1f56d
commit
fb4234b6f1
|
@ -18,6 +18,8 @@ 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.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
|
@ -702,6 +704,7 @@ class JaasExtensionTest {
|
|||
// region JaasExtension#interceptTestClassConstructor
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ConstructorWithoutAccessId {
|
||||
ConstructorWithoutAccessId() {
|
||||
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
|
||||
|
@ -714,6 +717,7 @@ class JaasExtensionTest {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ConstructorWithAccessId {
|
||||
@WithAccessId(user = "constructor")
|
||||
ConstructorWithAccessId() {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package pro.taskana.common.internal.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class SpiLoader {
|
||||
|
||||
private SpiLoader() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static <T> List<T> load(Class<T> clazz) {
|
||||
ServiceLoader<T> serviceLoader = ServiceLoader.load(clazz);
|
||||
return StreamSupport.stream(serviceLoader.spliterator(), false).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package pro.taskana.common.internal.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import pro.taskana.common.internal.util.spi.ServiceProviderInterface;
|
||||
|
||||
class SpiLoaderTest {
|
||||
|
||||
@Test
|
||||
void should_loadServiceProviders() {
|
||||
List<ServiceProviderInterface> serviceProviders =
|
||||
SpiLoader.load(ServiceProviderInterface.class);
|
||||
|
||||
assertThat(serviceProviders)
|
||||
.isNotEmpty()
|
||||
.extracting(ServiceProviderInterface::doStuff)
|
||||
.containsExactly("doing Stuff");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package pro.taskana.common.internal.util.spi;
|
||||
|
||||
public interface ServiceProviderInterface {
|
||||
String doStuff();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package pro.taskana.common.internal.util.spi;
|
||||
|
||||
public class ServiceProviderInterfaceImpl implements ServiceProviderInterface {
|
||||
|
||||
@Override
|
||||
public String doStuff() {
|
||||
return "doing Stuff";
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pro.taskana.common.internal.util.spi.ServiceProviderInterfaceImpl
|
|
@ -46,15 +46,18 @@ public class ClassificationServiceImpl implements ClassificationService {
|
|||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationServiceImpl.class);
|
||||
private final HistoryEventManager historyEventManager;
|
||||
private final PriorityServiceManager priorityServiceManager;
|
||||
private final ClassificationMapper classificationMapper;
|
||||
private final TaskMapper taskMapper;
|
||||
private final InternalTaskanaEngine taskanaEngine;
|
||||
|
||||
public ClassificationServiceImpl(
|
||||
InternalTaskanaEngine taskanaEngine,
|
||||
PriorityServiceManager priorityServiceManager,
|
||||
ClassificationMapper classificationMapper,
|
||||
TaskMapper taskMapper) {
|
||||
this.taskanaEngine = taskanaEngine;
|
||||
this.priorityServiceManager = priorityServiceManager;
|
||||
this.classificationMapper = classificationMapper;
|
||||
this.taskMapper = taskMapper;
|
||||
this.historyEventManager = taskanaEngine.getHistoryEventManager();
|
||||
|
@ -132,7 +135,7 @@ public class ClassificationServiceImpl implements ClassificationService {
|
|||
try {
|
||||
this.classificationMapper.deleteClassification(classificationId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
classification, newClassification("", "", ""));
|
||||
|
@ -201,7 +204,7 @@ public class ClassificationServiceImpl implements ClassificationService {
|
|||
|
||||
classificationMapper.insert(classificationImpl);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
newClassification("", "", ""), classificationImpl);
|
||||
|
@ -255,11 +258,11 @@ public class ClassificationServiceImpl implements ClassificationService {
|
|||
this.checkExistenceOfParentClassification(oldClassification, classificationImpl);
|
||||
classificationMapper.update(classificationImpl);
|
||||
|
||||
if (!PriorityServiceManager.isPriorityServiceEnabled()) {
|
||||
if (!priorityServiceManager.isEnabled()) {
|
||||
this.createJobIfPriorityOrServiceLevelHasChanged(oldClassification, classificationImpl);
|
||||
}
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
oldClassification, classificationImpl);
|
||||
|
|
|
@ -97,7 +97,6 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
|||
createTransactionFactory(taskanaEngineConfiguration.getUseManagedTransactions());
|
||||
this.sessionManager = createSqlSessionManager();
|
||||
initializeDbSchema(taskanaEngineConfiguration);
|
||||
createTaskPreprocessorManager = CreateTaskPreprocessorManager.getInstance();
|
||||
this.internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
|
||||
workingDaysToDaysConverter =
|
||||
new WorkingDaysToDaysConverter(
|
||||
|
@ -109,9 +108,10 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
|||
|
||||
// IMPORTANT: SPI has to be initialized last (and in this order) in order
|
||||
// to provide a fully initialized TaskanaEngine instance during the SPI initialization!
|
||||
historyEventManager = HistoryEventManager.getInstance(this);
|
||||
taskRoutingManager = TaskRoutingManager.getInstance(this);
|
||||
priorityServiceManager = PriorityServiceManager.getInstance();
|
||||
historyEventManager = new HistoryEventManager(this);
|
||||
taskRoutingManager = new TaskRoutingManager(this);
|
||||
priorityServiceManager = new PriorityServiceManager();
|
||||
createTaskPreprocessorManager = new CreateTaskPreprocessorManager();
|
||||
}
|
||||
|
||||
public static TaskanaEngine createTaskanaEngine(
|
||||
|
@ -138,6 +138,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
|||
public WorkbasketService getWorkbasketService() {
|
||||
return new WorkbasketServiceImpl(
|
||||
internalTaskanaEngineImpl,
|
||||
historyEventManager,
|
||||
sessionManager.getMapper(WorkbasketMapper.class),
|
||||
sessionManager.getMapper(DistributionTargetMapper.class),
|
||||
sessionManager.getMapper(WorkbasketAccessMapper.class));
|
||||
|
@ -147,10 +148,18 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
|||
public ClassificationService getClassificationService() {
|
||||
return new ClassificationServiceImpl(
|
||||
internalTaskanaEngineImpl,
|
||||
priorityServiceManager,
|
||||
sessionManager.getMapper(ClassificationMapper.class),
|
||||
sessionManager.getMapper(TaskMapper.class));
|
||||
}
|
||||
|
||||
// This should be part of the InternalTaskanaEngine. Unfortunately the jobs don't have access to
|
||||
// that engine.
|
||||
// Therefore, this getter exits and will be removed as soon as our jobs will be refactored.
|
||||
public PriorityServiceManager getPriorityServiceManager() {
|
||||
return priorityServiceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobService getJobService() {
|
||||
return new JobServiceImpl(internalTaskanaEngineImpl, sessionManager.getMapper(JobMapper.class));
|
||||
|
@ -174,7 +183,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
|||
|
||||
@Override
|
||||
public boolean isHistoryEnabled() {
|
||||
return HistoryEventManager.isHistoryEnabled();
|
||||
return historyEventManager.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package pro.taskana.spi.history.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.api.exceptions.SystemException;
|
||||
import pro.taskana.common.internal.util.CheckedConsumer;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.spi.history.api.TaskanaHistory;
|
||||
import pro.taskana.spi.history.api.events.classification.ClassificationHistoryEvent;
|
||||
import pro.taskana.spi.history.api.events.task.TaskHistoryEvent;
|
||||
|
@ -17,107 +16,55 @@ import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEvent;
|
|||
public final class HistoryEventManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HistoryEventManager.class);
|
||||
private static HistoryEventManager singleton;
|
||||
private final ServiceLoader<TaskanaHistory> serviceLoader;
|
||||
private boolean enabled = false;
|
||||
private final List<TaskanaHistory> taskanaHistories;
|
||||
|
||||
private HistoryEventManager(TaskanaEngine taskanaEngine) {
|
||||
serviceLoader = ServiceLoader.load(TaskanaHistory.class);
|
||||
for (TaskanaHistory history : serviceLoader) {
|
||||
public HistoryEventManager(TaskanaEngine taskanaEngine) {
|
||||
taskanaHistories = SpiLoader.load(TaskanaHistory.class);
|
||||
for (TaskanaHistory history : taskanaHistories) {
|
||||
history.initialize(taskanaEngine);
|
||||
LOGGER.info("Registered history provider: {}", history.getClass().getName());
|
||||
enabled = true;
|
||||
}
|
||||
if (!enabled) {
|
||||
LOGGER.info("No history provider found. Running without history.");
|
||||
if (taskanaHistories.isEmpty()) {
|
||||
LOGGER.info("No TaskanaHistory provider found. Running without History.");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized HistoryEventManager getInstance(TaskanaEngine taskanaEngine) {
|
||||
if (singleton == null) {
|
||||
singleton = new HistoryEventManager(taskanaEngine);
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public static boolean isHistoryEnabled() {
|
||||
return Objects.nonNull(singleton) && singleton.enabled;
|
||||
public boolean isEnabled() {
|
||||
return !taskanaHistories.isEmpty();
|
||||
}
|
||||
|
||||
public void createEvent(TaskHistoryEvent event) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending event to history service providers: {}", event);
|
||||
}
|
||||
serviceLoader.forEach(
|
||||
historyProvider -> {
|
||||
try {
|
||||
historyProvider.create(event);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught an exception while trying to create TaskHistoryEvent in class %s",
|
||||
historyProvider.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
});
|
||||
taskanaHistories.forEach(
|
||||
CheckedConsumer.wrap(historyProvider -> historyProvider.create(event)));
|
||||
}
|
||||
|
||||
public void createEvent(WorkbasketHistoryEvent event) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending event to history service providers: {}", event);
|
||||
}
|
||||
serviceLoader.forEach(
|
||||
historyProvider -> {
|
||||
try {
|
||||
historyProvider.create(event);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught an exception while trying to create WorkbasketHistoryEvent in class %s",
|
||||
historyProvider.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
});
|
||||
taskanaHistories.forEach(
|
||||
CheckedConsumer.wrap(historyProvider -> historyProvider.create(event)));
|
||||
}
|
||||
|
||||
public void createEvent(ClassificationHistoryEvent event) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending event to history service providers: {}", event);
|
||||
}
|
||||
serviceLoader.forEach(
|
||||
historyProvider -> {
|
||||
try {
|
||||
historyProvider.create(event);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught an exception while trying to create "
|
||||
+ "ClassificationHistoryEvent in class %s",
|
||||
historyProvider.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
});
|
||||
|
||||
taskanaHistories.forEach(
|
||||
CheckedConsumer.wrap(historyProvider -> historyProvider.create(event)));
|
||||
}
|
||||
|
||||
public void deleteEvents(List<String> taskIds) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending taskIds to history service providers: {}", taskIds);
|
||||
}
|
||||
serviceLoader.forEach(
|
||||
historyProvider -> {
|
||||
try {
|
||||
historyProvider.deleteHistoryEventsByTaskIds(taskIds);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught an exception while trying to delete HistoryEvents in class %s",
|
||||
historyProvider.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
});
|
||||
|
||||
taskanaHistories.forEach(
|
||||
CheckedConsumer.wrap(
|
||||
historyProvider -> historyProvider.deleteHistoryEventsByTaskIds(taskIds)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.taskana.spi.priority.api;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import pro.taskana.task.api.models.Task;
|
||||
import pro.taskana.task.api.models.TaskSummary;
|
||||
|
@ -21,5 +21,5 @@ public interface PriorityServiceProvider {
|
|||
* priority} for
|
||||
* @return the computed {@linkplain Task#getPriority() priority}
|
||||
*/
|
||||
Optional<Integer> calculatePriority(TaskSummary taskSummary);
|
||||
OptionalInt calculatePriority(TaskSummary taskSummary);
|
||||
}
|
||||
|
|
|
@ -1,88 +1,57 @@
|
|||
package pro.taskana.spi.priority.internal;
|
||||
|
||||
import static pro.taskana.common.internal.util.CheckedFunction.wrap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import pro.taskana.common.api.exceptions.SystemException;
|
||||
import pro.taskana.common.internal.util.LogSanitizer;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.task.api.models.TaskSummary;
|
||||
|
||||
public class PriorityServiceManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PriorityServiceManager.class);
|
||||
private static PriorityServiceManager singleton;
|
||||
private final ServiceLoader<PriorityServiceProvider> serviceLoader;
|
||||
private boolean enabled = false;
|
||||
private final List<PriorityServiceProvider> priorityServiceProviders;
|
||||
|
||||
private PriorityServiceManager() {
|
||||
serviceLoader = ServiceLoader.load(PriorityServiceProvider.class);
|
||||
for (PriorityServiceProvider priorityProvider : serviceLoader) {
|
||||
public PriorityServiceManager() {
|
||||
priorityServiceProviders = SpiLoader.load(PriorityServiceProvider.class);
|
||||
for (PriorityServiceProvider priorityProvider : priorityServiceProviders) {
|
||||
LOGGER.info("Registered PriorityServiceProvider: {}", priorityProvider.getClass().getName());
|
||||
enabled = true;
|
||||
}
|
||||
if (!enabled) {
|
||||
if (priorityServiceProviders.isEmpty()) {
|
||||
LOGGER.info("No PriorityServiceProvider found. Running without PriorityServiceProvider.");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized PriorityServiceManager getInstance() {
|
||||
if (singleton == null) {
|
||||
singleton = new PriorityServiceManager();
|
||||
}
|
||||
return singleton;
|
||||
public boolean isEnabled() {
|
||||
return !priorityServiceProviders.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isPriorityServiceEnabled() {
|
||||
return Objects.nonNull(singleton) && singleton.enabled;
|
||||
}
|
||||
|
||||
public long countRegisteredServices() {
|
||||
return StreamSupport.stream(serviceLoader.spliterator(), false).count();
|
||||
}
|
||||
|
||||
public Optional<Integer> calculatePriorityOfTask(TaskSummary task) {
|
||||
public OptionalInt calculatePriorityOfTask(TaskSummary task) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending task to PriorityServiceProviders: {}", task);
|
||||
}
|
||||
|
||||
// ServiceLoader.stream() is only available in Java11.
|
||||
List<Integer> priorities =
|
||||
StreamSupport.stream(serviceLoader.spliterator(), false)
|
||||
.map(provider -> getPriorityByProvider(task, provider))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Set<OptionalInt> priorities =
|
||||
priorityServiceProviders.stream()
|
||||
.map(wrap(provider -> provider.calculatePriority(task)))
|
||||
.filter(OptionalInt::isPresent)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (priorities.size() <= 1) {
|
||||
return priorities.stream().findFirst();
|
||||
}
|
||||
|
||||
if (LOGGER.isErrorEnabled()) {
|
||||
if (priorities.size() == 1) {
|
||||
return priorities.iterator().next();
|
||||
} else if (!priorities.isEmpty() && LOGGER.isErrorEnabled()) {
|
||||
LOGGER.error(
|
||||
"The PriorityServiceProviders determined more than one priority for Task {}.",
|
||||
LogSanitizer.stripLineBreakingChars(task));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<Integer> getPriorityByProvider(
|
||||
TaskSummary task, PriorityServiceProvider provider) {
|
||||
try {
|
||||
return provider.calculatePriority(task);
|
||||
} catch (Exception e) {
|
||||
throw new SystemException(
|
||||
String.format(
|
||||
"Caught exception while calculating priority of Task in provider %s.",
|
||||
provider.getClass().getName()),
|
||||
e);
|
||||
}
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package pro.taskana.spi.routing.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.api.exceptions.SystemException;
|
||||
import pro.taskana.common.internal.util.CheckedFunction;
|
||||
import pro.taskana.common.internal.util.LogSanitizer;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.spi.routing.api.TaskRoutingProvider;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
|
@ -22,37 +21,20 @@ import pro.taskana.task.api.models.Task;
|
|||
public final class TaskRoutingManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TaskRoutingManager.class);
|
||||
private static TaskRoutingManager singleton;
|
||||
private final List<TaskRoutingProvider> theTaskRoutingProviders = new ArrayList<>();
|
||||
private final ServiceLoader<TaskRoutingProvider> serviceLoader;
|
||||
private boolean enabled = false;
|
||||
private final List<TaskRoutingProvider> taskRoutingProviders;
|
||||
|
||||
private TaskRoutingManager(TaskanaEngine taskanaEngine) {
|
||||
serviceLoader = ServiceLoader.load(TaskRoutingProvider.class);
|
||||
for (TaskRoutingProvider router : serviceLoader) {
|
||||
router.initialize(taskanaEngine);
|
||||
theTaskRoutingProviders.add(router);
|
||||
LOGGER.info("Registered TaskRouter provider: {}", router.getClass().getName());
|
||||
public TaskRoutingManager(TaskanaEngine taskanaEngine) {
|
||||
taskRoutingProviders = SpiLoader.load(TaskRoutingProvider.class);
|
||||
for (TaskRoutingProvider taskRoutingProvider : taskRoutingProviders) {
|
||||
taskRoutingProvider.initialize(taskanaEngine);
|
||||
LOGGER.info("Registered TaskRouter provider: {}", taskRoutingProvider.getClass().getName());
|
||||
}
|
||||
|
||||
if (theTaskRoutingProviders.isEmpty()) {
|
||||
LOGGER.info("No TaskRouter provider found. Running without Task Routing.");
|
||||
} else {
|
||||
enabled = true;
|
||||
if (taskRoutingProviders.isEmpty()) {
|
||||
LOGGER.info("No TaskRouter provider found. Running without Task routing.");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized TaskRoutingManager getInstance(TaskanaEngine taskanaEngine) {
|
||||
if (singleton == null) {
|
||||
singleton = new TaskRoutingManager(taskanaEngine);
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public static boolean isTaskRoutingEnabled() {
|
||||
return Objects.nonNull(singleton) && singleton.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a workbasket id for a given task. Algorithm: The task that needs a workbasket id is
|
||||
* passed to all registered TaskRoutingProviders. If they return no or more than one workbasketId,
|
||||
|
@ -64,24 +46,12 @@ public final class TaskRoutingManager {
|
|||
*/
|
||||
public String determineWorkbasketId(Task task) {
|
||||
String workbasketId = null;
|
||||
if (isTaskRoutingEnabled()) {
|
||||
// route to all TaskRoutingProviders
|
||||
// collect in a set to see whether different workbasket ids are returned
|
||||
if (isEnabled()) {
|
||||
Set<String> workbasketIds =
|
||||
theTaskRoutingProviders.stream()
|
||||
taskRoutingProviders.stream()
|
||||
.map(
|
||||
rtr -> {
|
||||
try {
|
||||
return rtr.determineWorkbasketId(task);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught Exception while trying to determine workbasket in class %s",
|
||||
rtr.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
})
|
||||
CheckedFunction.wrap(
|
||||
taskRoutingProvider -> taskRoutingProvider.determineWorkbasketId(task)))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
if (workbasketIds.isEmpty()) {
|
||||
|
@ -97,9 +67,13 @@ public final class TaskRoutingManager {
|
|||
LogSanitizer.stripLineBreakingChars(task));
|
||||
}
|
||||
} else {
|
||||
workbasketId = workbasketIds.stream().findFirst().orElse(null);
|
||||
workbasketId = workbasketIds.iterator().next();
|
||||
}
|
||||
}
|
||||
return workbasketId;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return !taskRoutingProviders.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,43 @@
|
|||
package pro.taskana.spi.task.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import static pro.taskana.common.internal.util.CheckedConsumer.wrap;
|
||||
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import pro.taskana.common.api.exceptions.SystemException;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
public class CreateTaskPreprocessorManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTaskPreprocessorManager.class);
|
||||
private static CreateTaskPreprocessorManager singleton;
|
||||
private final ServiceLoader<CreateTaskPreprocessor> serviceLoader;
|
||||
private boolean enabled = false;
|
||||
private final List<CreateTaskPreprocessor> createTaskPreprocessors;
|
||||
|
||||
private CreateTaskPreprocessorManager() {
|
||||
serviceLoader = ServiceLoader.load(CreateTaskPreprocessor.class);
|
||||
for (CreateTaskPreprocessor preprocessor : serviceLoader) {
|
||||
public CreateTaskPreprocessorManager() {
|
||||
createTaskPreprocessors = SpiLoader.load(CreateTaskPreprocessor.class);
|
||||
for (CreateTaskPreprocessor preprocessor : createTaskPreprocessors) {
|
||||
LOGGER.info(
|
||||
"Registered CreateTaskPreprocessor provider: {}", preprocessor.getClass().getName());
|
||||
enabled = true;
|
||||
}
|
||||
if (!enabled) {
|
||||
if (createTaskPreprocessors.isEmpty()) {
|
||||
LOGGER.info("No CreateTaskPreprocessor found. Running without CreateTaskPreprocessor.");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized CreateTaskPreprocessorManager getInstance() {
|
||||
if (singleton == null) {
|
||||
singleton = new CreateTaskPreprocessorManager();
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public static boolean isCreateTaskPreprocessorEnabled() {
|
||||
return Objects.nonNull(singleton) && singleton.enabled;
|
||||
}
|
||||
|
||||
public Task processTaskBeforeCreation(Task taskToProcess) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending task to CreateTaskPreprocessor providers: {}", taskToProcess);
|
||||
}
|
||||
serviceLoader.forEach(
|
||||
createTaskPreprocessorProvider -> {
|
||||
try {
|
||||
createTaskPreprocessorProvider.processTaskBeforeCreation(taskToProcess);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
String.format(
|
||||
"Caught exception while processing task before creation in class %s",
|
||||
createTaskPreprocessorProvider.getClass().getName()),
|
||||
e);
|
||||
throw new SystemException(e.getMessage(), e.getCause());
|
||||
}
|
||||
});
|
||||
createTaskPreprocessors.forEach(
|
||||
wrap(
|
||||
createTaskPreprocessor ->
|
||||
createTaskPreprocessor.processTaskBeforeCreation(taskToProcess)));
|
||||
return taskToProcess;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return !createTaskPreprocessors.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException,
|
||||
TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException {
|
||||
|
||||
if (CreateTaskPreprocessorManager.isCreateTaskPreprocessorEnabled()) {
|
||||
if (createTaskPreprocessorManager.isEnabled()) {
|
||||
taskToCreate = createTaskPreprocessorManager.processTaskBeforeCreation(taskToCreate);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
workbasket = workbasketService.getWorkbasket(workbasketId);
|
||||
task.setWorkbasketSummary(workbasket.asSummary());
|
||||
} else {
|
||||
throw new InvalidArgumentException("Cannot create a task outside a workbasket");
|
||||
throw new InvalidArgumentException("Cannot create a Task outside a Workbasket");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,20 +226,14 @@ public class TaskServiceImpl implements TaskService {
|
|||
ObjectReference.validate(task.getPrimaryObjRef(), "primary ObjectReference", "Task");
|
||||
standardSettingsOnTaskCreation(task, classification);
|
||||
setCallbackStateOnTaskCreation(task);
|
||||
|
||||
if (PriorityServiceManager.isPriorityServiceEnabled()) {
|
||||
Optional<Integer> newPriority = priorityServiceManager.calculatePriorityOfTask(task);
|
||||
if (newPriority.isPresent()) {
|
||||
task.setPriority(newPriority.get());
|
||||
}
|
||||
}
|
||||
priorityServiceManager.calculatePriorityOfTask(task).ifPresent(task::setPriority);
|
||||
|
||||
try {
|
||||
this.taskMapper.insert(task);
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Method createTask() created Task '{}'.", task.getId());
|
||||
}
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(newTask(), task);
|
||||
|
@ -426,12 +420,9 @@ public class TaskServiceImpl implements TaskService {
|
|||
|
||||
standardUpdateActions(oldTaskImpl, newTaskImpl);
|
||||
|
||||
if (PriorityServiceManager.isPriorityServiceEnabled()) {
|
||||
Optional<Integer> newPriority = priorityServiceManager.calculatePriorityOfTask(newTaskImpl);
|
||||
if (newPriority.isPresent()) {
|
||||
newTaskImpl.setPriority(newPriority.get());
|
||||
}
|
||||
}
|
||||
priorityServiceManager
|
||||
.calculatePriorityOfTask(newTaskImpl)
|
||||
.ifPresent(newTaskImpl::setPriority);
|
||||
|
||||
taskMapper.update(newTaskImpl);
|
||||
|
||||
|
@ -439,7 +430,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
LOGGER.debug("Method updateTask() updated task '{}' for user '{}'.", task.getId(), userId);
|
||||
}
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String changeDetails =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(oldTaskImpl, newTaskImpl);
|
||||
|
@ -771,7 +762,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
taskanaEngine.openConnection();
|
||||
cancelledTask = terminateCancelCommonActions(taskId, TaskState.CANCELLED);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
historyEventManager.createEvent(
|
||||
new TaskCancelledEvent(
|
||||
IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT),
|
||||
|
@ -797,7 +788,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
taskanaEngine.openConnection();
|
||||
terminatedTask = terminateCancelCommonActions(taskId, TaskState.TERMINATED);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
historyEventManager.createEvent(
|
||||
new TaskTerminatedEvent(
|
||||
IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT),
|
||||
|
@ -1124,7 +1115,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Task '{}' claimed by user '{}'.", taskId, userId);
|
||||
}
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
historyEventManager.createEvent(
|
||||
new TaskClaimedEvent(
|
||||
IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT),
|
||||
|
@ -1221,7 +1212,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Task '{}' unclaimed by user '{}'.", taskId, userId);
|
||||
}
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
historyEventManager.createEvent(
|
||||
new TaskClaimCancelledEvent(
|
||||
IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT),
|
||||
|
@ -1261,7 +1252,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Task '{}' completed by user '{}'.", taskId, userId);
|
||||
}
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
historyEventManager.createEvent(
|
||||
new TaskCompletedEvent(
|
||||
IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT),
|
||||
|
@ -1533,7 +1524,7 @@ public class TaskServiceImpl implements TaskService {
|
|||
if (!updateClaimedTaskIds.isEmpty()) {
|
||||
taskMapper.updateClaimed(updateClaimedTaskIds, claimedReference);
|
||||
}
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
createTasksCompletedEvents(taskSummaryList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ final class TaskTransferrer {
|
|||
|
||||
applyTransferValuesForTask(task, destinationWorkbasket, setTransferFlag);
|
||||
taskMapper.update(task);
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
createTransferredEvent(
|
||||
oldTask, task, originWorkbasket.getId(), destinationWorkbasket.getId());
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ final class TaskTransferrer {
|
|||
taskMapper.updateTransfered(
|
||||
taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toSet()), updateObject);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
taskSummaries.forEach(
|
||||
oldSummary -> {
|
||||
TaskSummaryImpl newSummary = (TaskSummaryImpl) oldSummary.copy();
|
||||
|
|
|
@ -182,6 +182,16 @@ public class TaskBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public TaskBuilder priority(Integer priority) {
|
||||
if (priority != null) {
|
||||
testTask.setPriorityIgnoreFreeze(priority);
|
||||
testTask.freezePriority();
|
||||
} else {
|
||||
testTask.unfreezePriority();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Task buildAndStore(TaskService taskService)
|
||||
throws TaskAlreadyExistException, InvalidArgumentException, WorkbasketNotFoundException,
|
||||
ClassificationNotFoundException, NotAuthorizedException, AttachmentPersistenceException,
|
||||
|
|
|
@ -12,6 +12,7 @@ class TaskTestImpl extends TaskImpl {
|
|||
private boolean freezeModified = false;
|
||||
private boolean freezeRead = false;
|
||||
private boolean freezeTransferred = false;
|
||||
private boolean freezePriority = false;
|
||||
|
||||
@Override
|
||||
public void setState(TaskState state) {
|
||||
|
@ -68,6 +69,17 @@ class TaskTestImpl extends TaskImpl {
|
|||
super.setTransferred(isTransferred);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(int priority) {
|
||||
if (!freezePriority) {
|
||||
super.setPriority(priority);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPriorityIgnoreFreeze(int priority) {
|
||||
super.setPriority(priority);
|
||||
}
|
||||
|
||||
public void freezeState() {
|
||||
freezeState = true;
|
||||
}
|
||||
|
@ -107,4 +119,12 @@ class TaskTestImpl extends TaskImpl {
|
|||
public void unfreezeTransferred() {
|
||||
freezeTransferred = false;
|
||||
}
|
||||
|
||||
public void freezePriority() {
|
||||
freezePriority = true;
|
||||
}
|
||||
|
||||
public void unfreezePriority() {
|
||||
freezePriority = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public class TaskUpdatePriorityBatchStatement {
|
|||
preparedStatement = connection.prepareStatement("update TASK set PRIORITY = ? where ID = ?");
|
||||
}
|
||||
|
||||
public void addPriorityUpdate(String taskId, Integer priority) throws SQLException {
|
||||
public void addPriorityUpdate(String taskId, int priority) throws SQLException {
|
||||
preparedStatement.setInt(1, priority);
|
||||
preparedStatement.setString(2, taskId);
|
||||
LOGGER.debug("Job update priority to {} for task {}.", priority, taskId);
|
||||
|
|
|
@ -2,11 +2,12 @@ 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 java.util.OptionalInt;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
import pro.taskana.common.api.BaseQuery.SortDirection;
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||
import pro.taskana.spi.priority.internal.PriorityServiceManager;
|
||||
import pro.taskana.task.api.TaskQueryColumnName;
|
||||
import pro.taskana.task.api.TaskState;
|
||||
|
@ -16,14 +17,15 @@ public class TaskUpdatePriorityWorker {
|
|||
|
||||
private final SqlConnectionRunner sqlConnectionRunner;
|
||||
private final TaskanaEngine taskanaEngine;
|
||||
private final PriorityServiceManager priorityServiceManager;
|
||||
|
||||
public TaskUpdatePriorityWorker(TaskanaEngine taskanaEngine) {
|
||||
this.taskanaEngine = taskanaEngine;
|
||||
this.sqlConnectionRunner = new SqlConnectionRunner(taskanaEngine);
|
||||
sqlConnectionRunner = new SqlConnectionRunner(taskanaEngine);
|
||||
priorityServiceManager = ((TaskanaEngineImpl) taskanaEngine).getPriorityServiceManager();
|
||||
}
|
||||
|
||||
public List<String> executeBatch(List<String> taskIds) {
|
||||
|
||||
List<String> updatedTaskIds = new ArrayList<>();
|
||||
sqlConnectionRunner.runWithConnection(
|
||||
connection -> {
|
||||
|
@ -32,11 +34,11 @@ public class TaskUpdatePriorityWorker {
|
|||
|
||||
List<TaskSummary> list = getTaskSummariesByIds(taskIds);
|
||||
for (TaskSummary taskSummary : list) {
|
||||
Optional<Integer> calculatedPriority = getCalculatedPriority(taskSummary);
|
||||
OptionalInt calculatedPriority = getCalculatedPriority(taskSummary);
|
||||
if (calculatedPriority.isPresent()) {
|
||||
final String taskId = taskSummary.getId();
|
||||
updatedTaskIds.add(taskId);
|
||||
taskUpdateBatch.addPriorityUpdate(taskId, calculatedPriority.get());
|
||||
taskUpdateBatch.addPriorityUpdate(taskId, calculatedPriority.getAsInt());
|
||||
}
|
||||
}
|
||||
taskUpdateBatch.executeBatch();
|
||||
|
@ -71,13 +73,16 @@ public class TaskUpdatePriorityWorker {
|
|||
.list();
|
||||
}
|
||||
|
||||
public Optional<Integer> getCalculatedPriority(TaskSummary taskSummary) {
|
||||
return PriorityServiceManager.getInstance()
|
||||
.calculatePriorityOfTask(taskSummary)
|
||||
.filter(hasDifferentPriority(taskSummary));
|
||||
public OptionalInt getCalculatedPriority(TaskSummary taskSummary) {
|
||||
OptionalInt computedPriority = priorityServiceManager.calculatePriorityOfTask(taskSummary);
|
||||
if (computedPriority.isPresent()
|
||||
&& hasDifferentPriority(taskSummary).test(computedPriority.getAsInt())) {
|
||||
return computedPriority;
|
||||
}
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
public static Predicate<Integer> hasDifferentPriority(TaskSummary taskSummary) {
|
||||
public static IntPredicate hasDifferentPriority(TaskSummary taskSummary) {
|
||||
return prio -> taskSummary != null && prio != taskSummary.getPriority();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
public WorkbasketServiceImpl(
|
||||
InternalTaskanaEngine taskanaEngine,
|
||||
HistoryEventManager historyEventManager,
|
||||
WorkbasketMapper workbasketMapper,
|
||||
DistributionTargetMapper distributionTargetMapper,
|
||||
WorkbasketAccessMapper workbasketAccessMapper) {
|
||||
|
@ -74,7 +75,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
this.workbasketMapper = workbasketMapper;
|
||||
this.distributionTargetMapper = distributionTargetMapper;
|
||||
this.workbasketAccessMapper = workbasketAccessMapper;
|
||||
this.historyEventManager = taskanaEngine.getHistoryEventManager();
|
||||
this.historyEventManager = historyEventManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,7 +146,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
workbasketMapper.insert(workbasket);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
newWorkbasket("", ""), newWorkbasket);
|
||||
|
@ -202,7 +203,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
workbasketMapper.update(workbasketImplToUpdate);
|
||||
}
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
oldWorkbasket, workbasketToUpdate);
|
||||
|
@ -266,7 +267,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
try {
|
||||
workbasketAccessMapper.insert(accessItem);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
|
@ -326,7 +327,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
workbasketAccessMapper.update(accessItem);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(originalItem, accessItem);
|
||||
|
@ -359,13 +360,13 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
WorkbasketAccessItem accessItem = null;
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
accessItem = workbasketAccessMapper.findById(accessItemId);
|
||||
}
|
||||
|
||||
workbasketAccessMapper.delete(accessItemId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled() && accessItem != null) {
|
||||
if (historyEventManager.isEnabled() && accessItem != null) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
|
@ -490,14 +491,14 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
List<WorkbasketAccessItemImpl> originalAccessItems = new ArrayList<>();
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
originalAccessItems = workbasketAccessMapper.findByWorkbasketId(workbasketId);
|
||||
}
|
||||
// delete all current ones
|
||||
workbasketAccessMapper.deleteAllAccessItemsForWorkbasketId(workbasketId);
|
||||
accessItems.forEach(workbasketAccessMapper::insert);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
|
@ -601,7 +602,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
|
||||
List<String> originalTargetWorkbasketIds = new ArrayList<>();
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
originalTargetWorkbasketIds = distributionTargetMapper.findBySourceId(sourceWorkbasketId);
|
||||
}
|
||||
|
||||
|
@ -624,7 +625,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
}
|
||||
}
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled() && !targetWorkbasketIds.isEmpty()) {
|
||||
if (historyEventManager.isEnabled() && !targetWorkbasketIds.isEmpty()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
|
@ -674,7 +675,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
} else {
|
||||
distributionTargetMapper.insert(sourceWorkbasketId, targetWorkbasketId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
"{\"changes\":{\"newValue\":\"" + targetWorkbasketId + "\",\"oldValue\":\"\"}}";
|
||||
|
@ -717,7 +718,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
if (numberOfDistTargets > 0) {
|
||||
distributionTargetMapper.delete(sourceWorkbasketId, targetWorkbasketId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
Workbasket workbasket = workbasketMapper.findById(sourceWorkbasketId);
|
||||
|
||||
|
@ -805,7 +806,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
workbasketMapper.delete(workbasketId);
|
||||
deleteReferencesToWorkbasket(workbasketId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
String details =
|
||||
ObjectAttributeChangeDetector.determineChangesInAttributes(
|
||||
|
@ -912,12 +913,12 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
}
|
||||
|
||||
List<WorkbasketAccessItemImpl> workbasketAccessItems = new ArrayList<>();
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
workbasketAccessItems = workbasketAccessMapper.findByAccessId(accessId);
|
||||
}
|
||||
workbasketAccessMapper.deleteAccessItemsForAccessId(accessId);
|
||||
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
for (WorkbasketAccessItemImpl workbasketAccessItem : workbasketAccessItems) {
|
||||
|
||||
|
@ -1104,7 +1105,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
|
|||
WorkbasketImpl workbasket = workbasketMapper.findById(workbasketId);
|
||||
workbasket.setMarkedForDeletion(true);
|
||||
workbasketMapper.update(workbasket);
|
||||
if (HistoryEventManager.isHistoryEnabled()) {
|
||||
if (historyEventManager.isEnabled()) {
|
||||
|
||||
historyEventManager.createEvent(
|
||||
new WorkbasketMarkedForDeletionEvent(
|
||||
|
|
|
@ -8,6 +8,7 @@ import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_
|
|||
import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.tngtech.archunit.base.DescribedPredicate;
|
||||
import com.tngtech.archunit.base.Optional;
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
|
||||
|
@ -37,8 +38,11 @@ import org.apache.ibatis.annotations.UpdateProvider;
|
|||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
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 testapi.TaskanaIntegrationTest;
|
||||
|
||||
|
@ -85,7 +89,8 @@ class ArchitectureTest {
|
|||
@BeforeAll
|
||||
static void init() {
|
||||
// time intensive operation should only be done once
|
||||
importedClasses = new ClassFileImporter().importPackages("pro.taskana", "acceptance");
|
||||
importedClasses =
|
||||
new ClassFileImporter().importPackages("pro.taskana", "acceptance", "testapi");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,8 +98,6 @@ class ArchitectureTest {
|
|||
ArchRule myRule =
|
||||
classes()
|
||||
.that()
|
||||
.haveNameNotMatching(".*ScheduledJob.Type")
|
||||
.and()
|
||||
.resideInAPackage("..api..")
|
||||
.should()
|
||||
.onlyDependOnClassesThat(
|
||||
|
@ -184,7 +187,8 @@ class ArchitectureTest {
|
|||
List<Pattern> excludePackages =
|
||||
Stream.of(
|
||||
"pro.taskana", // from TaskanaEngineConfiguration
|
||||
"acceptance.*" // all our acceptance tests
|
||||
"acceptance.*", // all our acceptance tests
|
||||
"testapi.*" // our test API
|
||||
)
|
||||
.map(Pattern::compile)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -233,8 +237,6 @@ class ArchitectureTest {
|
|||
.and()
|
||||
.haveSimpleNameNotEndingWith("AbstractTaskanaJob")
|
||||
.and()
|
||||
.haveNameNotMatching(".*ScheduledJob.Type")
|
||||
.and()
|
||||
.resideInAPackage("..common..")
|
||||
.and()
|
||||
.resideOutsideOfPackage("..common.test..")
|
||||
|
@ -302,17 +304,59 @@ class ArchitectureTest {
|
|||
classes()
|
||||
.that()
|
||||
.areAnnotatedWith(TaskanaIntegrationTest.class)
|
||||
.or(areNestedTaskanaIntegrationTestClasses())
|
||||
.should(onlyHaveFieldsWithNoModifier());
|
||||
|
||||
rule.check(importedClasses);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedTaskanaIntegrationTestsShouldBeAnnotatedWithTestInstance() {
|
||||
ArchRule rule =
|
||||
classes()
|
||||
.that(areNestedTaskanaIntegrationTestClasses())
|
||||
.should(beAnnotatedWithTestInstancePerClass());
|
||||
|
||||
rule.check(importedClasses);
|
||||
}
|
||||
|
||||
private ArchCondition<JavaClass> beAnnotatedWithTestInstancePerClass() {
|
||||
return new ArchCondition<JavaClass>("be annotated with @TestInstance(Lifecycle.PER_CLASS)") {
|
||||
@Override
|
||||
public void check(JavaClass item, ConditionEvents events) {
|
||||
Optional<TestInstance> testInstanceOptional =
|
||||
item.tryGetAnnotationOfType(TestInstance.class);
|
||||
if (!testInstanceOptional.isPresent()
|
||||
|| testInstanceOptional.get().value() != Lifecycle.PER_CLASS) {
|
||||
events.add(
|
||||
SimpleConditionEvent.violated(
|
||||
item,
|
||||
String.format(
|
||||
"Class '%s' is not annotated with @TestInstance(Lifecycle.PER_CLASS)",
|
||||
item.getFullName())));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private DescribedPredicate<JavaClass> areNestedTaskanaIntegrationTestClasses() {
|
||||
return new DescribedPredicate<JavaClass>("are nested TaskanaIntegrationTest classes") {
|
||||
@Override
|
||||
public boolean apply(JavaClass input) {
|
||||
Optional<JavaClass> enclosingClass = input.getEnclosingClass();
|
||||
return input.isAnnotatedWith(Nested.class)
|
||||
&& enclosingClass.isPresent()
|
||||
&& enclosingClass.get().isAnnotatedWith(TaskanaIntegrationTest.class);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ArchCondition<JavaClass> onlyHaveFieldsWithNoModifier() {
|
||||
return new ArchCondition<JavaClass>("only have fields with no modifier") {
|
||||
@Override
|
||||
public void check(JavaClass item, ConditionEvents events) {
|
||||
for (JavaField field : item.getAllFields()) {
|
||||
if (!field.getModifiers().isEmpty()) {
|
||||
if (!field.reflect().isSynthetic() && !field.getModifiers().isEmpty()) {
|
||||
events.add(
|
||||
SimpleConditionEvent.violated(
|
||||
item,
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
package acceptance;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import pro.taskana.classification.internal.builder.ClassificationBuilder;
|
||||
import pro.taskana.task.internal.builder.ObjectReferenceBuilder;
|
||||
import pro.taskana.workbasket.api.WorkbasketType;
|
||||
import pro.taskana.workbasket.internal.builder.WorkbasketBuilder;
|
||||
|
||||
public class DefaultTestEntities {
|
||||
|
||||
public static ClassificationBuilder defaultTestClassification() {
|
||||
return ClassificationBuilder.newClassification()
|
||||
.key(UUID.randomUUID().toString().replace("-", ""))
|
||||
.domain("DOMAIN_A");
|
||||
}
|
||||
|
||||
public static WorkbasketBuilder defaultTestWorkbasket() {
|
||||
return WorkbasketBuilder.newWorkbasket()
|
||||
.key(UUID.randomUUID().toString())
|
||||
.domain("DOMAIN_A")
|
||||
.name("Megabasket")
|
||||
.type(WorkbasketType.GROUP)
|
||||
|
|
|
@ -176,9 +176,7 @@ class TaskBuilderTest {
|
|||
expectedTask.setTransferred(true);
|
||||
expectedTask.setCreator("user-1-1");
|
||||
expectedTask.addAttachment(attachment);
|
||||
// ATTENTION: We have an SPI running which transforms custom1 of every created Task to that.
|
||||
// Please fix after removal of that SPI during TSK-1704 ;)
|
||||
expectedTask.setCustomAttribute(TaskCustomField.CUSTOM_1, "preprocessedCustomField");
|
||||
expectedTask.setCustomAttribute(TaskCustomField.CUSTOM_1, "custom1");
|
||||
expectedTask.setCustomAttribute(TaskCustomField.CUSTOM_2, "custom2");
|
||||
expectedTask.setCustomAttribute(TaskCustomField.CUSTOM_3, "custom3");
|
||||
expectedTask.setCustomAttribute(TaskCustomField.CUSTOM_4, "custom4");
|
||||
|
@ -246,10 +244,9 @@ class TaskBuilderTest {
|
|||
Task::getModified),
|
||||
Quadruple.of("read", true, (b, v) -> b.read((Boolean) v), Task::isRead),
|
||||
Quadruple.of(
|
||||
"transferred",
|
||||
true,
|
||||
(b, v) -> b.transferred((Boolean) v),
|
||||
Task::isTransferred));
|
||||
"transferred", true, (b, v) -> b.transferred((Boolean) v), Task::isTransferred),
|
||||
Quadruple.of(
|
||||
"priority", 1337, (b, v) -> b.priority((Integer) v), Task::getPriority));
|
||||
|
||||
Stream<DynamicTest> applyBuilderFunction =
|
||||
DynamicTest.stream(
|
||||
|
|
|
@ -1,134 +1,159 @@
|
|||
package acceptance.jobs.helper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
|
||||
import acceptance.AbstractAccTest;
|
||||
import acceptance.DefaultTestEntities;
|
||||
import acceptance.priorityservice.TestPriorityServiceProvider;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import java.util.function.IntPredicate;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
import testapi.TaskanaInject;
|
||||
import testapi.TaskanaIntegrationTest;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.common.api.exceptions.NotAuthorizedException;
|
||||
import pro.taskana.common.test.security.JaasExtension;
|
||||
import pro.taskana.classification.api.ClassificationService;
|
||||
import pro.taskana.classification.api.models.ClassificationSummary;
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.test.security.WithAccessId;
|
||||
import pro.taskana.spi.priority.internal.PriorityServiceManager;
|
||||
import pro.taskana.task.api.exceptions.TaskNotFoundException;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.task.api.TaskService;
|
||||
import pro.taskana.task.api.TaskState;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
import pro.taskana.task.api.models.TaskSummary;
|
||||
import pro.taskana.task.internal.builder.TaskBuilder;
|
||||
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityWorker;
|
||||
import pro.taskana.task.internal.models.TaskImpl;
|
||||
import pro.taskana.workbasket.api.WorkbasketService;
|
||||
import pro.taskana.workbasket.api.models.WorkbasketSummary;
|
||||
|
||||
/** Acceptance test for all "jobs tasks runner" scenarios. */
|
||||
@ExtendWith(JaasExtension.class)
|
||||
class TaskUpdatePriorityWorkerAccTest extends AbstractAccTest {
|
||||
@TaskanaIntegrationTest
|
||||
class TaskUpdatePriorityWorkerAccTest {
|
||||
|
||||
@BeforeEach
|
||||
void before() throws Exception {
|
||||
// required if single tests modify database
|
||||
// TODO split test class into readOnly & modifying tests to improve performance
|
||||
resetDb(true);
|
||||
@TaskanaInject TaskanaEngine taskanaEngine;
|
||||
@TaskanaInject TaskService taskService;
|
||||
|
||||
TaskUpdatePriorityWorker worker;
|
||||
|
||||
TaskSummary task1;
|
||||
TaskSummary task2;
|
||||
Task completedTask;
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
@BeforeAll
|
||||
void setUp(ClassificationService classificationService, WorkbasketService workbasketService)
|
||||
throws Exception {
|
||||
ClassificationSummary classificationSummary =
|
||||
DefaultTestEntities.defaultTestClassification()
|
||||
.buildAndStore(classificationService)
|
||||
.asSummary();
|
||||
WorkbasketSummary workbasketSummary =
|
||||
DefaultTestEntities.defaultTestWorkbasket().buildAndStore(workbasketService).asSummary();
|
||||
|
||||
TaskBuilder taskBuilder =
|
||||
TaskBuilder.newTask()
|
||||
.classificationSummary(classificationSummary)
|
||||
.workbasketSummary(workbasketSummary)
|
||||
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build());
|
||||
|
||||
task1 = taskBuilder.buildAndStore(taskService).asSummary();
|
||||
task2 = taskBuilder.buildAndStore(taskService).asSummary();
|
||||
completedTask = taskBuilder.state(TaskState.COMPLETED).buildAndStore(taskService);
|
||||
worker = new TaskUpdatePriorityWorker(taskanaEngine);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithAccessId(user = "admin")
|
||||
void should_loadAnyRelevantTaskId() {
|
||||
// given
|
||||
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(taskanaEngine);
|
||||
|
||||
void should_loadAnyRelevantTaskIds() {
|
||||
// when
|
||||
final List<String> allRelevantTaskIds = worker.getAllRelevantTaskIds();
|
||||
|
||||
// then
|
||||
assertThat(allRelevantTaskIds).hasSizeGreaterThan(0);
|
||||
assertThat(allRelevantTaskIds).containsExactlyInAnyOrder(task1.getId(), task2.getId());
|
||||
}
|
||||
|
||||
@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));
|
||||
final List<TaskSummary> taskSummariesByIds =
|
||||
worker.getTaskSummariesByIds(List.of(task1.getId(), task2.getId()));
|
||||
|
||||
// then
|
||||
assertThat(taskSummariesByIds)
|
||||
.hasSize(1)
|
||||
.extracting(TaskSummary::getId)
|
||||
.containsExactly(foundTaskId);
|
||||
assertThat(taskSummariesByIds).containsExactlyInAnyOrder(task1, task2);
|
||||
}
|
||||
|
||||
@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());
|
||||
assertThat(allRelevantTaskIds).isNotEmpty().doesNotContain(completedTask.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_noticeDifferentPriority_When_PriorityHasChanged() {
|
||||
// given
|
||||
final TaskImpl task = (TaskImpl) taskanaEngine.getTaskService().newTask();
|
||||
TaskImpl task = (TaskImpl) taskService.newTask();
|
||||
task.setPriority(232);
|
||||
|
||||
// when
|
||||
final Predicate<Integer> differentPriority =
|
||||
TaskUpdatePriorityWorker.hasDifferentPriority(task);
|
||||
IntPredicate differentPriority = TaskUpdatePriorityWorker.hasDifferentPriority(task);
|
||||
|
||||
// then
|
||||
assertThat(differentPriority).rejects(232).accepts(2, 3, 4, 5);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = TestPriorityServiceProvider.class)
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class WithSpi {
|
||||
|
||||
@TaskanaInject TaskService taskService;
|
||||
TaskUpdatePriorityWorker worker;
|
||||
|
||||
@BeforeAll
|
||||
void setup(TaskanaEngine taskanaEngine) {
|
||||
worker = new TaskUpdatePriorityWorker(taskanaEngine);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithAccessId(user = "admin")
|
||||
void should_executeBatch(
|
||||
WorkbasketService workbasketService, ClassificationService classificationService)
|
||||
throws Exception {
|
||||
// given
|
||||
ClassificationSummary classificationSummary =
|
||||
DefaultTestEntities.defaultTestClassification()
|
||||
.buildAndStore(classificationService)
|
||||
.asSummary();
|
||||
WorkbasketSummary workbasketSummary =
|
||||
DefaultTestEntities.defaultTestWorkbasket().buildAndStore(workbasketService).asSummary();
|
||||
Task oldTask =
|
||||
TaskBuilder.newTask()
|
||||
.classificationSummary(classificationSummary)
|
||||
.workbasketSummary(workbasketSummary)
|
||||
.created(Instant.parse("2020-04-30T07:12:00.000Z"))
|
||||
.priority(1337)
|
||||
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
|
||||
.buildAndStore(taskService);
|
||||
|
||||
// when
|
||||
final List<String> updatedTaskIds = worker.executeBatch(List.of(oldTask.getId()));
|
||||
|
||||
// then
|
||||
final Task updatedTask = taskService.getTask(oldTask.getId());
|
||||
|
||||
assertThat(updatedTaskIds).containsExactly(oldTask.getId());
|
||||
assertThat(updatedTask.getPriority()).isNotEqualTo(oldTask.getPriority());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package acceptance.priorityservice;
|
|||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.task.api.TaskCustomField;
|
||||
|
@ -12,13 +12,13 @@ public class TestPriorityServiceProvider implements PriorityServiceProvider {
|
|||
private static final int MULTIPLIER = 10;
|
||||
|
||||
@Override
|
||||
public Optional<Integer> calculatePriority(TaskSummary taskSummary) {
|
||||
public OptionalInt calculatePriority(TaskSummary taskSummary) {
|
||||
long diffInDays = Duration.between(taskSummary.getCreated(), Instant.now()).toDays();
|
||||
int priority = diffInDays >= 1 ? Math.toIntExact(diffInDays) : 1;
|
||||
|
||||
if ("true".equals(taskSummary.getCustomAttribute(TaskCustomField.CUSTOM_6))) {
|
||||
priority *= MULTIPLIER;
|
||||
}
|
||||
return Optional.of(priority);
|
||||
return OptionalInt.of(priority);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,41 +2,76 @@ package acceptance.taskpreprocessing;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import acceptance.AbstractAccTest;
|
||||
import acceptance.DefaultTestEntities;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import testapi.TaskanaInject;
|
||||
import testapi.TaskanaIntegrationTest;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.common.test.security.JaasExtension;
|
||||
import pro.taskana.classification.api.ClassificationService;
|
||||
import pro.taskana.classification.api.models.ClassificationSummary;
|
||||
import pro.taskana.common.test.security.WithAccessId;
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.TaskCustomField;
|
||||
import pro.taskana.task.api.TaskService;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
import pro.taskana.task.internal.models.TaskImpl;
|
||||
import pro.taskana.workbasket.api.WorkbasketPermission;
|
||||
import pro.taskana.workbasket.api.WorkbasketService;
|
||||
import pro.taskana.workbasket.api.models.WorkbasketSummary;
|
||||
import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder;
|
||||
|
||||
/** Acceptance test for "task preprocessing" scenario. */
|
||||
@ExtendWith(JaasExtension.class)
|
||||
class CreateTaskPreprocessingAccTest extends AbstractAccTest {
|
||||
@TaskanaIntegrationTest
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = CreateTaskPreprocessingAccTest.TestCreateTaskPreprocessorProvider.class)
|
||||
class CreateTaskPreprocessingAccTest {
|
||||
|
||||
private final TaskService taskService = taskanaEngine.getTaskService();
|
||||
@TaskanaInject TaskService taskService;
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
WorkbasketSummary workbasketSummary;
|
||||
ClassificationSummary classificationSummary;
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@BeforeAll
|
||||
void setup(ClassificationService classificationService, WorkbasketService workbasketService)
|
||||
throws Exception {
|
||||
classificationSummary =
|
||||
DefaultTestEntities.defaultTestClassification()
|
||||
.buildAndStore(classificationService)
|
||||
.asSummary();
|
||||
|
||||
workbasketSummary =
|
||||
DefaultTestEntities.defaultTestWorkbasket().buildAndStore(workbasketService).asSummary();
|
||||
|
||||
WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
|
||||
.accessId("user-1-1")
|
||||
.workbasketId(workbasketSummary.getId())
|
||||
.permission(WorkbasketPermission.READ)
|
||||
.permission(WorkbasketPermission.OPEN)
|
||||
.permission(WorkbasketPermission.APPEND)
|
||||
.buildAndStore(workbasketService);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-1")
|
||||
@Test
|
||||
void should_processTaskBeforeCreation_When_CreateTaskPreprocessorEnabled() throws Exception {
|
||||
|
||||
TaskImpl newTaskToCreate = (TaskImpl) taskService.newTask();
|
||||
|
||||
newTaskToCreate.setClassificationKey("L10303");
|
||||
|
||||
newTaskToCreate.setPrimaryObjRef(
|
||||
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||
|
||||
newTaskToCreate.setWorkbasketKey("GPK_KSC");
|
||||
|
||||
newTaskToCreate.setDomain("DOMAIN_A");
|
||||
Task newTaskToCreate = taskService.newTask(workbasketSummary.getId());
|
||||
newTaskToCreate.setClassificationKey(classificationSummary.getKey());
|
||||
newTaskToCreate.setPrimaryObjRef(DefaultTestEntities.defaultTestObjectReference().build());
|
||||
|
||||
Task createdTask = taskService.createTask(newTaskToCreate);
|
||||
|
||||
assertThat(createdTask.getCustomAttribute(TaskCustomField.CUSTOM_1))
|
||||
.isEqualTo("preprocessedCustomField");
|
||||
}
|
||||
|
||||
public static class TestCreateTaskPreprocessorProvider implements CreateTaskPreprocessor {
|
||||
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
taskToProcess.setCustomAttribute(TaskCustomField.CUSTOM_1, "preprocessedCustomField");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package acceptance.taskpreprocessing;
|
||||
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.TaskCustomField;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
public class TestCreateTaskPreprocessorProvider implements CreateTaskPreprocessor {
|
||||
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
taskToProcess.setCustomAttribute(TaskCustomField.CUSTOM_1, "preprocessedCustomField");
|
||||
}
|
||||
}
|
|
@ -3,92 +3,101 @@ package acceptance.taskrouting;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
|
||||
import acceptance.AbstractAccTest;
|
||||
import acceptance.DefaultTestEntities;
|
||||
import acceptance.taskrouting.TaskRoutingAccTest.TaskRoutingProviderForDomainA;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import testapi.TaskanaInject;
|
||||
import testapi.TaskanaIntegrationTest;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.classification.api.ClassificationService;
|
||||
import pro.taskana.classification.api.models.ClassificationSummary;
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||
import pro.taskana.common.test.security.JaasExtension;
|
||||
import pro.taskana.common.test.security.WithAccessId;
|
||||
import pro.taskana.task.api.TaskCustomField;
|
||||
import pro.taskana.spi.routing.api.TaskRoutingProvider;
|
||||
import pro.taskana.task.api.TaskService;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
import pro.taskana.task.internal.models.TaskImpl;
|
||||
import pro.taskana.workbasket.api.WorkbasketPermission;
|
||||
import pro.taskana.workbasket.api.WorkbasketService;
|
||||
import pro.taskana.workbasket.api.models.WorkbasketSummary;
|
||||
import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder;
|
||||
|
||||
/** Acceptance test for all "create task" scenarios. */
|
||||
@ExtendWith(JaasExtension.class)
|
||||
class TaskRoutingAccTest extends AbstractAccTest {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = TaskRoutingProvider.class,
|
||||
serviceProviders = TaskRoutingProviderForDomainA.class)
|
||||
@TaskanaIntegrationTest
|
||||
class TaskRoutingAccTest {
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
@Test
|
||||
void testCreateTaskWithoutWorkbasketAndVoidNewTaskMethod() throws Exception {
|
||||
TaskService taskService = taskanaEngine.getTaskService();
|
||||
@TaskanaInject TaskanaEngine taskanaEngine;
|
||||
@TaskanaInject TaskService taskService;
|
||||
|
||||
Task newTask = taskService.newTask();
|
||||
newTask.setClassificationKey("L10303");
|
||||
newTask.setPrimaryObjRef(
|
||||
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||
final Task taskToCreate = newTask;
|
||||
assertThatThrownBy(() -> taskService.createTask(taskToCreate))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
((TaskImpl) taskToCreate).setDomain("DOMAIN_C");
|
||||
assertThatThrownBy(() -> taskService.createTask(taskToCreate))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
((TaskImpl) taskToCreate).setDomain("DOMAIN_B");
|
||||
Task createdTask = taskService.createTask(taskToCreate);
|
||||
assertThat(createdTask.getWorkbasketSummary().getId())
|
||||
.isEqualTo("WBI:100000000000000000000000000000000011");
|
||||
ClassificationSummary classificationSummary;
|
||||
WorkbasketSummary domainAWorkbasket;
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@BeforeAll
|
||||
void setUp(ClassificationService classificationService, WorkbasketService workbasketService)
|
||||
throws Exception {
|
||||
classificationSummary =
|
||||
DefaultTestEntities.defaultTestClassification()
|
||||
.buildAndStore(classificationService)
|
||||
.asSummary();
|
||||
domainAWorkbasket =
|
||||
DefaultTestEntities.defaultTestWorkbasket()
|
||||
.key("DOMAIN_A_WORKBASKET")
|
||||
.buildAndStore(workbasketService)
|
||||
.asSummary();
|
||||
|
||||
WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
|
||||
.workbasketId(domainAWorkbasket.getId())
|
||||
.accessId("user-1-1")
|
||||
.permission(WorkbasketPermission.OPEN)
|
||||
.permission(WorkbasketPermission.READ)
|
||||
.permission(WorkbasketPermission.APPEND)
|
||||
.buildAndStore(workbasketService);
|
||||
|
||||
TaskRoutingProviderForDomainA.domainAWorkbasketId = domainAWorkbasket.getId();
|
||||
}
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
@WithAccessId(user = "user-1-1")
|
||||
@Test
|
||||
void testCreateTaskWithNullWorkbasket() throws Exception {
|
||||
TaskImpl createdTaskA = createTask("DOMAIN_A", "L12010");
|
||||
assertThat(createdTaskA.getWorkbasketSummary().getId())
|
||||
.isEqualTo("WBI:100000000000000000000000000000000001");
|
||||
TaskImpl createdTaskB = createTask("DOMAIN_B", "T21001");
|
||||
assertThat(createdTaskB.getWorkbasketSummary().getId())
|
||||
.isEqualTo("WBI:100000000000000000000000000000000011");
|
||||
assertThatThrownBy(() -> createTask(null, "L12010"))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
void should_ThrowException_When_TaskRouterDoesNotRouteTask() {
|
||||
Task task = taskService.newTask();
|
||||
task.setClassificationKey(classificationSummary.getKey());
|
||||
task.setPrimaryObjRef(DefaultTestEntities.defaultTestObjectReference().build());
|
||||
|
||||
assertThatThrownBy(() -> taskService.createTask(task))
|
||||
.isInstanceOf(InvalidArgumentException.class)
|
||||
.hasMessage("Cannot create a Task outside a Workbasket");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
@WithAccessId(user = "user-1-1")
|
||||
@Test
|
||||
void testCreateTaskWithNullRouting() throws Exception {
|
||||
void should_SetWorkbasketForTask_When_TaskRouterDeterminesWorkbasket() throws Exception {
|
||||
Task task = taskService.newTask(null, "DOMAIN_A");
|
||||
task.setClassificationKey(classificationSummary.getKey());
|
||||
task.setPrimaryObjRef(DefaultTestEntities.defaultTestObjectReference().build());
|
||||
|
||||
TaskService taskService = taskanaEngine.getTaskService();
|
||||
Task newTask = taskService.newTask(null, "DOMAIN_A");
|
||||
newTask.setClassificationKey("L12010");
|
||||
newTask.setPrimaryObjRef(
|
||||
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||
newTask.setCustomAttribute(TaskCustomField.CUSTOM_7, "noRouting");
|
||||
assertThatThrownBy(() -> taskService.createTask(newTask))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
Task createdTask = taskService.createTask(task);
|
||||
|
||||
assertThat(createdTask.getWorkbasketSummary()).isEqualTo(domainAWorkbasket);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "admin")
|
||||
@Test
|
||||
void testCreateTaskWithRoutingToMultipleWorkbaskets() throws Exception {
|
||||
public static class TaskRoutingProviderForDomainA implements TaskRoutingProvider {
|
||||
|
||||
TaskService taskService = taskanaEngine.getTaskService();
|
||||
Task newTask = taskService.newTask(null, "DOMAIN_B");
|
||||
newTask.setClassificationKey("L12010");
|
||||
newTask.setPrimaryObjRef(
|
||||
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||
newTask.setCustomAttribute(TaskCustomField.CUSTOM_7, "multipleWorkbaskets");
|
||||
assertThatThrownBy(() -> taskService.createTask(newTask))
|
||||
.isInstanceOf(InvalidArgumentException.class);
|
||||
}
|
||||
static String domainAWorkbasketId;
|
||||
|
||||
private TaskImpl createTask(String domain, String classificationKey) throws Exception {
|
||||
TaskService taskService = taskanaEngine.getTaskService();
|
||||
@Override
|
||||
public void initialize(TaskanaEngine taskanaEngine) {}
|
||||
|
||||
Task newTask = taskService.newTask(null, domain);
|
||||
newTask.setClassificationKey(classificationKey);
|
||||
|
||||
newTask.setPrimaryObjRef(
|
||||
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||
return (TaskImpl) taskService.createTask(newTask);
|
||||
@Override
|
||||
public String determineWorkbasketId(Task task) {
|
||||
if ("DOMAIN_A".equals(task.getDomain())) {
|
||||
return domainAWorkbasketId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package acceptance.taskrouting;
|
||||
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.spi.routing.api.TaskRoutingProvider;
|
||||
import pro.taskana.task.api.TaskCustomField;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
/** This is a sample implementation of TaskRouter. */
|
||||
public class TestTaskRoutingProviderForDomainA implements TaskRoutingProvider {
|
||||
|
||||
@Override
|
||||
public void initialize(TaskanaEngine taskanaEngine) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String determineWorkbasketId(Task task) {
|
||||
String att7 = task.getCustomAttribute(TaskCustomField.CUSTOM_7);
|
||||
|
||||
if (att7 != null && att7.equals("multipleWorkbaskets")) {
|
||||
return "WBI:100000000000000000000000000000000005";
|
||||
} else if ("DOMAIN_A".equals(task.getDomain())) {
|
||||
if (att7 != null && att7.equals("noRouting")) {
|
||||
return null;
|
||||
} else {
|
||||
return "WBI:100000000000000000000000000000000001";
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package acceptance.taskrouting;
|
||||
|
||||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.spi.routing.api.TaskRoutingProvider;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
/** This is a sample implementation of TaskRouter. */
|
||||
public class TestTaskRoutingProviderForDomainB implements TaskRoutingProvider {
|
||||
|
||||
TaskanaEngine theEngine;
|
||||
|
||||
@Override
|
||||
public void initialize(TaskanaEngine taskanaEngine) {
|
||||
theEngine = taskanaEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String determineWorkbasketId(Task task) {
|
||||
if ("DOMAIN_B".equals(task.getDomain())) {
|
||||
return "WBI:100000000000000000000000000000000011";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import pro.taskana.TaskanaEngineConfiguration;
|
|||
import pro.taskana.common.api.TaskanaEngine;
|
||||
import pro.taskana.common.api.exceptions.ConcurrencyException;
|
||||
import pro.taskana.common.internal.InternalTaskanaEngine;
|
||||
import pro.taskana.spi.history.internal.HistoryEventManager;
|
||||
import pro.taskana.task.api.TaskQuery;
|
||||
import pro.taskana.task.api.TaskService;
|
||||
import pro.taskana.workbasket.api.WorkbasketType;
|
||||
|
@ -66,9 +67,12 @@ class WorkbasketServiceImplTest {
|
|||
|
||||
@Mock private TaskanaEngineConfiguration taskanaEngineConfigurationMock;
|
||||
|
||||
@Mock private HistoryEventManager historyEventManager;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
lenient().when(internalTaskanaEngineMock.getEngine()).thenReturn(taskanaEngine);
|
||||
lenient().when(historyEventManager.isEnabled()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,7 +97,7 @@ class WorkbasketServiceImplTest {
|
|||
verify(taskanaEngine, times(4)).checkRoleMembership(any());
|
||||
verify(internalTaskanaEngineMock, times(4)).getEngine();
|
||||
verify(internalTaskanaEngineMock, times(3)).domainExists(any());
|
||||
verify(internalTaskanaEngineMock, times(1)).getHistoryEventManager();
|
||||
verify(historyEventManager, times(5)).isEnabled();
|
||||
verifyNoMoreInteractions(
|
||||
taskQueryMock,
|
||||
taskServiceMock,
|
||||
|
@ -139,7 +143,7 @@ class WorkbasketServiceImplTest {
|
|||
verify(internalTaskanaEngineMock, times(1)).domainExists(any());
|
||||
verify(distributionTargetMapperMock).deleteAllDistributionTargetsBySourceId(expectedWb.getId());
|
||||
verify(workbasketMapperMock).update(expectedWb);
|
||||
verify(internalTaskanaEngineMock, times(1)).getHistoryEventManager();
|
||||
verify(historyEventManager, times(2)).isEnabled();
|
||||
|
||||
verifyNoMoreInteractions(
|
||||
taskQueryMock,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package testapi;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import testapi.WithServiceProvider.WithServiceProviders;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(WithServiceProviders.class)
|
||||
public @interface WithServiceProvider {
|
||||
|
||||
Class<?> serviceProviderInterface();
|
||||
|
||||
Class<?>[] serviceProviders();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface WithServiceProviders {
|
||||
WithServiceProvider[] value();
|
||||
}
|
||||
}
|
|
@ -10,8 +10,12 @@ import org.junit.jupiter.api.extension.ExtensionContext;
|
|||
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
|
||||
import org.junit.platform.commons.JUnitException;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import testapi.CleanTaskanaContext;
|
||||
import testapi.TaskanaEngineConfigurationModifier;
|
||||
import testapi.WithServiceProvider;
|
||||
import testapi.util.ServiceProviderExtractor;
|
||||
|
||||
import pro.taskana.TaskanaEngineConfiguration;
|
||||
import pro.taskana.classification.api.ClassificationService;
|
||||
|
@ -24,6 +28,7 @@ import pro.taskana.common.api.security.CurrentUserContext;
|
|||
import pro.taskana.common.internal.JobServiceImpl;
|
||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||
import pro.taskana.common.internal.security.CurrentUserContextImpl;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.monitor.api.MonitorService;
|
||||
import pro.taskana.monitor.internal.MonitorServiceImpl;
|
||||
import pro.taskana.task.api.TaskService;
|
||||
|
@ -41,6 +46,7 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
|||
Class<?> testClass = testInstance.getClass();
|
||||
if (isTopLevelClass(testClass)
|
||||
|| isAnnotated(testClass, CleanTaskanaContext.class)
|
||||
|| isAnnotated(testClass, WithServiceProvider.class)
|
||||
|| testInstance instanceof TaskanaEngineConfigurationModifier) {
|
||||
Store store = getClassLevelStore(context);
|
||||
TaskanaEngineConfiguration taskanaEngineConfiguration =
|
||||
|
@ -52,7 +58,14 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
|||
modifier.modify(taskanaEngineConfiguration);
|
||||
}
|
||||
|
||||
TaskanaEngine taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
|
||||
TaskanaEngine taskanaEngine;
|
||||
try (MockedStatic<SpiLoader> staticMock = Mockito.mockStatic(SpiLoader.class)) {
|
||||
ServiceProviderExtractor.extractServiceProviders(testClass)
|
||||
.forEach(
|
||||
(spi, serviceProviders) ->
|
||||
staticMock.when(() -> SpiLoader.load(spi)).thenReturn(serviceProviders));
|
||||
taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
|
||||
}
|
||||
taskanaEngine.setConnectionManagementMode(ConnectionManagementMode.AUTOCOMMIT);
|
||||
|
||||
store.put(STORE_TASKANA_ENTITY_MAP, generateTaskanaEntityMap(taskanaEngine));
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.testcontainers.containers.GenericContainer;
|
|||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import testapi.CleanTaskanaContext;
|
||||
import testapi.TaskanaEngineConfigurationModifier;
|
||||
import testapi.WithServiceProvider;
|
||||
import testapi.util.DockerContainerCreator;
|
||||
|
||||
import pro.taskana.common.internal.configuration.DB;
|
||||
|
@ -51,7 +52,8 @@ public class TestContainerExtension implements AfterAllCallback, InvocationInter
|
|||
},
|
||||
() -> store.put(STORE_DATA_SOURCE, createDataSourceForH2()));
|
||||
|
||||
} else if (TaskanaEngineConfigurationModifier.class.isAssignableFrom(testClass)) {
|
||||
} else if (TaskanaEngineConfigurationModifier.class.isAssignableFrom(testClass)
|
||||
|| isAnnotated(testClass, WithServiceProvider.class)) {
|
||||
// since the implementation of TaskanaEngineConfigurationModifier implies the generation of a
|
||||
// new TaskanaEngine, we have to copy the schema name and datasource from the enclosing class'
|
||||
// store to the testClass store.
|
||||
|
|
|
@ -2,15 +2,20 @@ package testapi.tests;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import acceptance.priorityservice.TestPriorityServiceProvider;
|
||||
import java.util.List;
|
||||
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 testapi.CleanTaskanaContext;
|
||||
import testapi.TaskanaEngineConfigurationModifier;
|
||||
import testapi.TaskanaInject;
|
||||
import testapi.TaskanaIntegrationTest;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.TaskanaEngineConfiguration;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
|
||||
@TaskanaIntegrationTest
|
||||
class TaskanaInitializationExtensionTest {
|
||||
|
@ -24,6 +29,7 @@ class TaskanaInitializationExtensionTest {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ReuseTaskana {
|
||||
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
@ -36,6 +42,7 @@ class TaskanaInitializationExtensionTest {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ModifiedTaskanaEngineConfig implements TaskanaEngineConfigurationModifier {
|
||||
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
@ -59,6 +66,7 @@ class TaskanaInitializationExtensionTest {
|
|||
|
||||
@CleanTaskanaContext
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassAnnotatedWithCleanTaskanaContext {
|
||||
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
@ -75,4 +83,26 @@ class TaskanaInitializationExtensionTest {
|
|||
.containsExactlyInAnyOrder("DOMAIN_A", "DOMAIN_B");
|
||||
}
|
||||
}
|
||||
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = TestPriorityServiceProvider.class)
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassWithServiceProvider {
|
||||
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
||||
@Test
|
||||
void should_createNewTaskanaInstance_For_NestedTestClassAnnotatedWithCleanTaskanaContext() {
|
||||
assertThat(taskanaEngineConfiguration)
|
||||
.isNotSameAs(TaskanaInitializationExtensionTest.this.taskanaEngineConfiguration);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_UseDefaultTaskanaEngine_When_NestedClassDoesNotImplementModifier() {
|
||||
assertThat(taskanaEngineConfiguration.getDomains())
|
||||
.containsExactlyInAnyOrder("DOMAIN_A", "DOMAIN_B");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,20 @@ package testapi.tests;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import acceptance.priorityservice.TestPriorityServiceProvider;
|
||||
import javax.sql.DataSource;
|
||||
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 testapi.CleanTaskanaContext;
|
||||
import testapi.TaskanaEngineConfigurationModifier;
|
||||
import testapi.TaskanaInject;
|
||||
import testapi.TaskanaIntegrationTest;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.TaskanaEngineConfiguration;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
|
||||
@TaskanaIntegrationTest
|
||||
class TestContainerExtensionTest {
|
||||
|
@ -25,6 +30,7 @@ class TestContainerExtensionTest {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClass {
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
||||
|
@ -39,6 +45,7 @@ class TestContainerExtensionTest {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassWithConfigurationModifier implements TaskanaEngineConfigurationModifier {
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
||||
|
@ -59,6 +66,7 @@ class TestContainerExtensionTest {
|
|||
|
||||
@CleanTaskanaContext
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassAnnotatedWithCleanTaskanaContext {
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
||||
|
@ -74,6 +82,7 @@ class TestContainerExtensionTest {
|
|||
|
||||
@CleanTaskanaContext
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassAnnotatedWithCleanTaskanaContextAndConfigModifier
|
||||
implements TaskanaEngineConfigurationModifier {
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
@ -92,4 +101,22 @@ class TestContainerExtensionTest {
|
|||
assertThat(nestedDataSource).isNotSameAs(topLevelDataSource).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = TestPriorityServiceProvider.class)
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class NestedTestClassWithServiceProvider {
|
||||
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||
|
||||
@Test
|
||||
void should_ReuseDataSource_For_NestedTestClassWithServiceProvider() {
|
||||
DataSource nestedDataSource = taskanaEngineConfiguration.getDatasource();
|
||||
DataSource topLevelDataSource =
|
||||
TestContainerExtensionTest.this.taskanaEngineConfiguration.getDatasource();
|
||||
|
||||
assertThat(nestedDataSource).isSameAs(topLevelDataSource).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
|||
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||
import testapi.CleanTaskanaContext;
|
||||
import testapi.TaskanaEngineConfigurationModifier;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
public class ExtensionCommunicator {
|
||||
|
||||
|
@ -30,7 +31,9 @@ public class ExtensionCommunicator {
|
|||
if (isTopLevelClass(testClass)) {
|
||||
return Namespace.create(testClass);
|
||||
} else if (isAnnotated(testClass, CleanTaskanaContext.class)) {
|
||||
return Namespace.create(testClass.getEnclosingClass(), testClass);
|
||||
return Namespace.create(testClass.getEnclosingClass(), testClass, CleanTaskanaContext.class);
|
||||
} else if (isAnnotated(testClass, WithServiceProvider.class)) {
|
||||
return Namespace.create(testClass.getEnclosingClass(), testClass, WithServiceProvider.class);
|
||||
} else if (TaskanaEngineConfigurationModifier.class.isAssignableFrom(testClass)) {
|
||||
return Namespace.create(
|
||||
testClass.getEnclosingClass(), testClass, TaskanaEngineConfigurationModifier.class);
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package testapi.util;
|
||||
|
||||
import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations;
|
||||
import static pro.taskana.common.internal.util.CheckedFunction.wrap;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.platform.commons.JUnitException;
|
||||
import testapi.WithServiceProvider;
|
||||
|
||||
import pro.taskana.spi.history.api.TaskanaHistory;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.spi.routing.api.TaskRoutingProvider;
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
|
||||
public class ServiceProviderExtractor {
|
||||
|
||||
private static final Set<Class<?>> TASKANA_SERVICE_PROVIDER_INTERFACES =
|
||||
Set.of(
|
||||
TaskanaHistory.class,
|
||||
PriorityServiceProvider.class,
|
||||
TaskRoutingProvider.class,
|
||||
CreateTaskPreprocessor.class);
|
||||
|
||||
private ServiceProviderExtractor() {
|
||||
throw new IllegalStateException("utility class");
|
||||
}
|
||||
|
||||
public static Map<Class<?>, List<Object>> extractServiceProviders(Class<?> testClass) {
|
||||
List<WithServiceProvider> withServiceProviders =
|
||||
findRepeatableAnnotations(testClass, WithServiceProvider.class);
|
||||
|
||||
return groupServiceProvidersByServiceProviderInterface(withServiceProviders).entrySet().stream()
|
||||
.peek(entry -> validateServiceProviders(entry.getKey(), entry.getValue()))
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
Entry::getKey, entry -> instantiateServiceProviders(entry.getValue())));
|
||||
}
|
||||
|
||||
private static void validateServiceProviders(Class<?> spi, List<Class<?>> serviceProviders) {
|
||||
if (!TASKANA_SERVICE_PROVIDER_INTERFACES.contains(spi)) {
|
||||
throw new JUnitException(String.format("SPI '%s' is not a TASKANA SPI.", spi));
|
||||
}
|
||||
if (!serviceProviders.stream().allMatch(spi::isAssignableFrom)) {
|
||||
throw new JUnitException(
|
||||
String.format(
|
||||
"At least one ServiceProvider does not implement the requested SPI '%s'", spi));
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Class<?>, List<Class<?>>> groupServiceProvidersByServiceProviderInterface(
|
||||
List<WithServiceProvider> withServiceProviders) {
|
||||
return withServiceProviders.stream()
|
||||
.collect(
|
||||
Collectors.groupingBy(
|
||||
WithServiceProvider::serviceProviderInterface,
|
||||
Collectors.flatMapping(
|
||||
annotation -> Arrays.stream(annotation.serviceProviders()),
|
||||
Collectors.toList())));
|
||||
}
|
||||
|
||||
private static List<Object> instantiateServiceProviders(List<Class<?>> serviceProviders) {
|
||||
return serviceProviders.stream()
|
||||
.map(wrap(Class::getDeclaredConstructor))
|
||||
.map(wrap(Constructor::newInstance))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
acceptance.taskrouting.TestTaskRoutingProviderForDomainA
|
||||
acceptance.taskrouting.TestTaskRoutingProviderForDomainB
|
|
@ -1 +0,0 @@
|
|||
acceptance.taskpreprocessing.TestCreateTaskPreprocessorProvider
|
|
@ -36,7 +36,7 @@ class DmnTaskRouterAccTest extends AbstractAccTest {
|
|||
|
||||
@WithAccessId(user = "taskadmin")
|
||||
@Test
|
||||
void should_ThrowException_When_DmnTaskRouterFindsNoRule() throws Exception {
|
||||
void should_ThrowException_When_DmnTaskRouterFindsNoRule() {
|
||||
|
||||
Task taskToRoute = taskService.newTask();
|
||||
taskToRoute.setClassificationKey("T2100");
|
||||
|
@ -48,6 +48,6 @@ class DmnTaskRouterAccTest extends AbstractAccTest {
|
|||
assertThatThrownBy(call)
|
||||
.isInstanceOf(InvalidArgumentException.class)
|
||||
.extracting(Throwable::getMessage)
|
||||
.isEqualTo("Cannot create a task outside a workbasket");
|
||||
.isEqualTo("Cannot create a Task outside a Workbasket");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue