TSK-1937: test-api now supports instantiation off all class types
except for anonymous classes since they're not assignable to the WithAccessId annotation
This commit is contained in:
parent
63315eaf22
commit
f7b668835c
|
@ -166,7 +166,7 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
|
|||
DynamicTestInvocationContext invocationContext,
|
||||
ExtensionContext extensionContext) {
|
||||
ExtensionContext testContext = getParentMethodExtensionContent(extensionContext);
|
||||
// Check if the test factory provided an access Id for this dynamic test.
|
||||
// Check if the test factory provided an accessId for this dynamic test.
|
||||
WithAccessId o = getMethodLevelStore(testContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
|
||||
if (o != null) {
|
||||
performInvocationWithAccessId(invocation, o);
|
||||
|
@ -269,11 +269,11 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
|
|||
Optional<ExtensionContext> parent = extensionContext.getParent();
|
||||
// the class MethodExtensionContext is part of junit-jupiter-engine and has only a
|
||||
// package-private visibility thus this workaround is needed.
|
||||
while (!parent
|
||||
while (parent
|
||||
.map(Object::getClass)
|
||||
.map(Class::getName)
|
||||
.filter(s -> s.endsWith("MethodExtensionContext"))
|
||||
.isPresent()) {
|
||||
.isEmpty()) {
|
||||
parent = parent.flatMap(ExtensionContext::getParent);
|
||||
}
|
||||
return parent.orElseThrow(
|
||||
|
|
|
@ -4,6 +4,7 @@ import static org.junit.platform.commons.support.AnnotationSupport.findRepeatabl
|
|||
import static pro.taskana.common.internal.util.CheckedFunction.wrap;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -66,8 +67,22 @@ public class ServiceProviderExtractor {
|
|||
|
||||
private static List<Object> instantiateServiceProviders(List<Class<?>> serviceProviders) {
|
||||
return serviceProviders.stream()
|
||||
.map(wrap(Class::getDeclaredConstructor))
|
||||
.map(wrap(Constructor::newInstance))
|
||||
.map(wrap(ServiceProviderExtractor::instantiateClass))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Object instantiateClass(Class<?> clz) throws Exception {
|
||||
// we don't have to consider anonymous classes since they can't be passed as an argument to
|
||||
// the WithServiceProvider annotation.
|
||||
if (clz.isLocalClass() || (clz.isMemberClass() && !Modifier.isStatic(clz.getModifiers()))) {
|
||||
Class<?> motherClass = clz.getEnclosingClass();
|
||||
Object motherInstance = instantiateClass(motherClass);
|
||||
Constructor<?> constructor = clz.getDeclaredConstructor(motherClass);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(motherInstance);
|
||||
}
|
||||
Constructor<?> constructor = clz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,394 @@
|
|||
package pro.taskana.testapi.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static pro.taskana.testapi.util.ServiceProviderExtractor.extractServiceProviders;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
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 org.junit.platform.commons.JUnitException;
|
||||
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
import pro.taskana.task.api.models.TaskSummary;
|
||||
import pro.taskana.testapi.WithServiceProvider;
|
||||
|
||||
class ServiceProviderExtractorTest {
|
||||
|
||||
static class StaticCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyTaskPreprocessor1 implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyTaskPreprocessor2 implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyPriorityServiceProvider1 implements PriorityServiceProvider {
|
||||
@Override
|
||||
public OptionalInt calculatePriority(TaskSummary taskSummary) {
|
||||
// implementation not important for the tests
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyPriorityServiceProvider2 implements PriorityServiceProvider {
|
||||
@Override
|
||||
public OptionalInt calculatePriority(TaskSummary taskSummary) {
|
||||
// implementation not important for the tests
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PrivateStaticCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ServiceProviderInstantiation {
|
||||
|
||||
@Test
|
||||
void should_ReturnEmptyMap_When_NoServiceProviderIsDefined() {
|
||||
class ExampleClazzWithNoServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClazzWithNoServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsTopLevelClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = TopLevelCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(TopLevelCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsStaticMemberClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = StaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(StaticCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsPrivateStaticMemberClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = PrivateStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(PrivateStaticCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsLocalClass() {
|
||||
class LocalCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = LocalCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(LocalCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsNonStaticMemberClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = NonStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(NonStaticCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsPrivateNonStaticMemberClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = PrivateNonStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(PrivateNonStaticCreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
class NonStaticCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
class PrivateNonStaticCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ExtractServiceProvidersFromSingleServiceProviderInterface {
|
||||
|
||||
@Test
|
||||
void should_ExtractServiceProvider() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ExtractMultipleServiceProviders_When_MultipleAreDefinedInOneAnnotation() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ExtractMultipleServiceProviders_When_MultipleAreDefinedInMultipleAnnotations() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor2.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ExtractSameServiceProviderMultipleTimes_When_ItIsDefinedMultipleTimes() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyTaskPreprocessor1.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor1.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ExtractMultipleServiceProvidersFromMultipleServiceProviderInterfaces {
|
||||
|
||||
@Test
|
||||
void should_ExtractServiceProviders() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = DummyPriorityServiceProvider1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders)
|
||||
.containsOnlyKeys(CreateTaskPreprocessor.class, PriorityServiceProvider.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class);
|
||||
assertThat(extractServiceProviders.get(PriorityServiceProvider.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyPriorityServiceProvider1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ExtractMultipleServiceProviders_When_MultipleAreDefinedInOneAnnotation() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class})
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = {
|
||||
DummyPriorityServiceProvider1.class,
|
||||
DummyPriorityServiceProvider2.class
|
||||
})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThat(extractServiceProviders)
|
||||
.containsOnlyKeys(CreateTaskPreprocessor.class, PriorityServiceProvider.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
assertThat(extractServiceProviders.get(PriorityServiceProvider.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(
|
||||
DummyPriorityServiceProvider1.class, DummyPriorityServiceProvider2.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ErrorHandling {
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_ServiceProviderInterfaceIsUnknown() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = ErrorHandling.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
.hasMessage("SPI '%s' is not a TASKANA SPI.", ErrorHandling.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_ServiceProviderIsIncompatibleToServiceProviderInterface() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyPriorityServiceProvider1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
.hasMessage(
|
||||
"At least one ServiceProvider does not implement the requested SPI '%s'",
|
||||
CreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_AnyServiceProviderIsIncompatibleToServiceProviderInterface() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyPriorityServiceProvider1.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
.hasMessage(
|
||||
"At least one ServiceProvider does not implement the requested SPI '%s'",
|
||||
CreateTaskPreprocessor.class);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.taskana.testapi.util;
|
||||
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
||||
public class TopLevelCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue