TSK-1730: Allow modification of TaskanaEngineConfiguration for tests

This commit is contained in:
Mustapha Zorgati 2021-09-20 14:17:35 +02:00
parent 60cdb4b08f
commit 761c6edade
25 changed files with 800 additions and 477 deletions

View File

@ -106,28 +106,6 @@
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<version>${version.testcontainers}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${version.testcontainers}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- TEST DEPENDENCIES -->
<dependency>

View File

@ -139,7 +139,7 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
StreamSupport.stream(newChildrenForDynamicContainer.spliterator(), false)
.map(x -> duplicateDynamicNode(x, childrenMap)));
Store store = getStore(extensionContext);
Store store = getMethodLevelStore(extensionContext);
return (T)
Stream.of(annotation.value())
.peek(a -> store.put(ACCESS_IDS_STORE_KEY, a))
@ -155,7 +155,7 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
WithAccessId accessId =
getStore(extensionContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
getMethodLevelStore(extensionContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
performInvocationWithAccessId(invocation, accessId);
}
@ -163,7 +163,7 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
public void interceptDynamicTest(Invocation<Void> invocation, ExtensionContext extensionContext) {
ExtensionContext testContext = getParentMethodExtensionContent(extensionContext);
// Check if the test factory provided an access Id for this dynamic test.
WithAccessId o = getStore(testContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
WithAccessId o = getMethodLevelStore(testContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
if (o != null) {
performInvocationWithAccessId(invocation, o);
} else {
@ -202,7 +202,7 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
ExtensionContext context) {
List<WithAccessId> accessIds =
AnnotationSupport.findRepeatableAnnotations(context.getElement(), WithAccessId.class);
Store store = getStore(context);
Store store = getMethodLevelStore(context);
return accessIds.stream()
.peek(a -> store.put(ACCESS_IDS_STORE_KEY, a))
.map(JaasExtensionInvocationContext::new);
@ -279,14 +279,9 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
"Test '%s' does not have a parent method", extensionContext.getUniqueId())));
}
/**
* Gets the store with a <b>method-level</b> scope.
*
* @param context context for current extension
* @return The store
*/
private Store getStore(ExtensionContext context) {
return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod()));
private static Store getMethodLevelStore(ExtensionContext context) {
return context.getStore(
Namespace.create(context.getRequiredTestClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(WithAccessId withAccessId) {

View File

@ -111,6 +111,30 @@
<version>${version.archunit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<version>${version.testcontainers}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${version.testcontainers}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<repositories>

View File

@ -12,6 +12,7 @@ import com.tngtech.archunit.base.Optional;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaField;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchCondition;
@ -39,6 +40,7 @@ import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
import testapi.TaskanaIntegrationTest;
import pro.taskana.common.api.exceptions.ErrorCode;
import pro.taskana.common.api.exceptions.TaskanaException;
@ -294,6 +296,33 @@ class ArchitectureTest {
rule.check(importedClasses);
}
@Test
void taskanaIntegrationTestsShouldOnlyHavePackagePrivateFields() {
ArchRule rule =
classes()
.that()
.areAnnotatedWith(TaskanaIntegrationTest.class)
.should(onlyHaveFieldsWithNoModifier());
rule.check(importedClasses);
}
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()) {
events.add(
SimpleConditionEvent.violated(
item,
String.format("Field '%s' should not have any modifier", field.getFullName())));
}
}
}
};
}
private static ArchCondition<JavaClass> beDefinedInTaskanaSubPackages(
List<Pattern> excludePackages) {
return new ArchCondition<JavaClass>("all be defined in TASKANA_SUB_PACKAGES") {

View File

@ -1,69 +0,0 @@
package acceptance;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.platform.commons.JUnitException;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.classification.internal.ClassificationServiceImpl;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
import pro.taskana.common.api.WorkingDaysToDaysConverter;
import pro.taskana.common.internal.JobServiceImpl;
import pro.taskana.common.internal.TaskanaEngineImpl;
import pro.taskana.common.test.config.DataSourceGenerator;
import pro.taskana.monitor.internal.MonitorServiceImpl;
import pro.taskana.task.internal.TaskServiceImpl;
import pro.taskana.workbasket.internal.WorkbasketServiceImpl;
public class TaskanaDependencyInjectionExtension implements ParameterResolver {
private final Map<Class<?>, Object> instanceByClass;
public TaskanaDependencyInjectionExtension(DataSource dataSource) throws Exception {
String schemaName = DataSourceGenerator.getSchemaName();
TaskanaEngineConfiguration taskanaEngineConfiguration =
new TaskanaEngineConfiguration(dataSource, false, schemaName);
taskanaEngineConfiguration.setGermanPublicHolidaysEnabled(true);
TaskanaEngine taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
taskanaEngine.setConnectionManagementMode(ConnectionManagementMode.AUTOCOMMIT);
instanceByClass =
Map.ofEntries(
Map.entry(TaskanaEngineConfiguration.class, taskanaEngineConfiguration),
Map.entry(TaskanaEngineImpl.class, taskanaEngine),
Map.entry(TaskServiceImpl.class, taskanaEngine.getTaskService()),
Map.entry(MonitorServiceImpl.class, taskanaEngine.getMonitorService()),
Map.entry(WorkbasketServiceImpl.class, taskanaEngine.getWorkbasketService()),
Map.entry(ClassificationServiceImpl.class, taskanaEngine.getClassificationService()),
Map.entry(JobServiceImpl.class, taskanaEngine.getJobService()),
Map.entry(
WorkingDaysToDaysConverter.class, taskanaEngine.getWorkingDaysToDaysConverter()));
}
@Override
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return instanceByClass.keySet().stream()
.anyMatch(getParameterType(parameterContext)::isAssignableFrom);
}
@Override
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return instanceByClass.keySet().stream()
.filter(getParameterType(parameterContext)::isAssignableFrom)
.map(instanceByClass::get)
.findFirst()
.orElseThrow(() -> new JUnitException("This should never happen."));
}
private Class<?> getParameterType(ParameterContext parameterContext) {
return parameterContext.getParameter().getType();
}
}

