diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
index ed4ce6c6774..d414e8dc6e0 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
@@ -271,7 +271,8 @@ public class GroupAdapter implements GroupModel {
@Override
public Long getSubGroupsCount() {
if (isUpdated()) return updated.getSubGroupsCount();
- return getGroupModel().getSubGroupsCount();
+ GroupModel model = modelSupplier.get();
+ return model == null ? null : model.getSubGroupsCount();
}
@Override
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java
index a7024010e49..4345d256ce4 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java
@@ -58,6 +58,7 @@ public class CachedGroup extends AbstractRevisioned implements InRealm {
this.type = group.getType();
}
+ @Override
public String getRealm() {
return realm;
}
diff --git a/services/src/main/java/org/keycloak/utils/GroupUtils.java b/services/src/main/java/org/keycloak/utils/GroupUtils.java
index 3c0495192b5..68343a2f059 100644
--- a/services/src/main/java/org/keycloak/utils/GroupUtils.java
+++ b/services/src/main/java/org/keycloak/utils/GroupUtils.java
@@ -98,14 +98,4 @@ public class GroupUtils {
rep.setAccess(groupsEvaluator.getAccess(groupTree));
return rep;
}
-
- private static boolean groupMatchesSearchOrIsPathElement(GroupModel group, String search) {
- if (StringUtil.isBlank(search)) {
- return true;
- }
- if (group.getName().contains(search)) {
- return true;
- }
- return group.getSubGroupsStream().findAny().isPresent();
- }
}
diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/group/GroupTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/group/GroupTest.java
index d20a12cac8f..92d5ec172ce 100755
--- a/tests/base/src/test/java/org/keycloak/tests/admin/group/GroupTest.java
+++ b/tests/base/src/test/java/org/keycloak/tests/admin/group/GroupTest.java
@@ -25,6 +25,7 @@ import jakarta.ws.rs.core.Response.Status;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.keycloak.admin.client.Keycloak;
@@ -76,6 +77,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.IntStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anEmptyMap;
@@ -90,6 +94,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Marko Strukelj
@@ -109,6 +114,49 @@ public class GroupTest extends AbstractGroupTest {
@InjectHttpClient
CloseableHttpClient httpClient;
+
+ @Test
+ public void createMultiDeleteMultiReadMulti() {
+ // create multiple groups
+ List groupUuuids = new ArrayList<>();
+ IntStream.range(0, 100).forEach(groupIndex -> {
+ GroupRepresentation group = new GroupRepresentation();
+ group.setName("Test Group " + groupIndex);
+ try (Response response = managedRealm.admin().groups().add(group)) {
+ boolean created = response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL;
+ if (created) {
+ final String groupUuid = ApiUtil.getCreatedId(response);
+ groupUuuids.add(groupUuid);
+ } else {
+ fail("Failed to create group: " + response.getStatusInfo().getReasonPhrase());
+ }
+ }
+ });
+
+ AtomicBoolean deletedAll = new AtomicBoolean(false);
+ List caughtExceptions = new CopyOnWriteArrayList<>();
+ // read groups in a separate thread
+ new Thread(() -> {
+ while (!deletedAll.get()) {
+ try {
+ // just loading briefs
+ managedRealm.admin().groups().groups(null, 0, Integer.MAX_VALUE, true);
+ } catch (Exception e) {
+
+ caughtExceptions.add(e);
+ }
+ }
+ }).start();
+
+ // delete groups
+ groupUuuids.forEach(groupUuid -> {
+ managedRealm.admin().groups().group(groupUuid).remove();
+ });
+ deletedAll.set(true);
+
+ assertThat(caughtExceptions, Matchers.empty());
+ }
+
// KEYCLOAK-2716 Can't delete client if its role is assigned to a group
@Test
public void testClientRemoveWithClientRoleGroupMapping() {