From 290456efb9d5b974acc6e5152cd9384a7860d1d1 Mon Sep 17 00:00:00 2001 From: stianst Date: Tue, 9 Jul 2024 11:22:25 +0200 Subject: [PATCH] TestSuite PoC - Add support to configure lifecycle for realms and clients Closes #30610 Signed-off-by: stianst --- .../test/base/GlobalManagedResourcesTest.java | 37 +++++++++++++++++++ .../test/base/ManagedResources2Test.java | 37 +++++++++++++++++++ .../test/base/ManagedResourcesTest.java | 3 +- .../KeycloakIntegrationTestExtension.java | 12 +++--- .../keycloak/test/framework/TestClient.java | 3 ++ .../keycloak/test/framework/TestRealm.java | 3 ++ .../admin/KeycloakAdminClientSupplier.java | 7 +--- .../framework/injection/InstanceWrapper.java | 11 +++++- .../test/framework/injection/LifeCycle.java | 3 +- .../test/framework/injection/Registry.java | 22 ++++++++--- .../test/framework/injection/Supplier.java | 2 - .../test/framework/realm/ClientSupplier.java | 11 ++---- .../test/framework/realm/RealmSupplier.java | 11 ++---- .../server/KeycloakTestServerSupplier.java | 7 +--- .../webdriver/ChromeWebDriverSupplier.java | 7 +--- .../webdriver/FirefoxWebDriverSupplier.java | 7 +--- 16 files changed, 128 insertions(+), 55 deletions(-) create mode 100644 test-poc/base/src/test/java/org/keycloak/test/base/GlobalManagedResourcesTest.java create mode 100644 test-poc/base/src/test/java/org/keycloak/test/base/ManagedResources2Test.java diff --git a/test-poc/base/src/test/java/org/keycloak/test/base/GlobalManagedResourcesTest.java b/test-poc/base/src/test/java/org/keycloak/test/base/GlobalManagedResourcesTest.java new file mode 100644 index 000000000000..eb1bc7c967f0 --- /dev/null +++ b/test-poc/base/src/test/java/org/keycloak/test/base/GlobalManagedResourcesTest.java @@ -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 clients = realmResource.clients().findByClientId("GlobalManagedResourcesTest"); + Assertions.assertEquals(1, clients.size()); + } + +} diff --git a/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResources2Test.java b/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResources2Test.java new file mode 100644 index 000000000000..4aecd64a1354 --- /dev/null +++ b/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResources2Test.java @@ -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 clients = realmResource.clients().findByClientId("ManagedResources2Test"); + Assertions.assertEquals(1, clients.size()); + } + +} diff --git a/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResourcesTest.java b/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResourcesTest.java index 32604895572f..25fabbc87594 100644 --- a/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResourcesTest.java +++ b/test-poc/base/src/test/java/org/keycloak/test/base/ManagedResourcesTest.java @@ -8,13 +8,14 @@ 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 diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/KeycloakIntegrationTestExtension.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/KeycloakIntegrationTestExtension.java index b359de5c4d67..19d13f55c59e 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/KeycloakIntegrationTestExtension.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/KeycloakIntegrationTestExtension.java @@ -1,24 +1,24 @@ 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 { +public class KeycloakIntegrationTestExtension implements BeforeEachCallback, AfterEachCallback, AfterAllCallback { @Override - public void beforeAll(ExtensionContext context) { + public void beforeEach(ExtensionContext context) { if (isExtensionEnabled(context)) { - getRegistry(context).beforeAll(context.getRequiredTestClass()); + getRegistry(context).beforeEach(context.getRequiredTestInstance()); } } @Override - public void beforeEach(ExtensionContext context) { + public void afterEach(ExtensionContext context) throws Exception { if (isExtensionEnabled(context)) { - getRegistry(context).beforeEach(context.getRequiredTestInstance()); + getRegistry(context).afterEach(); } } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/TestClient.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/TestClient.java index 221f84390d5c..1dfc3f0fe16a 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/TestClient.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/TestClient.java @@ -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 @@ Class config() default DefaultClientConfig.class; + LifeCycle lifecycle() default LifeCycle.CLASS; + } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/TestRealm.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/TestRealm.java index c0d41a1b0e23..bbc328a8894d 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/TestRealm.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/TestRealm.java @@ -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 @@ Class config() default DefaultRealmConfig.class; + LifeCycle lifecycle() default LifeCycle.CLASS; + } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/admin/KeycloakAdminClientSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/admin/KeycloakAdminClientSupplier.java index f755644f7065..2f4ae15f15b5 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/admin/KeycloakAdminClientSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/admin/KeycloakAdminClientSupplier.java @@ -27,16 +27,11 @@ public InstanceWrapper getValue(Registry registry, Te 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 a, InstanceWrapper b) { return true; diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceWrapper.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceWrapper.java index 05475c2bc109..4f1193c64707 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceWrapper.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceWrapper.java @@ -12,6 +12,7 @@ public class InstanceWrapper { private final A annotation; private final Set> dependencies = new HashSet<>(); private T value; + private LifeCycle lifeCycle; private final Map notes = new HashMap<>(); public InstanceWrapper(Supplier supplier, A annotation) { @@ -19,14 +20,16 @@ public InstanceWrapper(Supplier supplier, A annotation) { this.annotation = annotation; } - public InstanceWrapper(Supplier supplier, A annotation, T value) { + public InstanceWrapper(Supplier 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 getSupplier() { @@ -37,6 +40,10 @@ public T getValue() { return value; } + public LifeCycle getLifeCycle() { + return lifeCycle; + } + public A getAnnotation() { return annotation; } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/LifeCycle.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/LifeCycle.java index 7f1b03c09b44..f9e8d1763b4a 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/LifeCycle.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/LifeCycle.java @@ -3,6 +3,7 @@ public enum LifeCycle { GLOBAL, - CLASS + CLASS, + METHOD } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Registry.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Registry.java index 5a03fe02eb56..076cdb5ededf 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Registry.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Registry.java @@ -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 T getDependency(Class typeClass, InstanceWrapper dependent) { 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 void beforeAll(Class testClass) { itr.remove(); } - } - - public void beforeEach(Object testInstance) { for (Field f : testInstance.getClass().getDeclaredFields()) { InstanceWrapper instance = getDeployedInstance(f.getAnnotations()); try { @@ -152,7 +151,20 @@ public void beforeEach(Object testInstance) { } public void afterAll() { - List> destroy = deployedInstances.stream().filter(i -> i.getSupplier().getLifeCycle().equals(LifeCycle.CLASS)).toList(); + LOGGER.trace("Closing instances with class lifecycle"); + List> 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> 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> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.GLOBAL)).toList(); destroy.forEach(this::destroy); } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Supplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Supplier.java index d86040f288d9..8280413e2b9c 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Supplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/Supplier.java @@ -10,8 +10,6 @@ public interface Supplier { InstanceWrapper getValue(Registry registry, S annotation); - LifeCycle getLifeCycle(); - boolean compatible(InstanceWrapper a, InstanceWrapper b); default void close(T instance) {} diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/ClientSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/ClientSupplier.java index ab69f3188956..3fd0c06ed644 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/ClientSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/ClientSupplier.java @@ -28,6 +28,7 @@ public Class getValueType() { @Override public InstanceWrapper getValue(Registry registry, TestClient annotation) { InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); + LifeCycle lifecycle = annotation.lifecycle(); RealmResource realm = registry.getDependency(RealmResource.class, wrapper); @@ -35,7 +36,8 @@ public InstanceWrapper getValue(Registry registry, T 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 InstanceWrapper getValue(Registry registry, T 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 a, InstanceWrapper b) { return a.getAnnotation().config().equals(b.getAnnotation().config()) && diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/RealmSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/RealmSupplier.java index 5ce4e8250ca8..80413ffe5df3 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/RealmSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/RealmSupplier.java @@ -27,6 +27,7 @@ public Class getValueType() { @Override public InstanceWrapper getValue(Registry registry, TestRealm annotation) { InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); + LifeCycle lifecycle = annotation.lifecycle(); Keycloak adminClient = registry.getDependency(Keycloak.class, wrapper); @@ -34,7 +35,8 @@ public InstanceWrapper getValue(Registry registry, Tes 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 InstanceWrapper getValue(Registry registry, Tes 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 a, InstanceWrapper b) { return a.getAnnotation().config().equals(b.getAnnotation().config()) && diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerSupplier.java index d82b2446cde8..70ab47291c20 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerSupplier.java @@ -28,12 +28,7 @@ public InstanceWrapper getValue(Reg 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 diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/ChromeWebDriverSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/ChromeWebDriverSupplier.java index 90758d5f9546..76b4f8ccd4f2 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/ChromeWebDriverSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/ChromeWebDriverSupplier.java @@ -22,12 +22,7 @@ public Class getValueType() { @Override public InstanceWrapper 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 diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/FirefoxWebDriverSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/FirefoxWebDriverSupplier.java index 7badd2c42994..f9a403def3be 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/FirefoxWebDriverSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/FirefoxWebDriverSupplier.java @@ -22,12 +22,7 @@ public Class getValueType() { @Override public InstanceWrapper 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