View File

@ -1,185 +0,0 @@
package acceptance;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.internal.ClassificationServiceImpl;
import pro.taskana.common.api.JobService;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.WorkingDaysToDaysConverter;
import pro.taskana.common.internal.JobServiceImpl;
import pro.taskana.common.internal.TaskanaEngineImpl;
import pro.taskana.monitor.api.MonitorService;
import pro.taskana.monitor.internal.MonitorServiceImpl;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.internal.TaskServiceImpl;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.internal.WorkbasketServiceImpl;
@ExtendWith(TaskanaIntegrationTestExtension.class)
public class TaskanaDependencyInjectionExtensionTest {
@Nested
class TaskanaEngineConfigurationInjectionTest {
private final TaskanaEngineConfiguration taskanaEngineConfiguration;
public TaskanaEngineConfigurationInjectionTest(
TaskanaEngineConfiguration taskanaEngineConfiguration) {
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
}
@Test
void should_InjectTaskanaEngineConfiguration_When_ConstructorContainsParameter() {
assertThat(taskanaEngineConfiguration).isNotNull();
}
}
@Nested
class TaskanaEngineInjectionTest {
private final TaskanaEngine taskanaEngine;
private final TaskanaEngineImpl taskanaEngineImpl;
TaskanaEngineInjectionTest(TaskanaEngine taskanaEngine, TaskanaEngineImpl taskanaEngineImpl) {
this.taskanaEngine = taskanaEngine;
this.taskanaEngineImpl = taskanaEngineImpl;
}
@Test
void should_InjectTaskanaEngine_When_ConstructorContainsParameter() {
assertThat(taskanaEngine).isNotNull();
}
@Test
void should_InjectTaskanaEngineImpl_When_ConstructorContainsParameter() {
assertThat(taskanaEngineImpl).isNotNull();
}
}
@Nested
class TaskServiceInjectionTest {
private final TaskService taskService;
private final TaskServiceImpl taskServiceImpl;
TaskServiceInjectionTest(TaskService taskService, TaskServiceImpl taskServiceImpl) {
this.taskService = taskService;
this.taskServiceImpl = taskServiceImpl;
}
@Test
void should_InjectTaskService_When_ConstructorContainsParameter() {
assertThat(taskService).isNotNull();
}
@Test
void should_InjectTaskServiceImpl_When_ConstructorContainsParameter() {
assertThat(taskServiceImpl).isNotNull();
}
}
@Nested
class MonitorServiceInjectionTest {
private final MonitorService monitorService;
private final MonitorServiceImpl monitorServiceImpl;
MonitorServiceInjectionTest(
MonitorService monitorService, MonitorServiceImpl monitorServiceImpl) {
this.monitorService = monitorService;
this.monitorServiceImpl = monitorServiceImpl;
}
@Test
void should_InjectMonitorService_When_ConstructorContainsParameter() {
assertThat(monitorService).isNotNull();
}
@Test
void should_InjectMonitorServiceImpl_When_ConstructorContainsParameter() {
assertThat(monitorServiceImpl).isNotNull();
}
}
@Nested
class WorkbasketServiceInjectionTest {
private final WorkbasketService workbasketService;
private final WorkbasketServiceImpl workbasketServiceImpl;
WorkbasketServiceInjectionTest(
WorkbasketService workbasketService, WorkbasketServiceImpl workbasketServiceImpl) {
this.workbasketService = workbasketService;
this.workbasketServiceImpl = workbasketServiceImpl;
}
@Test
void should_InjectWorkbasketService_When_ConstructorContainsParameter() {
assertThat(workbasketService).isNotNull();
}
@Test
void should_InjectWorkbasketServiceImpl_When_ConstructorContainsParameter() {
assertThat(workbasketServiceImpl).isNotNull();
}
}
@Nested
class ClassificationServiceInjectionTest {
private final ClassificationService classificationService;
private final ClassificationServiceImpl classificationServiceImpl;
ClassificationServiceInjectionTest(
ClassificationService classificationService,
ClassificationServiceImpl classificationServiceImpl) {
this.classificationService = classificationService;
this.classificationServiceImpl = classificationServiceImpl;
}
@Test
void should_InjectClassificationService_When_ConstructorContainsParameter() {
assertThat(classificationService).isNotNull();
}
@Test
void should_InjectClassificationServiceImpl_When_ConstructorContainsParameter() {
assertThat(classificationServiceImpl).isNotNull();
}
}
@Nested
class JobServiceInjectionTest {
private final JobService jobService;
private final JobServiceImpl jobServiceImpl;
JobServiceInjectionTest(JobService jobService, JobServiceImpl jobServiceImpl) {
this.jobService = jobService;
this.jobServiceImpl = jobServiceImpl;
}
@Test
void should_InjectJobService_When_ConstructorContainsParameter() {
assertThat(jobService).isNotNull();
}
@Test
void should_InjectJobServiceImpl_When_ConstructorContainsParameter() {
assertThat(jobServiceImpl).isNotNull();
}
}
@Nested
class WorkingDaysToDaysConverterInjectionTest {
private final WorkingDaysToDaysConverter workingDaysToDaysConverter;
WorkingDaysToDaysConverterInjectionTest(WorkingDaysToDaysConverter workingDaysToDaysConverter) {
this.workingDaysToDaysConverter = workingDaysToDaysConverter;
}
@Test
void should_InjectWorkingDaysToDaysConverter_When_ConstructorContainsParameter() {
assertThat(workingDaysToDaysConverter).isNotNull();
}
}
}

