Add conditional workflow for test-poc (#31406)

Signed-off-by: stianst <stianst@gmail.com>
This commit is contained in:
Stian Thorgersen 2024-07-19 12:11:17 +02:00 committed by GitHub
parent 64c6dc00c0
commit 7216967465
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 274 additions and 226 deletions

View file

@ -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 }}

View file

@ -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

View file

@ -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

View file

@ -7,13 +7,13 @@ import java.util.Optional;
public class NoAdminUserKeycloakTestServerConfig implements KeycloakTestServerConfig {
@Override
public Optional<String> adminUserName() {
return Optional.empty();
public String adminUserName() {
return null;
}
@Override
public Optional<String> adminUserPassword() {
return Optional.empty();
public String adminUserPassword() {
return null;
}
}

View file

@ -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);
}
}
}

View file

@ -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<Keycloak, TestAdmin
}
@Override
public InstanceWrapper<Keycloak, TestAdminClient> getValue(Registry registry, TestAdminClient annotation) {
InstanceWrapper<Keycloak, TestAdminClient> 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<Keycloak, TestAdminClient> instanceContext) {
KeycloakTestServer testServer = instanceContext.getDependency(KeycloakTestServer.class);
return Keycloak.getInstance(testServer.getBaseUrl(), "master", "admin", "admin", "admin-cli");
}
@Override
public boolean compatible(InstanceWrapper<Keycloak, TestAdminClient> a, RequestedInstance<Keycloak, TestAdminClient> b) {
public LifeCycle getDefaultLifecycle() {
return LifeCycle.GLOBAL;
}
@Override
public boolean compatible(InstanceContext<Keycloak, TestAdminClient> a, RequestedInstance<Keycloak, TestAdminClient> b) {
return true;
}
@Override
public void close(Keycloak keycloak) {
keycloak.close();
public void close(InstanceContext<Keycloak, TestAdminClient> instanceContext) {
instanceContext.getValue().close();
}
}

View file

@ -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<TestDatabase,
}
@Override
public InstanceWrapper<TestDatabase, KeycloakTestDatabase> getValue(Registry registry, KeycloakTestDatabase annotation) {
public TestDatabase getValue(InstanceContext<TestDatabase, KeycloakTestDatabase> instanceContext) {
TestDatabase testDatabase = getTestDatabase();
testDatabase.start();
return new InstanceWrapper<>(this, annotation, testDatabase, LifeCycle.GLOBAL);
return testDatabase;
}
@Override
public boolean compatible(InstanceWrapper<TestDatabase, KeycloakTestDatabase> a, RequestedInstance<TestDatabase, KeycloakTestDatabase> b) {
public boolean compatible(InstanceContext<TestDatabase, KeycloakTestDatabase> a, RequestedInstance<TestDatabase, KeycloakTestDatabase> b) {
return true;
}
@Override
public LifeCycle getDefaultLifecycle() {
return LifeCycle.GLOBAL;
}
abstract TestDatabase getTestDatabase();
@Override
public void close(InstanceContext<TestDatabase, KeycloakTestDatabase> instanceContext) {
instanceContext.getValue().stop();
}
}

View file

@ -6,30 +6,35 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class InstanceWrapper<T, A extends Annotation> {
public class InstanceContext<T, A extends Annotation> {
private final Registry registry;
private final Supplier<T, A> supplier;
private final A annotation;
private final Set<InstanceWrapper<T, A>> dependencies = new HashSet<>();
private final Set<InstanceContext<T, A>> dependencies = new HashSet<>();
private T value;
private Class<? extends T> requestedValueType;
private LifeCycle lifeCycle;
private final Map<String, Object> notes = new HashMap<>();
public InstanceWrapper(Supplier<T, A> supplier, A annotation) {
public InstanceContext(Registry registry, Supplier<T, A> supplier, A annotation, Class<? extends T> requestedValueType) {
this.registry = registry;
this.supplier = supplier;
this.annotation = annotation;
this.requestedValueType = requestedValueType;
this.lifeCycle = supplier.getLifeCycle(annotation);
}
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 <D> D getDependency(Class<D> 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<T, A> getSupplier() {
@ -40,6 +45,10 @@ public class InstanceWrapper<T, A extends Annotation> {
return value;
}
public Class<? extends T> getRequestedValueType() {
return requestedValueType;
}
public LifeCycle getLifeCycle() {
return lifeCycle;
}
@ -48,12 +57,12 @@ public class InstanceWrapper<T, A extends Annotation> {
return annotation;
}
public Set<InstanceWrapper<T, A>> getDependencies() {
public Set<InstanceContext<T, A>> getDependencies() {
return dependencies;
}
public void registerDependency(InstanceWrapper<T, A> instanceWrapper) {
dependencies.add(instanceWrapper);
public void registerDependency(InstanceContext<T, A> instanceContext) {
dependencies.add(instanceContext);
}
public void addNote(String key, Object value) {

View file

@ -22,7 +22,7 @@ public class Registry {
private ExtensionContext currentContext;
private final List<Supplier<?, ?>> suppliers = new LinkedList<>();
private final List<InstanceWrapper<?, ?>> deployedInstances = new LinkedList<>();
private final List<InstanceContext<?, ?>> deployedInstances = new LinkedList<>();
private final List<RequestedInstance<?, ?>> requestedInstances = new LinkedList<>();
public Registry() {
@ -38,8 +38,8 @@ public class Registry {
this.currentContext = currentContext;
}
public <T> T getDependency(Class<T> typeClass, InstanceWrapper dependent) {
InstanceWrapper dependency = getDeployedInstance(typeClass);
public <T> T getDependency(Class<T> 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<Object, Annotation>(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<Supplier<?, ?>> supplied = suppliers.stream().filter(s -> s.getValueType().equals(typeClass)).findFirst();
if (supplied.isPresent()) {
Supplier<T, ?> supplier = (Supplier<T, ?>) 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<RequestedInstance<?, ?>> 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<InstanceWrapper<?, ?>> destroy = deployedInstances.stream().filter(i -> i.getLifeCycle().equals(LifeCycle.CLASS)).toList();
List<InstanceContext<?, ?>> 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();
List<InstanceContext<?, ?>> 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();
List<InstanceContext<?, ?>> 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<InstanceWrapper> dependencies = instanceWrapper.getDependencies();
Set<InstanceContext> 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);
}

View file

@ -7,11 +7,13 @@ public class RequestedInstance<T, A extends Annotation> {
private final Supplier<T, A> supplier;
private final A annotation;
private final Class<? extends T> valueType;
private final LifeCycle lifeCycle;
public RequestedInstance(Supplier<T, A> supplier, A annotation, Class<? extends T> valueType) {
this.supplier = supplier;
this.annotation = annotation;
this.valueType = valueType;
this.lifeCycle = supplier.getLifeCycle(annotation);
}
public Supplier<T, A> getSupplier() {
@ -25,4 +27,8 @@ public class RequestedInstance<T, A extends Annotation> {
public Class<? extends T> getValueType() {
return valueType;
}
public LifeCycle getLifeCycle() {
return lifeCycle;
}
}

View file

@ -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<T, S extends Annotation> {
@ -8,19 +11,29 @@ public interface Supplier<T, S extends Annotation> {
Class<T> getValueType();
InstanceWrapper<T, S> getValue(Registry registry, S annotation);
T getValue(InstanceContext<T, S> instanceContext);
default InstanceWrapper<T, S> getValue(Registry registry, S annotation, Class<? extends T> valueType) {
return getValue(registry, annotation);
default LifeCycle getLifeCycle(S annotation) {
if (annotation != null) {
Optional<Method> 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<T, S> a, RequestedInstance<T, S> b);
default void close(T value) {
default LifeCycle getDefaultLifecycle() {
return LifeCycle.CLASS;
}
default void close(InstanceWrapper<T, S> instanceWrapper) {
close(instanceWrapper.getValue());
boolean compatible(InstanceContext<T, S> a, RequestedInstance<T, S> b);
default void close(InstanceContext<T, S> instanceContext) {
}
default String getAlias() {

View file

@ -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<AbstractPage, TestPage> {
return AbstractPage.class;
}
public InstanceWrapper<AbstractPage, TestPage> getValue(Registry registry, TestPage annotation) {
throw new UnsupportedOperationException();
@Override
public AbstractPage getValue(InstanceContext<AbstractPage, TestPage> instanceContext) {
WebDriver webDriver = instanceContext.getDependency(WebDriver.class);
return createPage(webDriver, instanceContext.getRequestedValueType());
}
@Override
public InstanceWrapper<AbstractPage, TestPage> getValue(Registry registry, TestPage annotation, Class<? extends AbstractPage> valueType) {
InstanceWrapper<AbstractPage, TestPage> 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<AbstractPage, TestPage> a, RequestedInstance<AbstractPage, TestPage> b) {
public boolean compatible(InstanceContext<AbstractPage, TestPage> a, RequestedInstance<AbstractPage, TestPage> b) {
return true;
}

View file

@ -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<ClientResource, TestClient> {
}
@Override
public InstanceWrapper<ClientResource, TestClient> getValue(Registry registry, TestClient annotation) {
InstanceWrapper<ClientResource, TestClient> wrapper = new InstanceWrapper<>(this, annotation);
LifeCycle lifecycle = annotation.lifecycle();
public ClientResource getValue(InstanceContext<ClientResource, TestClient> 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<ClientResource, TestClient> {
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<ClientResource, TestClient> a, RequestedInstance<ClientResource, TestClient> b) {
public boolean compatible(InstanceContext<ClientResource, TestClient> a, RequestedInstance<ClientResource, TestClient> b) {
return a.getAnnotation().config().equals(b.getAnnotation().config());
}
@Override
public void close(ClientResource client) {
client.remove();
public void close(InstanceContext<ClientResource, TestClient> instanceContext) {
instanceContext.getValue().remove();
}
}

View file

@ -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<RealmResource, TestRealm> {
}
@Override
public InstanceWrapper<RealmResource, TestRealm> getValue(Registry registry, TestRealm annotation) {
InstanceWrapper<RealmResource, TestRealm> wrapper = new InstanceWrapper<>(this, annotation);
LifeCycle lifecycle = annotation.lifecycle();
public RealmResource getValue(InstanceContext<RealmResource, TestRealm> 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<RealmResource, TestRealm> a, RequestedInstance<RealmResource, TestRealm> b) {
public boolean compatible(InstanceContext<RealmResource, TestRealm> a, RequestedInstance<RealmResource, TestRealm> b) {
return a.getAnnotation().config().equals(b.getAnnotation().config());
}
@Override
public void close(RealmResource realm) {
realm.remove();
public void close(InstanceContext<RealmResource, TestRealm> instanceContext) {
instanceContext.getValue().remove();
}
}

View file

@ -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<UserResource, TestUser> {
}
@Override
public InstanceWrapper<UserResource, TestUser> getValue(Registry registry, TestUser annotation) {
InstanceWrapper<UserResource, TestUser> wrapper = new InstanceWrapper<>(this, annotation);
LifeCycle lifecycle = annotation.lifecycle();
public UserResource getValue(InstanceContext<UserResource, TestUser> 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<UserResource, TestUser> {
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<UserResource, TestUser> a, RequestedInstance<UserResource, TestUser> b) {
public boolean compatible(InstanceContext<UserResource, TestUser> a, RequestedInstance<UserResource, TestUser> b) {
return a.getAnnotation().config().equals(b.getAnnotation().config());
}
@Override
public void close(UserResource user) {
user.remove();
public void close(InstanceContext<UserResource, TestUser> instanceContext) {
instanceContext.getValue().remove();
}
}

View file

@ -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<Key
}
@Override
public InstanceWrapper<KeycloakTestServer, KeycloakIntegrationTest> getValue(Registry registry, KeycloakIntegrationTest annotation) {
public KeycloakTestServer getValue(InstanceContext<KeycloakTestServer, KeycloakIntegrationTest> instanceContext) {
KeycloakIntegrationTest annotation = instanceContext.getAnnotation();
KeycloakTestServerConfig serverConfig = SupplierHelpers.getInstance(annotation.config());
InstanceWrapper<KeycloakTestServer, KeycloakIntegrationTest> wrapper = new InstanceWrapper<>(this, annotation);
Map<String, String> 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<Key
KeycloakTestServer keycloakTestServer = getServer();
keycloakTestServer.start(serverConfig, databaseConfig);
wrapper.setValue(keycloakTestServer, LifeCycle.GLOBAL);
return wrapper;
return keycloakTestServer;
}
@Override
public boolean compatible(InstanceWrapper<KeycloakTestServer, KeycloakIntegrationTest> a, RequestedInstance<KeycloakTestServer, KeycloakIntegrationTest> b) {
public LifeCycle getDefaultLifecycle() {
return LifeCycle.GLOBAL;
}
@Override
public boolean compatible(InstanceContext<KeycloakTestServer, KeycloakIntegrationTest> a, RequestedInstance<KeycloakTestServer, KeycloakIntegrationTest> b) {
return a.getAnnotation().config().equals(b.getAnnotation().config());
}
@Override
public void close(KeycloakTestServer keycloakTestServer) {
keycloakTestServer.stop();
public void close(InstanceContext<KeycloakTestServer, KeycloakIntegrationTest> instanceContext) {
instanceContext.getValue().stop();
}
public abstract KeycloakTestServer getServer();

View file

@ -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<String> rawOptions = new LinkedList<>();
rawOptions.add("start-dev");

View file

@ -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));

View file

@ -15,12 +15,12 @@ public interface KeycloakTestServerConfig {
return Collections.emptySet();
}
default Optional<String> adminUserName() {
return Optional.of("admin");
default String adminUserName() {
return "admin";
}
default Optional<String> adminUserPassword() {
return Optional.of("admin");
default String adminUserPassword() {
return "admin";
}
}

View file

@ -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<WebDriver, TestWebDriver> {
@Override
public Class<TestWebDriver> getAnnotationClass() {
return TestWebDriver.class;
}
@Override
public Class<WebDriver> getValueType() {
return WebDriver.class;
}
@Override
public WebDriver getValue(InstanceContext<WebDriver, TestWebDriver> instanceContext) {
return getWebDriver();
}
@Override
public boolean compatible(InstanceContext<WebDriver, TestWebDriver> a, RequestedInstance<WebDriver, TestWebDriver> b) {
return true;
}
@Override
public LifeCycle getLifeCycle(TestWebDriver annotation) {
return LifeCycle.GLOBAL;
}
@Override
public void close(InstanceContext<WebDriver, TestWebDriver> instanceContext) {
instanceContext.getValue().quit();
}
public abstract WebDriver getWebDriver();
public void setGlobalOptions(AbstractDriverOptions<?> options) {
options.setImplicitWaitTimeout(Duration.ofSeconds(5));
options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
}
}

View file

@ -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<WebDriver, TestWebDriver> {
@Override
public Class<TestWebDriver> getAnnotationClass() {
return TestWebDriver.class;
}
@Override
public Class<WebDriver> getValueType() {
return WebDriver.class;
}
@Override
public InstanceWrapper<WebDriver, TestWebDriver> getValue(Registry registry, TestWebDriver annotation) {
final var driver = new ChromeDriver();
return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL);
}
@Override
public boolean compatible(InstanceWrapper<WebDriver, TestWebDriver> a, RequestedInstance<WebDriver, TestWebDriver> 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);
}
}

View file

@ -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<WebDriver, TestWebDriver> {
@Override
public Class<TestWebDriver> getAnnotationClass() {
return TestWebDriver.class;
}
@Override
public Class<WebDriver> getValueType() {
return WebDriver.class;
}
@Override
public InstanceWrapper<WebDriver, TestWebDriver> getValue(Registry registry, TestWebDriver annotation) {
final var driver = new FirefoxDriver();
return new InstanceWrapper<>(this, annotation, driver, LifeCycle.GLOBAL);
}
@Override
public boolean compatible(InstanceWrapper<WebDriver, TestWebDriver> a, RequestedInstance<WebDriver, TestWebDriver> 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);
}
}