Author: angela
Date: Fri Nov 30 14:55:56 2018
New Revision: 1847830

URL: http://svn.apache.org/viewvc?rev=1847830&view=rev
Log:
OAK-7928 : Avoid reference resolution for user query with scope and 
declaredMembersOnly

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicate.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicateTest.java
Modified:
    
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
    
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/FindAuthorizableWithScopeTest.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/UserQueryManager.java

Modified: 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java?rev=1847830&r1=1847829&r2=1847830&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
 Fri Nov 30 14:55:56 2018
@@ -128,7 +128,11 @@ public class BenchmarkRunner {
         OptionSpec<Long> expiration = parser.accepts("expiration", "Expiration 
time (e.g. principal cache.")
                         
.withOptionalArg().ofType(Long.class).defaultsTo(AbstractLoginTest.NO_CACHE);
         OptionSpec<Integer> numberOfGroups = parser.accepts("numberOfGroups", 
"Number of groups to create.")
-                        
.withOptionalArg().ofType(Integer.class).defaultsTo(LoginWithMembershipTest.NUMBER_OF_GROUPS_DEFAULT);
+                
.withOptionalArg().ofType(Integer.class).defaultsTo(LoginWithMembershipTest.NUMBER_OF_GROUPS_DEFAULT);
+        OptionSpec<Integer> queryMaxCount = parser.accepts("queryMaxCount", 
"Max number of query results.")
+                
.withOptionalArg().ofType(Integer.class).defaultsTo(Integer.MAX_VALUE);
+        OptionSpec<Boolean> declaredMembership = 
parser.accepts("declaredMembership", "Only look for declared membership.")
+                .withOptionalArg().ofType(Boolean.class).defaultsTo(true);
         OptionSpec<Integer> numberOfInitialAce = 
parser.accepts("numberOfInitialAce", "Number of ACE to create before running 
the test.")
                 
.withOptionalArg().ofType(Integer.class).defaultsTo(AceCreationTest.NUMBER_OF_INITIAL_ACE_DEFAULT);
         OptionSpec<Boolean> nestedGroups = parser.accepts("nestedGroups", "Use 
nested groups.")
@@ -470,7 +474,7 @@ public class BenchmarkRunner {
                     wikipedia.value(options),
                     flatStructure.value(options),
                     report.value(options), withStorage.value(options), 
withServer.value(options)),
-            new FindAuthorizableWithScopeTest(numberOfUsers.value(options), 
setScope.value(options)),
+            new FindAuthorizableWithScopeTest(numberOfUsers.value(options), 
numberOfGroups.value(options), queryMaxCount.value(options), 
setScope.value(options), declaredMembership.value(options), 
runAsAdmin.value(options)),
             new LucenePropertyFullTextTest(
                 wikipedia.value(options),
                 flatStructure.value(options),

Modified: 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/FindAuthorizableWithScopeTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/FindAuthorizableWithScopeTest.java?rev=1847830&r1=1847829&r2=1847830&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/FindAuthorizableWithScopeTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/FindAuthorizableWithScopeTest.java
 Fri Nov 30 14:55:56 2018
@@ -19,14 +19,19 @@ package org.apache.jackrabbit.oak.benchm
 import java.util.Iterator;
 import javax.jcr.Node;
 import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.Privilege;
 
 import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.Query;
 import org.apache.jackrabbit.api.security.user.QueryBuilder;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
+import 
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.util.Text;
 
@@ -35,37 +40,67 @@ public class FindAuthorizableWithScopeTe
     private static final String GROUP_ID = "testGroup";
 
     private final long numberOfUsers;
+    private final long numberOfMembership;
+    private final long maxCount;
     private final boolean setScope;
+    private final boolean declaredMembership;
+    private final boolean runAsAdmin;
 
-    private Session adminSession;
-    private UserManager userMgr;
+    private JackrabbitSession adminSession;
+    private UserManager testUserManager;
 
-    public FindAuthorizableWithScopeTest(long numberOfUsers, boolean setScope) 
{
+    public FindAuthorizableWithScopeTest(long numberOfUsers, long 
numberOfMembership, int maxCount, boolean setScope, boolean declaredMembership, 
boolean runAsAdmin) {
         this.numberOfUsers = numberOfUsers;
+        this.numberOfMembership = numberOfMembership;
+        this.maxCount = maxCount;
         this.setScope = setScope;
+        this.declaredMembership = declaredMembership;
+        this.runAsAdmin = runAsAdmin;
     }
 
     @Override
     protected void beforeSuite() throws Exception {
-        adminSession = loginWriter();
+        adminSession = (JackrabbitSession) loginWriter();
 
-        userMgr = ((JackrabbitSession) adminSession).getUserManager();
-        Group gr = userMgr.createGroup(GROUP_ID, new PrincipalImpl(GROUP_ID), 
"test");
+        UserManager userManager = adminSession.getUserManager();
+        Group gr = userManager.createGroup(GROUP_ID, new 
PrincipalImpl(GROUP_ID), "test");
+        User u = null;
         for (int i = 0; i < numberOfUsers; i++) {
-            User u = userMgr.createUser("testUser" + i, null, new 
PrincipalImpl("testUser" + i), "test");
+            u = userManager.createUser("testUser" + i, "pw", new 
PrincipalImpl("testUser" + i), "test");
             gr.addMember(u);
         }
+
+        for (int i = 1; i < numberOfMembership; i++) {
+            String id = GROUP_ID + i;
+            Group g = userManager.createGroup(id, new PrincipalImpl(id), 
"test");
+            g.addMember(u);
+        }
+
         adminSession.save();
+
+        if (runAsAdmin) {
+            testUserManager = userManager;
+        } else {
+            JackrabbitAccessControlList acl = 
AccessControlUtils.getAccessControlList(adminSession, "/");
+            if (acl != null) {
+                acl.addEntry(EveryonePrincipal.getInstance(), 
AccessControlUtils.privilegesFromNames(adminSession, Privilege.JCR_READ), true);
+                adminSession.getAccessControlManager().setPolicy("/", acl);
+                adminSession.save();
+            }
+            Session reader = login(new SimpleCredentials(u.getID(), 
"pw".toCharArray()));
+            testUserManager = ((JackrabbitSession) reader).getUserManager();
+        }
     }
 
     @Override
     protected void afterSuite() throws Exception {
-        Authorizable gr = userMgr.getAuthorizable(GROUP_ID);
+        UserManager userManager = adminSession.getUserManager();
+        Authorizable gr = userManager.getAuthorizable(GROUP_ID);
         if (gr != null) {
             Node n = adminSession.getNode(Text.getRelativeParent(gr.getPath(), 
1));
             n.remove();
         }
-        Authorizable u1 = userMgr.getAuthorizable("testUser0");
+        Authorizable u1 = userManager.getAuthorizable("testUser0");
         if (u1 != null) {
             Node n = adminSession.getNode(Text.getRelativeParent(u1.getPath(), 
1));
             n.remove();
@@ -75,7 +110,7 @@ public class FindAuthorizableWithScopeTe
 
     @Override
     protected void runTest() throws Exception {
-        Iterator<Authorizable> result = 
userMgr.findAuthorizables(createQuery());
+        Iterator<Authorizable> result = 
testUserManager.findAuthorizables(createQuery());
 
         while (result.hasNext()) {
             result.next();
@@ -83,19 +118,14 @@ public class FindAuthorizableWithScopeTe
     }
 
     private Query createQuery() {
-        if (setScope) {
-            return new Query() {
-                public <T> void build(QueryBuilder<T> builder) {
-                    builder.nameMatches("testUser");
-                    builder.setScope(GROUP_ID, true);
-                }
-            };
-        } else {
-            return new Query() {
-                public <T> void build(QueryBuilder<T> builder) {
-                    builder.nameMatches("testUser");
+        return new Query() {
+            public <T> void build(QueryBuilder<T> builder) {
+                builder.setLimit(0, maxCount);
+                builder.nameMatches("testUser%");
+                if (setScope) {
+                    builder.setScope(GROUP_ID, declaredMembership);
                 }
-            };
-        }
+            }
+        };
     }
 }
\ No newline at end of file

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicate.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicate.java?rev=1847830&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicate.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicate.java
 Fri Nov 30 14:55:56 2018
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.user;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import javax.jcr.RepositoryException;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Predicate used to filter authorizables based on their declared group 
membership.
+ */
+public class DeclaredMembershipPredicate implements Predicate<Authorizable> {
+
+    static final Logger log = 
LoggerFactory.getLogger(DeclaredMembershipPredicate.class);
+
+    private final MembershipProvider membershipProvider;
+    private final Iterator<String> contentIdIterator;
+    private final Set<String> declaredMemberContentIds = new HashSet<String>();
+
+    public DeclaredMembershipPredicate(UserManagerImpl userManager, String 
groupId) {
+        this.membershipProvider = userManager.getMembershipProvider();
+        Tree groupTree = membershipProvider.getByID(groupId, 
AuthorizableType.GROUP);
+        if (groupTree == null) {
+            contentIdIterator = Iterators.emptyIterator();
+        } else {
+            contentIdIterator = 
membershipProvider.getDeclaredMemberContentIDs(membershipProvider.getByID(groupId,
 AuthorizableType.GROUP));
+        }
+    }
+
+    @Override
+    public boolean apply(@Nullable Authorizable authorizable) {
+        String id = saveGetContentId(authorizable);
+        if (id != null) {
+            if (declaredMemberContentIds.contains(id)) {
+                return true;
+            } else {
+                // not contained in ids that have already been processed => 
look
+                // for occurrence in the remaining iterator entries.
+                while (contentIdIterator.hasNext()) {
+                    String memberContentId = contentIdIterator.next();
+                    if (memberContentId != null) {
+                        declaredMemberContentIds.add(memberContentId);
+                        if (memberContentId.equals(id)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Nullable
+    private String saveGetContentId(@Nullable Authorizable authorizable) {
+        if (authorizable != null) {
+            try {
+                return membershipProvider.getContentID(authorizable.getID());
+            } catch (RepositoryException e) {
+                log.debug("Error while retrieving ID for authorizable {}", 
authorizable, e);
+            }
+        }
+        return null;
+    }
+}

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java?rev=1847830&r1=1847829&r2=1847830&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
 Fri Nov 30 14:55:56 2018
@@ -223,6 +223,11 @@ class MembershipProvider extends Authori
         return getMembers(groupTree, getContentID(groupTree), 
includeInherited, new HashSet<String>());
     }
 
+    @NotNull
+    Iterator<String> getDeclaredMemberContentIDs(@NotNull Tree groupTree) {
+        return getDeclaredMemberReferenceIterator(groupTree);
+    }
+
     /**
      * Returns an iterator over all member paths of the given group.
      *
@@ -296,12 +301,7 @@ class MembershipProvider extends Authori
         }
 
         String contentId = getContentID(authorizableTree);
-        MemberReferenceIterator refs = new MemberReferenceIterator(groupTree) {
-            @Override
-            protected boolean hasProcessedReference(@NotNull String value) {
-                return true;
-            }
-        };
+        MemberReferenceIterator refs = 
getDeclaredMemberReferenceIterator(groupTree);
         return Iterators.contains(refs, contentId);
     }
 
@@ -382,6 +382,15 @@ class MembershipProvider extends Authori
         return writer.removeMembers(groupTree, memberIds);
     }
 
+    private MemberReferenceIterator 
getDeclaredMemberReferenceIterator(@NotNull Tree groupTree) {
+        return new MemberReferenceIterator(groupTree) {
+            @Override
+            protected boolean hasProcessedReference(@NotNull String value) {
+                return true;
+            }
+        };
+    }
+
     /**
      * Iterator that provides member references based on the rep:members 
properties of a underlying tree iterator.
      */

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/UserQueryManager.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/UserQueryManager.java?rev=1847830&r1=1847829&r2=1847830&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/UserQueryManager.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/UserQueryManager.java
 Fri Nov 30 14:55:56 2018
@@ -16,21 +16,17 @@
  */
 package org.apache.jackrabbit.oak.security.user.query;
 
-import static org.apache.jackrabbit.oak.api.QueryEngine.NO_BINDINGS;
-
 import java.text.ParseException;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
-
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterators;
-
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.Query;
@@ -40,6 +36,7 @@ import org.apache.jackrabbit.oak.api.Res
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.security.user.DeclaredMembershipPredicate;
 import org.apache.jackrabbit.oak.security.user.UserManagerImpl;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
@@ -52,6 +49,8 @@ import org.jetbrains.annotations.Nullabl
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.jackrabbit.oak.api.QueryEngine.NO_BINDINGS;
+
 /**
  * Query manager for user specific searches.
  */
@@ -109,9 +108,14 @@ public class UserQueryManager {
         } else {
             // filtering by group name included in query -> enforce offset and 
limit on the result set.
             Iterator<Authorizable> result = findAuthorizables(statement, 
Long.MAX_VALUE, 0, null);
-            Predicate<Authorizable> groupFilter = new 
GroupPredicate(userManager, groupId, builder.isDeclaredMembersOnly());
-            return ResultIterator.create(builder.getOffset(), 
builder.getMaxCount(),
-                    Iterators.filter(result, groupFilter));
+            Predicate<Authorizable> filter;
+            if (builder.isDeclaredMembersOnly()) {
+                filter = new DeclaredMembershipPredicate(userManager, groupId);
+            } else {
+                filter = new GroupPredicate(userManager, groupId, false);
+
+            }
+            return ResultIterator.create(builder.getOffset(), 
builder.getMaxCount(), Iterators.filter(result, filter));
         }
     }
 

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicateTest.java?rev=1847830&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicateTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/DeclaredMembershipPredicateTest.java
 Fri Nov 30 14:55:56 2018
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.user;
+
+import javax.jcr.RepositoryException;
+
+import com.google.common.base.Predicate;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+public class DeclaredMembershipPredicateTest extends AbstractSecurityTest {
+
+    private UserManager userManager;
+
+    private User testUser;
+    private User inheritedMember;
+
+    private Group testMember;
+    private Group testGroup;
+
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        userManager = getUserManager(root);
+
+        testUser = getTestUser();
+        inheritedMember = userManager.createUser("inheritedMember", null);
+
+        testMember = userManager.createGroup("testMember");
+        testMember.addMember(inheritedMember);
+
+        testGroup = userManager.createGroup("testGroup");
+        testGroup.addMember(testMember);
+        testGroup.addMember(testUser);
+
+        root.commit();
+    }
+
+    @Override
+    public void after() throws Exception {
+        try {
+            if (testMember != null) {
+                testMember.remove();
+            }
+            if (inheritedMember != null) {
+                inheritedMember.remove();
+            }
+            if (testGroup != null) {
+                testGroup.remove();
+            }
+            if (root.hasPendingChanges()) {
+                root.commit();
+            }
+        } finally {
+            super.after();
+        }
+    }
+
+    private Predicate<Authorizable> getDeclaredMembershipPredicate(@NotNull 
String id) {
+        return new DeclaredMembershipPredicate((UserManagerImpl) userManager, 
id);
+    }
+
+    @Test
+    public void testUnknownGroupId() throws Exception {
+        String id = "unknownGroupId";
+        assertNull(userManager.getAuthorizable(id));
+
+        Predicate<Authorizable> predicate = getDeclaredMembershipPredicate(id);
+        assertFalse(predicate.apply(testUser));
+        assertFalse(predicate.apply(testGroup));
+        assertFalse(predicate.apply(inheritedMember));
+        assertFalse(predicate.apply(null));
+    }
+
+    @Test
+    public void testUserId() throws Exception {
+        Predicate<Authorizable> predicate = 
getDeclaredMembershipPredicate(testUser.getID());
+        assertFalse(predicate.apply(testUser));
+        assertFalse(predicate.apply(testGroup));
+        assertFalse(predicate.apply(inheritedMember));
+        assertFalse(predicate.apply(null));
+    }
+
+    @Test
+    public void testMembers() throws Exception {
+        Predicate<Authorizable> predicate = 
getDeclaredMembershipPredicate(testGroup.getID());
+        assertTrue(predicate.apply(testMember));
+        assertTrue(predicate.apply(testUser));
+
+        assertFalse(predicate.apply(testGroup));
+        assertFalse(predicate.apply(inheritedMember));
+        assertFalse(predicate.apply(null));
+    }
+
+    @Test
+    public void testApplyTwice() throws Exception {
+        Predicate<Authorizable> predicate = 
getDeclaredMembershipPredicate(testGroup.getID());
+        predicate.apply(testMember);
+        assertTrue(predicate.apply(testMember));
+    }
+
+    @Test
+    public void testApplyTwiceNotMember() throws Exception {
+        Predicate<Authorizable> predicate = 
getDeclaredMembershipPredicate(testGroup.getID());
+        predicate.apply(inheritedMember);
+        assertFalse(predicate.apply(inheritedMember));
+    }
+
+    @Test
+    public void testGetIdFails() throws Exception {
+        Predicate<Authorizable> predicate = 
getDeclaredMembershipPredicate(testGroup.getID());
+
+        Authorizable a = Mockito.mock(Authorizable.class);
+        when(a.getID()).thenThrow(new RepositoryException());
+        assertFalse(predicate.apply(a));
+    }
+}
\ No newline at end of file


Reply via email to