keycloak-aplcache
Changes
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java 24(+19 -5)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java 148(+148 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTestWithTestRealm.java 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java 84(+84 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/EntityInvalidationClusterTest.java 134(+0 -134)
Details
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
index 80ed20f..f54e15b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
@@ -2,6 +2,7 @@ package org.keycloak.testsuite.cluster;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.arquillian.container.test.api.ContainerController;
@@ -10,6 +11,7 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.models.Constants;
+import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.ContainerInfo;
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
@@ -38,7 +40,7 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
if (currentFailNodeIndex >= getClusterSize()) {
currentFailNodeIndex = 0;
}
- logCurrentState();
+ logFailoverSetup();
}
protected ContainerInfo getCurrentFailNode() {
@@ -51,7 +53,8 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
return survivors;
}
- protected void logCurrentState() {
+ protected void logFailoverSetup() {
+ log.info("Current failover setup");
boolean started = controller.isStarted(getCurrentFailNode().getQualifier());
log.info("Fail node: " + getCurrentFailNode() + (started ? "" : " (stopped)"));
for (ContainerInfo survivor : getCurrentSurvivorNodes()) {
@@ -72,6 +75,10 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
}
}
+ protected ContainerInfo frontendNode() {
+ return suiteContext.getAuthServerInfo();
+ }
+
protected ContainerInfo backendNode(int i) {
return suiteContext.getAuthServerBackendsInfo().get(i);
}
@@ -101,15 +108,22 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
controller.kill(node.getQualifier());
}
- protected Keycloak getAdminClientFor(ContainerInfo backendNode) {
- return backendAdminClients.get(backendNode);
+ protected Keycloak getAdminClientFor(ContainerInfo node) {
+ return node.equals(suiteContext.getAuthServerInfo())
+ ? adminClient // frontend client
+ : backendAdminClients.get(node);
}
@Before
public void beforeClusterTest() {
failback();
- logCurrentState();
+ logFailoverSetup();
pause(3000);
}
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ // no test realms will be created by the default
+ }
+
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java
new file mode 100644
index 0000000..c129bbe
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java
@@ -0,0 +1,148 @@
+package org.keycloak.testsuite.cluster;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.arquillian.ContainerInfo;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractInvalidationClusterTest<T> extends AbstractClusterTest {
+
+ private final SecureRandom random = new SecureRandom();
+
+ protected String randomString(int length) {
+ return new BigInteger(130, random).toString(length);
+ }
+
+ protected RealmRepresentation createTestRealmRepresentation() {
+ RealmRepresentation testRealm = new RealmRepresentation();
+ testRealm.setRealm("test_" + randomString(5));
+ testRealm.setEnabled(true);
+ return testRealm;
+ }
+
+ protected abstract T createTestEntityRepresentation();
+
+ @Test
+ public void crudWithoutFailover() {
+ crud(false);
+ }
+
+ @Test
+ public void crudWithFailover() {
+ crud(true);
+ }
+
+ public void crud(boolean backendFailover) {
+ T testEntity = createTestEntityRepresentation();
+
+ // CREATE
+ testEntity = createEntityOnCurrentFailNode(testEntity);
+
+ if (backendFailover) {
+ failure();
+ }
+
+ assertEntityOnSurvivorNodesEqualsTo(testEntity);
+
+ failback();
+ iterateCurrentFailNode();
+
+ // UPDATE(s)
+ testEntity = testEntityUpdates(testEntity, backendFailover);
+
+ // DELETE
+ deleteEntityOnCurrentFailNode(testEntity);
+
+ if (backendFailover) {
+ failure();
+ }
+
+ assertEntityOnSurvivorNodesIsDeleted(testEntity);
+ }
+
+ protected abstract T createEntity(T testEntity, ContainerInfo node);
+
+ protected abstract T readEntity(T entity, ContainerInfo node);
+
+ protected abstract T updateEntity(T entity, ContainerInfo node);
+
+ protected abstract void deleteEntity(T testEntity, ContainerInfo node);
+
+ protected T createEntityOnCurrentFailNode(T testEntity) {
+ return createEntity(testEntity, getCurrentFailNode());
+ }
+
+ protected T readEntityOnCurrentFailNode(T entity) {
+ return readEntity(entity, getCurrentFailNode());
+ }
+
+ protected T updateEntityOnCurrentFailNode(T entity) {
+ return updateEntity(entity, getCurrentFailNode());
+ }
+
+ protected void deleteEntityOnCurrentFailNode(T testEntity) {
+ deleteEntity(testEntity, getCurrentFailNode());
+ }
+
+ protected abstract T testEntityUpdates(T testEntity, boolean backendFailover);
+
+ protected void verifyEntityUpdateDuringFailover(T testEntity, boolean backendFailover) {
+ if (backendFailover) {
+ failure();
+ }
+
+ assertEntityOnSurvivorNodesEqualsTo(testEntity);
+
+ failback();
+ iterateCurrentFailNode();
+ }
+
+ protected List<String> excludedComparisonFields = new ArrayList<>();
+
+ protected void assertEntityOnSurvivorNodesEqualsTo(T testEntityOnFailNode) {
+ boolean entityDiffers = false;
+ for (ContainerInfo survivorNode : getCurrentSurvivorNodes()) {
+ T testEntityOnSurvivorNode = readEntity(testEntityOnFailNode, survivorNode);
+ if (EqualsBuilder.reflectionEquals(testEntityOnSurvivorNode, testEntityOnFailNode, excludedComparisonFields)) {
+ log.info("Verification on survivor " + survivorNode + " PASSED");
+ } else {
+ entityDiffers = true;
+ log.error("Verification on survivor " + survivorNode + " FAILED");
+ String tf = ReflectionToStringBuilder.reflectionToString(testEntityOnFailNode, ToStringStyle.SHORT_PREFIX_STYLE);
+ String ts = ReflectionToStringBuilder.reflectionToString(testEntityOnSurvivorNode, ToStringStyle.SHORT_PREFIX_STYLE);
+ log.error("\nEntity on fail node: \n\n" + tf + "\n"
+ + "\nEntity on survivor node: \n" + ts + "\n"
+ + "\nDifference: \n" + StringUtils.difference(tf, ts) + "\n");
+ }
+ }
+ assertFalse(entityDiffers);
+ }
+
+ private void assertEntityOnSurvivorNodesIsDeleted(T testEntityOnFailNode) {
+ // check if deleted from all survivor nodes
+ boolean entityExists = false;
+ for (ContainerInfo survivorNode : getCurrentSurvivorNodes()) {
+ T testEntityOnSurvivorNode = readEntity(testEntityOnFailNode, survivorNode);
+ if (testEntityOnSurvivorNode == null) {
+ log.info("Verification of deletion on survivor " + survivorNode + " PASSED");
+ } else {
+ entityExists = true;
+ log.error("Verification of deletion on survivor " + survivorNode + " FAILED");
+ }
+ }
+ assertFalse(entityExists);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTestWithTestRealm.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTestWithTestRealm.java
new file mode 100644
index 0000000..a2e2013
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTestWithTestRealm.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.cluster;
+
+import org.junit.Before;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.arquillian.ContainerInfo;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractInvalidationClusterTestWithTestRealm<T> extends AbstractInvalidationClusterTest<T> {
+
+ protected String testRealmName = null;
+
+ @Before
+ public void createTestRealm() {
+ createTestRealm(frontendNode());
+ }
+
+ protected void createTestRealm(ContainerInfo node) {
+ RealmRepresentation r = createTestRealmRepresentation();
+ getAdminClientFor(node).realms().create(r);
+ testRealmName = r.getRealm();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java
new file mode 100644
index 0000000..f654260
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java
@@ -0,0 +1,84 @@
+package org.keycloak.testsuite.cluster;
+
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.core.Response;
+import static org.junit.Assert.assertNull;
+import org.junit.Before;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.arquillian.ContainerInfo;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm<ClientRepresentation> {
+
+ @Before
+ public void setExcludedComparisonFields() {
+ excludedComparisonFields.add("protocolMappers");
+ }
+
+ @Override
+ protected ClientRepresentation createTestEntityRepresentation() {
+ ClientRepresentation client = new ClientRepresentation();
+ String s = randomString(5);
+ client.setClientId("client_" + s);
+ client.setName("name_" + s);
+ return client;
+ }
+
+ protected ClientsResource clients(ContainerInfo node) {
+ return getAdminClientFor(node).realm(testRealmName).clients();
+ }
+
+ @Override
+ protected ClientRepresentation createEntity(ClientRepresentation client, ContainerInfo node) {
+ Response response = clients(node).create(client);
+ String id = ApiUtil.getCreatedId(response);
+ response.close();
+ client.setId(id);
+ return readEntity(client, node);
+ }
+
+ @Override
+ protected ClientRepresentation readEntity(ClientRepresentation client, ContainerInfo node) {
+ ClientRepresentation u = null;
+ try {
+ u = clients(node).get(client.getId()).toRepresentation();
+ } catch (NotFoundException nfe) {
+ // exoected when client doesn't exist
+ }
+ return u;
+ }
+
+ @Override
+ protected ClientRepresentation updateEntity(ClientRepresentation client, ContainerInfo node) {
+ clients(node).get(client.getId()).update(client);
+ return readEntity(client, node);
+ }
+
+ @Override
+ protected void deleteEntity(ClientRepresentation client, ContainerInfo node) {
+ clients(node).get(client.getId()).remove();
+ assertNull(readEntity(client, node));
+ }
+
+ @Override
+ protected ClientRepresentation testEntityUpdates(ClientRepresentation client, boolean backendFailover) {
+
+ // clientId
+ client.setClientId(client.getClientId() + "_updated");
+ client = updateEntity(client, getCurrentFailNode());
+ verifyEntityUpdateDuringFailover(client, backendFailover);
+
+ // name
+ client.setName(client.getName() + "_updated");
+ client = updateEntity(client, getCurrentFailNode());
+ verifyEntityUpdateDuringFailover(client, backendFailover);
+
+ return client;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java
new file mode 100644
index 0000000..af66a3e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java
@@ -0,0 +1,79 @@
+package org.keycloak.testsuite.cluster;
+
+import javax.ws.rs.NotFoundException;
+import static org.junit.Assert.assertNull;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.arquillian.ContainerInfo;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTest<RealmRepresentation> {
+
+ @Override
+ protected RealmRepresentation createTestEntityRepresentation() {
+ return createTestRealmRepresentation();
+ }
+
+ @Override
+ protected RealmRepresentation createEntity(RealmRepresentation realm, ContainerInfo node) {
+ log.info("Creating realm on : " + getCurrentFailNode());
+ getAdminClientFor(getCurrentFailNode()).realms().create(realm);
+ // get created entity
+ return readEntity(realm, node);
+ }
+
+ @Override
+ protected RealmRepresentation readEntity(RealmRepresentation realm, ContainerInfo node) {
+ RealmRepresentation realmOnNode = null;
+ try {
+ realmOnNode = getAdminClientFor(node).realm(realm.getRealm()).toRepresentation();
+ } catch (NotFoundException nfe) {
+ // expected if realm not found
+ }
+ return realmOnNode;
+ }
+
+ @Override
+ protected RealmRepresentation updateEntity(RealmRepresentation realm, ContainerInfo node) {
+ getAdminClientFor(node).realms().realm(realm.getRealm()).update(realm);
+ return readEntity(realm, node);
+ }
+
+ @Override
+ protected void deleteEntity(RealmRepresentation realm, ContainerInfo node) {
+ log.info("Deleting realm on: " + getCurrentFailNode());
+ getAdminClientFor(node).realms().realm(realm.getRealm()).remove();
+ // check if deleted
+ assertNull(readEntity(realm, node));
+ }
+
+ @Override
+ protected RealmRepresentation testEntityUpdates(RealmRepresentation realm, boolean backendFailover) {
+
+ realm = updateRealmName(realm, realm.getRealm() + "_updated");
+ verifyEntityUpdateDuringFailover(realm, backendFailover);
+
+ realm = updateRealmEnabled(realm);
+ verifyEntityUpdateDuringFailover(realm, backendFailover);
+
+ return realm;
+ }
+
+ protected RealmRepresentation updateRealmName(RealmRepresentation realm, String newName) {
+ log.info("Updating realm on: " + getCurrentFailNode());
+ String originalName = realm.getRealm();
+ realm.setRealm(newName);
+
+ getAdminClientFor(getCurrentFailNode()).realms().realm(originalName).update(realm);
+ return readEntity(realm, getCurrentFailNode());
+ }
+
+ protected RealmRepresentation updateRealmEnabled(RealmRepresentation realm) {
+ log.info("Updating realm on: " + getCurrentFailNode());
+ realm.setEnabled(!realm.isEnabled());
+ return updateEntity(realm, getCurrentFailNode());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/UserInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/UserInvalidationClusterTest.java
new file mode 100644
index 0000000..3df6498
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/UserInvalidationClusterTest.java
@@ -0,0 +1,82 @@
+package org.keycloak.testsuite.cluster;
+
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.core.Response;
+import static org.junit.Assert.assertNull;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.arquillian.ContainerInfo;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm<UserRepresentation> {
+
+ @Override
+ protected UserRepresentation createTestEntityRepresentation() {
+ String firstName = "user";
+ String lastName = randomString(5);
+ UserRepresentation user = new UserRepresentation();
+ user.setUsername(firstName + "_" + lastName);
+ user.setEmail(user.getUsername() + "@email.test");
+ user.setFirstName(firstName);
+ user.setLastName(lastName);
+ return user;
+ }
+
+ protected UsersResource users(ContainerInfo node) {
+ return getAdminClientFor(node).realm(testRealmName).users();
+ }
+
+ @Override
+ protected UserRepresentation createEntity(UserRepresentation user, ContainerInfo node) {
+ Response response = users(node).create(user);
+ String id = ApiUtil.getCreatedId(response);
+ response.close();
+ user.setId(id);
+ return readEntity(user, node);
+ }
+
+ @Override
+ protected UserRepresentation readEntity(UserRepresentation user, ContainerInfo node) {
+ UserRepresentation u = null;
+ try {
+ u = users(node).get(user.getId()).toRepresentation();
+ } catch (NotFoundException nfe) {
+ // exoected when user doesn't exist
+ }
+ return u;
+ }
+
+ @Override
+ protected UserRepresentation updateEntity(UserRepresentation user, ContainerInfo node) {
+ users(node).get(user.getId()).update(user);
+ return readEntity(user, node);
+ }
+
+ @Override
+ protected void deleteEntity(UserRepresentation user, ContainerInfo node) {
+ users(node).get(user.getId()).remove();
+ assertNull(readEntity(user, node));
+ }
+
+ @Override
+ protected UserRepresentation testEntityUpdates(UserRepresentation user, boolean backendFailover) {
+
+ // username
+ user.setUsername(user.getUsername() + "_updated");
+ user = updateEntity(user, getCurrentFailNode());
+ verifyEntityUpdateDuringFailover(user, backendFailover);
+
+ // first+lastName
+ user.setFirstName(user.getFirstName() + "_updated");
+ user.setLastName(user.getLastName() + "_updated");
+ user = updateEntity(user, getCurrentFailNode());
+ verifyEntityUpdateDuringFailover(user, backendFailover);
+
+ return user;
+ }
+
+}