diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java index b6657819bc..cc5d84abdc 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java @@ -17,11 +17,17 @@ package org.keycloak.testsuite.arquillian; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.jboss.arquillian.test.spi.execution.ExecutionDecision; import org.jboss.arquillian.test.spi.execution.TestExecutionDecider; import org.jboss.arquillian.core.api.Instance; import org.jboss.arquillian.core.api.annotation.Inject; import org.jboss.logging.Logger; +import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; +import org.keycloak.testsuite.arquillian.annotation.AppServerContainers; /** * @author Vlastislav Ramik @@ -29,18 +35,37 @@ import org.jboss.logging.Logger; public class AdapterTestExecutionDecider implements TestExecutionDecider { private final Logger log = Logger.getLogger(AdapterTestExecutionDecider.class); + private static final Map cache = new HashMap<>(); @Inject private Instance testContextInstance; @Override public ExecutionDecision decide(Method method) { + ExecutionDecision decision = getFromCache(method); + if (decision != null) { + return decision; + } + TestContext testContext = testContextInstance.get(); - if (!testContext.isAdapterTest()) return ExecutionDecision.execute(); + if (!testContext.isAdapterTest()) { + return execute(method, Boolean.TRUE, null); + } if (testContext.isAdapterContainerEnabled() || testContext.isAdapterContainerEnabledCluster()) { - return ExecutionDecision.execute(); + + if (method.isAnnotationPresent(AppServerContainer.class)) { // taking method level annotation first as it has higher priority + if (getCorrespondingAnnotation(method).skip()) { + return execute(method, Boolean.FALSE, "Skipped by @AppServerContainer method level annotation."); + } + } else { //taking class level annotation + if (getCorrespondingAnnotation(testContext.getTestClass()).skip()) { + return execute(method, Boolean.FALSE, "Skipped by @AppServerContainer class level annotation."); + } + } + // execute otherwise + return execute(method, Boolean.TRUE, null); + } else { - log.debug("Skipping test: Not enabled by @AppServerContainer annotations."); - return ExecutionDecision.dontExecute("Not enabled by @AppServerContainer annotations."); + return execute(method, Boolean.FALSE, "Not enabled by @AppServerContainer annotations."); } } @@ -49,4 +74,74 @@ public class AdapterTestExecutionDecider implements TestExecutionDecider { return 1; } + private AppServerContainer getCorrespondingAnnotation(Method method) { + String appServerContainerName = testContextInstance.get().getAppServerInfo().getArquillianContainer().getName(); + + AppServerContainers multipleAnnotations = method.getAnnotation(AppServerContainers.class); + + List appServerContainers; + if (multipleAnnotations != null) { // more than one @AppServerContainer annotation + appServerContainers = Arrays.asList(multipleAnnotations.value()); + } else { // single @AppServerContainer annotation + appServerContainers = Arrays.asList(method.getAnnotation(AppServerContainer.class)); + } + + return appServerContainers.stream() + .filter(annotation -> annotation.value().equals(appServerContainerName)) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Not found the @AppServerContainer annotation with current app server.")); + } + + private AppServerContainer getCorrespondingAnnotation(Class testClass) { + String appServerContainerName = testContextInstance.get().getAppServerInfo().getArquillianContainer().getName(); + + Class annotatedClass = AppServerTestEnricher.getNearestSuperclassWithAppServerAnnotation(testClass); + + AppServerContainers multipleAnnotations = annotatedClass.getAnnotation(AppServerContainers.class); + + List appServerContainers; + if (multipleAnnotations != null) { // more than one @AppServerContainer annotation + appServerContainers = Arrays.asList(multipleAnnotations.value()); + } else {// single @AppServerContainer annotation + appServerContainers = Arrays.asList(annotatedClass.getAnnotation(AppServerContainer.class)); + } + return appServerContainers.stream() + .filter(annotation -> annotation.value().equals(appServerContainerName)) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Not found the @AppServerContainer annotation with current app server.")); + } + + private ExecutionDecision execute(Method method, Boolean execute, String message) { + if (execute) { + cache.put(method, new CachedRecord(Boolean.TRUE, "")); + return ExecutionDecision.execute(); + } else { + cache.put(method, new CachedRecord(Boolean.FALSE, message)); + log.debug(message); + return ExecutionDecision.dontExecute(message); + } + } + + private ExecutionDecision getFromCache(Method method) { + if (cache.containsKey(method)) { + CachedRecord cachedRecord = cache.get(method); + + if (cachedRecord.execute) { + return ExecutionDecision.execute(cachedRecord.message); + } else { + return ExecutionDecision.dontExecute(cachedRecord.message); + } + } + return null; + } + + private class CachedRecord { + private final Boolean execute; + private final String message; + + public CachedRecord(Boolean execute, String message) { + this.execute = execute; + this.message = message; + } + } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java index fd0e2d5adb..68d49ca562 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java @@ -236,7 +236,7 @@ public class AppServerTestEnricher { * @return testClass or the nearest superclass of testClass annotated with * annotationClass */ - private static Class getNearestSuperclassWithAppServerAnnotation(Class testClass) { + public static Class getNearestSuperclassWithAppServerAnnotation(Class testClass) { return (testClass.isAnnotationPresent(AppServerContainer.class) || testClass.isAnnotationPresent(AppServerContainers.class)) ? testClass : (testClass.getSuperclass().equals(Object.class) ? null // stop recursion : getNearestSuperclassWithAppServerAnnotation(testClass.getSuperclass())); // continue recursion diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java index 647d32bf1a..062b6b0535 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java @@ -31,8 +31,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; */ @Documented @Retention(RUNTIME) -@Target({ElementType.TYPE}) +@Target({ElementType.TYPE, ElementType.METHOD}) @Repeatable(AppServerContainers.class) public @interface AppServerContainer { String value(); + boolean skip() default false; }