View File

@ -1,40 +0,0 @@
package acceptance;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import pro.taskana.common.test.config.TestContainerExtension;
public class TaskanaIntegrationTestExtension implements ParameterResolver, AfterAllCallback {
private final TaskanaDependencyInjectionExtension dependencyInjectionExtension;
private final TestContainerExtension testContainerExtension;
public TaskanaIntegrationTestExtension() throws Exception {
testContainerExtension = new TestContainerExtension();
dependencyInjectionExtension =
new TaskanaDependencyInjectionExtension(testContainerExtension.getDataSource());
}
@Override
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return dependencyInjectionExtension.supportsParameter(parameterContext, extensionContext);
}
@Override
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return dependencyInjectionExtension.resolveParameter(parameterContext, extensionContext);
}
@Override
public void afterAll(ExtensionContext context) {
testContainerExtension.afterAll(context);
}
}

View File

@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static pro.taskana.classification.internal.ClassificationBuilder.newClassification;
import acceptance.TaskanaIntegrationTestExtension;
import java.time.Instant;
import java.util.List;
import java.util.function.BiFunction;
@ -14,7 +13,8 @@ import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.classification.api.ClassificationCustomField;
import pro.taskana.classification.api.ClassificationService;
@ -22,17 +22,12 @@ import pro.taskana.classification.api.models.Classification;
import pro.taskana.classification.internal.ClassificationBuilder;
import pro.taskana.classification.internal.models.ClassificationImpl;
import pro.taskana.common.internal.util.Quadruple;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TaskanaIntegrationTest
class ClassificationBuilderTest {
private final ClassificationService classificationService;
public ClassificationBuilderTest(ClassificationService classificationService) {
this.classificationService = classificationService;
}
@TaskanaInject ClassificationService classificationService;
@WithAccessId(user = "businessadmin")
@Test

View File

@ -3,32 +3,26 @@ package acceptance.builder;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import acceptance.DefaultTestEntities;
import acceptance.TaskanaIntegrationTestExtension;
import java.time.Instant;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.classification.internal.ClassificationBuilder;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.Attachment;
import pro.taskana.task.api.models.ObjectReference;
import pro.taskana.task.internal.TaskAttachmentBuilder;
import pro.taskana.task.internal.models.AttachmentImpl;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TaskanaIntegrationTest
class TaskAttachmentBuilderTest {
private final ClassificationService classificationService;
private final TaskService taskService;
TaskAttachmentBuilderTest(ClassificationService classificationService, TaskService taskService) {
this.classificationService = classificationService;
this.taskService = taskService;
}
@TaskanaInject ClassificationService classificationService;
@TaskanaInject TaskService taskService;
@Test
void should_PopulateAttachment_When_UsingEveryBuilderFunction() throws Exception {

View File

@ -9,7 +9,6 @@ import static pro.taskana.common.internal.util.CheckedSupplier.wrap;
import static pro.taskana.task.internal.builder.TaskBuilder.newTask;
import static pro.taskana.workbasket.internal.WorkbasketAccessItemBuilder.newWorkbasketAccessItem;
import acceptance.TaskanaIntegrationTestExtension;
import java.time.Instant;
import java.util.List;
import java.util.Map;
@ -21,15 +20,13 @@ import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;
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.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.internal.util.Quadruple;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.task.api.CallbackState;
import pro.taskana.task.api.TaskCustomField;
@ -44,19 +41,13 @@ import pro.taskana.workbasket.api.WorkbasketPermission;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.api.models.WorkbasketSummary;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TestInstance(Lifecycle.PER_CLASS)
@TaskanaIntegrationTest
class TaskBuilderTest {
private final TaskanaEngine taskanaEngine;
private final TaskService taskService;
@TaskanaInject TaskanaEngine taskanaEngine;
@TaskanaInject TaskService taskService;
private WorkbasketSummary workbasketSummary;
private ClassificationSummary classificationSummary;
TaskBuilderTest(TaskanaEngine taskanaEngine, TaskService taskService) {
this.taskanaEngine = taskanaEngine;
this.taskService = taskService;
}
WorkbasketSummary workbasketSummary;
ClassificationSummary classificationSummary;
@WithAccessId(user = "businessadmin")
@BeforeAll

View File

@ -9,7 +9,6 @@ import static pro.taskana.common.internal.util.CheckedSupplier.wrap;
import static pro.taskana.task.internal.TaskCommentBuilder.newTaskComment;
import static pro.taskana.workbasket.internal.WorkbasketAccessItemBuilder.newWorkbasketAccessItem;
import acceptance.TaskanaIntegrationTestExtension;
import java.time.Instant;
import java.util.List;
import java.util.function.BiFunction;
@ -20,15 +19,13 @@ import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;
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.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.Classification;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.internal.util.Quadruple;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.ObjectReference;
@ -41,19 +38,13 @@ import pro.taskana.workbasket.api.WorkbasketPermission;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.api.models.Workbasket;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TestInstance(Lifecycle.PER_CLASS)
@TaskanaIntegrationTest
class TaskCommentBuilderTest {
private final TaskService taskService;
private final TaskanaEngine taskanaEngine;
@TaskanaInject TaskService taskService;
@TaskanaInject TaskanaEngine taskanaEngine;
private Task task;
TaskCommentBuilderTest(TaskService taskService, TaskanaEngine taskanaEngine) {
this.taskService = taskService;
this.taskanaEngine = taskanaEngine;
}
Task task;
@WithAccessId(user = "businessadmin")
@BeforeAll

View File

@ -6,13 +6,12 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
import static pro.taskana.common.internal.util.CheckedSupplier.wrap;
import static pro.taskana.workbasket.internal.WorkbasketAccessItemBuilder.newWorkbasketAccessItem;
import acceptance.TaskanaIntegrationTestExtension;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.workbasket.api.WorkbasketPermission;
import pro.taskana.workbasket.api.WorkbasketService;
@ -21,17 +20,11 @@ import pro.taskana.workbasket.api.models.WorkbasketAccessItem;
import pro.taskana.workbasket.internal.WorkbasketAccessItemBuilder;
import pro.taskana.workbasket.internal.models.WorkbasketAccessItemImpl;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TaskanaIntegrationTest
class WorkbasketAccessItemBuilderTest {
private final WorkbasketService workbasketService;
private final TaskanaEngine taskanaEngine;
WorkbasketAccessItemBuilderTest(
WorkbasketService workbasketService, TaskanaEngine taskanaEngine) {
this.workbasketService = workbasketService;
this.taskanaEngine = taskanaEngine;
}
@TaskanaInject WorkbasketService workbasketService;
@TaskanaInject TaskanaEngine taskanaEngine;
@WithAccessId(user = "businessadmin")
@Test

View File

@ -5,7 +5,6 @@ import static org.assertj.core.api.Assertions.assertThatCode;
import static pro.taskana.common.internal.util.CheckedSupplier.wrap;
import static pro.taskana.workbasket.internal.WorkbasketBuilder.newWorkbasket;
import acceptance.TaskanaIntegrationTestExtension;
import java.time.Instant;
import java.util.List;
import java.util.function.BiFunction;
@ -15,11 +14,11 @@ import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.extension.ExtendWith;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.internal.util.Quadruple;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.workbasket.api.WorkbasketCustomField;
import pro.taskana.workbasket.api.WorkbasketService;
@ -28,16 +27,11 @@ import pro.taskana.workbasket.api.models.Workbasket;
import pro.taskana.workbasket.internal.WorkbasketBuilder;
import pro.taskana.workbasket.internal.models.WorkbasketImpl;
@ExtendWith({JaasExtension.class, TaskanaIntegrationTestExtension.class})
@TaskanaIntegrationTest
class WorkbasketBuilderTest {
private final WorkbasketService workbasketService;
private final TaskanaEngine taskanaEngine;
WorkbasketBuilderTest(WorkbasketService workbasketService, TaskanaEngine taskanaEngine) {
this.workbasketService = workbasketService;
this.taskanaEngine = taskanaEngine;
}
@TaskanaInject WorkbasketService workbasketService;
@TaskanaInject TaskanaEngine taskanaEngine;
@WithAccessId(user = "businessadmin")
@Test

View File

@ -0,0 +1,10 @@
package testapi;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CleanTaskanaContext {}

View File

@ -0,0 +1,9 @@
package testapi;
import pro.taskana.TaskanaEngineConfiguration;
public interface TaskanaEngineConfigurationModifier {
void modify(TaskanaEngineConfiguration taskanaEngineConfiguration);
}

View File

@ -0,0 +1,10 @@
package testapi;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TaskanaInject {}

View File

@ -0,0 +1,26 @@
package testapi;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import testapi.extensions.TaskanaDependencyInjectionExtension;
import testapi.extensions.TaskanaInitializationExtension;
import testapi.extensions.TestContainerExtension;
import pro.taskana.common.test.security.JaasExtension;
@ExtendWith({
// ORDER IS IMPORTANT!
JaasExtension.class,
TestContainerExtension.class,
TaskanaInitializationExtension.class,
TaskanaDependencyInjectionExtension.class,
})
@TestInstance(Lifecycle.PER_CLASS)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TaskanaIntegrationTest {}

View File

@ -0,0 +1,63 @@
package testapi.extensions;
import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedFields;
import static testapi.util.ExtensionCommunicator.getClassLevelStore;
import java.lang.reflect.Field;
import java.util.Map;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
import org.junit.platform.commons.JUnitException;
import testapi.TaskanaInject;
public class TaskanaDependencyInjectionExtension
implements ParameterResolver, TestInstancePostProcessor {
@Override
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
Map<Class<?>, Object> instanceByClass = getTaskanaEntityMap(extensionContext);
return instanceByClass != null
&& instanceByClass.containsKey(parameterContext.getParameter().getType());
}
@Override
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return getTaskanaEntityMap(extensionContext).get(parameterContext.getParameter().getType());
}
@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context)
throws Exception {
Map<Class<?>, Object> instanceByClass = getTaskanaEntityMap(context);
if (instanceByClass == null) {
throw new JUnitException("Something went wrong! Could not find TASKANA entity Map in store.");
}
for (Field field : findAnnotatedFields(testInstance.getClass(), TaskanaInject.class)) {
Object toInject = instanceByClass.get(field.getType());
if (toInject != null) {
field.setAccessible(true);
field.set(testInstance, toInject);
} else {
throw new JUnitException(
String.format(
"Cannot inject field '%s'. " + "Type '%s' is not an injectable TASKANA type",
field.getName(), field.getType()));
}
}
}
@SuppressWarnings("unchecked")
private static Map<Class<?>, Object> getTaskanaEntityMap(ExtensionContext extensionContext) {
return (Map<Class<?>, Object>)
getClassLevelStore(extensionContext)
.get(TaskanaInitializationExtension.STORE_TASKANA_ENTITY_MAP);
}
}

View File

@ -0,0 +1,100 @@
package testapi.extensions;
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
import static testapi.util.ExtensionCommunicator.getClassLevelStore;
import static testapi.util.ExtensionCommunicator.isTopLevelClass;
import java.util.Map;
import javax.sql.DataSource;
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 testapi.CleanTaskanaContext;
import testapi.TaskanaEngineConfigurationModifier;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.internal.ClassificationServiceImpl;
import pro.taskana.common.api.JobService;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
import pro.taskana.common.api.WorkingDaysToDaysConverter;
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.monitor.api.MonitorService;
import pro.taskana.monitor.internal.MonitorServiceImpl;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.internal.TaskServiceImpl;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.internal.WorkbasketServiceImpl;
public class TaskanaInitializationExtension implements TestInstancePostProcessor {
public static final String STORE_TASKANA_ENTITY_MAP = "taskanaEntityMap";
@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context)
throws Exception {
Class<?> testClass = testInstance.getClass();
if (isTopLevelClass(testClass)
|| isAnnotated(testClass, CleanTaskanaContext.class)
|| testInstance instanceof TaskanaEngineConfigurationModifier) {
Store store = getClassLevelStore(context);
TaskanaEngineConfiguration taskanaEngineConfiguration =
createDefaultTaskanaEngineConfiguration(store);
if (testInstance instanceof TaskanaEngineConfigurationModifier) {
TaskanaEngineConfigurationModifier modifier =
(TaskanaEngineConfigurationModifier) testInstance;
modifier.modify(taskanaEngineConfiguration);
}
TaskanaEngine taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
taskanaEngine.setConnectionManagementMode(ConnectionManagementMode.AUTOCOMMIT);
store.put(STORE_TASKANA_ENTITY_MAP, generateTaskanaEntityMap(taskanaEngine));
}
}
private static TaskanaEngineConfiguration createDefaultTaskanaEngineConfiguration(Store store) {
String schemaName = store.get(TestContainerExtension.STORE_SCHEMA_NAME, String.class);
if (schemaName == null) {
throw new JUnitException("Expected schemaName to be defined in store, but it's not.");
}
DataSource dataSource = store.get(TestContainerExtension.STORE_DATA_SOURCE, DataSource.class);
if (dataSource == null) {
throw new JUnitException("Expected dataSource to be defined in store, but it's not.");
}
return new TaskanaEngineConfiguration(dataSource, false, schemaName);
}
private static Map<Class<?>, Object> generateTaskanaEntityMap(TaskanaEngine taskanaEngine) {
TaskService taskService = taskanaEngine.getTaskService();
MonitorService monitorService = taskanaEngine.getMonitorService();
WorkbasketService workbasketService = taskanaEngine.getWorkbasketService();
ClassificationService classificationService = taskanaEngine.getClassificationService();
JobService jobService = taskanaEngine.getJobService();
CurrentUserContext currentUserContext = taskanaEngine.getCurrentUserContext();
return Map.ofEntries(
Map.entry(TaskanaEngineConfiguration.class, taskanaEngine.getConfiguration()),
Map.entry(TaskanaEngineImpl.class, taskanaEngine),
Map.entry(TaskanaEngine.class, taskanaEngine),
Map.entry(TaskService.class, taskService),
Map.entry(TaskServiceImpl.class, taskService),
Map.entry(MonitorService.class, monitorService),
Map.entry(MonitorServiceImpl.class, monitorService),
Map.entry(WorkbasketService.class, workbasketService),
Map.entry(WorkbasketServiceImpl.class, workbasketService),
Map.entry(ClassificationService.class, classificationService),
Map.entry(ClassificationServiceImpl.class, classificationService),
Map.entry(JobService.class, jobService),
Map.entry(JobServiceImpl.class, jobService),
Map.entry(CurrentUserContext.class, currentUserContext),
Map.entry(CurrentUserContextImpl.class, currentUserContext),
Map.entry(WorkingDaysToDaysConverter.class, taskanaEngine.getWorkingDaysToDaysConverter()));
}
}

View File

@ -0,0 +1,115 @@
package testapi.extensions;
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
import static testapi.util.DockerContainerCreator.createDockerContainer;
import static testapi.util.ExtensionCommunicator.getClassLevelStore;
import static testapi.util.ExtensionCommunicator.isTopLevelClass;
import java.lang.reflect.Constructor;
import java.util.Optional;
import java.util.UUID;
import javax.sql.DataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.platform.commons.support.AnnotationSupport;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.JdbcDatabaseContainer;
import testapi.CleanTaskanaContext;
import testapi.TaskanaEngineConfigurationModifier;
import testapi.util.DockerContainerCreator;
import pro.taskana.common.internal.configuration.DB;
public class TestContainerExtension implements AfterAllCallback, InvocationInterceptor {
public static final String STORE_DATA_SOURCE = "datasource";
public static final String STORE_CONTAINER = "container";
public static final String STORE_SCHEMA_NAME = "schemaName";
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext,
ExtensionContext extensionContext)
throws Throwable {
Class<?> testClass = extensionContext.getRequiredTestClass();
if (isTopLevelClass(testClass) || isAnnotated(testClass, CleanTaskanaContext.class)) {
Store store = getClassLevelStore(extensionContext);
DB db = retrieveDatabaseFromEnv();
store.put(STORE_SCHEMA_NAME, determineSchemaName(db));
createDockerContainer(db)
.ifPresentOrElse(
container -> {
container.start();
store.put(STORE_DATA_SOURCE, DockerContainerCreator.createDataSource(container));
store.put(STORE_CONTAINER, container);
},
() -> store.put(STORE_DATA_SOURCE, createDataSourceForH2()));
} else if (TaskanaEngineConfigurationModifier.class.isAssignableFrom(testClass)) {
// 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.
// This allows the following extensions to generate a new TaskanaEngine for the testClass.
Store parentStore = getClassLevelStore(extensionContext, testClass.getEnclosingClass());
Store store = getClassLevelStore(extensionContext);
copyValue(TestContainerExtension.STORE_SCHEMA_NAME, parentStore, store);
copyValue(TestContainerExtension.STORE_DATA_SOURCE, parentStore, store);
}
return invocation.proceed();
}
@Override
public void afterAll(ExtensionContext context) {
Class<?> testClass = context.getRequiredTestClass();
if (isTopLevelClass(testClass)
|| AnnotationSupport.isAnnotated(testClass, CleanTaskanaContext.class)) {
Optional.ofNullable(getClassLevelStore(context).get(STORE_CONTAINER))
.map(JdbcDatabaseContainer.class::cast)
.ifPresent(GenericContainer::stop);
}
}
private static void copyValue(String key, Store source, Store destination) {
Object value = source.get(key);
destination.put(key, value);
}
private static String determineSchemaName(DB db) {
return db == DB.POSTGRES ? "taskana" : "TASKANA";
}
private static DB retrieveDatabaseFromEnv() {
String property = System.getenv("db.type");
DB db;
try {
db = DB.valueOf(property);
} catch (Exception ex) {
db = DB.H2;
}
return db;
}
private static DataSource createDataSourceForH2() {
PooledDataSource ds =
new PooledDataSource(
Thread.currentThread().getContextClassLoader(),
"org.h2.Driver",
"jdbc:h2:mem:"
+ UUID.randomUUID()
+ ";LOCK_MODE=0;"
+ "INIT=CREATE SCHEMA IF NOT EXISTS TASKANA\\;"
+ "SET COLLATION DEFAULT_de_DE ",
"sa",
"sa");
ds.setPoolTimeToWait(50);
ds.forceCloseAll(); // otherwise, the MyBatis pool is not initialized correctly
return ds;
}
}

View File

@ -0,0 +1,152 @@
package testapi.tests;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.internal.ClassificationServiceImpl;
import pro.taskana.common.api.JobService;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.WorkingDaysToDaysConverter;
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.monitor.api.MonitorService;
import pro.taskana.monitor.internal.MonitorServiceImpl;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.internal.TaskServiceImpl;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.internal.WorkbasketServiceImpl;
@TaskanaIntegrationTest
class TaskanaDependencyInjectionExtensionTest {
TaskanaEngineConfiguration taskanaEngineConfigurationNotAnnotated;
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@TaskanaInject TaskanaEngine taskanaEngine;
@TaskanaInject TaskanaEngine taskanaEngine2;
@TaskanaInject TaskanaEngineImpl taskanaEngineImpl;
@TaskanaInject ClassificationService classificationService;
@TaskanaInject ClassificationServiceImpl classificationServiceImpl;
@TaskanaInject WorkbasketService workbasketService;
@TaskanaInject WorkbasketServiceImpl workbasketServiceImpl;
@TaskanaInject TaskService taskService;
@TaskanaInject TaskServiceImpl taskServiceImpl;
@TaskanaInject MonitorService monitorService;
@TaskanaInject MonitorServiceImpl monitorServiceImpl;
@TaskanaInject JobService jobService;
@TaskanaInject JobServiceImpl jobServiceImpl;
@TaskanaInject WorkingDaysToDaysConverter workingDaysToDaysConverter;
@TaskanaInject CurrentUserContext currentUserContext;
@TaskanaInject CurrentUserContextImpl currentUserContextImpl;
@Test
void should_NotInjectTaskanaEngineConfiguration_When_FieldIsNotAnnotated() {
assertThat(taskanaEngineConfigurationNotAnnotated).isNull();
}
@Test
void should_InjectMultipleTimes_When_FieldIsDeclaredMultipleTimes() {
assertThat(taskanaEngine).isSameAs(taskanaEngine2).isNotNull();
}
@Test
void should_InjectTaskanaEngineConfiguration_When_FieldIsAnnotatedOrDeclaredAsParameter(
TaskanaEngineConfiguration taskanaEngineConfiguration) {
assertThat(taskanaEngineConfiguration).isSameAs(this.taskanaEngineConfiguration).isNotNull();
}
@Test
void should_InjectTaskanaEngine_When_FieldIsAnnotatedOrDeclaredAsParameter(
TaskanaEngine taskanaEngine) {
assertThat(taskanaEngine).isSameAs(this.taskanaEngine).isNotNull();
}
@Test
void should_InjectTaskanaEngineImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
TaskanaEngineImpl taskanaEngineImpl) {
assertThat(taskanaEngineImpl).isSameAs(this.taskanaEngineImpl).isNotNull();
}
@Test
void should_InjectClassificationService_When_FieldIsAnnotatedOrDeclaredAsParameter(
ClassificationService classificationService) {
assertThat(classificationService).isSameAs(this.classificationService).isNotNull();
}
@Test
void should_InjectClassificationServiceImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
ClassificationServiceImpl classificationServiceImpl) {
assertThat(classificationServiceImpl).isSameAs(this.classificationServiceImpl).isNotNull();
}
@Test
void should_InjectWorkbasketService_When_FieldIsAnnotatedOrDeclaredAsParameter(
WorkbasketService workbasketService) {
assertThat(workbasketService).isSameAs(this.workbasketService).isNotNull();
}
@Test
void should_InjectWorkbasketServiceImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
WorkbasketServiceImpl workbasketServiceImpl) {
assertThat(workbasketServiceImpl).isSameAs(this.workbasketServiceImpl).isNotNull();
}
@Test
void should_InjectTaskService_When_FieldIsAnnotatedOrDeclaredAsParameter(
TaskService taskService) {
assertThat(taskService).isSameAs(this.taskService).isNotNull();
}
@Test
void should_InjectTaskServiceImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
TaskServiceImpl taskServiceImpl) {
assertThat(taskServiceImpl).isSameAs(this.taskServiceImpl).isNotNull();
}
@Test
void should_InjectMonitorService_When_FieldIsAnnotatedOrDeclaredAsParameter(
MonitorService monitorService) {
assertThat(monitorService).isSameAs(this.monitorService).isNotNull();
}
@Test
void should_InjectMonitorServiceImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
MonitorServiceImpl monitorServiceImpl) {
assertThat(monitorServiceImpl).isSameAs(this.monitorServiceImpl).isNotNull();
}
@Test
void should_InjectJobService_When_FieldIsAnnotatedOrDeclaredAsParameter(JobService jobService) {
assertThat(jobService).isSameAs(this.jobService).isNotNull();
}
@Test
void should_InjectJobServiceImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
JobServiceImpl jobServiceImpl) {
assertThat(jobServiceImpl).isSameAs(this.jobServiceImpl).isNotNull();
}
@Test
void should_InjectWorkingDaysToDaysConverter_When_FieldIsAnnotatedOrDeclaredAsParameter(
WorkingDaysToDaysConverter workingDaysToDaysConverter) {
assertThat(workingDaysToDaysConverter).isSameAs(this.workingDaysToDaysConverter).isNotNull();
}
@Test
void should_InjectCurrentUserContext_When_FieldIsAnnotatedOrDeclaredAsParameter(
CurrentUserContext currentUserContext) {
assertThat(currentUserContext).isSameAs(this.currentUserContext).isNotNull();
}
@Test
void should_InjectCurrentUserContextImpl_When_FieldIsAnnotatedOrDeclaredAsParameter(
CurrentUserContextImpl currentUserContextImpl) {
assertThat(currentUserContextImpl).isSameAs(this.currentUserContextImpl).isNotNull();
}
}

