diff --git a/.github/actions/conditional/action.yml b/.github/actions/conditional/action.yml index b94861bf28b..43f69ebd182 100644 --- a/.github/actions/conditional/action.yml +++ b/.github/actions/conditional/action.yml @@ -22,6 +22,9 @@ outputs: ci-webauthn: description: Should "ci.yml" execute (WebAuthn) value: ${{ steps.changes.outputs.ci-webauthn }} + ci-test-poc: + description: Should "ci.yml" execute (Test PoC) + value: ${{ steps.changes.outputs.ci-test-poc }} operator: description: Should "operator-ci.yml" execute value: ${{ steps.changes.outputs.operator }} diff --git a/.github/actions/conditional/conditions b/.github/actions/conditional/conditions index 403bed2456d..cbda64b417b 100644 --- a/.github/actions/conditional/conditions +++ b/.github/actions/conditional/conditions @@ -48,3 +48,5 @@ js/libs/ui-shared/ ci ci-webauthn themes/ codeql-themes testsuite::database-suite ci-store + +test-poc/ ci ci-test-poc \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18c270ff673..b5bebfe341e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: ci-sssd: ${{ steps.conditional.outputs.ci-sssd }} ci-webauthn: ${{ steps.conditional.outputs.ci-webauthn }} ci-store-matrix: ${{ steps.conditional-stores.outputs.matrix }} + ci-test-poc: ${{ steps.conditional.outputs.ci-test-poc }} steps: - uses: actions/checkout@v4 @@ -863,6 +864,26 @@ jobs: with: job-id: migration-tests-${{ matrix.old-version }}-${{ matrix.database }} + test-poc: + name: Test PoC + runs-on: ubuntu-latest + if: needs.conditional.outputs.ci-test-poc == 'true' + needs: + - conditional + - build + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - id: integration-test-setup + name: Integration test setup + uses: ./.github/actions/integration-test-setup + + - name: Run tests + run: | + cd test-poc + mvn clean install + check: name: Status Check - Keycloak CI if: always() @@ -886,6 +907,7 @@ jobs: - sssd-unit-tests - migration-tests - external-infinispan-tests + - test-poc runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/test-poc/base/src/test/java/org/keycloak/test/base/NoAdminUserKeycloakTestServerConfig.java b/test-poc/base/src/test/java/org/keycloak/test/base/NoAdminUserKeycloakTestServerConfig.java index bf2cf27512b..d7181f256b1 100644 --- a/test-poc/base/src/test/java/org/keycloak/test/base/NoAdminUserKeycloakTestServerConfig.java +++ b/test-poc/base/src/test/java/org/keycloak/test/base/NoAdminUserKeycloakTestServerConfig.java @@ -7,13 +7,13 @@ import java.util.Optional; public class NoAdminUserKeycloakTestServerConfig implements KeycloakTestServerConfig { @Override - public Optional adminUserName() { - return Optional.empty(); + public String adminUserName() { + return null; } @Override - public Optional adminUserPassword() { - return Optional.empty(); + public String adminUserPassword() { + return null; } } diff --git a/test-poc/base/src/test/java/org/keycloak/test/base/PagesTest.java b/test-poc/base/src/test/java/org/keycloak/test/base/PagesTest.java index 0662c67f7df..8010a1c9e98 100644 --- a/test-poc/base/src/test/java/org/keycloak/test/base/PagesTest.java +++ b/test-poc/base/src/test/java/org/keycloak/test/base/PagesTest.java @@ -18,18 +18,8 @@ public class PagesTest { @Test public void testLoginFromWelcome() { welcomePage.navigateTo(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } loginPage.fillLogin("admin", "admin"); loginPage.submit(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } } } 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 dfd8517281f..e5e8ba3a093 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 @@ -2,9 +2,8 @@ package org.keycloak.test.framework.admin; import org.keycloak.admin.client.Keycloak; import org.keycloak.test.framework.TestAdminClient; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.keycloak.test.framework.server.KeycloakTestServer; @@ -22,25 +21,24 @@ public class KeycloakAdminClientSupplier implements Supplier getValue(Registry registry, TestAdminClient annotation) { - InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); - - KeycloakTestServer testServer = registry.getDependency(KeycloakTestServer.class, wrapper); - - Keycloak keycloak = Keycloak.getInstance(testServer.getBaseUrl(), "master", "admin", "admin", "admin-cli"); - wrapper.setValue(keycloak, LifeCycle.GLOBAL); - - return wrapper; + public Keycloak getValue(InstanceContext instanceContext) { + KeycloakTestServer testServer = instanceContext.getDependency(KeycloakTestServer.class); + return Keycloak.getInstance(testServer.getBaseUrl(), "master", "admin", "admin", "admin-cli"); } @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public LifeCycle getDefaultLifecycle() { + return LifeCycle.GLOBAL; + } + + @Override + public boolean compatible(InstanceContext a, RequestedInstance b) { return true; } @Override - public void close(Keycloak keycloak) { - keycloak.close(); + public void close(InstanceContext instanceContext) { + instanceContext.getValue().close(); } } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/database/AbstractDatabaseSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/database/AbstractDatabaseSupplier.java index 0a497393e81..40282a9717a 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/database/AbstractDatabaseSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/database/AbstractDatabaseSupplier.java @@ -1,9 +1,8 @@ package org.keycloak.test.framework.database; import org.keycloak.test.framework.KeycloakTestDatabase; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; @@ -23,17 +22,26 @@ public abstract class AbstractDatabaseSupplier implements Supplier getValue(Registry registry, KeycloakTestDatabase annotation) { + public TestDatabase getValue(InstanceContext instanceContext) { TestDatabase testDatabase = getTestDatabase(); testDatabase.start(); - return new InstanceWrapper<>(this, annotation, testDatabase, LifeCycle.GLOBAL); + return testDatabase; } @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public boolean compatible(InstanceContext a, RequestedInstance b) { return true; } + @Override + public LifeCycle getDefaultLifecycle() { + return LifeCycle.GLOBAL; + } + abstract TestDatabase getTestDatabase(); + @Override + public void close(InstanceContext instanceContext) { + instanceContext.getValue().stop(); + } } 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/InstanceContext.java similarity index 52% rename from test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceWrapper.java rename to test-poc/framework/src/main/java/org/keycloak/test/framework/injection/InstanceContext.java index 4f1193c6470..871bb70159b 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/InstanceContext.java @@ -6,30 +6,35 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -public class InstanceWrapper { +public class InstanceContext { + private final Registry registry; private final Supplier supplier; private final A annotation; - private final Set> dependencies = new HashSet<>(); + private final Set> dependencies = new HashSet<>(); private T value; + private Class requestedValueType; private LifeCycle lifeCycle; private final Map notes = new HashMap<>(); - public InstanceWrapper(Supplier supplier, A annotation) { + public InstanceContext(Registry registry, Supplier supplier, A annotation, Class requestedValueType) { + this.registry = registry; this.supplier = supplier; this.annotation = annotation; + this.requestedValueType = requestedValueType; + this.lifeCycle = supplier.getLifeCycle(annotation); } - public InstanceWrapper(Supplier supplier, A annotation, T value, LifeCycle lifeCycle) { - this.supplier = supplier; - this.annotation = annotation; - this.value = value; - this.lifeCycle = lifeCycle; + public D getDependency(Class typeClazz) { + return registry.getDependency(typeClazz, this); } - public void setValue(T value, LifeCycle lifeCycle) { + public Registry getRegistry() { + return registry; + } + + void setValue(T value) { this.value = value; - this.lifeCycle = lifeCycle; } public Supplier getSupplier() { @@ -40,6 +45,10 @@ public class InstanceWrapper { return value; } + public Class getRequestedValueType() { + return requestedValueType; + } + public LifeCycle getLifeCycle() { return lifeCycle; } @@ -48,12 +57,12 @@ public class InstanceWrapper { return annotation; } - public Set> getDependencies() { + public Set> getDependencies() { return dependencies; } - public void registerDependency(InstanceWrapper instanceWrapper) { - dependencies.add(instanceWrapper); + public void registerDependency(InstanceContext instanceContext) { + dependencies.add(instanceContext); } public void addNote(String key, Object value) { 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 317cdabd2a2..b92f8a46322 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 @@ -22,7 +22,7 @@ public class Registry { private ExtensionContext currentContext; private final List> suppliers = new LinkedList<>(); - private final List> deployedInstances = new LinkedList<>(); + private final List> deployedInstances = new LinkedList<>(); private final List> requestedInstances = new LinkedList<>(); public Registry() { @@ -38,8 +38,8 @@ public class Registry { this.currentContext = currentContext; } - public T getDependency(Class typeClass, InstanceWrapper dependent) { - InstanceWrapper dependency = getDeployedInstance(typeClass); + public T getDependency(Class typeClass, InstanceContext dependent) { + InstanceContext dependency = getDeployedInstance(typeClass); if (dependency != null) { dependency.registerDependency(dependent); @@ -54,7 +54,8 @@ public class Registry { RequestedInstance requestedDependency = getRequestedInstance(typeClass); if (requestedDependency != null) { - dependency = requestedDependency.getSupplier().getValue(this, requestedDependency.getAnnotation(), typeClass); + dependency = new InstanceContext(this, requestedDependency.getSupplier(), requestedDependency.getAnnotation(), requestedDependency.getValueType()); + dependency.setValue(requestedDependency.getSupplier().getValue(dependency)); dependency.registerDependency(dependent); deployedInstances.add(dependency); @@ -70,7 +71,10 @@ public class Registry { Optional> supplied = suppliers.stream().filter(s -> s.getValueType().equals(typeClass)).findFirst(); if (supplied.isPresent()) { Supplier supplier = (Supplier) supplied.get(); - dependency = supplier.getValue(this, null, typeClass); + dependency = new InstanceContext(this, supplier, null, typeClass); + dependency.registerDependency(dependent); + dependency.setValue(supplier.getValue(dependency)); + deployedInstances.add(dependency); if (LOGGER.isTraceEnabled()) { @@ -114,9 +118,9 @@ public class Registry { Iterator> itr = requestedInstances.iterator(); while (itr.hasNext()) { RequestedInstance requestedInstance = itr.next(); - InstanceWrapper deployedInstance = getDeployedInstance(requestedInstance); + InstanceContext deployedInstance = getDeployedInstance(requestedInstance); if (deployedInstance != null) { - if (deployedInstance.getSupplier().compatible(deployedInstance, requestedInstance)) { + if (requestedInstance.getLifeCycle().equals(deployedInstance.getLifeCycle()) && deployedInstance.getSupplier().compatible(deployedInstance, requestedInstance)) { if (LOGGER.isTraceEnabled()) { LOGGER.tracev("Reusing compatible: {0}", deployedInstance.getSupplier().getClass().getSimpleName()); @@ -140,7 +144,8 @@ public class Registry { while (itr.hasNext()) { RequestedInstance requestedInstance = itr.next(); - InstanceWrapper instance = requestedInstance.getSupplier().getValue(this, requestedInstance.getAnnotation(), requestedInstance.getValueType()); + InstanceContext instance = new InstanceContext(this, requestedInstance.getSupplier(), requestedInstance.getAnnotation(), requestedInstance.getValueType()); + instance.setValue(requestedInstance.getSupplier().getValue(instance)); if (LOGGER.isTraceEnabled()) { LOGGER.tracev("Created instance: {0}", @@ -155,7 +160,7 @@ public class Registry { private void injectFields(Object testInstance) { for (Field f : testInstance.getClass().getDeclaredFields()) { - InstanceWrapper instance = getDeployedInstance(f.getType(), f.getAnnotations()); + InstanceContext instance = getDeployedInstance(f.getType(), f.getAnnotations()); try { f.setAccessible(true); f.set(testInstance, instance.getValue()); @@ -167,19 +172,19 @@ public class Registry { public void afterAll() { LOGGER.trace("Closing instances with class lifecycle"); - List> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.CLASS)).toList(); + 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(); + 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(); + List> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.GLOBAL)).toList(); destroy.forEach(this::destroy); } @@ -194,9 +199,9 @@ public class Registry { return null; } - private InstanceWrapper getDeployedInstance(Class valueType, Annotation[] annotations) { + private InstanceContext getDeployedInstance(Class valueType, Annotation[] annotations) { for (Annotation a : annotations) { - for (InstanceWrapper i : deployedInstances) { + for (InstanceContext i : deployedInstances) { Supplier supplier = i.getSupplier(); if (supplier.getAnnotationClass().equals(a.annotationType()) && valueType.isAssignableFrom(i.getValue().getClass())) { return i; @@ -206,23 +211,23 @@ public class Registry { return null; } - private void destroy(InstanceWrapper instanceWrapper) { - boolean removed = deployedInstances.remove(instanceWrapper); + private void destroy(InstanceContext instanceContext) { + boolean removed = deployedInstances.remove(instanceContext); if (removed) { - Set dependencies = instanceWrapper.getDependencies(); + Set dependencies = instanceContext.getDependencies(); dependencies.forEach(this::destroy); - instanceWrapper.getSupplier().close(instanceWrapper); + instanceContext.getSupplier().close(instanceContext); if (LOGGER.isTraceEnabled()) { LOGGER.tracev("Closed instance: {0}", - instanceWrapper.getSupplier().getClass().getSimpleName()); + instanceContext.getSupplier().getClass().getSimpleName()); } } } - private InstanceWrapper getDeployedInstance(RequestedInstance requestedInstance) { + private InstanceContext getDeployedInstance(RequestedInstance requestedInstance) { Class requestedValueType = requestedInstance.getValueType(); - for (InstanceWrapper i : deployedInstances) { + for (InstanceContext i : deployedInstances) { if (requestedValueType != null) { if (requestedValueType.isAssignableFrom(i.getValue().getClass())) { return i; @@ -280,7 +285,7 @@ public class Registry { } } - private InstanceWrapper getDeployedInstance(Class typeClass) { + private InstanceContext getDeployedInstance(Class typeClass) { return deployedInstances.stream().filter(i -> i.getSupplier().getValueType().equals(typeClass)).findFirst().orElse(null); } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/RequestedInstance.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/RequestedInstance.java index d7d8bc94800..a5e45d6e0be 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/RequestedInstance.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/injection/RequestedInstance.java @@ -7,11 +7,13 @@ public class RequestedInstance { private final Supplier supplier; private final A annotation; private final Class valueType; + private final LifeCycle lifeCycle; public RequestedInstance(Supplier supplier, A annotation, Class valueType) { this.supplier = supplier; this.annotation = annotation; this.valueType = valueType; + this.lifeCycle = supplier.getLifeCycle(annotation); } public Supplier getSupplier() { @@ -25,4 +27,8 @@ public class RequestedInstance { public Class getValueType() { return valueType; } + + public LifeCycle getLifeCycle() { + return lifeCycle; + } } 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 8c69e1dbf63..f55e375e221 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 @@ -1,6 +1,9 @@ package org.keycloak.test.framework.injection; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; public interface Supplier { @@ -8,19 +11,29 @@ public interface Supplier { Class getValueType(); - InstanceWrapper getValue(Registry registry, S annotation); + T getValue(InstanceContext instanceContext); - default InstanceWrapper getValue(Registry registry, S annotation, Class valueType) { - return getValue(registry, annotation); + default LifeCycle getLifeCycle(S annotation) { + if (annotation != null) { + Optional lifecycle = Arrays.stream(annotation.annotationType().getMethods()).filter(m -> m.getName().equals("lifecycle")).findFirst(); + if (lifecycle.isPresent()) { + try { + return (LifeCycle) lifecycle.get().invoke(annotation); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + return getDefaultLifecycle(); } - boolean compatible(InstanceWrapper a, RequestedInstance b); - - default void close(T value) { + default LifeCycle getDefaultLifecycle() { + return LifeCycle.CLASS; } - default void close(InstanceWrapper instanceWrapper) { - close(instanceWrapper.getValue()); + boolean compatible(InstanceContext a, RequestedInstance b); + + default void close(InstanceContext instanceContext) { } default String getAlias() { diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/page/PageSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/page/PageSupplier.java index 9888c903423..2aaf5d40d28 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/page/PageSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/page/PageSupplier.java @@ -1,8 +1,6 @@ package org.keycloak.test.framework.page; -import org.keycloak.test.framework.injection.InstanceWrapper; -import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.openqa.selenium.WebDriver; @@ -21,21 +19,14 @@ public class PageSupplier implements Supplier { return AbstractPage.class; } - public InstanceWrapper getValue(Registry registry, TestPage annotation) { - throw new UnsupportedOperationException(); + @Override + public AbstractPage getValue(InstanceContext instanceContext) { + WebDriver webDriver = instanceContext.getDependency(WebDriver.class); + return createPage(webDriver, instanceContext.getRequestedValueType()); } @Override - public InstanceWrapper getValue(Registry registry, TestPage annotation, Class valueType) { - InstanceWrapper instanceWrapper = new InstanceWrapper<>(this, annotation); - WebDriver webDriver = registry.getDependency(WebDriver.class, instanceWrapper); - AbstractPage page = createPage(webDriver, valueType); - instanceWrapper.setValue(page, LifeCycle.CLASS); - return instanceWrapper; - } - - @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public boolean compatible(InstanceContext a, RequestedInstance b) { return true; } 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 50595d1e6bc..1931718a41f 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 @@ -5,9 +5,8 @@ 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.TestClient; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.keycloak.test.framework.injection.SupplierHelpers; @@ -27,17 +26,14 @@ public class ClientSupplier implements Supplier { } @Override - public InstanceWrapper getValue(Registry registry, TestClient annotation) { - InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); - LifeCycle lifecycle = annotation.lifecycle(); + public ClientResource getValue(InstanceContext instanceContext) { + RealmResource realm = instanceContext.getDependency(RealmResource.class); - RealmResource realm = registry.getDependency(RealmResource.class, wrapper); - - ClientConfig config = SupplierHelpers.getInstance(annotation.config()); + ClientConfig config = SupplierHelpers.getInstance(instanceContext.getAnnotation().config()); ClientRepresentation clientRepresentation = config.getRepresentation(); if (clientRepresentation.getClientId() == null) { - String clientId = lifecycle.equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : registry.getCurrentContext().getRequiredTestClass().getSimpleName(); + String clientId = instanceContext.getLifeCycle().equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : instanceContext.getRegistry().getCurrentContext().getRequiredTestClass().getSimpleName(); clientRepresentation.setClientId(clientId); } @@ -48,22 +44,19 @@ public class ClientSupplier implements Supplier { response.close(); - wrapper.addNote(CLIENT_UUID_KEY, clientId); + instanceContext.addNote(CLIENT_UUID_KEY, clientId); - ClientResource clientResource = realm.clients().get(clientId); - wrapper.setValue(clientResource, lifecycle); - - return wrapper; + return realm.clients().get(clientId); } @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public boolean compatible(InstanceContext a, RequestedInstance b) { return a.getAnnotation().config().equals(b.getAnnotation().config()); } @Override - public void close(ClientResource client) { - client.remove(); + public void close(InstanceContext instanceContext) { + instanceContext.getValue().remove(); } } 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 196d30fcfee..0dcd869f84a 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 @@ -4,9 +4,8 @@ import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.test.framework.TestRealm; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.keycloak.test.framework.injection.SupplierHelpers; @@ -26,39 +25,33 @@ public class RealmSupplier implements Supplier { } @Override - public InstanceWrapper getValue(Registry registry, TestRealm annotation) { - InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); - LifeCycle lifecycle = annotation.lifecycle(); + public RealmResource getValue(InstanceContext instanceContext) { + Keycloak adminClient = instanceContext.getDependency(Keycloak.class); - Keycloak adminClient = registry.getDependency(Keycloak.class, wrapper); - - RealmConfig config = SupplierHelpers.getInstance(annotation.config()); + RealmConfig config = SupplierHelpers.getInstance(instanceContext.getAnnotation().config()); RealmRepresentation realmRepresentation = config.getRepresentation(); if (realmRepresentation.getRealm() == null) { - String realmName = lifecycle.equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : registry.getCurrentContext().getRequiredTestClass().getSimpleName(); + String realmName = instanceContext.getLifeCycle().equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : instanceContext.getRegistry().getCurrentContext().getRequiredTestClass().getSimpleName(); realmRepresentation.setRealm(realmName); } String realmName = realmRepresentation.getRealm(); - wrapper.addNote(REALM_NAME_KEY, realmName); + instanceContext.addNote(REALM_NAME_KEY, realmName); adminClient.realms().create(realmRepresentation); - RealmResource realmResource = adminClient.realm(realmRepresentation.getRealm()); - wrapper.setValue(realmResource, lifecycle); - - return wrapper; + return adminClient.realm(realmRepresentation.getRealm()); } @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public boolean compatible(InstanceContext a, RequestedInstance b) { return a.getAnnotation().config().equals(b.getAnnotation().config()); } @Override - public void close(RealmResource realm) { - realm.remove(); + public void close(InstanceContext instanceContext) { + instanceContext.getValue().remove(); } } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/UserSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/UserSupplier.java index 2535f3331a2..3fe831e4195 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/UserSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/realm/UserSupplier.java @@ -5,9 +5,8 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.test.framework.TestUser; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.keycloak.test.framework.injection.SupplierHelpers; @@ -27,17 +26,14 @@ public class UserSupplier implements Supplier { } @Override - public InstanceWrapper getValue(Registry registry, TestUser annotation) { - InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); - LifeCycle lifecycle = annotation.lifecycle(); + public UserResource getValue(InstanceContext instanceContext) { + RealmResource realm = instanceContext.getDependency(RealmResource.class); - RealmResource realm = registry.getDependency(RealmResource.class, wrapper); - - UserConfig config = SupplierHelpers.getInstance(annotation.config()); + UserConfig config = SupplierHelpers.getInstance(instanceContext.getAnnotation().config()); UserRepresentation userRepresentation = config.getRepresentation(); if (userRepresentation.getUsername() == null) { - String username = lifecycle.equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : registry.getCurrentContext().getRequiredTestClass().getSimpleName(); + String username = instanceContext.getLifeCycle().equals(LifeCycle.GLOBAL) ? config.getClass().getSimpleName() : instanceContext.getRegistry().getCurrentContext().getRequiredTestClass().getSimpleName(); userRepresentation.setUsername(username); } @@ -48,22 +44,19 @@ public class UserSupplier implements Supplier { response.close(); - wrapper.addNote(USER_UUID_KEY, userId); + instanceContext.addNote(USER_UUID_KEY, userId); - UserResource userResource = realm.users().get(userId); - wrapper.setValue(userResource, lifecycle); - - return wrapper; + return realm.users().get(userId); } @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { + public boolean compatible(InstanceContext a, RequestedInstance b) { return a.getAnnotation().config().equals(b.getAnnotation().config()); } @Override - public void close(UserResource user) { - user.remove(); + public void close(InstanceContext instanceContext) { + instanceContext.getValue().remove(); } } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/AbstractKeycloakTestServerSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/AbstractKeycloakTestServerSupplier.java index eaeb6aa81c5..c75b17f746c 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/AbstractKeycloakTestServerSupplier.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/AbstractKeycloakTestServerSupplier.java @@ -2,9 +2,8 @@ package org.keycloak.test.framework.server; import org.keycloak.test.framework.KeycloakIntegrationTest; import org.keycloak.test.framework.database.TestDatabase; -import org.keycloak.test.framework.injection.InstanceWrapper; +import org.keycloak.test.framework.injection.InstanceContext; import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; import org.keycloak.test.framework.injection.RequestedInstance; import org.keycloak.test.framework.injection.Supplier; import org.keycloak.test.framework.injection.SupplierHelpers; @@ -25,13 +24,13 @@ public abstract class AbstractKeycloakTestServerSupplier implements Supplier getValue(Registry registry, KeycloakIntegrationTest annotation) { + public KeycloakTestServer getValue(InstanceContext instanceContext) { + KeycloakIntegrationTest annotation = instanceContext.getAnnotation(); KeycloakTestServerConfig serverConfig = SupplierHelpers.getInstance(annotation.config()); - InstanceWrapper wrapper = new InstanceWrapper<>(this, annotation); Map databaseConfig; if (requiresDatabase()) { - TestDatabase testDatabase = registry.getDependency(TestDatabase.class, wrapper); + TestDatabase testDatabase = instanceContext.getDependency(TestDatabase.class); databaseConfig = testDatabase.getServerConfig(); } else { databaseConfig = Collections.emptyMap(); @@ -39,20 +38,22 @@ public abstract class AbstractKeycloakTestServerSupplier implements Supplier a, RequestedInstance b) { + public LifeCycle getDefaultLifecycle() { + return LifeCycle.GLOBAL; + } + + @Override + public boolean compatible(InstanceContext a, RequestedInstance b) { return a.getAnnotation().config().equals(b.getAnnotation().config()); } @Override - public void close(KeycloakTestServer keycloakTestServer) { - keycloakTestServer.stop(); + public void close(InstanceContext instanceContext) { + instanceContext.getValue().stop(); } public abstract KeycloakTestServer getServer(); diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/DistributionKeycloakTestServer.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/DistributionKeycloakTestServer.java index f0698ce87dd..6d6f56fb2db 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/DistributionKeycloakTestServer.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/DistributionKeycloakTestServer.java @@ -21,8 +21,8 @@ public class DistributionKeycloakTestServer implements KeycloakTestServer { keycloak = new RawKeycloakDistribution(debug, manualStop, enableTls, reCreate, removeBuildOptionsAfterBuild, requestPort); // Set environment variables user and password for Keycloak Admin used by Keycloak instance. - keycloak.setEnvVar("KC_BOOTSTRAP_ADMIN_USERNAME", serverConfig.adminUserName().get()); - keycloak.setEnvVar("KC_BOOTSTRAP_ADMIN_PASSWORD", serverConfig.adminUserPassword().get()); + keycloak.setEnvVar("KC_BOOTSTRAP_ADMIN_USERNAME", serverConfig.adminUserName()); + keycloak.setEnvVar("KC_BOOTSTRAP_ADMIN_PASSWORD", serverConfig.adminUserPassword()); List rawOptions = new LinkedList<>(); rawOptions.add("start-dev"); diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/EmbeddedKeycloakTestServer.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/EmbeddedKeycloakTestServer.java index 2999f0db335..6cdaf41420f 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/EmbeddedKeycloakTestServer.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/EmbeddedKeycloakTestServer.java @@ -22,8 +22,16 @@ public class EmbeddedKeycloakTestServer implements KeycloakTestServer { rawOptions.add("--features=" + String.join(",", serverConfig.features())); } - serverConfig.adminUserName().ifPresent(username -> System.setProperty("keycloakAdmin", username)); - serverConfig.adminUserPassword().ifPresent(password -> System.setProperty("keycloakAdminPassword", password)); + if (serverConfig.adminUserName() != null) { + System.setProperty("keycloakAdmin", serverConfig.adminUserName()); + } else { + System.getProperties().remove("keycloakAdmin"); + } + if (serverConfig.adminUserPassword() != null) { + System.setProperty("keycloakAdminPassword", serverConfig.adminUserPassword()); + } else { + System.getProperties().remove("keycloakAdminPassword"); + } serverConfig.options().forEach((key, value) -> rawOptions.add("--" + key + "=" + value)); databaseConfig.forEach((key, value) -> rawOptions.add("--" + key + "=" + value)); diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerConfig.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerConfig.java index 009620be26f..2e42c32c008 100644 --- a/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerConfig.java +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/server/KeycloakTestServerConfig.java @@ -15,12 +15,12 @@ public interface KeycloakTestServerConfig { return Collections.emptySet(); } - default Optional adminUserName() { - return Optional.of("admin"); + default String adminUserName() { + return "admin"; } - default Optional adminUserPassword() { - return Optional.of("admin"); + default String adminUserPassword() { + return "admin"; } } diff --git a/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/AbstractWebDriverSupplier.java b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/AbstractWebDriverSupplier.java new file mode 100644 index 00000000000..a9ab295d260 --- /dev/null +++ b/test-poc/framework/src/main/java/org/keycloak/test/framework/webdriver/AbstractWebDriverSupplier.java @@ -0,0 +1,52 @@ +package org.keycloak.test.framework.webdriver; + +import org.keycloak.test.framework.injection.InstanceContext; +import org.keycloak.test.framework.injection.LifeCycle; +import org.keycloak.test.framework.injection.RequestedInstance; +import org.keycloak.test.framework.injection.Supplier; +import org.openqa.selenium.PageLoadStrategy; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.AbstractDriverOptions; + +import java.time.Duration; + +public abstract class AbstractWebDriverSupplier implements Supplier { + + @Override + public Class getAnnotationClass() { + return TestWebDriver.class; + } + + @Override + public Class getValueType() { + return WebDriver.class; + } + + @Override + public WebDriver getValue(InstanceContext instanceContext) { + return getWebDriver(); + } + + @Override + public boolean compatible(InstanceContext a, RequestedInstance b) { + return true; + } + + @Override + public LifeCycle getLifeCycle(TestWebDriver annotation) { + return LifeCycle.GLOBAL; + } + + @Override + public void close(InstanceContext instanceContext) { + instanceContext.getValue().quit(); + } + + public abstract WebDriver getWebDriver(); + + public void setGlobalOptions(AbstractDriverOptions options) { + options.setImplicitWaitTimeout(Duration.ofSeconds(5)); + options.setPageLoadStrategy(PageLoadStrategy.NORMAL); + } + +} 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 b46b50dc122..781f388b9f8 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 @@ -1,44 +1,27 @@ package org.keycloak.test.framework.webdriver; -import org.keycloak.test.framework.injection.InstanceWrapper; -import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; -import org.keycloak.test.framework.injection.RequestedInstance; -import org.keycloak.test.framework.injection.Supplier; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; -public class ChromeWebDriverSupplier implements Supplier { - - @Override - public Class getAnnotationClass() { - return TestWebDriver.class; - } - - @Override - public Class getValueType() { - return WebDriver.class; - } - - @Override - public InstanceWrapper getValue(Registry registry, TestWebDriver annotation) { - final var driver = new ChromeDriver(); - return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL); - } - - @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { - return true; - } - - @Override - public void close(WebDriver instance) { - instance.quit(); - } +public class ChromeWebDriverSupplier extends AbstractWebDriverSupplier { @Override public String getAlias() { return "chrome"; } + @Override + public WebDriver getWebDriver() { + ChromeOptions options = new ChromeOptions(); + setGlobalOptions(options); + options.addArguments( + "--headless", + "--disable-gpu", + "--window-size=1920,1200", + "--ignore-certificate-errors", + "--disable-dev-shm-usage" + ); + return new ChromeDriver(options); + } } 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 6f82b4a490d..931eda5e5cb 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 @@ -1,43 +1,21 @@ package org.keycloak.test.framework.webdriver; -import org.keycloak.test.framework.injection.InstanceWrapper; -import org.keycloak.test.framework.injection.LifeCycle; -import org.keycloak.test.framework.injection.Registry; -import org.keycloak.test.framework.injection.RequestedInstance; -import org.keycloak.test.framework.injection.Supplier; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxOptions; -public class FirefoxWebDriverSupplier implements Supplier { - - @Override - public Class getAnnotationClass() { - return TestWebDriver.class; - } - - @Override - public Class getValueType() { - return WebDriver.class; - } - - @Override - public InstanceWrapper getValue(Registry registry, TestWebDriver annotation) { - final var driver = new FirefoxDriver(); - return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL); - } - - @Override - public boolean compatible(InstanceWrapper a, RequestedInstance b) { - return true; - } - - @Override - public void close(WebDriver instance) { - instance.quit(); - } +public class FirefoxWebDriverSupplier extends AbstractWebDriverSupplier { @Override public String getAlias() { return "firefox"; } + + @Override + public WebDriver getWebDriver() { + FirefoxOptions options = new FirefoxOptions(); + setGlobalOptions(options); + options.addArguments("-headless"); + return new FirefoxDriver(options); + } }