Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions microprofile-jwt/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@
<groupId>org.jboss.threads</groupId>
<artifactId>jboss-threads</artifactId>
</dependency>

<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-docker-junit-rule</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-docker-ftest-containerobject-dsl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class KeycloakConfigurator extends ExternalResource {

private String rawAdminToken;

public static final String KEYCLOAK_INSTANCE_HOSTNAME = "localhost";
public static final int KEYCLOAK_EXPOSED_HTTP_PORT = 8179;

@Override
public void before() throws InterruptedException {
rawAdminToken = authorizeAndObtainRawJwtForAdminInterface(adminUsername, adminPassword);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.jboss.eap.qe.microprofile.jwt.keycloak;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.arquillian.cube.docker.impl.client.config.Await;
import org.arquillian.cube.docker.impl.docker.DockerClientExecutor;
import org.arquillian.cube.spi.Cube;
import org.arquillian.cube.spi.await.AwaitStrategy;
import org.awaitility.Awaitility;
import org.awaitility.core.ConditionTimeoutException;

/**
* Provides a custom waiting strategy for Arquillian Cube DOcker APIs to check that the Keycloak container was started
* successfully.
* <p>
* Used by {@link KeycloakIntegrationHighLevelScenarioTest}
* </p>
*/
public class KeycloakContainerAwaitStrategy implements AwaitStrategy {

Await params;
DockerClientExecutor dockerClientExecutor;
Cube<?> cube;

private static final long CONTAINER_READY_TIMEOUT = 2;
private static final TimeUnit CONTAINER_READY_TIMEOUT_TIME_UNIT = TimeUnit.MINUTES;

public KeycloakContainerAwaitStrategy() {
}

public void setCube(Cube<?> cube) {
this.cube = cube;
}

public void setDockerClientExecutor(DockerClientExecutor dockerClientExecutor) {
this.dockerClientExecutor = dockerClientExecutor;
}

public void setParams(Await params) {
this.params = params;
}

@Override
public boolean await() {
try {
Awaitility.await()
.atMost(CONTAINER_READY_TIMEOUT, CONTAINER_READY_TIMEOUT_TIME_UNIT)
.until(() -> isContainerReady(KeycloakConfigurator.KEYCLOAK_EXPOSED_HTTP_PORT));
} catch (ConditionTimeoutException ex) {
return false;
}
return true;
}

private static boolean isContainerReady(int port) {
try {
URL url = new URL("http://" + KeycloakConfigurator.KEYCLOAK_INSTANCE_HOSTNAME + ":" + port + "/health/ready");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

boolean ready = connection.getResponseCode() == HttpURLConnection.HTTP_OK;
if (ready) {
System.out.println(
"Let's wait additional 10 seconds before the post-start tasks (like creation of admin user) on container are done.");
Thread.sleep(10000L);
}
return ready;
} catch (Exception ex) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.equalTo;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.arquillian.cube.docker.impl.client.config.Await;
import org.arquillian.cube.docker.junit.rule.ContainerDslRule;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
Expand All @@ -16,7 +16,6 @@
import org.jboss.eap.qe.microprofile.jwt.testapp.Endpoints;
import org.jboss.eap.qe.microprofile.jwt.testapp.jaxrs.JaxRsTestApplication;
import org.jboss.eap.qe.microprofile.jwt.testapp.jaxrs.SecuredJaxRsEndpoint;
import org.jboss.eap.qe.ts.common.docker.Docker;
import org.jboss.eap.qe.ts.common.docker.junit.DockerRequiredTests;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
Expand All @@ -28,6 +27,8 @@
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Test a high level scenario which includes deploying a container with Keycloak, setting it up and obtaining
Expand All @@ -41,41 +42,41 @@ public class KeycloakIntegrationHighLevelScenarioTest {

private static final String KEYCLOAK_REALM_NAME = "foobar";

private static final String KEYCLOAK_INSTANCE_HOSTNAME = "localhost";

private static final String KEYCLOAK_CONTAINER_NAME = KeycloakIntegrationHighLevelScenarioTest.class.getSimpleName()
+ "-container";

private static final int KEYCLOAK_EXPOSED_HTTP_PORT = 8179;
private static final int KEYCLOAK_EXPOSED_TOKEN_PORT = 8149;
private static final int KEYCLOAK_EXPOSED_MANAGEMENT_PORT = 9988;

private static final String KEYCLOAK_ADMIN_USERNAME = "admin";
private static final String KEYCLOAK_ADMIN_PASSWORD = "password";
private static final Logger log = LoggerFactory.getLogger(KeycloakIntegrationHighLevelScenarioTest.class);

public static Docker keycloakContainer = new Docker.Builder(KEYCLOAK_CONTAINER_NAME,
"quay.io/keycloak/keycloak:24.0")
.setContainerReadyTimeout(2, TimeUnit.MINUTES)
.setContainerReadyCondition(() -> isContainerReady(KEYCLOAK_EXPOSED_HTTP_PORT))
.withPortMapping(KEYCLOAK_EXPOSED_HTTP_PORT + ":8080")
.withEnvVar("KEYCLOAK_ADMIN", KEYCLOAK_ADMIN_USERNAME)
.withEnvVar("KEYCLOAK_ADMIN_PASSWORD", KEYCLOAK_ADMIN_PASSWORD)
.withEnvVar("KC_HEALTH_ENABLED", "true")
.withCmdArg("start-dev")
.build();
public static ContainerDslRule keycloakContainerDslRule = new ContainerDslRule("quay.io/keycloak/keycloak:24.0",
KEYCLOAK_CONTAINER_NAME)
.withAwaitStrategy(keycloakContainerAwaitStrategy())
.withPortBinding(KeycloakConfigurator.KEYCLOAK_EXPOSED_HTTP_PORT + "->8080")
.withEnvironment("KEYCLOAK_ADMIN", KEYCLOAK_ADMIN_USERNAME)
.withEnvironment("KEYCLOAK_ADMIN_PASSWORD", KEYCLOAK_ADMIN_PASSWORD)
.withEnvironment("KC_HEALTH_ENABLED", "true")
.withCommand("start-dev");

public static KeycloakConfigurator keycloakConfigurator = new KeycloakConfigurator.Builder(KEYCLOAK_REALM_NAME)
.adminPassword(KEYCLOAK_ADMIN_PASSWORD)
.adminUsername(KEYCLOAK_ADMIN_USERNAME)
.clientId("client-custom-id")
.keycloakBindAddress(KEYCLOAK_INSTANCE_HOSTNAME)
.keycloakHttpPort(KEYCLOAK_EXPOSED_HTTP_PORT)
.keycloakBindAddress(KeycloakConfigurator.KEYCLOAK_INSTANCE_HOSTNAME)
.keycloakHttpPort(KeycloakConfigurator.KEYCLOAK_EXPOSED_HTTP_PORT)
.build();

@ClassRule
public static TestRule ruleChain = RuleChain.outerRule(keycloakContainer)
public static TestRule ruleChain = RuleChain.outerRule(keycloakContainerDslRule)
.around(keycloakConfigurator);

private static Await keycloakContainerAwaitStrategy() {
Await await = new Await();
await.setStrategy(
"org.jboss.eap.qe.microprofile.jwt.keycloak.KeycloakContainerAwaitStrategy");
return await;
}

@Deployment
public static Archive<?> createDeployment() {
//visit http://localhost:8179/auth/realms/foobar/.well-known/openid-configuration with running keycloak for values
Expand All @@ -99,6 +100,7 @@ public static Archive<?> createDeployment() {
*/
@Test
public void accessSecuredEndpointWithKeycloakProvidedJwt(@ArquillianResource URL url) {

final String username = "qux";
final String password = "foo";
keycloakConfigurator.addUser(username, password);
Expand All @@ -110,23 +112,4 @@ public void accessSecuredEndpointWithKeycloakProvidedJwt(@ArquillianResource URL
.body(equalTo(rawToken))
.statusCode(200);
}

private static boolean isContainerReady(int port) {
try {
URL url = new URL("http://" + KEYCLOAK_INSTANCE_HOSTNAME + ":" + port + "/health/ready");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

boolean ready = connection.getResponseCode() == HttpURLConnection.HTTP_OK;
if (ready) {
System.out.println(
"Let's wait addional 10 seconds before the post-start tasks (like creation of admin user) on container are done.");
Thread.sleep(10000L);
}
return ready;
} catch (Exception ex) {
return false;
}
}

}
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@

<!-- Using JUnit @Category to dynamically select executed test groups, based on multiple factors (e.g.: regular vs. bootable and Linux vs. Windows executions -->
<current-execution.excluded-groups></current-execution.excluded-groups>
<version.arquillian-cube>2.1.0.Alpha2</version.arquillian-cube>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -164,6 +165,23 @@
<version>${version.org.wildfly.arquillian}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-bom</artifactId>
<version>${version.arquillian-cube}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-docker-ftest-containerobject</artifactId>
<version>${version.arquillian-cube}</version>
</dependency>
<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-docker-ftest-containerobject-dsl</artifactId>
<version>${version.arquillian-cube}</version>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-dist</artifactId>
Expand Down
Loading