diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c46f556..93164e0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,14 @@ jobs: --health-retries 5 ports: - 5432:5432 + keycloak-it: + image: "jboss/keycloak:11.0.0" + env: + KEYCLOAK_USER: admin + KEYCLOAK_PASSWORD: admin + DB_VENDOR: h2 + ports: + - 18080:8080 steps: - uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index f3f1a1a..39798a4 100644 --- a/.gitignore +++ b/.gitignore @@ -136,7 +136,7 @@ ehthumbs_vista.db # Dump file *.stackdump -# Folder initializerConfig file +# Folder config file Desktop.ini # Recycle Bin used on file shares diff --git a/README.md b/README.md index 3d1cf88..d2243ef 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ container provided external services. ## The initializers ### PostgresInitializer + ### KeycloakInitializer + ## Local development Please note, that any paths used in this documentation are relative to this projects root directory diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index 069c022..2c8d2ea 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -14,6 +14,17 @@ services: - "${DB_IT_PORT}:5432" volumes: - db-it-data:/var/lib/postgresql/data + keycloak-it: + image: "jboss/keycloak:11.0.0" + container_name: "${COMPOSE_PROJECT_NAME}-keycloak-it" + hostname: keycloak-it + restart: unless-stopped + environment: + - "KEYCLOAK_USER=admin" + - "KEYCLOAK_PASSWORD=admin" + - "DB_VENDOR=h2" + ports: + - "18080:8080" volumes: db-it-data: diff --git a/pom.xml b/pom.xml index ad8e698..bf4f416 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ ${java.version} UTF-8 UTF-8 - 0.0.1 + 0.1.0 ${skipTests} @@ -42,34 +42,36 @@ 3.1.2 3.24.2 ${version.org.assertj} - 1.5.0 - 9.16.3 + 1.6.0 + 9.22.3 0.8.11 - 5.9.1 - 2.1.0 + 5.10.1 + 2.2.0 ${version.org.junit} + 11.0.0 42.6.0 1.6.13 - 3.1.5 + 3.2.2 + + org.springframework.boot + spring-boot-dependencies + ${version.org.springframework.boot} + pom + import + org.flywaydb flyway-core ${version.org.flywaydb.flyway-core} - org.springframework.boot - spring-boot-test - ${version.org.springframework.boot.spring-boot-test} - - - org.postgresql - postgresql - ${version.org.postgresql.postgresql} - runtime + org.keycloak + keycloak-admin-client + ${version.org.keycloak.keycloak-admin-client} org.assertj @@ -83,20 +85,26 @@ ${version.org.junit-pioneer.junit-pioneer} test - - org.junit.jupiter - junit-jupiter-engine - ${version.org.junit.jupiter.junit-jupiter-engine} - test - + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + org.flywaydb flyway-core + + org.keycloak + keycloak-admin-client + org.springframework.boot spring-boot-test @@ -106,6 +114,12 @@ postgresql runtime + + io.rest-assured + rest-assured + test + + org.assertj assertj-core diff --git a/src/main/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializer.java b/src/main/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializer.java new file mode 100644 index 0000000..f2eaa43 --- /dev/null +++ b/src/main/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializer.java @@ -0,0 +1,396 @@ +package de.denktmit.testsupport.spring; + +import org.keycloak.admin.client.CreatedResponseUtil; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.KeycloakBuilder; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.*; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +import javax.ws.rs.core.Response; +import java.util.Collections; +import java.util.List; + +/** + * {@code KeycloakTestContextInitializer} is an implementation of the + * {@link ApplicationContextInitializer} interface for setting up Keycloak configuration + * during integration tests. It initializes a Keycloak test environment, creating realms, + * clients, users, and roles necessary for testing with Keycloak. + *