View File

@ -0,0 +1,78 @@
package testapi.tests;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import testapi.CleanTaskanaContext;
import testapi.TaskanaEngineConfigurationModifier;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.TaskanaEngineConfiguration;
@TaskanaIntegrationTest
class TaskanaInitializationExtensionTest {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Test
void should_UseDefaultTaskanaEngine_When_TestIsCreated() {
assertThat(taskanaEngineConfiguration.getDomains())
.containsExactlyInAnyOrder("DOMAIN_A", "DOMAIN_B");
}
@Nested
class ReuseTaskana {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Test
void should_useTopLevelTaskanaInstance_For_NestedTestClasses() {
assertThat(taskanaEngineConfiguration)
.isSameAs(TaskanaInitializationExtensionTest.this.taskanaEngineConfiguration);
}
}
@Nested
class ModifiedTaskanaEngineConfig implements TaskanaEngineConfigurationModifier {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Override
public void modify(TaskanaEngineConfiguration taskanaEngineConfiguration) {
taskanaEngineConfiguration.setDomains(List.of("A", "B"));
}
@Test
void should_OverrideConfiguration_When_ClassImplementsTaskanaEngineConfigurationModifier() {
assertThat(taskanaEngineConfiguration.getDomains()).containsExactlyInAnyOrder("A", "B");
}
@Test
void should_createNewTaskanaInstance_For_NestedTestClassImplementingModifierInterface() {
assertThat(taskanaEngineConfiguration)
.isNotSameAs(TaskanaInitializationExtensionTest.this.taskanaEngineConfiguration);
}
}
@CleanTaskanaContext
@Nested
class NestedTestClassAnnotatedWithCleanTaskanaContext {
@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");
}
}
}

