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