This is an automated email from the ASF dual-hosted git repository.

enapps-enorman pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-jcr-mock.git


The following commit(s) were added to refs/heads/master by this push:
     new f576fb0  SLING-13177 MockGroup declaredMembers state is lost for new 
session (#43)
f576fb0 is described below

commit f576fb07e8bb7f374aab7ddcf3d79f2d15329f00
Author: Eric Norman <[email protected]>
AuthorDate: Thu Apr 23 10:48:18 2026 -0700

    SLING-13177 MockGroup declaredMembers state is lost for new session (#43)
---
 .../apache/sling/testing/mock/jcr/MockGroup.java   | 74 ++++++++++++++++------
 .../sling/testing/mock/jcr/MockGroupTest.java      | 10 +++
 2 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockGroup.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockGroup.java
index f7d51c7..c3e71e8 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockGroup.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockGroup.java
@@ -20,16 +20,19 @@ package org.apache.sling.testing.mock.jcr;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.Value;
 
 import java.security.Principal;
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.Map;
+import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -37,7 +40,6 @@ import org.jetbrains.annotations.Nullable;
  * Mock {@link Group} implementation.
  */
 class MockGroup extends MockAuthorizable implements Group {
-    private Map<String, Authorizable> declaredMembers = new HashMap<>();
 
     public MockGroup(
             @Nullable String id,
@@ -47,9 +49,29 @@ class MockGroup extends MockAuthorizable implements Group {
         super(id, principal, homeNode, mockUserMgr);
     }
 
+    /**
+     * Convert the declared members property value to a set of ids
+     * @return set of declared member ids (if any)
+     */
+    protected @NotNull Set<String> getDeclaredMembersIds() throws 
RepositoryException {
+        Set<String> memberIds = new LinkedHashSet<>();
+        if (homeNode.hasProperty(UserConstants.REP_MEMBERS)) {
+            for (Value value : 
homeNode.getProperty(UserConstants.REP_MEMBERS).getValues()) {
+                final String id = value.getString();
+                memberIds.add(id);
+            }
+        }
+        return memberIds;
+    }
+
     @Override
     public @NotNull Iterator<Authorizable> getDeclaredMembers() throws 
RepositoryException {
-        return declaredMembers.values().iterator();
+        List<Authorizable> declaredMembers = new ArrayList<>();
+        for (String id : getDeclaredMembersIds()) {
+            final @Nullable Authorizable authorizable = 
mockUserMgr.getAuthorizable(id);
+            declaredMembers.add(authorizable);
+        }
+        return declaredMembers.iterator();
     }
 
     @Override
@@ -88,16 +110,21 @@ class MockGroup extends MockAuthorizable implements Group {
 
     @Override
     public boolean isDeclaredMember(@NotNull Authorizable authorizable) throws 
RepositoryException {
-        return declaredMembers.containsValue(authorizable);
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
+        final @NotNull String authorizableId = authorizable.getID();
+        return declaredMembersIds.contains(authorizableId);
     }
 
     @Override
     public boolean isMember(@NotNull Authorizable authorizable) throws 
RepositoryException {
-        boolean value = declaredMembers.containsValue(authorizable);
+        final @NotNull String authorizableId = authorizable.getID();
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
+        boolean value = declaredMembersIds.contains(authorizableId);
         if (!value) {
             // groups
-            for (Authorizable m : declaredMembers.values()) {
-                if (m.isGroup()) {
+            for (String id : declaredMembersIds) {
+                final @Nullable Authorizable m = 
mockUserMgr.getAuthorizable(id);
+                if (m != null && m.isGroup()) {
                     value = ((Group) m).isDeclaredMember(authorizable);
                 }
                 if (value) {
@@ -110,42 +137,47 @@ class MockGroup extends MockAuthorizable implements Group 
{
 
     @Override
     public boolean addMember(@NotNull Authorizable authorizable) throws 
RepositoryException {
-        boolean added = false;
-        if (!isMember(authorizable)) {
-            declaredMembers.put(authorizable.getID(), authorizable);
-            added = true;
-        }
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
+        final @NotNull String authorizableId = authorizable.getID();
+        boolean added = declaredMembersIds.add(authorizableId);
+        homeNode.setProperty(UserConstants.REP_MEMBERS, 
declaredMembersIds.toArray(String[]::new));
         return added;
     }
 
     @Override
     public @NotNull Set<String> addMembers(@NotNull String... memberIds) 
throws RepositoryException {
         Set<String> added = new HashSet<>();
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
         for (String id : memberIds) {
-            if (!declaredMembers.containsKey(id)) {
-                @Nullable Authorizable authorizable = 
mockUserMgr.getAuthorizable(id);
-                if (authorizable != null) {
-                    addMember(authorizable);
-                    added.add(id);
-                }
+            final @Nullable Authorizable m = mockUserMgr.getAuthorizable(id);
+            if (m != null && declaredMembersIds.add(id)) {
+                added.add(id);
             }
         }
+        homeNode.setProperty(UserConstants.REP_MEMBERS, 
declaredMembersIds.toArray(String[]::new));
         return added;
     }
 
     @Override
     public boolean removeMember(@NotNull Authorizable authorizable) throws 
RepositoryException {
-        return declaredMembers.remove(authorizable.getID(), authorizable);
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
+        final @NotNull String authorizableId = authorizable.getID();
+        boolean removed = declaredMembersIds.remove(authorizableId);
+        homeNode.setProperty(UserConstants.REP_MEMBERS, 
declaredMembersIds.toArray(String[]::new));
+        return removed;
     }
 
     @Override
     public @NotNull Set<String> removeMembers(@NotNull String... memberIds) 
throws RepositoryException {
         Set<String> removed = new HashSet<>();
+        final Set<String> declaredMembersIds = getDeclaredMembersIds();
         for (String id : memberIds) {
-            if (declaredMembers.remove(id) != null) {
+            if (declaredMembersIds.remove(id)) {
                 removed.add(id);
             }
         }
+        homeNode.setProperty(UserConstants.REP_MEMBERS, 
declaredMembersIds.toArray(String[]::new));
+
         return removed;
     }
 
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockGroupTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockGroupTest.java
index b7af412..30d7be8 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockGroupTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockGroupTest.java
@@ -166,6 +166,16 @@ public class MockGroupTest extends 
MockAuthorizableTest<Group> {
 
         authorizable.addMember(member1);
         assertTrue(authorizable.isMember(member2));
+
+        // member of subgroup
+        @NotNull Group member4 = userManager.createGroup("member4");
+        assertFalse(authorizable.isMember(member4));
+        member1.addMember(member4);
+        assertTrue(authorizable.isMember(member4));
+
+        // memberOf contains item that resolves to null authorizable
+        member1.remove();
+        assertFalse(authorizable.isMember(member4));
     }
 
     /**

Reply via email to