View File

@ -0,0 +1,95 @@
package testapi.tests;
import static org.assertj.core.api.Assertions.assertThat;
import javax.sql.DataSource;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import testapi.CleanTaskanaContext;
import testapi.TaskanaEngineConfigurationModifier;
import testapi.TaskanaInject;
import testapi.TaskanaIntegrationTest;
import pro.taskana.TaskanaEngineConfiguration;
@TaskanaIntegrationTest
class TestContainerExtensionTest {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Test
void should_CreateNewDataSource_For_TopLevelTestClass() {
DataSource datasource = taskanaEngineConfiguration.getDatasource();
assertThat(datasource).isNotNull();
}
@Nested
class NestedTestClass {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Test
void should_ReuseDataSource_For_NestedTestClass() {
DataSource nestedDataSource = taskanaEngineConfiguration.getDatasource();
DataSource topLevelDataSource =
TestContainerExtensionTest.this.taskanaEngineConfiguration.getDatasource();
assertThat(nestedDataSource).isSameAs(topLevelDataSource).isNotNull();
}
}
@Nested
class NestedTestClassWithConfigurationModifier implements TaskanaEngineConfigurationModifier {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Override
public void modify(TaskanaEngineConfiguration taskanaEngineConfiguration) {
// do nothing
}
@Test
void should_ReuseDataSource_For_NestedTestClassWhichImplementsConfigurationModifier() {
DataSource nestedDataSource = taskanaEngineConfiguration.getDatasource();
DataSource topLevelDataSource =
TestContainerExtensionTest.this.taskanaEngineConfiguration.getDatasource();
assertThat(nestedDataSource).isSameAs(topLevelDataSource).isNotNull();
}
}
@CleanTaskanaContext
@Nested
class NestedTestClassAnnotatedWithCleanTaskanaContext {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Test
void should_CreateNewDataSource_For_NestedTestAnnotatedWithCleanTaskanaContext() {
DataSource nestedDataSource = taskanaEngineConfiguration.getDatasource();
DataSource topLevelDataSource =
TestContainerExtensionTest.this.taskanaEngineConfiguration.getDatasource();
assertThat(nestedDataSource).isNotSameAs(topLevelDataSource).isNotNull();
}
}
@CleanTaskanaContext
@Nested
class NestedTestClassAnnotatedWithCleanTaskanaContextAndConfigModifier
implements TaskanaEngineConfigurationModifier {
@TaskanaInject TaskanaEngineConfiguration taskanaEngineConfiguration;
@Override
public void modify(TaskanaEngineConfiguration taskanaEngineConfiguration) {
// do nothing
}
@Test
void should_CreateNewDataSource_For_NestedTestAnnotatedWithCleanTaskanaContext() {
DataSource nestedDataSource = taskanaEngineConfiguration.getDatasource();
DataSource topLevelDataSource =
TestContainerExtensionTest.this.taskanaEngineConfiguration.getDatasource();
assertThat(nestedDataSource).isNotSameAs(topLevelDataSource).isNotNull();
}
}
}

