You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by en...@apache.org on 2023/04/20 23:14:13 UTC
[sling-org-apache-sling-testing-jcr-mock] branch master updated: SLING-11830 Provide a basic MockPrincipalManager and MockUserManager (#18)
This is an automated email from the ASF dual-hosted git repository.
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 fd71883 SLING-11830 Provide a basic MockPrincipalManager and MockUserManager (#18)
fd71883 is described below
commit fd71883a6a9e1db741f1b7196c6b9639aea8fc50
Author: Eric Norman <en...@apache.org>
AuthorDate: Thu Apr 20 16:14:08 2023 -0700
SLING-11830 Provide a basic MockPrincipalManager and MockUserManager (#18)
---
pom.xml | 11 +
.../sling/testing/mock/jcr/MockAuthorizable.java | 182 +++++++++++
.../apache/sling/testing/mock/jcr/MockGroup.java | 156 +++++++++
.../testing/mock/jcr/MockPrincipalManager.java | 160 +++++++++
.../apache/sling/testing/mock/jcr/MockSession.java | 57 +++-
.../apache/sling/testing/mock/jcr/MockUser.java | 125 +++++++
.../sling/testing/mock/jcr/MockUserManager.java | 235 +++++++++++++
.../apache/sling/testing/mock/jcr/LogCapture.java | 91 ++++++
.../testing/mock/jcr/MockAuthorizableTest.java | 250 ++++++++++++++
.../sling/testing/mock/jcr/MockGroupTest.java | 245 ++++++++++++++
.../testing/mock/jcr/MockPrincipalManagerTest.java | 362 +++++++++++++++++++++
.../sling/testing/mock/jcr/MockSessionTest.java | 67 ++++
.../testing/mock/jcr/MockUserManagerTest.java | 344 ++++++++++++++++++++
.../sling/testing/mock/jcr/MockUserTest.java | 191 +++++++++++
src/test/resources/logback-test.xml | 30 ++
15 files changed, 2505 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 98bf0f6..ab6c021 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,11 @@
<artifactId>jcr</artifactId>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
@@ -115,6 +120,12 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockAuthorizable.java b/src/main/java/org/apache/sling/testing/mock/jcr/MockAuthorizable.java
new file mode 100644
index 0000000..e8be563
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockAuthorizable.java
@@ -0,0 +1,182 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import java.nio.file.Paths;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Mock {@link Authorizable} implementation.
+ */
+abstract class MockAuthorizable implements Authorizable {
+ static final String REP_PRINCIPAL_NAME = "rep:principalName";
+ protected String id;
+ protected Principal principal;
+ protected String path;
+ protected MockUserManager mockUserMgr;
+ protected Map<String, Value[]> propsMap = new HashMap<>();
+ protected Set<Group> declaredMemberOf = new HashSet<>();
+
+ MockAuthorizable(@Nullable String id, @Nullable Principal principal,
+ @Nullable String intermediatePath,
+ @NotNull MockUserManager mockUserMgr) {
+ this.principal = principal;
+ if (id == null && principal != null) {
+ this.id = principal.getName();
+ } else {
+ this.id = id;
+ }
+ if (principal == null) {
+ this.principal = () -> this.id;
+ }
+
+ if (intermediatePath == null) {
+ // use a default intermediate path when none supplied
+ if (isGroup()) {
+ intermediatePath = "/home/groups"; // NOSONAR
+ } else {
+ intermediatePath = "/home/users"; // NOSONAR
+ }
+ }
+ this.path = Paths.get(intermediatePath, this.id).toString();
+ this.mockUserMgr = mockUserMgr;
+
+ // pre-populate the principalName property that is needed by MockPrincipalManager#findPrincipals
+ propsMap.put(REP_PRINCIPAL_NAME, new Value[] {ValueFactoryImpl.getInstance().createValue(this.id)});
+ }
+
+ @Override
+ public @NotNull String getID() throws RepositoryException {
+ return id;
+ }
+
+ @Override
+ public boolean isGroup() {
+ return this instanceof Group;
+ }
+
+ @Override
+ public @NotNull Principal getPrincipal() throws RepositoryException {
+ return principal;
+ }
+
+ @Override
+ public @NotNull Iterator<Group> declaredMemberOf() throws RepositoryException {
+ return declaredMemberOf.iterator();
+ }
+
+ @Override
+ public @NotNull Iterator<Group> memberOf() throws RepositoryException {
+ Set<Group> memberOf = new HashSet<>();
+ calcMemberOf(memberOf, this, new HashSet<>());
+ return memberOf.iterator();
+ }
+ /**
+ * Drills down into nested groups to find all the members
+ *
+ * @param members the set to add the found people to
+ * @param group the group to process
+ * @param processedGroups the set of groups that have already been processed
+ * @throws RepositoryException
+ */
+ private void calcMemberOf(Set<Group> memberOf, Authorizable authorizable, Set<Authorizable> processedAuthorizables) throws RepositoryException {
+ if (!processedAuthorizables.contains(authorizable)) {
+ // mark as processed
+ processedAuthorizables.add(authorizable);
+
+ @NotNull Iterator<Group> declaredIt = authorizable.declaredMemberOf();
+ while(declaredIt.hasNext()) {
+ Group group = declaredIt.next();
+ memberOf.add(group);
+
+ calcMemberOf(memberOf, group, processedAuthorizables);
+ }
+ }
+ }
+
+
+ @Override
+ public void remove() throws RepositoryException {
+ mockUserMgr.removeAuthorizable(this);
+ }
+
+ @Override
+ public @NotNull Iterator<String> getPropertyNames() throws RepositoryException {
+ Set<String> propNames = propsMap.keySet().stream()
+ .filter(key -> key.indexOf('/') == -1)
+ .collect(Collectors.toSet());
+ return propNames.iterator();
+ }
+
+ @Override
+ public @NotNull Iterator<String> getPropertyNames(@NotNull String relPath) throws RepositoryException {
+ Set<String> propNames = propsMap.keySet().stream()
+ .filter(key -> key.startsWith(relPath))
+ .collect(Collectors.toSet());
+ return propNames.iterator();
+ }
+
+ @Override
+ public boolean hasProperty(@NotNull String relPath) throws RepositoryException {
+ return propsMap.containsKey(relPath);
+ }
+
+ @Override
+ public void setProperty(@NotNull String relPath, @Nullable Value value) throws RepositoryException {
+ propsMap.put(relPath, new Value[] {value});
+ }
+
+ @Override
+ public void setProperty(@NotNull String relPath, @Nullable Value[] value) throws RepositoryException {
+ propsMap.put(relPath, value);
+ }
+
+ @Override
+ public @Nullable Value[] getProperty(@NotNull String relPath) throws RepositoryException {
+ return propsMap.get(relPath);
+ }
+
+ @Override
+ public boolean removeProperty(@NotNull String relPath) throws RepositoryException {
+ return propsMap.remove(relPath) != null;
+ }
+
+ @Override
+ public @NotNull String getPath() throws RepositoryException {
+ return path;
+ }
+
+ public void addDeclaredMemberOf(Group group) {
+ declaredMemberOf.add(group);
+ }
+
+}
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
new file mode 100644
index 0000000..27ff95b
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockGroup.java
@@ -0,0 +1,156 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.jetbrains.annotations.NotNull;
+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, @Nullable Principal principal,
+ @Nullable String intermediatePath,
+ @NotNull MockUserManager mockUserMgr) {
+ super(id, principal, intermediatePath, mockUserMgr);
+ }
+
+ @Override
+ public @NotNull Iterator<Authorizable> getDeclaredMembers() throws RepositoryException {
+ return declaredMembers.values().iterator();
+ }
+
+ @Override
+ public @NotNull Iterator<Authorizable> getMembers() throws RepositoryException {
+ Set<Authorizable> members = new HashSet<>();
+ calcMembers(members, this, new HashSet<>());
+ return members.iterator();
+ }
+
+ /**
+ * Drills down into nested groups to find all the members
+ *
+ * @param members the set to add the found people to
+ * @param group the group to process
+ * @param processedGroups the set of groups that have already been processed
+ * @throws RepositoryException
+ */
+ private void calcMembers(Set<Authorizable> members, Group group, Set<Group> processedGroups) throws RepositoryException {
+ if (!processedGroups.contains(group)) {
+ // mark as processed
+ processedGroups.add(group);
+
+ @NotNull Iterator<Authorizable> declaredIt = group.getDeclaredMembers();
+ while(declaredIt.hasNext()) {
+ Authorizable authorizable = declaredIt.next();
+ members.add(authorizable);
+
+ if (authorizable instanceof Group) {
+ Group subgroup = (Group)authorizable;
+ calcMembers(members, subgroup, processedGroups);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isDeclaredMember(@NotNull Authorizable authorizable) throws RepositoryException {
+ return declaredMembers.containsValue(authorizable);
+ }
+
+ @Override
+ public boolean isMember(@NotNull Authorizable authorizable) throws RepositoryException {
+ boolean value = declaredMembers.containsValue(authorizable);
+ if (!value) {
+ // groups
+ for (Authorizable m : declaredMembers.values()) {
+ if (m.isGroup()) {
+ value = ((Group)m).isDeclaredMember(authorizable);
+ }
+ if (value) {
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public boolean addMember(@NotNull Authorizable authorizable) throws RepositoryException {
+ boolean added = false;
+ if (!isMember(authorizable)) {
+ declaredMembers.put(authorizable.getID(), authorizable);
+ ((MockAuthorizable)authorizable).addDeclaredMemberOf(this);
+ added = true;
+ }
+ return added;
+ }
+
+ @Override
+ public @NotNull Set<String> addMembers(@NotNull String... memberIds) throws RepositoryException {
+ Set<String> added = new HashSet<>();
+ for (String id : memberIds) {
+ if (!declaredMembers.containsKey(id)) {
+ @Nullable Authorizable authorizable = mockUserMgr.getAuthorizable(id);
+ if (authorizable != null) {
+ addMember(authorizable);
+ added.add(id);
+ }
+ }
+ }
+ return added;
+ }
+
+ @Override
+ public boolean removeMember(@NotNull Authorizable authorizable) throws RepositoryException {
+ return declaredMembers.remove(authorizable.getID(), authorizable);
+ }
+
+ @Override
+ public @NotNull Set<String> removeMembers(@NotNull String... memberIds) throws RepositoryException {
+ Set<String> removed = new HashSet<>();
+ for (String id : memberIds) {
+ if (declaredMembers.remove(id) != null) {
+ removed.add(id);
+ }
+ }
+ return removed;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("MockGroup [id=");
+ builder.append(id);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockPrincipalManager.java b/src/main/java/org/apache/sling/testing/mock/jcr/MockPrincipalManager.java
new file mode 100644
index 0000000..ba32cd5
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockPrincipalManager.java
@@ -0,0 +1,160 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class MockPrincipalManager implements PrincipalManager {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ protected MockUserManager mockUserManager;
+ private Principal everyone = () -> "everyone";
+
+ MockPrincipalManager(MockUserManager mockUserManager) {
+ this.mockUserManager = mockUserManager;
+ }
+
+ @Override
+ public @NotNull PrincipalIterator findPrincipals(@Nullable String simpleFilter) {
+ return findPrincipals(simpleFilter, UserManager.SEARCH_TYPE_AUTHORIZABLE);
+ }
+
+ @Override
+ public @NotNull PrincipalIterator findPrincipals(@Nullable String simpleFilter, int searchType) {
+ Set<Principal> principals = new HashSet<>();
+ try {
+ @NotNull Iterator<Authorizable> authorizables = mockUserManager.findAuthorizables(
+ MockAuthorizable.REP_PRINCIPAL_NAME, simpleFilter, searchType);
+ while (authorizables.hasNext()) {
+ Authorizable next = authorizables.next();
+ principals.add(next.getPrincipal());
+ }
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to find principals", e);
+ }
+ }
+ return new PrincipalIteratorAdapter(principals);
+ }
+
+ @Override
+ public @NotNull Principal getEveryone() {
+ return everyone;
+ }
+
+ @Override
+ public @NotNull PrincipalIterator getGroupMembership(@NotNull Principal principal) {
+ Set<Principal> groups = new HashSet<>();
+ try {
+ @Nullable Authorizable authorizable = mockUserManager.getAuthorizable(principal);
+ if (authorizable != null) {
+ @NotNull Iterator<Group> memberOf = authorizable.memberOf();
+ while (memberOf.hasNext()) {
+ groups.add(memberOf.next().getPrincipal());
+ }
+ }
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to get group membership", e);
+ }
+ }
+ return new PrincipalIteratorAdapter(groups);
+ }
+
+ @Override
+ public @Nullable Principal getPrincipal(@NotNull String principalName) {
+ Principal value = null;
+ try {
+ @Nullable Authorizable authorizable = mockUserManager.getAuthorizable(principalName);
+ if (authorizable != null) {
+ value = authorizable.getPrincipal();
+ }
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to get principal", e);
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public @NotNull PrincipalIterator getPrincipals(int searchType) {
+ Set<Principal> principals = new HashSet<>();
+ try {
+ @NotNull Set<Authorizable> authorizables = mockUserManager.all(searchType);
+ for (Authorizable authorizable : authorizables) {
+ principals.add(authorizable.getPrincipal());
+ }
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to get principals", e);
+ }
+ }
+ return new PrincipalIteratorAdapter(principals);
+ }
+
+ static class PrincipalIteratorAdapter extends RangeIteratorAdapter implements PrincipalIterator {
+
+ public PrincipalIteratorAdapter(Collection<Principal> collection) {
+ super(collection);
+ }
+
+ @Override
+ public @NotNull Principal nextPrincipal() {
+ return (Principal)next();
+ }
+
+ }
+
+ @Override
+ public boolean hasPrincipal(@NotNull String principalName) {
+ boolean value = false;
+ try {
+ value = mockUserManager.getAuthorizable(principalName) != null;
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to determine principal exists", e);
+ }
+ }
+ return value;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockSession.java b/src/main/java/org/apache/sling/testing/mock/jcr/MockSession.java
index d944a3e..05a110c 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockSession.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockSession.java
@@ -47,15 +47,19 @@ import javax.jcr.retention.RetentionManager;
import javax.jcr.security.AccessControlManager;
import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.jetbrains.annotations.NotNull;
import org.xml.sax.ContentHandler;
/**
* Mock {@link Session} implementation. This instance holds the JCR data in a
* simple ordered map.
*/
-class MockSession implements Session {
+class MockSession implements Session, JackrabbitSession {
private final MockRepository repository;
private final Workspace workspace;
@@ -63,12 +67,16 @@ class MockSession implements Session {
private final String userId;
private boolean isLive;
private boolean hasKnownChanges;
+ private MockPrincipalManager principalManager;
+ private MockUserManager userManager;
private AccessControlManager accessControlManager = null;
public MockSession(MockRepository repository, Map<String, ItemData> items,
String userId, String workspaceName) throws RepositoryException {
this.repository = repository;
this.workspace = new MockWorkspace(repository, this, workspaceName);
+ this.userManager = new MockUserManager();
+ this.principalManager = new MockPrincipalManager(this.userManager);
this.items = items;
this.userId = userId;
isLive = true;
@@ -502,6 +510,53 @@ class MockSession implements Session {
throw new UnsupportedOperationException();
}
+
+ // --- jackrabbit session operations ---
+
+ @Override
+ public Item getItemOrNull(final String absPath) throws RepositoryException {
+ Item item = null;
+ if (itemExists(absPath)) {
+ item = getItem(absPath);
+ }
+ return item;
+ }
+
+ @Override
+ public Node getNodeOrNull(final String absPath) throws RepositoryException {
+ Node node = null;
+ if (nodeExists(absPath)) {
+ node = getNode(absPath);
+ }
+ return node;
+ }
+
+ @Override
+ public Property getPropertyOrNull(final String absPath) throws RepositoryException {
+ Property prop = null;
+ if (propertyExists(absPath)) {
+ prop = getProperty(absPath);
+ }
+ return prop;
+ }
+
+ @Override
+ public PrincipalManager getPrincipalManager()
+ throws RepositoryException {
+ return principalManager;
+ }
+
+ @Override
+ public UserManager getUserManager()
+ throws RepositoryException {
+ return userManager;
+ }
+
+ @Override
+ public boolean hasPermission(@NotNull String absPath, @NotNull String... actions) throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
/**
* To allow a test to provide mock implementation of the AccessControlManager
* @param acm the access control manager to use for the session
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java b/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
new file mode 100644
index 0000000..a4ae6b2
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
@@ -0,0 +1,125 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import java.security.Principal;
+import java.util.Arrays;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.user.User;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mock {@link User} implementation.
+ */
+class MockUser extends MockAuthorizable implements User {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private char[] pwd = {};
+ private boolean disabled;
+ private String disabledReason;
+
+ public MockUser(@Nullable String id, @Nullable Principal principal,
+ @Nullable String intermediatePath,
+ @NotNull MockUserManager mockUserMgr) {
+ super(id, principal, intermediatePath, mockUserMgr);
+ }
+
+ @Override
+ public boolean isAdmin() {
+ boolean result = false;
+ try {
+ result = "admin".equals(getID());
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to determine if this is admin", e);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isSystemUser() {
+ return false;
+ }
+
+ @Override
+ public @NotNull Credentials getCredentials() throws RepositoryException {
+ return new SimpleCredentials(id, pwd);
+ }
+
+ @Override
+ public @NotNull Impersonation getImpersonation() throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void changePassword(@Nullable String password) throws RepositoryException {
+ if (password == null) {
+ throw new RepositoryException("Attempt to set 'null' password for user " + getID());
+ }
+
+ pwd = password.toCharArray();
+ }
+
+ @Override
+ public void changePassword(@Nullable String password, @NotNull String oldPassword) throws RepositoryException {
+ if (Arrays.equals(pwd, oldPassword.toCharArray())) {
+ changePassword(password);
+ } else {
+ throw new RepositoryException("old password did not match");
+ }
+ }
+
+ @Override
+ public void disable(@Nullable String reason) throws RepositoryException {
+ if (reason == null) {
+ this.disabled = false;
+ this.disabledReason = null;
+ } else {
+ this.disabled = true;
+ this.disabledReason = reason;
+ }
+ }
+
+ @Override
+ public boolean isDisabled() throws RepositoryException {
+ return disabled;
+ }
+
+ @Override
+ public @Nullable String getDisabledReason() throws RepositoryException {
+ return disabledReason;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("MockUser [id=");
+ builder.append(id);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java b/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
new file mode 100644
index 0000000..ed1b0e5
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
@@ -0,0 +1,235 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+import org.apache.jackrabbit.api.security.user.AuthorizableTypeException;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.Query;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mock {@link UserManager} implementation.
+ */
+public class MockUserManager implements UserManager {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ protected Map<String, Authorizable> authorizables = new HashMap<>();
+ private boolean autoSave;
+
+ /**
+ * Callback function for {@link MockUser#remove()} and {@link MockGroup#remove()} to
+ * invoke.
+ *
+ * @param id the user or group id
+ * @param a the user or group object
+ * @return true if removed, false otherwise
+ */
+ boolean removeAuthorizable(Authorizable a) throws RepositoryException {
+ return authorizables.remove(a.getID(), a);
+ }
+
+ Set<Authorizable> all(int searchType) throws RepositoryException { // NOSONAR
+ return authorizables.values().stream()
+ .filter(a -> {
+ boolean match;
+ if (PrincipalManager.SEARCH_TYPE_ALL == searchType) {
+ match = true;
+ } else if (PrincipalManager.SEARCH_TYPE_GROUP == searchType) {
+ match = a.isGroup();
+ } else if (PrincipalManager.SEARCH_TYPE_NOT_GROUP == searchType) {
+ match = !a.isGroup();
+ } else {
+ match = false;
+ }
+ return match;
+ })
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean isAutoSave() {
+ return autoSave;
+ }
+
+ @Override
+ public void autoSave(boolean autoSave) throws RepositoryException {
+ this.autoSave = autoSave;
+ }
+
+ @Override
+ public @NotNull Group createGroup(@NotNull String groupID) throws RepositoryException {
+ return maybeCreateGroup(groupID, null, null);
+ }
+
+ @Override
+ public @NotNull Group createGroup(@NotNull Principal principal) throws RepositoryException {
+ return maybeCreateGroup(null, principal, null);
+ }
+
+ @Override
+ public @NotNull Group createGroup(@NotNull Principal principal, @Nullable String intermediatePath)
+ throws RepositoryException {
+ return maybeCreateGroup(null, principal, intermediatePath);
+ }
+
+ @Override
+ public @NotNull Group createGroup(@NotNull String groupID, @NotNull Principal principal, @Nullable String intermediatePath)
+ throws RepositoryException {
+ return maybeCreateGroup(groupID, principal, intermediatePath);
+ }
+
+ private @NotNull Group maybeCreateGroup(@Nullable String groupID, @Nullable Principal principal, @Nullable String intermediatePath)
+ throws RepositoryException {
+ if (authorizables.containsKey(groupID)) {
+ throw new AuthorizableExistsException("Group already exists");
+ }
+ return (Group)authorizables.computeIfAbsent(groupID, id -> new MockGroup(id, principal, intermediatePath, this));
+ }
+
+ @Override
+ public @NotNull User createSystemUser(@NotNull String userID, @Nullable String intermediatePath)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public @NotNull User createUser(@NotNull String userID, @Nullable String password)
+ throws RepositoryException {
+ return maybeCreateUser(userID, password, null, null);
+ }
+
+ @Override
+ public @NotNull User createUser(@NotNull String userID, @Nullable String password, @NotNull Principal principal,
+ @Nullable String intermediatePath) throws RepositoryException {
+ return maybeCreateUser(userID, password, principal, intermediatePath);
+ }
+
+ private @NotNull User maybeCreateUser(@Nullable String userID, @Nullable String password, @Nullable Principal principal,
+ @Nullable String intermediatePath) throws RepositoryException {
+ if (authorizables.containsKey(userID)) {
+ throw new AuthorizableExistsException("User already exists");
+ }
+ return (User)authorizables.computeIfAbsent(userID, id -> new MockUser(id, principal, intermediatePath, this));
+ }
+
+ @Override
+ public @NotNull Iterator<Authorizable> findAuthorizables(@NotNull Query query) throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public @NotNull Iterator<Authorizable> findAuthorizables(@NotNull String relPath, @Nullable String value)
+ throws RepositoryException {
+ return findAuthorizables(relPath, value, UserManager.SEARCH_TYPE_AUTHORIZABLE);
+ }
+
+ @Override
+ public @NotNull Iterator<Authorizable> findAuthorizables(@NotNull String relPath, @Nullable String value, int searchType)
+ throws RepositoryException {
+ Set<Authorizable> matches = new HashSet<>();
+ for (Authorizable authorizable : authorizables.values()) {
+ if (UserManager.SEARCH_TYPE_GROUP == searchType) {
+ if (!authorizable.isGroup()) {
+ continue; //not a group, so skip it
+ }
+ } else if (UserManager.SEARCH_TYPE_USER == searchType) {
+ if (authorizable.isGroup()) {
+ continue; //not a user, so skip it
+ }
+ } else if (UserManager.SEARCH_TYPE_AUTHORIZABLE != searchType) {
+ continue; // some other invalid value?
+ }
+ Value[] property = authorizable.getProperty(relPath);
+ if (property != null) {
+ if (value == null) {
+ // found a match?
+ matches.add(authorizable);
+ } else {
+ for (Value value2 : property) {
+ if (value.equals(value2.getString())) {
+ // found a match?
+ matches.add(authorizable);
+ break; // no need to check other values
+ }
+ }
+ }
+ }
+ }
+ return matches.iterator();
+ }
+
+ @Override
+ public @Nullable Authorizable getAuthorizable(@NotNull String id) throws RepositoryException {
+ return authorizables.get(id);
+ }
+
+ @Override
+ public @Nullable Authorizable getAuthorizable(@NotNull Principal principal) throws RepositoryException {
+ return authorizables.get(principal.getName());
+ }
+
+ @Override
+ public <T extends Authorizable> @Nullable T getAuthorizable(@NotNull String id, @NotNull Class<T> authorizableClass)
+ throws RepositoryException {
+ T a = null;
+ Authorizable authorizable = authorizables.get(id);
+ if (authorizableClass.isInstance(authorizable)) {
+ a = authorizableClass.cast(authorizable);
+ } else {
+ throw new AuthorizableTypeException("Not the expected authorizable class");
+ }
+ return a;
+ }
+
+ @Override
+ public @Nullable Authorizable getAuthorizableByPath(@NotNull String path)
+ throws RepositoryException {
+ return authorizables.values().stream()
+ .filter(a -> {
+ try {
+ return path.equals(a.getPath());
+ } catch (RepositoryException e) {
+ // ignore and log
+ if (logger.isDebugEnabled()) {
+ logger.debug("Failed to match authorizable path", e);
+ }
+ return false;
+ }
+ })
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/LogCapture.java b/src/test/java/org/apache/sling/testing/mock/jcr/LogCapture.java
new file mode 100644
index 0000000..be27de1
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/LogCapture.java
@@ -0,0 +1,91 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.fail;
+
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+/**
+ * Capture logs for testing
+ *
+ * Initially cloned from: https://github.com/apache/sling-org-apache-sling-graphql-core/blob/0b1c1dd72ed04324ea84d2227c3223ec65b0b21e/src/test/java/org/apache/sling/graphql/core/util/LogCapture.java
+ */
+public class LogCapture extends ListAppender<ILoggingEvent> implements AutoCloseable {
+ private final boolean verboseFailure;
+ private Logger logger;
+
+ public LogCapture(String loggerName, boolean verboseFailure) {
+ this.verboseFailure = verboseFailure;
+ logger = (Logger) LoggerFactory.getLogger(loggerName);
+ logger.setLevel(Level.ALL);
+ setContext((LoggerContext) LoggerFactory.getILoggerFactory());
+ logger.addAppender(this);
+ start();
+ }
+
+ public void setLoggerLevel(Level newLevel) {
+ ((ch.qos.logback.classic.Logger)logger).setLevel(newLevel);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (logger != null) {
+ logger.detachAppender(this);
+ }
+ }
+
+ public boolean anyMatch(Predicate<ILoggingEvent> p) {
+ return this.list.stream().anyMatch(p);
+ }
+
+ public void assertContains(Level atLevel, String ... substrings) {
+ Stream.of(substrings).forEach(substring -> {
+ if (!anyMatch(event -> event.getLevel() == atLevel && event.getFormattedMessage().contains(substring))) {
+ if (verboseFailure) {
+ fail(String.format("No log message contains [%s] in log%n%s", substring, this.list.toString()));
+ } else {
+ fail(String.format("No log message contains [%s]", substring));
+ }
+ }
+ });
+ }
+
+ public void assertNotContains(Level atLevel, String ... substrings) {
+ Stream.of(substrings).forEach(substring -> {
+ if (anyMatch(event -> event.getLevel() == atLevel && event.getFormattedMessage().contains(substring))) {
+ if (verboseFailure) {
+ fail(String.format("Unexpected log message contains [%s] in log%n%s", substring, this.list.toString()));
+ } else {
+ fail(String.format("Unexpacted log message contains [%s]", substring));
+ }
+ }
+ });
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockAuthorizableTest.java b/src/test/java/org/apache/sling/testing/mock/jcr/MockAuthorizableTest.java
new file mode 100644
index 0000000..e0474ae
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockAuthorizableTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public abstract class MockAuthorizableTest<T extends Authorizable> {
+ protected UserManager userManager;
+ protected T authorizable;
+ protected ValueFactory vf = ValueFactoryImpl.getInstance();
+
+ @Before
+ public void before() throws RepositoryException {
+ userManager = new MockUserManager();
+ authorizable = createAuthorizable();
+ }
+
+ protected abstract T createAuthorizable() throws RepositoryException;
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getID()}.
+ */
+ public abstract void testGetID() throws RepositoryException;
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#isGroup()}.
+ */
+ public abstract void testIsGroup();
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getPrincipal()}.
+ */
+ @Test
+ public void testGetPrincipal() throws RepositoryException {
+ @NotNull String id = authorizable.getID();
+ @NotNull Principal principal = authorizable.getPrincipal();
+ assertEquals(id, principal.getName());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#declaredMemberOf()}.
+ */
+ @Test
+ public void testDeclaredMemberOf() throws RepositoryException {
+ // initially not member of any group
+ @NotNull Iterator<Group> declaredMemberOf = authorizable.declaredMemberOf();
+ assertFalse(declaredMemberOf.hasNext());
+
+ // member of a group
+ @NotNull Group members1 = userManager.createGroup("members1");
+ members1.addMember(authorizable);
+ declaredMemberOf = authorizable.declaredMemberOf();
+ assertTrue(declaredMemberOf.hasNext());
+ assertEquals(members1, declaredMemberOf.next());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#memberOf()}.
+ */
+ @Test
+ public void testMemberOf() throws RepositoryException {
+ // initially not member of any group
+ @NotNull Iterator<Group> memberOf = authorizable.memberOf();
+ assertFalse(memberOf.hasNext());
+
+ // member of a group
+ @NotNull Group members1 = userManager.createGroup("members1");
+ @NotNull Group members2 = userManager.createGroup("members2");
+ members1.addMember(members2);
+ members2.addMember(authorizable);
+ memberOf = authorizable.memberOf();
+ assertTrue(memberOf.hasNext());
+ Set<Group> memberOfSet = new HashSet<>();
+ memberOf.forEachRemaining(memberOfSet::add);
+ assertTrue(memberOfSet.contains(members1));
+ assertTrue(memberOfSet.contains(members2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#remove()}.
+ */
+ @Test
+ public void testRemove() throws RepositoryException {
+ @NotNull String id = authorizable.getID();
+ authorizable.remove();
+ assertNull(userManager.getAuthorizable(id));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getPropertyNames()}.
+ */
+ @Test
+ public void testGetPropertyNames() throws RepositoryException {
+ // only rep:principalName property
+ @NotNull Iterator<String> propertyNames = authorizable.getPropertyNames();
+ assertTrue(propertyNames.hasNext());
+ Set<String> propertyNamesSet = new HashSet<>();
+ propertyNames.forEachRemaining(propertyNamesSet::add);
+ assertEquals(1, propertyNamesSet.size());
+ assertTrue(propertyNamesSet.contains(MockAuthorizable.REP_PRINCIPAL_NAME));
+
+ // set some props
+ authorizable.setProperty("prop1", vf.createValue("value1"));
+ authorizable.setProperty("relPath/prop2", vf.createValue("value2"));
+
+ propertyNames = authorizable.getPropertyNames();
+ assertTrue(propertyNames.hasNext());
+ propertyNamesSet.clear();
+ propertyNames.forEachRemaining(propertyNamesSet::add);
+ assertEquals(2, propertyNamesSet.size());
+ assertTrue(propertyNamesSet.contains("prop1"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getPropertyNames(java.lang.String)}.
+ */
+ @Test
+ public void testGetPropertyNamesString() throws RepositoryException {
+ // no properties
+ @NotNull Iterator<String> propertyNames = authorizable.getPropertyNames("relPath");
+ assertFalse(propertyNames.hasNext());
+
+ // set some props
+ authorizable.setProperty("prop1", vf.createValue("value1"));
+ authorizable.setProperty("relPath/prop2", vf.createValue("value2"));
+
+ propertyNames = authorizable.getPropertyNames("relPath");
+ assertTrue(propertyNames.hasNext());
+ Set<String> propertyNamesSet = new HashSet<>();
+ propertyNames.forEachRemaining(propertyNamesSet::add);
+ assertEquals(1, propertyNamesSet.size());
+ assertTrue(propertyNamesSet.contains("relPath/prop2"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#hasProperty(java.lang.String)}.
+ */
+ @Test
+ public void testHasProperty() throws RepositoryException {
+ assertFalse(authorizable.hasProperty("prop1"));
+ authorizable.setProperty("prop1", ValueFactoryImpl.getInstance().createValue("value1"));
+ assertTrue(authorizable.hasProperty("prop1"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#setProperty(java.lang.String, javax.jcr.Value)}.
+ */
+ @Test
+ public void testSetPropertyStringValue() throws RepositoryException {
+ authorizable.setProperty("relPath", vf.createValue("value1"));
+ Value[] property = authorizable.getProperty("relPath");
+ assertNotNull(property);
+ assertEquals(1, property.length);
+ assertEquals("value1", property[0].getString());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#setProperty(java.lang.String, javax.jcr.Value[])}.
+ */
+ @Test
+ public void testSetPropertyStringValueArray() throws RepositoryException {
+ authorizable.setProperty("relPath", new Value [] {
+ vf.createValue("value1"),
+ vf.createValue("value2")});
+ Value[] property = authorizable.getProperty("relPath");
+ assertNotNull(property);
+ assertEquals(2, property.length);
+ assertEquals("value1", property[0].getString());
+ assertEquals("value2", property[1].getString());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getProperty(java.lang.String)}.
+ */
+ @Test
+ public void testGetProperty() throws RepositoryException {
+ // not set
+ @Nullable Value[] property = authorizable.getProperty("relPath");
+ assertNull(property);
+
+ authorizable.setProperty("relPath", vf.createValue("value1"));
+ property = authorizable.getProperty("relPath");
+ assertNotNull(property);
+ assertEquals(1, property.length);
+ assertEquals("value1", property[0].getString());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#removeProperty(java.lang.String)}.
+ */
+ @Test
+ public void testRemoveProperty() throws RepositoryException {
+ authorizable.setProperty("prop1", ValueFactoryImpl.getInstance().createValue("value1"));
+ assertTrue(authorizable.removeProperty("prop1"));
+ assertFalse(authorizable.hasProperty("prop1"));
+
+ assertFalse(authorizable.removeProperty("prop1"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockAuthorizable#getPath()}.
+ */
+ public abstract void testGetPath() throws UnsupportedRepositoryOperationException, RepositoryException;
+
+ @Test
+ public void testToString() {
+ assertNotNull(authorizable.toString());
+ }
+
+}
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
new file mode 100644
index 0000000..28aaa12
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockGroupTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class MockGroupTest extends MockAuthorizableTest<Group> {
+
+ @Override
+ protected Group createAuthorizable() throws RepositoryException {
+ return userManager.createGroup("group1");
+ }
+
+ @Test
+ @Override
+ public void testGetID() throws RepositoryException {
+ assertEquals("group1", authorizable.getID());
+ }
+
+ @Test
+ @Override
+ public void testIsGroup() {
+ assertTrue(authorizable.isGroup());
+ }
+
+ @Test
+ public void testGetMemberOfWithNestedGroups() throws RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull Group submember1 = userManager.createGroup("submember1");
+ member1.addMember(submember1);
+ submember1.addMember(member1); // to verify no circular loop
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ submember1.addMember(member2);
+ authorizable.addMember(member1);
+
+ @NotNull Iterator<Group> groups = member2.memberOf();
+ Set<Authorizable> memberOfSet = new HashSet<>();
+ groups.forEachRemaining(memberOfSet::add);
+ assertEquals(3, memberOfSet.size());
+ assertTrue(memberOfSet.contains(member1));
+ assertTrue(memberOfSet.contains(submember1));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#getDeclaredMembers()}.
+ */
+ @Test
+ public void testGetDeclaredMembers() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ member1.addMember(member2);
+ authorizable.addMember(member1);
+
+ @NotNull Iterator<Authorizable> members = authorizable.getDeclaredMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ members.forEachRemaining(membersSet::add);
+ assertEquals(1, membersSet.size());
+ assertTrue(membersSet.contains(member1));
+ assertFalse(membersSet.contains(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#getMembers()}.
+ */
+ @Test
+ public void testGetMembers() throws RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ member1.addMember(member2);
+ authorizable.addMember(member1);
+
+ @NotNull Iterator<Authorizable> members = authorizable.getMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ members.forEachRemaining(membersSet::add);
+ assertEquals(2, membersSet.size());
+ assertTrue(membersSet.contains(member1));
+ assertTrue(membersSet.contains(member2));
+ }
+ @Test
+ public void testGetMembersWithNestedGroups() throws RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull Group submember1 = userManager.createGroup("submember1");
+ member1.addMember(submember1);
+ submember1.addMember(member1); // to verify no circular loop
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ submember1.addMember(member2);
+ authorizable.addMember(member1);
+
+ @NotNull Iterator<Authorizable> members = authorizable.getMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ members.forEachRemaining(membersSet::add);
+ assertEquals(3, membersSet.size());
+ assertTrue(membersSet.contains(member1));
+ assertTrue(membersSet.contains(member2));
+ assertTrue(membersSet.contains(submember1));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#isDeclaredMember(org.apache.jackrabbit.api.security.user.Authorizable)}.
+ */
+ @Test
+ public void testIsDeclaredMember() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ member1.addMember(member2);
+
+ assertFalse(authorizable.isDeclaredMember(member1));
+ assertFalse(authorizable.isDeclaredMember(member2));
+
+ authorizable.addMember(member1);
+ assertTrue(authorizable.isDeclaredMember(member1));
+ assertFalse(authorizable.isDeclaredMember(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#isMember(org.apache.jackrabbit.api.security.user.Authorizable)}.
+ */
+ @Test
+ public void testIsMember() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ @NotNull User member3 = userManager.createUser("member3", "pwd");
+ member1.addMember(member2);
+ authorizable.addMember(member3);
+
+ assertFalse(authorizable.isMember(member2));
+ assertTrue(authorizable.isMember(member3));
+
+ authorizable.addMember(member1);
+ assertTrue(authorizable.isMember(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#addMember(org.apache.jackrabbit.api.security.user.Authorizable)}.
+ */
+ @Test
+ public void testAddMember() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ assertTrue(authorizable.addMember(member1));
+ assertTrue(authorizable.addMember(member2));
+ // one more time
+ assertFalse(authorizable.addMember(member2));
+
+ @NotNull Iterator<Authorizable> declaredMembers = authorizable.getDeclaredMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ declaredMembers.forEachRemaining(membersSet::add);
+ assertEquals(2, membersSet.size());
+ assertTrue(membersSet.contains(member1));
+ assertTrue(membersSet.contains(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#addMembers(java.lang.String[])}.
+ */
+ @Test
+ public void testAddMembers() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ @NotNull Set<String> added = authorizable.addMembers(member1.getID(), member2.getID(), member1.getID(), "invalid");
+ assertEquals(2, added.size());
+
+ @NotNull Iterator<Authorizable> declaredMembers = authorizable.getDeclaredMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ declaredMembers.forEachRemaining(membersSet::add);
+ assertEquals(2, membersSet.size());
+ assertTrue(membersSet.contains(member1));
+ assertTrue(membersSet.contains(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#removeMember(org.apache.jackrabbit.api.security.user.Authorizable)}.
+ */
+ @Test
+ public void testRemoveMember() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ authorizable.addMember(member1);
+ authorizable.addMember(member2);
+ assertTrue(authorizable.removeMember(member1));
+
+ @NotNull Iterator<Authorizable> declaredMembers = authorizable.getDeclaredMembers();
+ Set<Authorizable> membersSet = new HashSet<>();
+ declaredMembers.forEachRemaining(membersSet::add);
+ assertEquals(1, membersSet.size());
+ assertFalse(membersSet.contains(member1));
+ assertTrue(membersSet.contains(member2));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockGroup#removeMembers(java.lang.String[])}.
+ */
+ @Test
+ public void testRemoveMembers() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group member1 = userManager.createGroup("member1");
+ @NotNull User member2 = userManager.createUser("member2", "pwd");
+ authorizable.addMember(member1);
+ authorizable.addMember(member2);
+ @NotNull Set<String> removed = authorizable.removeMembers(member1.getID(), member2.getID(), "invalid");
+ assertEquals(2, removed.size());
+
+ @NotNull Iterator<Authorizable> declaredMembers = authorizable.getDeclaredMembers();
+ assertFalse(declaredMembers.hasNext());
+ }
+
+ @Test
+ @Override
+ public void testGetPath() throws UnsupportedRepositoryOperationException, RepositoryException {
+ assertEquals("/home/groups/group1", authorizable.getPath());
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockPrincipalManagerTest.java b/src/test/java/org/apache/sling/testing/mock/jcr/MockPrincipalManagerTest.java
new file mode 100644
index 0000000..eaa1a39
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockPrincipalManagerTest.java
@@ -0,0 +1,362 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+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.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import ch.qos.logback.classic.Level;
+
+/**
+ *
+ */
+public class MockPrincipalManagerTest {
+ protected UserManager userManager;
+ protected MockPrincipalManager principalManager;
+
+ @Before
+ public void before() throws RepositoryException {
+ userManager = new MockUserManager();
+ principalManager = new MockPrincipalManager((MockUserManager)userManager);
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#findPrincipals(java.lang.String)}.
+ */
+ @Test
+ public void testFindPrincipalsString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @NotNull Group group1 = userManager.createGroup("group1", () -> "group1", "/home/groups/path1");
+
+ @NotNull PrincipalIterator principals = principalManager.findPrincipals("other");
+ assertFalse(principals.hasNext());
+
+ principals = principalManager.findPrincipals("user1");
+ assertTrue(principals.hasNext());
+ assertEquals(user1.getPrincipal(), principals.nextPrincipal());
+
+ principals = principalManager.findPrincipals("group1");
+ assertTrue(principals.hasNext());
+ assertEquals(group1.getPrincipal(), principals.nextPrincipal());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#findPrincipals(java.lang.String, int)}.
+ */
+ @Test
+ public void testFindPrincipalsStringInt() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @NotNull Group group1 = userManager.createGroup("group1", () -> "group1", "/home/groups/path1");
+
+ @NotNull PrincipalIterator principals = principalManager.findPrincipals("other", PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ principals = principalManager.findPrincipals("user1", PrincipalManager.SEARCH_TYPE_NOT_GROUP);
+ assertTrue(principals.hasNext());
+ assertEquals(user1.getPrincipal(), principals.nextPrincipal());
+
+ principals = principalManager.findPrincipals("group1", PrincipalManager.SEARCH_TYPE_GROUP);
+ assertTrue(principals.hasNext());
+ assertEquals(group1.getPrincipal(), principals.nextPrincipal());
+ }
+ @Test
+ public void testFindPrincipalsStringIntCatchRepositoryException() throws Exception {
+ MockUserManager mockUserManager = Mockito.spy((MockUserManager)userManager);
+ Mockito.doThrow(RepositoryException.class).when(mockUserManager).findAuthorizables(anyString(), anyString(), anyInt());
+ // replace the field with our mocked variant
+ principalManager.mockUserManager = mockUserManager;
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ @NotNull PrincipalIterator principals = principalManager.findPrincipals("other", PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ // verify the msg was not logged
+ capture.assertNotContains(Level.DEBUG, "Failed to find principals");
+ }
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ @NotNull PrincipalIterator principals = principalManager.findPrincipals("other", PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to find principals");
+ }
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#getEveryone()}.
+ */
+ @Test
+ public void testGetEveryone() {
+ @NotNull Principal everyone = principalManager.getEveryone();
+ assertNotNull(everyone);
+ assertEquals("everyone", everyone.getName());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#getGroupMembership(java.security.Principal)}.
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetGroupMembership() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd");
+ Principal principal = principalManager.getPrincipal("user1");
+ PrincipalIterator groupMembership = principalManager.getGroupMembership(principal);
+ assertFalse(groupMembership.hasNext());
+
+ @NotNull Group members1 = userManager.createGroup("members1");
+ @NotNull Group members2 = userManager.createGroup("members2");
+ members1.addMember(members2);
+ members2.addMember(user1);
+
+ groupMembership = principalManager.getGroupMembership(principal);
+ assertTrue(groupMembership.hasNext());
+ final Set<Principal> groupsSet = new HashSet<>();
+ groupMembership.forEachRemaining(p -> groupsSet.add((Principal) p));
+ assertEquals(2, groupsSet.size());
+ assertTrue(groupsSet.stream().anyMatch(p -> "members1".equals(p.getName())));
+ assertTrue(groupsSet.stream().anyMatch(p -> "members2".equals(p.getName())));
+
+ // non-existing principal
+ groupMembership = principalManager.getGroupMembership(() -> "other");
+ assertFalse(groupMembership.hasNext());
+ }
+ @Test
+ public void testGetGroupMembershipCatchRepositoryException() throws Exception {
+ MockUserManager mockUserManager = Mockito.spy((MockUserManager)userManager);
+ Mockito.doThrow(RepositoryException.class).when(mockUserManager).getAuthorizable(any(Principal.class));
+ // replace the field with our mocked variant
+ principalManager.mockUserManager = mockUserManager;
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ @NotNull PrincipalIterator principals = principalManager.getGroupMembership(() -> "other");
+ assertFalse(principals.hasNext());
+
+ // verify the msg was not logged
+ capture.assertNotContains(Level.DEBUG, "Failed to get group membership");
+ }
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ @NotNull PrincipalIterator principals = principalManager.getGroupMembership(() -> "other");
+ assertFalse(principals.hasNext());
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to get group membership");
+ }
+ }
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#getPrincipal(java.lang.String)}.
+ */
+ @Test
+ public void testGetPrincipal() throws AuthorizableExistsException, RepositoryException {
+ // no
+ Principal principal = principalManager.getPrincipal("user1");
+ assertNull(principal);
+
+ // yes!
+ userManager.createUser("user1", "pwd");
+ principal = principalManager.getPrincipal("user1");
+ assertNotNull(principal);
+ assertEquals("user1", principal.getName());
+ }
+ @Test
+ public void testGetPrincipalCatchRepositoryException() throws Exception {
+ MockUserManager mockUserManager = Mockito.spy((MockUserManager)userManager);
+ Mockito.doThrow(RepositoryException.class).when(mockUserManager).getAuthorizable(anyString());
+ // replace the field with our mocked variant
+ principalManager.mockUserManager = mockUserManager;
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ assertNull(principalManager.getPrincipal("other"));
+
+ // verify the msg was not logged
+ capture.assertNotContains(Level.DEBUG, "Failed to get principal");
+ }
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ assertNull(principalManager.getPrincipal("other"));
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to get principal");
+ }
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#getPrincipals(int)}.
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetPrincipals() throws AuthorizableExistsException, RepositoryException {
+ // none
+ PrincipalIterator principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ userManager.createUser("user1", "pwd");
+ userManager.createGroup("group1");
+
+ principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_ALL);
+ assertTrue(principals.hasNext());
+ final Set<Principal> principalsSet = new HashSet<>();
+ principals.forEachRemaining(p -> principalsSet.add((Principal) p));
+ assertEquals(2, principalsSet.size());
+
+ principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_GROUP);
+ assertTrue(principals.hasNext());
+ principalsSet.clear();
+ principals.forEachRemaining(p -> principalsSet.add((Principal) p));
+ assertEquals(1, principalsSet.size());
+ assertEquals("group1", principalsSet.iterator().next().getName());
+
+ principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_NOT_GROUP);
+ assertTrue(principals.hasNext());
+ principalsSet.clear();
+ principals.forEachRemaining(p -> principalsSet.add((Principal) p));
+ assertEquals(1, principalsSet.size());
+ assertEquals("user1", principalsSet.iterator().next().getName());
+ }
+ @Test
+ public void testGetPrincipalsCatchRepositoryException() throws Exception {
+ MockUserManager mockUserManager = Mockito.spy((MockUserManager)userManager);
+ Mockito.doThrow(RepositoryException.class).when(mockUserManager).all(anyInt());
+ // replace the field with our mocked variant
+ principalManager.mockUserManager = mockUserManager;
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ PrincipalIterator principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ // verify the msg was not logged
+ capture.assertNotContains(Level.DEBUG, "Failed to get principals");
+ }
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ PrincipalIterator principals = principalManager.getPrincipals(PrincipalManager.SEARCH_TYPE_ALL);
+ assertFalse(principals.hasNext());
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to get principals");
+ }
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockPrincipalManager#hasPrincipal(java.lang.String)}.
+ */
+ @Test
+ public void testHasPrincipal() throws AuthorizableExistsException, RepositoryException {
+ // no
+ assertFalse(principalManager.hasPrincipal("user1"));
+
+ // yes!
+ userManager.createUser("user1", "pwd");
+ assertTrue(principalManager.hasPrincipal("user1"));
+ }
+ @Test
+ public void testHasPrincipalCatchRepositoryException() throws Exception {
+ MockUserManager mockUserManager = Mockito.spy((MockUserManager)userManager);
+ Mockito.doThrow(RepositoryException.class).when(mockUserManager).getAuthorizable(anyString());
+ // replace the field with our mocked variant
+ principalManager.mockUserManager = mockUserManager;
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ assertFalse(principalManager.hasPrincipal("user1"));
+
+ // verify the msg was not logged
+ capture.assertNotContains(Level.DEBUG, "Failed to determine principal exists");
+ }
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(principalManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ assertFalse(principalManager.hasPrincipal("user1"));
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to determine principal exists");
+ }
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockSessionTest.java b/src/test/java/org/apache/sling/testing/mock/jcr/MockSessionTest.java
index 0cea4a1..ca8eddc 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockSessionTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockSessionTest.java
@@ -22,9 +22,11 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import javax.jcr.AccessDeniedException;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.NamespaceRegistry;
@@ -34,9 +36,11 @@ import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.security.AccessControlManager;
import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitSession;
import org.junit.Test;
import org.mockito.Mockito;
@@ -411,6 +415,69 @@ public class MockSessionTest {
assertTrue(session.propertyExists("/node1/child2/grandchild1/prop1"));
}
+
+ // --- jackrabbit session operations ---
+
+ @Test
+ public void testGetItemOrNull() throws RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ Node node1 = s.getRootNode().addNode("node1");
+ Node child1 = node1.addNode("child1");
+ String childPath = child1.getPath();
+ Property prop1 = child1.setProperty("prop1", "value1");
+ String propPath = prop1.getPath();
+
+ assertNotNull(s.getItemOrNull(childPath));
+ assertNotNull(s.getItemOrNull(propPath));
+ prop1.remove();
+ assertNull(s.getItemOrNull(propPath));
+ child1.remove();
+ assertNull(s.getItemOrNull(childPath));
+ }
+
+ @Test
+ public void testGetNodeOrNull() throws RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ Node node1 = s.getRootNode().addNode("node1");
+ Node child1 = node1.addNode("child1");
+ String path = child1.getPath();
+ assertNotNull(s.getNodeOrNull(path));
+ child1.remove();
+ assertNull(s.getNodeOrNull(path));
+ }
+
+ @Test
+ public void testGetPropertyOrNull() throws RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ Node node1 = s.getRootNode().addNode("node1");
+ Node child1 = node1.addNode("child1");
+ Property prop1 = child1.setProperty("prop1", "value1");
+ String path = prop1.getPath();
+ assertNotNull(s.getPropertyOrNull(path));
+ prop1.remove();
+ assertNull(s.getPropertyOrNull(path));
+ }
+
+ @Test
+ public void testGetPrincipalManager()
+ throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ assertNotNull(s.getPrincipalManager());
+ }
+
+ @Test
+ public void testGetUserManager()
+ throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ assertNotNull(s.getUserManager());
+ }
+
+ @Test
+ public void testHasPermission() throws RepositoryException {
+ JackrabbitSession s = (JackrabbitSession)MockJcr.newSession();
+ assertThrows(UnsupportedOperationException.class, () -> s.hasPermission("/path1", JackrabbitSession.ACTION_ADD_PROPERTY, JackrabbitSession.ACTION_MODIFY_PROPERTY));
+ }
+
@Test
public void testSetAccessControlManager() throws RepositoryException {
Session s = MockJcr.newSession();
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
new file mode 100644
index 0000000..057791b
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
@@ -0,0 +1,344 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+import org.apache.jackrabbit.api.security.user.AuthorizableTypeException;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.Query;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import ch.qos.logback.classic.Level;
+
+/**
+ *
+ */
+public class MockUserManagerTest {
+ protected MockUserManager userManager;
+ protected ValueFactory vf = ValueFactoryImpl.getInstance();
+
+ @Before
+ public void before() throws RepositoryException {
+ userManager = new MockUserManager();
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#removeAuthorizable(org.apache.jackrabbit.api.security.user.Authorizable)}.
+ */
+ @Test
+ public void testRemoveAuthorizable() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup("group1");
+ @NotNull User user1 = userManager.createUser("user1", "pwd");
+ assertTrue(userManager.removeAuthorizable(user1));
+ assertTrue(userManager.removeAuthorizable(group1));
+
+ assertFalse(userManager.removeAuthorizable(user1));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#all(int)}.
+ */
+ @Test
+ public void testAll() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup("group1");
+ @NotNull User user1 = userManager.createUser("user1", "pwd");
+ Set<Authorizable> allAuthorizables = userManager.all(UserManager.SEARCH_TYPE_AUTHORIZABLE);
+ assertEquals(2, allAuthorizables.size());
+ assertTrue(allAuthorizables.contains(user1));
+ assertTrue(allAuthorizables.contains(group1));
+
+ Set<Authorizable> allUsers = userManager.all(UserManager.SEARCH_TYPE_USER);
+ assertEquals(1, allUsers.size());
+ assertTrue(allUsers.contains(user1));
+
+ Set<Authorizable> allGroups = userManager.all(UserManager.SEARCH_TYPE_GROUP);
+ assertEquals(1, allGroups.size());
+ assertTrue(allGroups.contains(group1));
+
+ Set<Authorizable> invalidType = userManager.all(-1);
+ assertTrue(invalidType.isEmpty());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#isAutoSave()}.
+ */
+ @Test
+ public void testIsAutoSave() {
+ assertFalse(userManager.isAutoSave());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#autoSave(boolean)}.
+ */
+ @Test
+ public void testAutoSave() throws UnsupportedRepositoryOperationException, RepositoryException {
+ userManager.autoSave(true);
+ assertTrue(userManager.isAutoSave());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createGroup(java.lang.String)}.
+ */
+ @Test
+ public void testCreateGroupString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup("group1");
+ assertNotNull(group1);
+
+ assertThrows(AuthorizableExistsException.class, () -> userManager.createGroup("group1"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createGroup(java.security.Principal)}.
+ */
+ @Test
+ public void testCreateGroupPrincipal() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup(() -> "group1");
+ assertNotNull(group1);
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createGroup(java.security.Principal, java.lang.String)}.
+ */
+ @Test
+ public void testCreateGroupPrincipalString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup(() -> "group1", "/home/groups/path1");
+ assertNotNull(group1);
+ assertEquals("/home/groups/path1/group1", group1.getPath());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createGroup(java.lang.String, java.security.Principal, java.lang.String)}.
+ */
+ @Test
+ public void testCreateGroupStringPrincipalString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull Group group1 = userManager.createGroup("group1", () -> "group1", "/home/groups/path1");
+ assertNotNull(group1);
+ assertEquals("/home/groups/path1/group1", group1.getPath());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createSystemUser(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCreateSystemUser() {
+ assertThrows(UnsupportedOperationException.class, () -> userManager.createSystemUser("systemuser1", "/home/users/system"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createUser(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCreateUserStringString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd");
+ assertNotNull(user1);
+
+ assertThrows(AuthorizableExistsException.class, () -> userManager.createUser("user1", "pwd"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#createUser(java.lang.String, java.lang.String, java.security.Principal, java.lang.String)}.
+ */
+ @Test
+ public void testCreateUserStringStringPrincipalString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ assertNotNull(user1);
+ assertEquals("/home/users/path1/user1", user1.getPath());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#findAuthorizables(org.apache.jackrabbit.api.security.user.Query)}.
+ */
+ @Test
+ public void testFindAuthorizablesQuery() throws RepositoryException {
+ Query query = Mockito.mock(Query.class);
+ assertThrows(UnsupportedOperationException.class, () -> userManager.findAuthorizables(query));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#findAuthorizables(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testFindAuthorizablesStringString() throws RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ user1.setProperty("prop1", vf.createValue("prop1Value"));
+ user1.setProperty("sub1/prop2", vf.createValue("prop2Value"));
+
+ // none found
+ @NotNull Iterator<Authorizable> authorizables = userManager.findAuthorizables("prop1", "other");
+ assertFalse(authorizables.hasNext());
+
+ // found by name
+ authorizables = userManager.findAuthorizables("prop1", "prop1Value");
+ assertTrue(authorizables.hasNext());
+ assertEquals(user1, authorizables.next());
+
+ // found by relPath
+ authorizables = userManager.findAuthorizables("sub1/prop2", "prop2Value");
+ assertTrue(authorizables.hasNext());
+ assertEquals(user1, authorizables.next());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#findAuthorizables(java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testFindAuthorizablesStringStringInt() throws RepositoryException {
+ @NotNull Group group1 = userManager.createGroup("group1", () -> "group1", "/home/groups/path1");
+ group1.setProperty("prop1", vf.createValue("prop1Value"));
+ group1.setProperty("sub1/prop2", vf.createValue("prop2Value"));
+
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ user1.setProperty("prop1", vf.createValue("prop1Value"));
+ user1.setProperty("sub1/prop2", vf.createValue("prop2Value"));
+
+ // none found
+ @NotNull Iterator<Authorizable> authorizables = userManager.findAuthorizables("prop1", "other", UserManager.SEARCH_TYPE_AUTHORIZABLE);
+ assertFalse(authorizables.hasNext());
+
+ // found by name
+ authorizables = userManager.findAuthorizables("prop1", "prop1Value", UserManager.SEARCH_TYPE_USER);
+ assertTrue(authorizables.hasNext());
+ assertEquals(user1, authorizables.next());
+
+ // found by name
+ authorizables = userManager.findAuthorizables("prop1", "prop1Value", UserManager.SEARCH_TYPE_GROUP);
+ assertTrue(authorizables.hasNext());
+ assertEquals(group1, authorizables.next());
+
+ // found by relPath
+ authorizables = userManager.findAuthorizables("sub1/prop2", "prop2Value", UserManager.SEARCH_TYPE_USER);
+ assertTrue(authorizables.hasNext());
+ assertEquals(user1, authorizables.next());
+
+ // found by relPath
+ authorizables = userManager.findAuthorizables("sub1/prop2", "prop2Value", UserManager.SEARCH_TYPE_GROUP);
+ assertTrue(authorizables.hasNext());
+ assertEquals(group1, authorizables.next());
+
+ // found by relPath but specific value is not necessary
+ authorizables = userManager.findAuthorizables("sub1/prop2", null, UserManager.SEARCH_TYPE_GROUP);
+ assertTrue(authorizables.hasNext());
+ assertEquals(group1, authorizables.next());
+
+ // not found by relPath
+ authorizables = userManager.findAuthorizables("sub1/prop3","prop3Value", UserManager.SEARCH_TYPE_GROUP);
+ assertFalse(authorizables.hasNext());
+
+ // some invalid type
+ authorizables = userManager.findAuthorizables("sub1/prop2", "prop2Value", -1);
+ assertFalse(authorizables.hasNext());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#getAuthorizable(java.lang.String)}.
+ */
+ @Test
+ public void testGetAuthorizableString() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @Nullable Authorizable authorizable = userManager.getAuthorizable(user1.getID());
+ assertEquals(user1, authorizable);
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#getAuthorizable(java.security.Principal)}.
+ */
+ @Test
+ public void testGetAuthorizablePrincipal() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @Nullable Authorizable authorizable = userManager.getAuthorizable(() -> "user1");
+ assertEquals(user1, authorizable);
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#getAuthorizable(java.lang.String, java.lang.Class)}.
+ */
+ @Test
+ public void testGetAuthorizableStringClassOfT() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @Nullable Authorizable authorizable = userManager.getAuthorizable("user1", User.class);
+ assertEquals(user1, authorizable);
+
+ assertThrows(AuthorizableTypeException.class, () -> userManager.getAuthorizable("user1", Group.class));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUserManager#getAuthorizableByPath(java.lang.String)}.
+ */
+ @Test
+ public void testGetAuthorizableByPath() throws AuthorizableExistsException, RepositoryException {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ @Nullable Authorizable authorizable = userManager.getAuthorizableByPath(user1.getPath());
+ assertEquals(user1, authorizable);
+
+ //throws exception
+ }
+ @Test
+ public void testGetAuthorizableByPathCatchRepositoryException() throws Exception {
+ @NotNull User user1 = userManager.createUser("user1", "pwd", () -> "user1", "/home/users/path1");
+ User mockAuthorizable = Mockito.spy(user1);
+ // replace the original with our mocked copy
+ userManager.authorizables.put(mockAuthorizable.getID(), mockAuthorizable);
+ Mockito.doThrow(RepositoryException.class).when(mockAuthorizable).getPath();
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(userManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ assertNull(userManager.getAuthorizableByPath(user1.getPath()));
+
+ // verify the msg was logged
+ capture.assertNotContains(Level.DEBUG, "Failed to match authorizable path");
+ }
+
+ // verify that the debug msg about exception was logged
+ try (LogCapture capture = new LogCapture(userManager.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ assertNull(userManager.getAuthorizableByPath(user1.getPath()));
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to match authorizable path");
+ }
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
new file mode 100644
index 0000000..11e44e8
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.sling.testing.mock.jcr;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import org.apache.jackrabbit.api.security.user.User;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import ch.qos.logback.classic.Level;
+
+/**
+ *
+ */
+public class MockUserTest extends MockAuthorizableTest<User> {
+
+ @Override
+ protected User createAuthorizable() throws RepositoryException {
+ return userManager.createUser("user1", "pwd");
+ }
+
+ @Test
+ @Override
+ public void testGetID() throws RepositoryException {
+ assertEquals("user1", authorizable.getID());
+ }
+
+ @Test
+ @Override
+ public void testIsGroup() {
+ assertFalse(authorizable.isGroup());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#isAdmin()}.
+ */
+ @Test
+ public void testIsAdmin() throws RepositoryException {
+ assertFalse(authorizable.isAdmin());
+ assertTrue(userManager.createUser("admin", "admin").isAdmin());
+ }
+ @Test
+ public void testIsAdminCatchRepositoryException() throws Exception {
+ User mockAuthorizable = Mockito.spy(authorizable);
+ Mockito.doThrow(RepositoryException.class).when(mockAuthorizable).getID();
+
+ // verify that the debug msg about exception was not logged
+ try (LogCapture capture = new LogCapture(authorizable.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.WARN);
+
+ // this should log an warning message
+ assertFalse(mockAuthorizable.isAdmin());
+
+ // verify the msg was logged
+ capture.assertNotContains(Level.DEBUG, "Failed to determine if this is admin");
+ }
+
+ // verify that the debug msg about exception was logged
+ try (LogCapture capture = new LogCapture(authorizable.getClass().getName(), true)) {
+ // bump up the log level
+ capture.setLoggerLevel(Level.DEBUG);
+
+ // this should log an warning message
+ assertFalse(mockAuthorizable.isAdmin());
+
+ // verify the msg was logged
+ capture.assertContains(Level.DEBUG, "Failed to determine if this is admin");
+ }
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#isSystemUser()}.
+ */
+ @Test
+ public void testIsSystemUser() {
+ assertFalse(authorizable.isSystemUser());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#getCredentials()}.
+ */
+ @Test
+ public void testGetCredentials() throws RepositoryException {
+ @NotNull Credentials credentials = authorizable.getCredentials();
+ assertTrue(credentials instanceof SimpleCredentials);
+ assertEquals(authorizable.getID(), ((SimpleCredentials)credentials).getUserID());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#getImpersonation()}.
+ */
+ @Test
+ public void testGetImpersonation() {
+ assertThrows(UnsupportedOperationException.class, () -> authorizable.getImpersonation());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#changePassword(java.lang.String)}.
+ */
+ @Test
+ public void testChangePasswordString() throws RepositoryException {
+ authorizable.changePassword("changed");
+ assertPassword("changed".toCharArray());
+
+ assertThrows(RepositoryException.class, () -> authorizable.changePassword(null));
+ }
+
+ protected void assertPassword(char [] expectedPwd) throws RepositoryException {
+ SimpleCredentials creds = (SimpleCredentials)authorizable.getCredentials();
+ assertArrayEquals(expectedPwd, creds.getPassword());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#changePassword(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testChangePasswordStringString() throws RepositoryException {
+ authorizable.changePassword("changed", "");
+ assertPassword("changed".toCharArray());
+
+ assertThrows(RepositoryException.class, () -> authorizable.changePassword("changed2", "wrong"));
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#disable(java.lang.String)}.
+ */
+ @Test
+ public void testDisable() throws RepositoryException {
+ authorizable.disable("Expired");
+ assertTrue(authorizable.isDisabled());
+ assertEquals("Expired", authorizable.getDisabledReason());
+
+ authorizable.disable(null);
+ assertFalse(authorizable.isDisabled());
+ assertNull(authorizable.getDisabledReason());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#isDisabled()}.
+ */
+ @Test
+ public void testIsDisabled() throws RepositoryException {
+ assertFalse(authorizable.isDisabled());
+ authorizable.disable("Obsolete");
+ assertTrue(authorizable.isDisabled());
+ }
+
+ /**
+ * Test method for {@link org.apache.sling.testing.mock.jcr.MockUser#getDisabledReason()}.
+ */
+ @Test
+ public void testGetDisabledReason() throws RepositoryException {
+ assertNull(authorizable.getDisabledReason());
+ authorizable.disable("Obsolete");
+ assertEquals("Obsolete", authorizable.getDisabledReason());
+ }
+
+ @Test
+ @Override
+ public void testGetPath() throws UnsupportedRepositoryOperationException, RepositoryException {
+ assertEquals("/home/users/user1", authorizable.getPath());
+ }
+
+}
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..ac70aa8
--- /dev/null
+++ b/src/test/resources/logback-test.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<configuration>
+ <appender name="file" class="ch.qos.logback.core.FileAppender">
+ <File>target/testing.log</File>
+ <encoder>
+ <pattern>%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m \(%F, line %L\)%n</pattern>
+ </encoder>
+ </appender>
+ <root level="INFO">
+ <appender-ref ref="file"/>
+ </root>
+</configuration>