+ * This class provides default configuration values that can be overridden using + * environment variable . It also exposes an {@link Config} class to customize + * the Keycloak configuration. + * + * @author [Your Name] + * @version 1.0 + * @see ApplicationContextInitializer + */ +public class KeycloakTestContextInitializer implements ApplicationContextInitializer { + private Config config = new Config(); + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + setupKeycloak(config); + TestPropertyValues.of( + "spring.security.oauth2.client.provider.keycloak.issuer-uri=http://" + config.keycloakAddress + "/auth/realms/" + config.testRealmName, + "spring.security.oauth2.client.registration.keycloak.client-id=" + config.testClientId, + "spring.security.oauth2.client.registration.keycloak.client-secret=" + config.testClientSecret + ).applyTo(applicationContext.getEnvironment()); + } + + private void setupKeycloak(Config ic) { + KeycloakSession keycloakSession = new KeycloakSession(ic); + keycloakSession.connectAdminClient(); + keycloakSession.createSandboxRealm(); + keycloakSession.createSandboxRealmClient(); + keycloakSession.setupNewUser(); + } + + /** + * Gets the resolved {@link Config} to be used by the initializer + * + * @return resolved {@link Config} + */ + public Config getConfig() { + return config; + } + + /** + * Configuration class holding values for Keycloak setup. Provides default values + * that can be overridden using environment variable . + */ + public static class Config { + /** + * Default schema for Keycloak. Defaults to "http". + */ + public static String URI_SCHEMA = "http"; + + /** + * Default host for Keycloak. Defaults to "localhost". + */ + public static String DEFAULT_HOST = "localhost"; + + /** + * Default port for Keycloak. Defaults to 18080. + */ + public static int DEFAULT_PORT = 18080; + + /** + * Default administrator username for Keycloak. Defaults to "admin". + */ + public static String DEFAULT_ADMIN_USERNAME = "admin"; + + /** + * Default administrator password for Keycloak. Defaults to "admin". + */ + public static String DEFAULT_ADMIN_PASSWORD = "admin"; + + /** + * Default master realm for Keycloak. Defaults to "master". + */ + public static String DEFAULT_MASTER_REALM = "master"; + + /** + * Default client ID for the Keycloak admin client. Defaults to "admin-cli". + */ + public static String DEFAULT_ADMIN_CLIENT_ID = "admin-cli"; + + /** + * Default client ID for the Keycloak test client. Defaults to "sb-client". + */ + public static String TEST_CLIENT_ID = "sb-client"; + + /** + * Default client secret for the Keycloak test client. + */ + public static String TEST_CLIENT_SECRET = "ad0be000-0000-4000-a000-000000000000"; + + /** + * Default realm name for the Keycloak test environment. Defaults to "sandbox". + */ + public static String TEST_REALM_NAME = "sandbox"; + + /** + * Default user role for the Keycloak test user. Defaults to "sb-manager". + */ + public static String TEST_USER_ROLE = "sb-manager"; + + /** + * Default description for the Keycloak test user role. Defaults to "sandbox manager". + */ + public static String TEST_USER_ROLE_DESCRIPTION = "sandbox manager"; + + /** + * Default username for the Keycloak test admin user. Defaults to "sb-admin". + */ + public static String TEST_ADMIN_USERNAME = "sb-admin"; + + /** + * Default password for the Keycloak test admin user. Defaults to "ThisIsHow2ConnectAnAdmin!". + */ + public static String TEST_ADMIN_PASSWORD = "ThisIsHow2ConnectAnAdmin!"; + + private String keycloakUriSchema = System.getenv("KEYCLOAK_HOST_URI_SCHEMA") != null ? System.getenv("KEYCLOAK_HOST_URI_SCHEMA") : URI_SCHEMA; + private String keycloakHost = System.getenv("KEYCLOAK_HOST") != null ? System.getenv("KEYCLOAK_HOST") : DEFAULT_HOST; + private int keycloakPort = System.getenv("KEYCLOAK_PORT") != null ? Integer.parseInt(System.getenv("KEYCLOAK_PORT")) : DEFAULT_PORT; + private String keycloakAdminName = System.getenv("KEYCLOAK_USER") != null ? System.getenv("KEYCLOAK_USER") : DEFAULT_ADMIN_USERNAME; + private String keycloakAdminPassword = System.getenv("KEYCLOAK_PASSWORD") != null ? System.getenv("KEYCLOAK_PASSWORD") : DEFAULT_ADMIN_PASSWORD; + private String keycloakAddress = keycloakUriSchema + "://" + keycloakHost + ":" + keycloakPort; + private String keycloakMasterRealm = System.getenv("KEYCLOAK_MASTER_REALM") != null ? System.getenv("KEYCLOAK_MASTER_REALM") : DEFAULT_MASTER_REALM; + private String keycloakAdminClientId = System.getenv("KEYCLOAK_ADMIN_CLIENT_ID") != null ? System.getenv("KEYCLOAK_ADMIN_CLIENT_ID") : DEFAULT_ADMIN_CLIENT_ID; + private String testClientId = System.getenv("KEYCLOAK_TEST_CLIENT_ID") != null ? System.getenv("KEYCLOAK_TEST_CLIENT_ID") : TEST_CLIENT_ID; + private String testClientSecret = System.getenv("KEYCLOAK_TEST_CLIENT_SECRET") != null ? System.getenv("KEYCLOAK_TEST_CLIENT_SECRET") : TEST_CLIENT_SECRET; + private String testRealmName = System.getenv("KEYCLOAK_TEST_REALM_NAME") != null ? System.getenv("KEYCLOAK_TEST_REALM_NAME") : TEST_REALM_NAME; + private String testUserRole = System.getenv("KEYCLOAK_TEST_USER_ROLE") != null ? System.getenv("KEYCLOAK_TEST_USER_ROLE") : TEST_USER_ROLE; + private String testUserRoleDescription = System.getenv("KEYCLOAK_TEST_USER_ROLE_DESCRIPTION") != null ? System.getenv("KEYCLOAK_TEST_USER_ROLE_DESCRIPTION") : TEST_USER_ROLE_DESCRIPTION; + private String testAdminUsername = System.getenv("KEYCLOAK_TEST_ADMIN_USERNAME") != null ? System.getenv("KEYCLOAK_TEST_ADMIN_USERNAME") : TEST_ADMIN_USERNAME; + private String testAdminPassword = System.getenv("KEYCLOAK_TEST_ADMIN_PASSWORD") != null ? System.getenv("KEYCLOAK_TEST_ADMIN_PASSWORD") : TEST_ADMIN_PASSWORD; + + /** + * Get the Keycloak uri schema. Defaults to {@link #URI_SCHEMA} if not provided through environment variable KEYCLOAK_HOST_URI_SCHEMA. + * + * @return The Keycloak host. + */ + public String getKeycloakUriSchema() { + return keycloakUriSchema; + } + + /** + * Get the Keycloak host. Defaults to {@link #DEFAULT_HOST} if not provided through environment variable KEYCLOAK_HOST. + * + * @return The Keycloak host. + */ + public String getKeycloakHost() { + return keycloakHost; + } + + /** + * Get the Keycloak port. Defaults to {@link #DEFAULT_PORT} if not provided through environment variable KEYCLOAK_PORT. + * + * @return The Keycloak port. + */ + public int getKeycloakPort() { + return keycloakPort; + } + + /** + * Get the administrator username for Keycloak. Defaults to {@link #DEFAULT_ADMIN_USERNAME} if not provided through environment variable KEYCLOAK_USER. + * + * @return The Keycloak administrator username. + */ + public String getKeycloakAdminName() { + return keycloakAdminName; + } + + /** + * Get the administrator password for Keycloak. Defaults to {@link #DEFAULT_ADMIN_PASSWORD} if not provided through environment variable KEYCLOAK_PASSWORD. + * + * @return The Keycloak administrator password. + */ + public String getKeycloakAdminPassword() { + return keycloakAdminPassword; + } + + /** + * Get the Keycloak server address in the format "host:port". Defaults to a combination + * of {@code keycloakHost} and {@code keycloakPort} separated by ':'. + * + * @return The Keycloak server address. + */ + public String getKeycloakAddress() { + return keycloakAddress; + } + + /** + * Get the master realm for Keycloak. Defaults to {@link #DEFAULT_MASTER_REALM} if not provided through environment variable KEYCLOAK_MASTER_REALM. + * + * @return The Keycloak master realm. + */ + public String getKeycloakMasterRealm() { + return keycloakMasterRealm; + } + + /** + * Get the client ID for the Keycloak admin client. Defaults to {@link #DEFAULT_ADMIN_CLIENT_ID} if not provided through environment variable KEYCLOAK_ADMIN_CLIENT_ID. + * + * @return The Keycloak admin client ID. + */ + public String getKeycloakAdminClientId() { + return keycloakAdminClientId; + } + + /** + * Get the client ID for the Keycloak test client. Defaults to {@link #TEST_CLIENT_ID} if not provided through environment variable KEYCLOAK_TEST_CLIENT_ID. + * + * @return The Keycloak test client ID. + */ + public String getTestClientId() { + return testClientId; + } + + /** + * Get the client secret for the Keycloak test client. Defaults to {@link #TEST_CLIENT_SECRET} if not provided through environment variable KEYCLOAK_TEST_CLIENT_SECRET. + * + * @return The Keycloak test client secret. + */ + public String getTestClientSecret() { + return testClientSecret; + } + + /** + * Get the realm name for the Keycloak test environment. Defaults to {@link #TEST_REALM_NAME} if not provided through environment variable KEYCLOAK_TEST_REALM_NAME. + * + * @return The Keycloak test realm name. + */ + public String getTestRealmName() { + return testRealmName; + } + + /** + * Get the user role for the Keycloak test user. Defaults to {@link #TEST_USER_ROLE} if not provided through environment variable KEYCLOAK_TEST_USER_ROLE. + * + * @return The Keycloak test user role. + */ + public String getTestUserRole() { + return testUserRole; + } + + /** + * Get the description for the Keycloak test user role. Defaults to {@link #TEST_USER_ROLE_DESCRIPTION} if not provided through environment variable KEYCLOAK_TEST_USER_ROLE_DESCRIPTION. + * + * @return The Keycloak test user role description. + */ + public String getTestUserRoleDescription() { + return testUserRoleDescription; + } + + /** + * Get the username for the Keycloak test admin user. Defaults to {@link #TEST_ADMIN_USERNAME} if not provided through environment variable KEYCLOAK_TEST_ADMIN_USERNAME. + * + * @return The Keycloak test admin username. + */ + public String getTestAdminUsername() { + return testAdminUsername; + } + + /** + * Get the password for the Keycloak test admin user. Defaults to {@link #TEST_ADMIN_PASSWORD} if not provided through environment variable KEYCLOAK_TEST_ADMIN_PASSWORD. + * + * @return The Keycloak test admin password. + */ + public String getTestAdminPassword() { + return testAdminPassword; + } + } + + private static class KeycloakSession { + private final Config ic; + private Keycloak keycloakAdminClient; + private RealmResource realm; + private UsersResource users; + + public KeycloakSession(Config ic) { + this.ic = ic; + } + + private void connectAdminClient() { + keycloakAdminClient = KeycloakBuilder.builder() + .serverUrl(ic.keycloakAddress + "/auth") + .realm(ic.keycloakMasterRealm) + .clientId(ic.keycloakAdminClientId) + .username(ic.keycloakAdminName) + .password(ic.keycloakAdminPassword) + .build(); + } + + private void createSandboxRealm() { + deleteRealmIfExists(); + keycloakAdminClient.realms().create( + new RealmRepresentation() {{ + setRealm(ic.testRealmName); + setEnabled(true); + }} + ); + realm = keycloakAdminClient.realm(ic.testRealmName); + users = realm.users(); + } + + private void deleteRealmIfExists() { + keycloakAdminClient.realms().findAll().stream() + .filter(r -> r.getRealm().equals(ic.testRealmName)) + .findFirst() + .ifPresent(r -> keycloakAdminClient.realm(ic.testRealmName).remove()); + } + + private void createSandboxRealmClient() { + realm.clients().create( + new ClientRepresentation() {{ + setId(ic.testClientId); + setSecret(ic.testClientSecret); + setRedirectUris(List.of("*")); + setWebOrigins(List.of("*")); + setProtocol("openid-connect"); + }} + ); + } + + private void setupNewUser() { + deleteUserIfExists(); + Response userCreateResponse = createUser(); + UserResource userResource = users.get(CreatedResponseUtil.getCreatedId(userCreateResponse)); + setUserPassword(userResource); + createRole(userResource); + } + + private void deleteUserIfExists() { + users.list().stream() + .filter(user -> user.getUsername().equals(ic.testAdminUsername)) + .findFirst() + .ifPresent(user -> users.delete(user.getId())); + } + + private Response createUser() { + return users.create( + new UserRepresentation() {{ + setEnabled(true); + setUsername(ic.testAdminUsername); + setFirstName("JUnit"); + setLastName("Tester"); + setEmail("junit+tester1@gec.io"); + setAttributes(java.util.Collections.singletonMap("origin", List.of("demo"))); + }} + ); + } + + private void setUserPassword(UserResource userResource) { + userResource.resetPassword( + new CredentialRepresentation() {{ + setTemporary(false); + setType(CredentialRepresentation.PASSWORD); + setValue(ic.testAdminPassword); + }} + ); + } + + private void createRole(UserResource... assignees) { + deleteRoleIfExists(); + realm.roles().create(new RoleRepresentation(ic.testUserRole, ic.testUserRoleDescription, false)); + RoleRepresentation role = realm.roles().get(ic.testUserRole).toRepresentation(); + for (UserResource user : assignees) { + user.roles().realmLevel().add(Collections.singletonList(role)); + } + } + + private void deleteRoleIfExists() { + realm.roles().list().stream() + .filter(r -> r.getName().equals(ic.testUserRole)) + .findFirst() + .ifPresent(r -> realm.roles().deleteRole(r.getName())); + } + } + +} diff --git a/src/main/java/de/denktmit/testsupport/spring/PostgresTestContextInitializer.java b/src/main/java/de/denktmit/testsupport/spring/PostgresTestContextInitializer.java index 3d50f92..11ce25f 100644 --- a/src/main/java/de/denktmit/testsupport/spring/PostgresTestContextInitializer.java +++ b/src/main/java/de/denktmit/testsupport/spring/PostgresTestContextInitializer.java @@ -50,7 +50,11 @@ public class PostgresTestContextInitializer implements ApplicationContextInitial */ public static boolean DEFAULT_FLYWAY_MIGRATE = true; - public static class InitializerConfig { + /** + * Configuration class holding values for Postgres setup. Provides default values + * that can be overridden using environment variable . + */ + public static class Config { String dbHost = System.getenv("POSTGRES_HOST") != null ? System.getenv("POSTGRES_HOST") : DEFAULT_HOST; int dbPort = System.getenv("POSTGRES_PORT") != null ? Integer.parseInt(System.getenv("POSTGRES_PORT")) : DEFAULT_PORT; String dbName = System.getenv("POSTGRES_DB") != null ? System.getenv("POSTGRES_DB") : DEFAULT_DB_NAME; @@ -61,23 +65,23 @@ public static class InitializerConfig { boolean flywayMigrate = System.getenv("FLYWAY_MIGRATE") != null ? Boolean.parseBoolean(System.getenv("FLYWAY_MIGRATE")) : DEFAULT_FLYWAY_MIGRATE; } - private final InitializerConfig ic = new InitializerConfig(); + private final Config config = new Config(); @Override public void initialize(@NonNull ConfigurableApplicationContext configurableApplicationContext) { - injectIntoSpringTestContext(configurableApplicationContext, ic); - resetDBWithFlyway(ic); + injectIntoSpringTestContext(configurableApplicationContext, config); + resetDBWithFlyway(config); } - private void injectIntoSpringTestContext(ConfigurableApplicationContext configurableApplicationContext, InitializerConfig initializerConfig) { + private void injectIntoSpringTestContext(ConfigurableApplicationContext configurableApplicationContext, Config config) { TestPropertyValues.of( - "spring.datasource.url=" + initializerConfig.dbUrl, - "spring.datasource.username=" + initializerConfig.dbUser, - "spring.datasource.password=" + initializerConfig.dbPassword + "spring.datasource.url=" + config.dbUrl, + "spring.datasource.username=" + config.dbUser, + "spring.datasource.password=" + config.dbPassword ).applyTo(configurableApplicationContext.getEnvironment()); } - private void resetDBWithFlyway(InitializerConfig ic) { + private void resetDBWithFlyway(Config ic) { ClassicConfiguration config = new ClassicConfiguration(); config.setCleanDisabled(false); config.setLocationsAsStrings(""); @@ -91,7 +95,13 @@ private void resetDBWithFlyway(InitializerConfig ic) { } } - public InitializerConfig getIc() { - return ic; + + /** + * Gets the resolved {@link Config} to be used by the initializer + * + * @return resolved {@link Config} + */ + public Config getConfig() { + return config; } } diff --git a/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerIT.java b/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerIT.java new file mode 100644 index 0000000..10caa32 --- /dev/null +++ b/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerIT.java @@ -0,0 +1,84 @@ +package de.denktmit.testsupport.spring; + +import io.restassured.RestAssured; +import io.restassured.filter.cookie.CookieFilter; +import io.restassured.path.xml.XmlPath; +import io.restassured.response.Response; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +import static io.restassured.http.Method.GET; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.startsWith; + +public class KeycloakTestContextInitializerIT { + + private static final String REDIRECT_URI = "http://localhost/login/oauth2/code/keycloak"; + private KeycloakTestContextInitializer initializer; + private ConfigurableApplicationContext ctx; + + + @BeforeEach + void setUp() { + initializer = new KeycloakTestContextInitializer(); + ctx = new GenericApplicationContext(); + } + + @Test + void testInitialize() { + initializer.initialize(ctx); + KeycloakTestContextInitializer.Config ic = initializer.getConfig(); + RestAssured.baseURI = ic.getKeycloakAddress(); + CookieFilter cookieFilter = new CookieFilter(); + String authenticationUri = visitAndVerifyLoginPage(ic, cookieFilter); + login(ic, cookieFilter, authenticationUri); + } + + private static String visitAndVerifyLoginPage(KeycloakTestContextInitializer.Config ic, CookieFilter cookieFilter) { + Response response = RestAssured + .given() + .filter(cookieFilter) + .queryParam("client_id", ic.getTestClientId()) + .queryParam("redirect_uri", REDIRECT_URI) + .queryParam("response_type", "code") + .queryParam("scope", "openid") + + .when() + .request(GET, "/auth/realms/{realmName}/protocol/openid-connect/auth", ic.getTestRealmName()) + + .then() + .statusCode(200) + .body(containsString("Username or email")) + .extract().response(); + + XmlPath htmlPath = new XmlPath(XmlPath.CompatibilityMode.HTML, response.body().asString()); + return htmlPath.getString("html.body.**.findAll { it.name() == 'form' }.@action"); + } + + private static void login(KeycloakTestContextInitializer.Config ic, CookieFilter cookieFilter, String authenticationUri) { + String redirectUri = ic.getKeycloakAddress() + "/auth/realms/" + ic.getTestRealmName() + "/login-actions/authenticate"; + RestAssured + .given() + .filter(cookieFilter) + .redirects().follow(false) + .formParam("username", ic.getTestAdminUsername()) + .formParam("password", ic.getTestAdminPassword()) + .formParam("credentialId", "") + .queryParam("client_id", ic.getTestClientId()) + .queryParam("redirect_uri", redirectUri) + .queryParam("response_type", "code") + .queryParam("scope", "openid") + + .when() + .post(authenticationUri) + + .then() + .statusCode(302) + .header("Location", startsWith(REDIRECT_URI)) + .extract().response(); + } + +} diff --git a/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerTest.java b/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerTest.java new file mode 100644 index 0000000..ce9a02b --- /dev/null +++ b/src/test/java/de/denktmit/testsupport/spring/KeycloakTestContextInitializerTest.java @@ -0,0 +1,47 @@ +package de.denktmit.testsupport.spring; + +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.SetEnvironmentVariable; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KeycloakTestContextInitializerTest { + + @Test + @SetEnvironmentVariable(key = "KEYCLOAK_HOST_URI_SCHEMA", value = "https") + @SetEnvironmentVariable(key = "KEYCLOAK_HOST", value = "keycloak.dangerzone.denktmit.tech") + @SetEnvironmentVariable(key = "KEYCLOAK_PORT", value = "28080") + @SetEnvironmentVariable(key = "KEYCLOAK_USER", value = "superuser") + @SetEnvironmentVariable(key = "KEYCLOAK_PASSWORD", value = "superpassword") + @SetEnvironmentVariable(key = "KEYCLOAK_MASTER_REALM", value = "main") + @SetEnvironmentVariable(key = "KEYCLOAK_ADMIN_CLIENT_ID", value = "superuser-cli") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_CLIENT_ID", value = "junit-client") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_CLIENT_SECRET", value = "decade00-0000-4000-a000-000000000000") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_REALM_NAME", value = "playground") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_USER_ROLE", value = "playground-manager") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_USER_ROLE_DESCRIPTION", value = "playground manager") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_ADMIN_USERNAME", value = "playground-admin") + @SetEnvironmentVariable(key = "KEYCLOAK_TEST_ADMIN_PASSWORD", value = "ThisIsHow2ConnectAnPlaygroundAdmin!") + void testEnvironmentVariablePickup() throws Exception { + KeycloakTestContextInitializer initializer = new KeycloakTestContextInitializer(); + + // Verify the properties of the initializerConfig using AssertJ + KeycloakTestContextInitializer.Config ic = initializer.getConfig(); + assertThat(ic.getKeycloakUriSchema()).isEqualTo("https"); + assertThat(ic.getKeycloakHost()).isEqualTo("keycloak.dangerzone.denktmit.tech"); + assertThat(ic.getKeycloakPort()).isEqualTo(28080); + assertThat(ic.getKeycloakAddress()).isEqualTo("https://keycloak.dangerzone.denktmit.tech:28080"); + assertThat(ic.getKeycloakAdminName()).isEqualTo("superuser"); + assertThat(ic.getKeycloakAdminPassword()).isEqualTo("superpassword"); + assertThat(ic.getKeycloakMasterRealm()).isEqualTo("main"); + assertThat(ic.getKeycloakAdminClientId()).isEqualTo("superuser-cli"); + assertThat(ic.getTestClientId()).isEqualTo("junit-client"); + assertThat(ic.getTestClientSecret()).isEqualTo("decade00-0000-4000-a000-000000000000"); + assertThat(ic.getTestRealmName()).isEqualTo("playground"); + assertThat(ic.getTestUserRole()).isEqualTo("playground-manager"); + assertThat(ic.getTestUserRoleDescription()).isEqualTo("playground manager"); + assertThat(ic.getTestAdminUsername()).isEqualTo("playground-admin"); + assertThat(ic.getTestAdminPassword()).isEqualTo("ThisIsHow2ConnectAnPlaygroundAdmin!"); + } + +} diff --git a/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerIT.java b/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerIT.java index 1d2096a..efef5b1 100644 --- a/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerIT.java +++ b/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerIT.java @@ -25,9 +25,9 @@ void setUp() throws Exception { } void dropAllTablesIfExistent() throws Exception { - String jdbcUrl = initializer.getIc().dbUrl; - String username = initializer.getIc().dbUser; - String password = initializer.getIc().dbPassword; + String jdbcUrl = initializer.getConfig().dbUrl; + String username = initializer.getConfig().dbUser; + String password = initializer.getConfig().dbPassword; try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password); Statement statement = connection.createStatement()) { statement.execute("DROP TABLE IF EXISTS example_table"); statement.execute("DROP TABLE IF EXISTS flyway_schema_history"); @@ -45,16 +45,16 @@ void testInitialize() throws Exception { private void validateSpringIntegration() { PropertySource testPropertySource = ctx.getEnvironment().getPropertySources().get("test"); assertThat(testPropertySource).isNotNull(); - assertThat(testPropertySource.getProperty("spring.datasource.url")).isEqualTo(initializer.getIc().dbUrl); - assertThat(testPropertySource.getProperty("spring.datasource.username")).isEqualTo(initializer.getIc().dbUser); - assertThat(testPropertySource.getProperty("spring.datasource.password")).isEqualTo(initializer.getIc().dbPassword); + assertThat(testPropertySource.getProperty("spring.datasource.url")).isEqualTo(initializer.getConfig().dbUrl); + assertThat(testPropertySource.getProperty("spring.datasource.username")).isEqualTo(initializer.getConfig().dbUser); + assertThat(testPropertySource.getProperty("spring.datasource.password")).isEqualTo(initializer.getConfig().dbPassword); } void validateDataInExampleTable() throws Exception { // Database connection information - String jdbcUrl = initializer.getIc().dbUrl; - String username = initializer.getIc().dbUser; - String password = initializer.getIc().dbPassword; + String jdbcUrl = initializer.getConfig().dbUrl; + String username = initializer.getConfig().dbUser; + String password = initializer.getConfig().dbPassword; try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password); Statement statement = connection.createStatement(); diff --git a/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerTest.java b/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerTest.java index 84a50eb..1bfa579 100644 --- a/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerTest.java +++ b/src/test/java/de/denktmit/testsupport/spring/PostgresTestContextInitializerTest.java @@ -32,13 +32,13 @@ void testEnvironmentVariablePickup() throws Exception { initializer.initialize(new GenericApplicationContext()); // Verify the properties of the initializerConfig using AssertJ - assertThat(initializer.getIc().dbHost).isEqualTo("db.example.com"); - assertThat(initializer.getIc().dbPort).isEqualTo(5432); - assertThat(initializer.getIc().dbName).isEqualTo("prod"); - assertThat(initializer.getIc().dbUser).isEqualTo("db-test-user"); - assertThat(initializer.getIc().dbPassword).isEqualTo("db-test-password"); - assertThat(initializer.getIc().flywayClean).isFalse(); - assertThat(initializer.getIc().flywayMigrate).isFalse(); + assertThat(initializer.getConfig().dbHost).isEqualTo("db.example.com"); + assertThat(initializer.getConfig().dbPort).isEqualTo(5432); + assertThat(initializer.getConfig().dbName).isEqualTo("prod"); + assertThat(initializer.getConfig().dbUser).isEqualTo("db-test-user"); + assertThat(initializer.getConfig().dbPassword).isEqualTo("db-test-password"); + assertThat(initializer.getConfig().flywayClean).isFalse(); + assertThat(initializer.getConfig().flywayMigrate).isFalse(); }