View File

@ -1,14 +1,11 @@
package pro.taskana.common.test.config;
package testapi.util;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.time.Duration;
import java.util.Optional;
import java.util.UUID;
import javax.sql.DataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.testcontainers.containers.Db2Container;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.PostgreSQLContainer;
@ -17,70 +14,13 @@ import org.testcontainers.utility.DockerImageName;
import pro.taskana.common.internal.configuration.DB;
public class TestContainerExtension implements AfterAllCallback {
public class DockerContainerCreator {
private final DataSource dataSource;
private final String schemaName;
private final JdbcDatabaseContainer<?> container;
public TestContainerExtension() {
DB db = getTestDatabase();
Optional<JdbcDatabaseContainer<?>> container = createDockerContainer(db);
if (container.isPresent()) {
this.container = container.get();
this.container.start();
dataSource = createDataSource(this.container);
} else {
dataSource = createDataSourceForH2();
this.container = null;
}
schemaName = determineSchemaName(db);
private DockerContainerCreator() {
throw new IllegalStateException("Utility class");
}
@Override
public void afterAll(ExtensionContext context) {
if (container != null) {
container.stop();
}
}
public DataSource getDataSource() {
return dataSource;
}
public String getSchemaName() {
return schemaName;
}
private DB getTestDatabase() {
String property = System.getenv("db.type");
DB db;
try {
db = DB.valueOf(property);
} catch (Exception ex) {
db = DB.H2;
}
return db;
}
private static String determineSchemaName(DB db) {
return db == DB.POSTGRES ? "taskana" : "TASKANA";
}
private static DataSource createDataSource(JdbcDatabaseContainer<?> container) {
PooledDataSource ds =
new PooledDataSource(
Thread.currentThread().getContextClassLoader(),
container.getDriverClassName(),
container.getJdbcUrl(),
container.getUsername(),
container.getPassword());
ds.setPoolTimeToWait(50);
ds.forceCloseAll(); // otherwise, the MyBatis pool is not initialized correctly
return ds;
}
private static Optional<JdbcDatabaseContainer<?>> createDockerContainer(DB db) {
public static Optional<JdbcDatabaseContainer<?>> createDockerContainer(DB db) {
switch (db) {
case DB2:
return Optional.of(
@ -116,21 +56,16 @@ public class TestContainerExtension implements AfterAllCallback {
}
}
private static DataSource createDataSourceForH2() {
public static DataSource createDataSource(JdbcDatabaseContainer<?> container) {
PooledDataSource ds =
new PooledDataSource(
Thread.currentThread().getContextClassLoader(),
"org.h2.Driver",
"jdbc:h2:mem:"
+ UUID.randomUUID()
+ ";LOCK_MODE=0;"
+ "INIT=CREATE SCHEMA IF NOT EXISTS TASKANA\\;"
+ "SET COLLATION DEFAULT_de_DE ",
"sa",
"sa");
container.getDriverClassName(),
container.getJdbcUrl(),
container.getUsername(),
container.getPassword());
ds.setPoolTimeToWait(50);
ds.forceCloseAll(); // otherwise, the MyBatis pool is not initialized correctly
return ds;
}
}

View File

@ -0,0 +1,40 @@
package testapi.util;
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import testapi.CleanTaskanaContext;
import testapi.TaskanaEngineConfigurationModifier;
public class ExtensionCommunicator {
private ExtensionCommunicator() {
throw new IllegalStateException("utility class");
}
public static boolean isTopLevelClass(Class<?> testClass) {
return testClass.getEnclosingClass() == null;
}
public static Store getClassLevelStore(ExtensionContext context) {
return getClassLevelStore(context, context.getRequiredTestClass());
}
public static Store getClassLevelStore(ExtensionContext context, Class<?> testClass) {
return context.getStore(determineNamespace(testClass));
}
private static Namespace determineNamespace(Class<?> testClass) {
if (isTopLevelClass(testClass)) {
return Namespace.create(testClass);
} else if (isAnnotated(testClass, CleanTaskanaContext.class)) {
return Namespace.create(testClass.getEnclosingClass(), testClass);
} else if (TaskanaEngineConfigurationModifier.class.isAssignableFrom(testClass)) {
return Namespace.create(
testClass.getEnclosingClass(), testClass, TaskanaEngineConfigurationModifier.class);
}
return Namespace.create(testClass.getEnclosingClass());
}
}