From 65a840be3d2a6406b27ed594267ffb8b71433cfa Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Tue, 16 Feb 2016 18:57:12 +0100 Subject: [PATCH] KEYCLOAK-1678 added invalidation tests for groups and roles, added mroe update tests for realm --- .../org/keycloak/testsuite/admin/ApiUtil.java | 41 ++++-- .../cluster/AbstractClusterTest.java | 2 +- .../AbstractInvalidationClusterTest.java | 59 +++++--- ...tInvalidationClusterTestWithTestRealm.java | 2 +- .../ClientInvalidationClusterTest.java | 28 ++-- .../cluster/GroupInvalidationClusterTest.java | 136 ++++++++++++++++++ .../cluster/RealmInvalidationClusterTest.java | 82 +++++++---- .../cluster/RoleInvalidationClusterTest.java | 86 +++++++++++ .../cluster/UserInvalidationClusterTest.java | 30 ++-- 9 files changed, 386 insertions(+), 80 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java index b7af504488..275fd9ca63 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java @@ -30,8 +30,10 @@ import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.apache.commons.lang.builder.EqualsBuilder; import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD; +import org.keycloak.representations.idm.GroupRepresentation; /** * Created by st on 28.05.15. @@ -39,7 +41,7 @@ import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD public class ApiUtil { private static final Logger log = Logger.getLogger(ApiUtil.class); - + public static String getCreatedId(Response response) { URI location = response.getLocation(); if (location == null) { @@ -48,7 +50,7 @@ public class ApiUtil { String path = location.getPath(); return path.substring(path.lastIndexOf('/') + 1); } - + public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) { for (ClientRepresentation c : realm.clients().findAll()) { if (c.getClientId().equals(clientId)) { @@ -57,7 +59,7 @@ public class ApiUtil { } return null; } - + public static ClientResource findClientResourceByName(RealmResource realm, String name) { for (ClientRepresentation c : realm.clients().findAll()) { if (c.getName().equals(name)) { @@ -66,7 +68,7 @@ public class ApiUtil { } return null; } - + public static ClientRepresentation findClientByClientId(RealmResource realm, String clientId) { ClientRepresentation client = null; for (ClientRepresentation c : realm.clients().findAll()) { @@ -76,7 +78,7 @@ public class ApiUtil { } return client; } - + public static UserRepresentation findUserByUsername(RealmResource realm, String username) { UserRepresentation user = null; List ur = realm.users().search(username, null, null); @@ -85,7 +87,7 @@ public class ApiUtil { } return user; } - + public static String createUserWithAdminClient(RealmResource realm, UserRepresentation user) { Response response = realm.users().create(user); String createdId = getCreatedId(response); @@ -98,7 +100,7 @@ public class ApiUtil { resetUserPassword(realm.users().get(id), password, false); return id; } - + public static void resetUserPassword(UserResource userResource, String newPassword, boolean temporary) { CredentialRepresentation newCredential = new CredentialRepresentation(); newCredential.setType(PASSWORD); @@ -106,7 +108,7 @@ public class ApiUtil { newCredential.setTemporary(temporary); userResource.resetPassword(newCredential); } - + public static void assignClientRoles(RealmResource realm, String userId, String clientName, String... roles) { String realmName = realm.toRepresentation().getRealm(); String clientId = ""; @@ -118,21 +120,32 @@ public class ApiUtil { if (!clientId.isEmpty()) { ClientResource clientResource = realm.clients().get(clientId); - + List roleRepresentations = new ArrayList<>(); for (String roleName : roles) { RoleRepresentation role = clientResource.roles().get(roleName).toRepresentation(); roleRepresentations.add(role); } - + UserResource userResource = realm.users().get(userId); - log.debug("assigning roles: " + Arrays.toString(roles) + " to user: \"" + - userResource.toRepresentation().getUsername() + "\" of client: \"" + - clientName + "\" in realm: \"" + realmName + "\""); + log.debug("assigning roles: " + Arrays.toString(roles) + " to user: \"" + + userResource.toRepresentation().getUsername() + "\" of client: \"" + + clientName + "\" in realm: \"" + realmName + "\""); userResource.roles().clientLevel(clientId).add(roleRepresentations); } else { log.warn("client with name " + clientName + "doesn't exist in realm " + realmName); } } - + + public static boolean groupContainsSubgroup(GroupRepresentation group, GroupRepresentation subgroup) { + boolean contains = false; + for (GroupRepresentation sg : group.getSubGroups()) { + if (subgroup.getId().equals(sg.getId())) { + contains = true; + break; + } + } + return contains; + } + } 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 f54e15b529..24b505aa5a 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 @@ -78,7 +78,7 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest { protected ContainerInfo frontendNode() { return suiteContext.getAuthServerInfo(); } - + protected ContainerInfo backendNode(int i) { return suiteContext.getAuthServerBackendsInfo().get(i); } 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 index c129bbe4d0..89ac45027a 100644 --- 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 @@ -1,9 +1,8 @@ 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.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.ReflectionToStringBuilder; @@ -16,18 +15,14 @@ import org.keycloak.testsuite.arquillian.ContainerInfo; /** * * @author tkyjovsk + * @param entity representation + * @param entity resource */ -public abstract class AbstractInvalidationClusterTest extends AbstractClusterTest { - - private final SecureRandom random = new SecureRandom(); - - protected String randomString(int length) { - return new BigInteger(130, random).toString(length); - } +public abstract class AbstractInvalidationClusterTest extends AbstractClusterTest { protected RealmRepresentation createTestRealmRepresentation() { RealmRepresentation testRealm = new RealmRepresentation(); - testRealm.setRealm("test_" + randomString(5)); + testRealm.setRealm("test_" + RandomStringUtils.randomAlphabetic(5)); testRealm.setEnabled(true); return testRealm; } @@ -72,6 +67,10 @@ public abstract class AbstractInvalidationClusterTest extends AbstractCluster assertEntityOnSurvivorNodesIsDeleted(testEntity); } + protected abstract TR entityResource(T testEntity, ContainerInfo node); + + protected abstract TR entityResource(String idOrName, ContainerInfo node); + protected abstract T createEntity(T testEntity, ContainerInfo node); protected abstract T readEntity(T entity, ContainerInfo node); @@ -80,20 +79,36 @@ public abstract class AbstractInvalidationClusterTest extends AbstractCluster protected abstract void deleteEntity(T testEntity, ContainerInfo node); - protected T createEntityOnCurrentFailNode(T testEntity) { - return createEntity(testEntity, getCurrentFailNode()); + protected TR entityResourceOnCurrentFailNode(T testEntity) { + return entityResource(testEntity, getCurrentFailNode()); + } + + protected String getEntityType(T entity) { + return entity.getClass().getSimpleName().replace("Representation", ""); + } + + protected T createEntityOnCurrentFailNode(T entity) { + log.info("Creating " + getEntityType(entity) + " on " + getCurrentFailNode()); + return createEntity(entity, getCurrentFailNode()); } protected T readEntityOnCurrentFailNode(T entity) { + log.debug("Reading " + getEntityType(entity) + " on " + getCurrentFailNode()); return readEntity(entity, getCurrentFailNode()); } protected T updateEntityOnCurrentFailNode(T entity) { + return updateEntityOnCurrentFailNode(entity, ""); + } + + protected T updateEntityOnCurrentFailNode(T entity, String updateType) { + log.info("Updating " + getEntityType(entity) + " " + updateType + " on " + getCurrentFailNode()); return updateEntity(entity, getCurrentFailNode()); } - protected void deleteEntityOnCurrentFailNode(T testEntity) { - deleteEntity(testEntity, getCurrentFailNode()); + protected void deleteEntityOnCurrentFailNode(T entity) { + log.info("Creating " + getEntityType(entity) + " on " + getCurrentFailNode()); + deleteEntity(entity, getCurrentFailNode()); } protected abstract T testEntityUpdates(T testEntity, boolean backendFailover); @@ -116,15 +131,17 @@ public abstract class AbstractInvalidationClusterTest extends AbstractCluster for (ContainerInfo survivorNode : getCurrentSurvivorNodes()) { T testEntityOnSurvivorNode = readEntity(testEntityOnFailNode, survivorNode); if (EqualsBuilder.reflectionEquals(testEntityOnSurvivorNode, testEntityOnFailNode, excludedComparisonFields)) { - log.info("Verification on survivor " + survivorNode + " PASSED"); + log.info(String.format("Verification of %s on survivor %s PASSED", getEntityType(testEntityOnFailNode), survivorNode)); } else { entityDiffers = true; - log.error("Verification on survivor " + survivorNode + " FAILED"); + log.error(String.format("Verification of %s on survivor %s FAILED", getEntityType(testEntityOnFailNode), survivorNode)); 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"); + log.error(String.format( + "\nEntity on fail node: \n%s\n" + + "\nEntity on survivor node: \n%s\n" + + "\nDifference: \n%s\n", + tf, ts, StringUtils.difference(tf, ts))); } } assertFalse(entityDiffers); @@ -136,10 +153,10 @@ public abstract class AbstractInvalidationClusterTest extends AbstractCluster for (ContainerInfo survivorNode : getCurrentSurvivorNodes()) { T testEntityOnSurvivorNode = readEntity(testEntityOnFailNode, survivorNode); if (testEntityOnSurvivorNode == null) { - log.info("Verification of deletion on survivor " + survivorNode + " PASSED"); + log.info(String.format("Verification of %s deletion on survivor %s PASSED", getEntityType(testEntityOnFailNode), survivorNode)); } else { entityExists = true; - log.error("Verification of deletion on survivor " + survivorNode + " FAILED"); + log.error(String.format("Verification of %s deletion on survivor %s FAILED", getEntityType(testEntityOnFailNode), survivorNode)); } } 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 index a2e2013898..0fe6c0df66 100644 --- 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 @@ -8,7 +8,7 @@ import org.keycloak.testsuite.arquillian.ContainerInfo; * * @author tkyjovsk */ -public abstract class AbstractInvalidationClusterTestWithTestRealm extends AbstractInvalidationClusterTest { +public abstract class AbstractInvalidationClusterTestWithTestRealm extends AbstractInvalidationClusterTest { protected String testRealmName = null; 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 index f654260fdd..506b626619 100644 --- 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 @@ -2,8 +2,10 @@ package org.keycloak.testsuite.cluster; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; +import org.apache.commons.lang.RandomStringUtils; import static org.junit.Assert.assertNull; import org.junit.Before; +import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.testsuite.admin.ApiUtil; @@ -13,7 +15,7 @@ import org.keycloak.testsuite.arquillian.ContainerInfo; * * @author tkyjovsk */ -public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { +public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { @Before public void setExcludedComparisonFields() { @@ -23,7 +25,7 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe @Override protected ClientRepresentation createTestEntityRepresentation() { ClientRepresentation client = new ClientRepresentation(); - String s = randomString(5); + String s = RandomStringUtils.randomAlphabetic(5); client.setClientId("client_" + s); client.setName("name_" + s); return client; @@ -33,6 +35,16 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe return getAdminClientFor(node).realm(testRealmName).clients(); } + @Override + protected ClientResource entityResource(ClientRepresentation client, ContainerInfo node) { + return entityResource(client.getId(), node); + } + + @Override + protected ClientResource entityResource(String id, ContainerInfo node) { + return clients(node).get(id); + } + @Override protected ClientRepresentation createEntity(ClientRepresentation client, ContainerInfo node) { Response response = clients(node).create(client); @@ -46,22 +58,22 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe protected ClientRepresentation readEntity(ClientRepresentation client, ContainerInfo node) { ClientRepresentation u = null; try { - u = clients(node).get(client.getId()).toRepresentation(); + u = entityResource(client, node).toRepresentation(); } catch (NotFoundException nfe) { - // exoected when client doesn't exist + // expected when client doesn't exist } return u; } @Override protected ClientRepresentation updateEntity(ClientRepresentation client, ContainerInfo node) { - clients(node).get(client.getId()).update(client); + entityResource(client, node).update(client); return readEntity(client, node); } @Override protected void deleteEntity(ClientRepresentation client, ContainerInfo node) { - clients(node).get(client.getId()).remove(); + entityResource(client, node).remove(); assertNull(readEntity(client, node)); } @@ -70,12 +82,12 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe // clientId client.setClientId(client.getClientId() + "_updated"); - client = updateEntity(client, getCurrentFailNode()); + client = updateEntityOnCurrentFailNode(client, "clientId"); verifyEntityUpdateDuringFailover(client, backendFailover); // name client.setName(client.getName() + "_updated"); - client = updateEntity(client, getCurrentFailNode()); + client = updateEntityOnCurrentFailNode(client, "name"); verifyEntityUpdateDuringFailover(client, backendFailover); return client; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java new file mode 100644 index 0000000000..4b9495aa04 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java @@ -0,0 +1,136 @@ +package org.keycloak.testsuite.cluster; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.Response; +import org.apache.commons.lang.RandomStringUtils; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.keycloak.admin.client.resource.GroupResource; +import org.keycloak.admin.client.resource.GroupsResource; +import org.keycloak.representations.idm.GroupRepresentation; +import org.keycloak.testsuite.admin.ApiUtil; +import org.keycloak.testsuite.arquillian.ContainerInfo; + +/** + * + * @author tkyjovsk + */ +public class GroupInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { + + @Before + public void setExcludedComparisonFields() { + excludedComparisonFields.add("subGroups"); + } + + @Override + protected GroupRepresentation createTestEntityRepresentation() { + GroupRepresentation group = new GroupRepresentation(); + group.setName("group_" + RandomStringUtils.randomAlphabetic(5)); + group.setAttributes(new HashMap>()); + group.getAttributes().put("attr1", Arrays.asList(new String[]{"attr1 value"})); + group.getAttributes().put("attr2", Arrays.asList(new String[]{"attr2 value", "attr2 value2"})); + return group; + } + + protected GroupsResource groups(ContainerInfo node) { + return getAdminClientFor(node).realm(testRealmName).groups(); + } + + @Override + protected GroupResource entityResource(GroupRepresentation group, ContainerInfo node) { + return entityResource(group.getId(), node); + } + + @Override + protected GroupResource entityResource(String id, ContainerInfo node) { + return groups(node).group(id); + } + + @Override + protected GroupRepresentation createEntity(GroupRepresentation group, ContainerInfo node) { + Response response = groups(node).add(group); + String id = ApiUtil.getCreatedId(response); + response.close(); + group.setId(id); + return readEntity(group, node); + } + + @Override + protected GroupRepresentation readEntity(GroupRepresentation group, ContainerInfo node) { + GroupRepresentation u = null; + try { + u = entityResource(group, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected when group doesn't exist + } + return u; + } + + @Override + protected GroupRepresentation updateEntity(GroupRepresentation group, ContainerInfo node) { + entityResource(group, node).update(group); + return readEntity(group, node); + } + + @Override + protected void deleteEntity(GroupRepresentation group, ContainerInfo node) { + entityResource(group, node).remove(); + assertNull(readEntity(group, node)); + } + + @Override + protected GroupRepresentation testEntityUpdates(GroupRepresentation group, boolean backendFailover) { + + // groupname + group.setName(group.getName() + "_updated"); + group = updateEntityOnCurrentFailNode(group, "name"); + verifyEntityUpdateDuringFailover(group, backendFailover); + + // attributes - add new + group.getAttributes().put("attr3", Arrays.asList(new String[]{"attr3 value"})); + group = updateEntityOnCurrentFailNode(group, "attributes - adding"); + verifyEntityUpdateDuringFailover(group, backendFailover); + + // attributes - remove + group.getAttributes().remove("attr3"); + group = updateEntityOnCurrentFailNode(group, "attributes - removing"); + verifyEntityUpdateDuringFailover(group, backendFailover); + + // attributes - update 1 + group.getAttributes().get("attr1").set(0, + group.getAttributes().get("attr1").get(0) + " - updated"); + group = updateEntityOnCurrentFailNode(group, "attributes"); + verifyEntityUpdateDuringFailover(group, backendFailover); + + // attributes - update 2 + group.getAttributes().get("attr2").set(1, + group.getAttributes().get("attr2").get(1) + " - updated"); + group = updateEntityOnCurrentFailNode(group, "attributes"); + verifyEntityUpdateDuringFailover(group, backendFailover); + + // move + log.info("Updating Group parent on " + getCurrentFailNode()); + GroupRepresentation parentGroup = new GroupRepresentation(); + parentGroup.setName("parent"); + parentGroup = createEntityOnCurrentFailNode(parentGroup); + assertEquals("/" + parentGroup.getName(), parentGroup.getPath()); + + Response r = entityResourceOnCurrentFailNode(parentGroup).subGroup(group); + r.close(); + parentGroup = readEntityOnCurrentFailNode(parentGroup); + group = readEntityOnCurrentFailNode(group); + + assertTrue(ApiUtil.groupContainsSubgroup(parentGroup, group)); + assertEquals(parentGroup.getPath() + "/" + group.getName(), group.getPath()); + + verifyEntityUpdateDuringFailover(group, backendFailover); + + return group; + } + +} 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 index af66a3e823..667dde9e70 100644 --- 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 @@ -1,7 +1,10 @@ package org.keycloak.testsuite.cluster; import javax.ws.rs.NotFoundException; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.RealmsResource; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.arquillian.ContainerInfo; @@ -9,18 +12,30 @@ import org.keycloak.testsuite.arquillian.ContainerInfo; * * @author tkyjovsk */ -public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTest { +public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTest { @Override protected RealmRepresentation createTestEntityRepresentation() { return createTestRealmRepresentation(); } + protected RealmsResource realms(ContainerInfo node) { + return getAdminClientFor(node).realms(); + } + + @Override + protected RealmResource entityResource(RealmRepresentation realm, ContainerInfo node) { + return entityResource(realm.getRealm(), node); + } + + @Override + protected RealmResource entityResource(String name, ContainerInfo node) { + return getAdminClientFor(node).realm(name); + } + @Override protected RealmRepresentation createEntity(RealmRepresentation realm, ContainerInfo node) { - log.info("Creating realm on : " + getCurrentFailNode()); - getAdminClientFor(getCurrentFailNode()).realms().create(realm); - // get created entity + realms(node).create(realm); return readEntity(realm, node); } @@ -28,7 +43,7 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes protected RealmRepresentation readEntity(RealmRepresentation realm, ContainerInfo node) { RealmRepresentation realmOnNode = null; try { - realmOnNode = getAdminClientFor(node).realm(realm.getRealm()).toRepresentation(); + realmOnNode = entityResource(realm, node).toRepresentation(); } catch (NotFoundException nfe) { // expected if realm not found } @@ -37,14 +52,17 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected RealmRepresentation updateEntity(RealmRepresentation realm, ContainerInfo node) { - getAdminClientFor(node).realms().realm(realm.getRealm()).update(realm); + return updateEntity(realm.getRealm(), realm, node); + } + + private RealmRepresentation updateEntity(String realmName, RealmRepresentation realm, ContainerInfo node) { + entityResource(realmName, node).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(); + entityResource(realm, node).remove(); // check if deleted assertNull(readEntity(realm, node)); } @@ -52,28 +70,40 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected RealmRepresentation testEntityUpdates(RealmRepresentation realm, boolean backendFailover) { - realm = updateRealmName(realm, realm.getRealm() + "_updated"); + // realm name + String originalName = realm.getRealm(); + realm.setRealm(realm.getRealm() + "_updated"); + realm = updateEntity(originalName, realm, getCurrentFailNode()); verifyEntityUpdateDuringFailover(realm, backendFailover); - realm = updateRealmEnabled(realm); + // enabled + realm.setEnabled(!realm.isEnabled()); + realm = updateEntityOnCurrentFailNode(realm, "enabled"); verifyEntityUpdateDuringFailover(realm, backendFailover); - + + // public key + realm.setPublicKey("GENERATE"); + realm = updateEntityOnCurrentFailNode(realm, "public key"); + assertNotEquals("GENERATE", realm.getPublicKey()); + verifyEntityUpdateDuringFailover(realm, backendFailover); + + // require ssl + realm.setSslRequired("all"); + realm = updateEntityOnCurrentFailNode(realm, "require ssl"); + verifyEntityUpdateDuringFailover(realm, backendFailover); + + // brute force detection + realm.setBruteForceProtected(!realm.isBruteForceProtected()); + realm = updateEntityOnCurrentFailNode(realm, "brute force"); + verifyEntityUpdateDuringFailover(realm, backendFailover); + + // brute force detection - failure factor + realm.setBruteForceProtected(true); + realm.setFailureFactor(realm.getFailureFactor() + 1); + realm = updateEntityOnCurrentFailNode(realm, "brute force failure factor"); + 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/RoleInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java new file mode 100644 index 0000000000..6ae26950d7 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java @@ -0,0 +1,86 @@ +package org.keycloak.testsuite.cluster; + +import javax.ws.rs.NotFoundException; +import org.apache.commons.lang.RandomStringUtils; +import static org.junit.Assert.assertNull; +import org.keycloak.admin.client.resource.RoleResource; +import org.keycloak.admin.client.resource.RolesResource; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.testsuite.arquillian.ContainerInfo; + +/** + * + * @author tkyjovsk + */ +public class RoleInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { + + @Override + protected RoleRepresentation createTestEntityRepresentation() { + RoleRepresentation role = new RoleRepresentation(); + role.setName("role_" + RandomStringUtils.randomAlphabetic(5)); + role.setComposite(false); + role.setDescription("description of "+role.getName()); + return role; + } + + protected RolesResource roles(ContainerInfo node) { + return getAdminClientFor(node).realm(testRealmName).roles(); + } + + @Override + protected RoleResource entityResource(RoleRepresentation role, ContainerInfo node) { + return entityResource(role.getName(), node); + } + + @Override + protected RoleResource entityResource(String name, ContainerInfo node) { + return roles(node).get(name); + } + + @Override + protected RoleRepresentation createEntity(RoleRepresentation role, ContainerInfo node) { + roles(node).create(role); + return readEntity(role, node); + } + + @Override + protected RoleRepresentation readEntity(RoleRepresentation role, ContainerInfo node) { + RoleRepresentation u = null; + try { + u = entityResource(role, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected when role doesn't exist + } + return u; + } + + @Override + protected RoleRepresentation updateEntity(RoleRepresentation role, ContainerInfo node) { + return updateEntity(role.getName(), role, node); + } + + private RoleRepresentation updateEntity(String roleName, RoleRepresentation role, ContainerInfo node) { + entityResource(roleName, node).update(role); + return readEntity(role, node); + } + + @Override + protected void deleteEntity(RoleRepresentation role, ContainerInfo node) { + entityResource(role, node).remove(); + assertNull(readEntity(role, node)); + } + + @Override + protected RoleRepresentation testEntityUpdates(RoleRepresentation role, boolean backendFailover) { + + // description + role.setDescription(role.getDescription()+"_- updated"); + role = updateEntityOnCurrentFailNode(role, "description"); + verifyEntityUpdateDuringFailover(role, backendFailover); + + // TODO composites + + return role; + } + +} 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 index 3df64987d8..440848e938 100644 --- 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 @@ -2,7 +2,9 @@ package org.keycloak.testsuite.cluster; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; +import org.apache.commons.lang.RandomStringUtils; import static org.junit.Assert.assertNull; +import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.admin.ApiUtil; @@ -12,12 +14,12 @@ import org.keycloak.testsuite.arquillian.ContainerInfo; * * @author tkyjovsk */ -public class UserInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { +public class UserInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm { @Override protected UserRepresentation createTestEntityRepresentation() { String firstName = "user"; - String lastName = randomString(5); + String lastName = RandomStringUtils.randomAlphabetic(5); UserRepresentation user = new UserRepresentation(); user.setUsername(firstName + "_" + lastName); user.setEmail(user.getUsername() + "@email.test"); @@ -30,6 +32,16 @@ public class UserInvalidationClusterTest extends AbstractInvalidationClusterTest return getAdminClientFor(node).realm(testRealmName).users(); } + @Override + protected UserResource entityResource(UserRepresentation user, ContainerInfo node) { + return entityResource(user.getId(), node); + } + + @Override + protected UserResource entityResource(String id, ContainerInfo node) { + return users(node).get(id); + } + @Override protected UserRepresentation createEntity(UserRepresentation user, ContainerInfo node) { Response response = users(node).create(user); @@ -43,37 +55,37 @@ public class UserInvalidationClusterTest extends AbstractInvalidationClusterTest protected UserRepresentation readEntity(UserRepresentation user, ContainerInfo node) { UserRepresentation u = null; try { - u = users(node).get(user.getId()).toRepresentation(); + u = entityResource(user, node).toRepresentation(); } catch (NotFoundException nfe) { - // exoected when user doesn't exist + // expected when user doesn't exist } return u; } @Override protected UserRepresentation updateEntity(UserRepresentation user, ContainerInfo node) { - users(node).get(user.getId()).update(user); + entityResource(user, node).update(user); return readEntity(user, node); } @Override protected void deleteEntity(UserRepresentation user, ContainerInfo node) { - users(node).get(user.getId()).remove(); + entityResource(user, node).remove(); assertNull(readEntity(user, node)); } @Override protected UserRepresentation testEntityUpdates(UserRepresentation user, boolean backendFailover) { - + // username user.setUsername(user.getUsername() + "_updated"); - user = updateEntity(user, getCurrentFailNode()); + user = updateEntityOnCurrentFailNode(user, "username"); verifyEntityUpdateDuringFailover(user, backendFailover); // first+lastName user.setFirstName(user.getFirstName() + "_updated"); user.setLastName(user.getLastName() + "_updated"); - user = updateEntity(user, getCurrentFailNode()); + user = updateEntityOnCurrentFailNode(user, "firstName/lastName"); verifyEntityUpdateDuringFailover(user, backendFailover); return user;