TestSuite PoC - Add support to configure lifecycle for realms and clients (#31145)
Closes #30610 Signed-off-by: stianst <stianst@gmail.com>
This commit is contained in:
parent
ffbfb7450f
commit
2dc37d2513
16 changed files with 131 additions and 58 deletions
|
@ -0,0 +1,37 @@
|
|||
package org.keycloak.test.base;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.test.framework.KeycloakIntegrationTest;
|
||||
import org.keycloak.test.framework.TestClient;
|
||||
import org.keycloak.test.framework.TestRealm;
|
||||
import org.keycloak.test.framework.injection.LifeCycle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class GlobalManagedResourcesTest {
|
||||
|
||||
@TestRealm(lifecycle = LifeCycle.GLOBAL)
|
||||
RealmResource realmResource;
|
||||
|
||||
@TestClient
|
||||
ClientResource clientResource;
|
||||
|
||||
@Test
|
||||
public void testCreatedRealm() {
|
||||
Assertions.assertEquals("DefaultRealmConfig", realmResource.toRepresentation().getRealm());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatedClient() {
|
||||
Assertions.assertEquals("GlobalManagedResourcesTest", clientResource.toRepresentation().getClientId());
|
||||
|
||||
List<ClientRepresentation> clients = realmResource.clients().findByClientId("GlobalManagedResourcesTest");
|
||||
Assertions.assertEquals(1, clients.size());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.keycloak.test.base;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.test.framework.KeycloakIntegrationTest;
|
||||
import org.keycloak.test.framework.TestClient;
|
||||
import org.keycloak.test.framework.TestRealm;
|
||||
import org.keycloak.test.framework.injection.LifeCycle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class ManagedResources2Test {
|
||||
|
||||
@TestRealm(lifecycle = LifeCycle.CLASS)
|
||||
RealmResource realmResource;
|
||||
|
||||
@TestClient
|
||||
ClientResource clientResource;
|
||||
|
||||
@Test
|
||||
public void testCreatedRealm() {
|
||||
Assertions.assertEquals("ManagedResources2Test", realmResource.toRepresentation().getRealm());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatedClient() {
|
||||
Assertions.assertEquals("ManagedResources2Test", clientResource.toRepresentation().getClientId());
|
||||
|
||||
List<ClientRepresentation> clients = realmResource.clients().findByClientId("ManagedResources2Test");
|
||||
Assertions.assertEquals(1, clients.size());
|
||||
}
|
||||
|
||||
}
|
|
@ -8,13 +8,14 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
|||
import org.keycloak.test.framework.KeycloakIntegrationTest;
|
||||
import org.keycloak.test.framework.TestClient;
|
||||
import org.keycloak.test.framework.TestRealm;
|
||||
import org.keycloak.test.framework.injection.LifeCycle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class ManagedResourcesTest {
|
||||
|
||||
@TestRealm
|
||||
@TestRealm(lifecycle = LifeCycle.CLASS)
|
||||
RealmResource realmResource;
|
||||
|
||||
@TestClient
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
package org.keycloak.test.framework;
|
||||
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.keycloak.test.framework.injection.Registry;
|
||||
|
||||
public class KeycloakIntegrationTestExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback {
|
||||
|
||||
@Override
|
||||
public void beforeAll(ExtensionContext context) {
|
||||
if (isExtensionEnabled(context)) {
|
||||
getRegistry(context).beforeAll(context.getRequiredTestClass());
|
||||
}
|
||||
}
|
||||
public class KeycloakIntegrationTestExtension implements BeforeEachCallback, AfterEachCallback, AfterAllCallback {
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) {
|
||||
|
@ -22,6 +15,13 @@ public class KeycloakIntegrationTestExtension implements BeforeAllCallback, Afte
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) throws Exception {
|
||||
if (isExtensionEnabled(context)) {
|
||||
getRegistry(context).afterEach();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll(ExtensionContext context) {
|
||||
if (isExtensionEnabled(context)) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.test.framework;
|
||||
|
||||
import org.keycloak.test.framework.injection.LifeCycle;
|
||||
import org.keycloak.test.framework.realm.ClientConfig;
|
||||
import org.keycloak.test.framework.realm.DefaultClientConfig;
|
||||
|
||||
|
@ -14,4 +15,6 @@ public @interface TestClient {
|
|||
|
||||
Class<? extends ClientConfig> config() default DefaultClientConfig.class;
|
||||
|
||||
LifeCycle lifecycle() default LifeCycle.CLASS;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.test.framework;
|
||||
|
||||
import org.keycloak.test.framework.injection.LifeCycle;
|
||||
import org.keycloak.test.framework.realm.DefaultRealmConfig;
|
||||
import org.keycloak.test.framework.realm.RealmConfig;
|
||||
|
||||
|
@ -14,4 +15,6 @@ public @interface TestRealm {
|
|||
|
||||
Class<? extends RealmConfig> config() default DefaultRealmConfig.class;
|
||||
|
||||
LifeCycle lifecycle() default LifeCycle.CLASS;
|
||||
|
||||
}
|
||||
|
|
|
@ -27,16 +27,11 @@ public class KeycloakAdminClientSupplier implements Supplier<Keycloak, TestAdmin
|
|||
KeycloakTestServer testServer = registry.getDependency(KeycloakTestServer.class, wrapper);
|
||||
|
||||
Keycloak keycloak = Keycloak.getInstance(testServer.getBaseUrl(), "master", "admin", "admin", "admin-cli");
|
||||
wrapper.setValue(keycloak);
|
||||
wrapper.setValue(keycloak, LifeCycle.GLOBAL);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(InstanceWrapper<Keycloak, TestAdminClient> a, InstanceWrapper<Keycloak, TestAdminClient> b) {
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@ public class InstanceWrapper<T, A extends Annotation> {
|
|||
private final A annotation;
|
||||
private final Set<InstanceWrapper<T, A>> dependencies = new HashSet<>();
|
||||
private T value;
|
||||
private LifeCycle lifeCycle;
|
||||
private final Map<String, Object> notes = new HashMap<>();
|
||||
|
||||
public InstanceWrapper(Supplier<T, A> supplier, A annotation) {
|
||||
|
@ -19,14 +20,16 @@ public class InstanceWrapper<T, A extends Annotation> {
|
|||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public InstanceWrapper(Supplier<T, A> supplier, A annotation, T value) {
|
||||
public InstanceWrapper(Supplier<T, A> supplier, A annotation, T value, LifeCycle lifeCycle) {
|
||||
this.supplier = supplier;
|
||||
this.annotation = annotation;
|
||||
this.value = value;
|
||||
this.lifeCycle = lifeCycle;
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
public void setValue(T value, LifeCycle lifeCycle) {
|
||||
this.value = value;
|
||||
this.lifeCycle = lifeCycle;
|
||||
}
|
||||
|
||||
public Supplier<T, A> getSupplier() {
|
||||
|
@ -37,6 +40,10 @@ public class InstanceWrapper<T, A extends Annotation> {
|
|||
return value;
|
||||
}
|
||||
|
||||
public LifeCycle getLifeCycle() {
|
||||
return lifeCycle;
|
||||
}
|
||||
|
||||
public A getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.test.framework.injection;
|
|||
public enum LifeCycle {
|
||||
|
||||
GLOBAL,
|
||||
CLASS
|
||||
CLASS,
|
||||
METHOD
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public class Registry {
|
|||
|
||||
public Registry() {
|
||||
loadSuppliers();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::onShutdown));
|
||||
}
|
||||
|
||||
public ExtensionContext getCurrentContext() {
|
||||
|
@ -82,7 +83,8 @@ public class Registry {
|
|||
throw new RuntimeException("Dependency not found: " + typeClass);
|
||||
}
|
||||
|
||||
public void beforeAll(Class testClass) {
|
||||
public void beforeEach(Object testInstance) {
|
||||
Class testClass = testInstance.getClass();
|
||||
InstanceWrapper requestedServerInstance = createInstanceWrapper(testClass.getAnnotations());
|
||||
requestedInstances.add(requestedServerInstance);
|
||||
|
||||
|
@ -137,9 +139,6 @@ public class Registry {
|
|||
itr.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void beforeEach(Object testInstance) {
|
||||
for (Field f : testInstance.getClass().getDeclaredFields()) {
|
||||
InstanceWrapper<?, ?> instance = getDeployedInstance(f.getAnnotations());
|
||||
try {
|
||||
|
@ -152,7 +151,20 @@ public class Registry {
|
|||
}
|
||||
|
||||
public void afterAll() {
|
||||
List<InstanceWrapper<?, ?>> destroy = deployedInstances.stream().filter(i -> i.getSupplier().getLifeCycle().equals(LifeCycle.CLASS)).toList();
|
||||
LOGGER.trace("Closing instances with class lifecycle");
|
||||
List<InstanceWrapper<?, ?>> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.CLASS)).toList();
|
||||
destroy.forEach(this::destroy);
|
||||
}
|
||||
|
||||
public void afterEach() {
|
||||
LOGGER.trace("Closing instances with method lifecycle");
|
||||
List<InstanceWrapper<?, ?>> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.METHOD)).toList();
|
||||
destroy.forEach(this::destroy);
|
||||
}
|
||||
|
||||
public void onShutdown() {
|
||||
LOGGER.trace("Closing instances with global lifecycle");
|
||||
List<InstanceWrapper<?, ?>> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.GLOBAL)).toList();
|
||||
destroy.forEach(this::destroy);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ public interface Supplier<T, S extends Annotation> {
|
|||
|
||||
InstanceWrapper<T, S> getValue(Registry registry, S annotation);
|
||||
|
||||
LifeCycle getLifeCycle();
|
||||
|
||||
boolean compatible(InstanceWrapper<T, S> a, InstanceWrapper<T, S> b);
|
||||
|
||||
default void close(T instance) {}
|
||||
|
|
|
@ -28,6 +28,7 @@ public class ClientSupplier implements Supplier<ClientResource, TestClient> {
|
|||
@Override
|
||||
public InstanceWrapper<ClientResource, TestClient> getValue(Registry registry, TestClient annotation) {
|
||||
InstanceWrapper<ClientResource, TestClient> wrapper = new InstanceWrapper<>(this, annotation);
|
||||
LifeCycle lifecycle = annotation.lifecycle();
|
||||
|
||||
RealmResource realm = registry.getDependency(RealmResource.class, wrapper);
|
||||
|
||||
|
@ -35,7 +36,8 @@ public class ClientSupplier implements Supplier<ClientResource, TestClient> {
|
|||
ClientRepresentation clientRepresentation = config.getRepresentation();
|
||||
|
||||
if (clientRepresentation.getClientId() == null) {
|
||||
clientRepresentation.setClientId(registry.getCurrentContext().getRequiredTestClass().getSimpleName());
|
||||
String clientId = lifecycle.equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : registry.getCurrentContext().getRequiredTestClass().getSimpleName();
|
||||
clientRepresentation.setClientId(clientId);
|
||||
}
|
||||
|
||||
Response response = realm.clients().create(clientRepresentation);
|
||||
|
@ -48,16 +50,11 @@ public class ClientSupplier implements Supplier<ClientResource, TestClient> {
|
|||
wrapper.addNote(CLIENT_UUID_KEY, clientId);
|
||||
|
||||
ClientResource clientResource = realm.clients().get(clientId);
|
||||
wrapper.setValue(clientResource);
|
||||
wrapper.setValue(clientResource, lifecycle);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(InstanceWrapper<ClientResource, TestClient> a, InstanceWrapper<ClientResource, TestClient> b) {
|
||||
return a.getAnnotation().config().equals(b.getAnnotation().config()) &&
|
||||
|
|
|
@ -27,6 +27,7 @@ public class RealmSupplier implements Supplier<RealmResource, TestRealm> {
|
|||
@Override
|
||||
public InstanceWrapper<RealmResource, TestRealm> getValue(Registry registry, TestRealm annotation) {
|
||||
InstanceWrapper<RealmResource, TestRealm> wrapper = new InstanceWrapper<>(this, annotation);
|
||||
LifeCycle lifecycle = annotation.lifecycle();
|
||||
|
||||
Keycloak adminClient = registry.getDependency(Keycloak.class, wrapper);
|
||||
|
||||
|
@ -34,7 +35,8 @@ public class RealmSupplier implements Supplier<RealmResource, TestRealm> {
|
|||
RealmRepresentation realmRepresentation = config.getRepresentation();
|
||||
|
||||
if (realmRepresentation.getRealm() == null) {
|
||||
realmRepresentation.setRealm(registry.getCurrentContext().getRequiredTestClass().getSimpleName());
|
||||
String realmName = lifecycle.equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : registry.getCurrentContext().getRequiredTestClass().getSimpleName();
|
||||
realmRepresentation.setRealm(realmName);
|
||||
}
|
||||
|
||||
String realmName = realmRepresentation.getRealm();
|
||||
|
@ -43,16 +45,11 @@ public class RealmSupplier implements Supplier<RealmResource, TestRealm> {
|
|||
adminClient.realms().create(realmRepresentation);
|
||||
|
||||
RealmResource realmResource = adminClient.realm(realmRepresentation.getRealm());
|
||||
wrapper.setValue(realmResource);
|
||||
wrapper.setValue(realmResource, lifecycle);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(InstanceWrapper<RealmResource, TestRealm> a, InstanceWrapper<RealmResource, TestRealm> b) {
|
||||
return a.getAnnotation().config().equals(b.getAnnotation().config()) &&
|
||||
|
|
|
@ -28,12 +28,7 @@ public class KeycloakTestServerSupplier implements Supplier<KeycloakTestServer,
|
|||
|
||||
keycloakTestServer.start(serverConfig);
|
||||
|
||||
return new InstanceWrapper<>(this, annotation, keycloakTestServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
return new InstanceWrapper<>(this, annotation, keycloakTestServer, LifeCycle.GLOBAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,12 +22,7 @@ public class ChromeWebDriverSupplier implements Supplier<WebDriver, TestWebDrive
|
|||
@Override
|
||||
public InstanceWrapper<WebDriver, TestWebDriver> getValue(Registry registry, TestWebDriver annotation) {
|
||||
final var driver = new ChromeDriver();
|
||||
return new InstanceWrapper<>(this, annotation, driver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,12 +22,7 @@ public class FirefoxWebDriverSupplier implements Supplier<WebDriver, TestWebDriv
|
|||
@Override
|
||||
public InstanceWrapper<WebDriver, TestWebDriver> getValue(Registry registry, TestWebDriver annotation) {
|
||||
final var driver = new FirefoxDriver();
|
||||
return new InstanceWrapper<>(this, annotation, driver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getLifeCycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue