This is an automated email from the ASF dual-hosted git repository. angela pushed a commit to branch OAK-9868 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit e552e3e7012cdb2a9d89ebbe7ccf4dc486af1d67 Author: angela <[email protected]> AuthorDate: Tue Aug 9 13:39:50 2022 +0200 OAK-9868 : Introduce interface to extract tree from users --- .../external/impl/principal/DynamicGroupUtil.java | 3 +- .../ExternalGroupPrincipalProviderTest.java | 9 +++++- .../authentication/token/TokenProviderImpl.java | 12 ++++++- .../oak/security/user/AuthorizableImpl.java | 12 ++++--- .../oak/security/user/UserAuthentication.java | 7 +--- .../jackrabbit/oak/security/user/UserImporter.java | 4 +-- .../apache/jackrabbit/oak/security/user/Utils.java | 11 +++++++ .../jackrabbit/oak/security/user/UtilsTest.java | 37 ++++++++++++++++++++++ .../tree/{package-info.java => TreeAware.java} | 18 +++++++++-- .../jackrabbit/oak/plugins/tree/package-info.java | 2 +- .../security/user/action/PasswordChangeAction.java | 7 ++-- .../user/action/PasswordChangeActionTest.java | 33 +++++++++++++++---- 12 files changed, 128 insertions(+), 27 deletions(-) diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicGroupUtil.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicGroupUtil.java index d49479bfd2..8612c64a67 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicGroupUtil.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicGroupUtil.java @@ -22,6 +22,7 @@ import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType; import org.apache.jackrabbit.oak.spi.security.user.UserConstants; @@ -65,7 +66,7 @@ class DynamicGroupUtil { @NotNull static Tree getTree(@NotNull Authorizable authorizable, @NotNull Root root) throws RepositoryException { - return root.getTree(authorizable.getPath()); + return (authorizable instanceof TreeAware) ? ((TreeAware) authorizable).getTree() : root.getTree(authorizable.getPath()); } static boolean hasStoredMemberInfo(@NotNull Group group, @NotNull Root root) { diff --git a/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalGroupPrincipalProviderTest.java b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalGroupPrincipalProviderTest.java index c6e6329150..4925a1b9a2 100644 --- a/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalGroupPrincipalProviderTest.java +++ b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalGroupPrincipalProviderTest.java @@ -30,6 +30,7 @@ import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.namepath.NamePathMapper; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityException; @@ -70,6 +71,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; public class ExternalGroupPrincipalProviderTest extends AbstractPrincipalTest { @@ -401,8 +403,10 @@ public class ExternalGroupPrincipalProviderTest extends AbstractPrincipalTest { @Test public void testGetPrincipalsNonExistingUserTree() throws Exception { - Authorizable a = spy(getUserManager(root).getAuthorizable(USER_ID)); + Authorizable a = mock(Authorizable.class, withSettings().extraInterfaces(User.class)); + when(a.getID()).thenReturn(USER_ID); when(a.getPath()).thenReturn("/path/to/non/existing/item"); + UserManager um = when(mock(UserManager.class).getAuthorizable(USER_ID)).thenReturn(a).getMock(); UserConfiguration uc = when(mock(UserConfiguration.class).getUserManager(root, getNamePathMapper())).thenReturn(um).getMock(); @@ -415,6 +419,9 @@ public class ExternalGroupPrincipalProviderTest extends AbstractPrincipalTest { Authorizable group = getUserManager(root).createGroup("testGroup"); Authorizable a = spy(getUserManager(root).getAuthorizable(USER_ID)); when(a.getPath()).thenReturn(group.getPath()); + if (a instanceof TreeAware && group instanceof TreeAware) { + when(((TreeAware) a).getTree()).thenReturn(((TreeAware)group).getTree()); + } UserManager um = when(mock(UserManager.class).getAuthorizable(USER_ID)).thenReturn(a).getMock(); UserConfiguration uc = when(mock(UserConfiguration.class).getUserManager(root, getNamePathMapper())).thenReturn(um).getMock(); diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java index 82b2e56df6..0ea39ff1ca 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java @@ -42,7 +42,9 @@ import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.namepath.NamePathMapper; +import org.apache.jackrabbit.oak.namepath.PathMapper; import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials; @@ -381,7 +383,7 @@ class TokenProviderImpl implements TokenProvider, TokenConstants { String userPath = user.getPath(); parentPath = userPath + '/' + TOKENS_NODE_NAME; - Tree userNode = root.getTree(userPath); + Tree userNode = getTree(user, userPath); tokenParent = TreeUtil.getOrAddChild(userNode, TOKENS_NODE_NAME, TOKENS_NT_NAME); root.commit(); @@ -403,6 +405,14 @@ class TokenProviderImpl implements TokenProvider, TokenConstants { return tokenParent; } + public @NotNull Tree getTree(@NotNull User user, @NotNull String userPath) { + if (user instanceof TreeAware) { + return ((TreeAware) user).getTree(); + } else { + return root.getTree(userPath); + } + } + /** * Create a new token node below the specified {@code parent}. * diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java index 1369abb911..7e4418682d 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java @@ -23,6 +23,7 @@ import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.security.user.monitor.UserMonitor; import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType; import org.apache.jackrabbit.oak.spi.security.user.DynamicMembershipProvider; @@ -43,7 +44,7 @@ import static org.apache.jackrabbit.oak.api.Type.STRING; /** * Base class for {@code User} and {@code Group} implementations. */ -abstract class AuthorizableImpl implements Authorizable, UserConstants { +abstract class AuthorizableImpl implements Authorizable, UserConstants, TreeAware { /** * logger instance @@ -179,10 +180,11 @@ abstract class AuthorizableImpl implements Authorizable, UserConstants { String typeStr = (isGroup()) ? "Group '" : "User '"; return new StringBuilder().append(typeStr).append(id).append('\'').toString(); } - - //-------------------------------------------------------------------------- + + //----------------------------------------------------------< TreeAware >--- + @Override @NotNull - Tree getTree() { + public Tree getTree() { if (tree.exists()) { return tree; } else { @@ -190,6 +192,8 @@ abstract class AuthorizableImpl implements Authorizable, UserConstants { } } + //-------------------------------------------------------------------------- + @Nullable String getPrincipalNameOrNull() { if (principalName == null) { diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java index 8d0828d3c1..09b35cf0b0 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java @@ -239,12 +239,7 @@ class UserAuthentication implements Authentication, UserConstants { @Nullable private Long getPasswordLastModified(@NotNull User user) throws RepositoryException { - Tree userTree; - if (user instanceof UserImpl) { - userTree = ((UserImpl) user).getTree(); - } else { - userTree = root.getTree(user.getPath()); - } + Tree userTree = Utils.getTree(user, root); PropertyState property = userTree.getChild(REP_PWD).getProperty(REP_PASSWORD_LAST_MODIFIED); return (property != null) ? property.getValue(Type.LONG) : null; } diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java index 1b36403755..90a0af8b8c 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java @@ -640,7 +640,7 @@ class UserImporter implements ProtectedPropertyImporter, ProtectedNodeImporter, if (!nonExisting.isEmpty()) { Stopwatch watch = Stopwatch.createStarted(); log.debug("ImportBehavior.BESTEFFORT: Found {} entries of rep:members pointing to non-existing authorizables. Adding to rep:members.", nonExisting.size()); - Tree groupTree = root.getTree(gr.getPath()); + Tree groupTree = Utils.getTree(gr, root); MembershipProvider membershipProvider = userManager.getMembershipProvider(); @@ -741,7 +741,7 @@ class UserImporter implements ProtectedPropertyImporter, ProtectedNodeImporter, // 2. adjust set of impersonators List<String> nonExisting = updateImpersonators(a, imp, toRemove, toAdd); if (!nonExisting.isEmpty()) { - Tree userTree = checkNotNull(root.getTree(a.getPath())); + Tree userTree = Utils.getTree(a, root); // copy over all existing impersonators to the nonExisting list PropertyState impersonators = userTree.getProperty(REP_IMPERSONATORS); if (impersonators != null) { diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java index f0f19031ef..197f661ab0 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java @@ -18,8 +18,10 @@ package org.apache.jackrabbit.oak.security.user; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.User; +import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; @@ -103,4 +105,13 @@ final class Utils { return null; } } + + @NotNull + static Tree getTree(@NotNull Authorizable authorizable, @NotNull Root root) throws RepositoryException { + if (authorizable instanceof TreeAware) { + return ((TreeAware) authorizable).getTree(); + } else { + return root.getTree(authorizable.getPath()); + } + } } diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java index 362d782a23..6462817d17 100644 --- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java +++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java @@ -21,8 +21,10 @@ import com.google.common.collect.ImmutableMap; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.oak.AbstractSecurityTest; +import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants; import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; import org.jetbrains.annotations.NotNull; @@ -35,8 +37,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; public class UtilsTest extends AbstractSecurityTest { @@ -149,4 +156,34 @@ public class UtilsTest extends AbstractSecurityTest { when(a.isGroup()).thenReturn(true); assertFalse(Utils.isEveryone(a)); } + + @Test + public void testGetTreeFromTreeAware() throws Exception { + Tree t = mock(Tree.class); + Root r = mock(Root.class); + + Authorizable a = mock(Authorizable.class, withSettings().extraInterfaces(TreeAware.class)); + when(((TreeAware) a).getTree()).thenReturn(t); + + assertSame(t, Utils.getTree(a, r)); + + verifyNoInteractions(r); + verify((TreeAware) a).getTree(); + verifyNoMoreInteractions(a); + } + + @Test + public void testGetTree() throws Exception { + Tree t = mock(Tree.class); + Root r = when(mock(Root.class).getTree("/user/path")).thenReturn(t).getMock(); + + Authorizable a = mock(Authorizable.class); + when(a.getPath()).thenReturn("/user/path"); + + assertSame(t, Utils.getTree(a, r)); + + verify(r).getTree(anyString()); + verify(a).getPath(); + verifyNoMoreInteractions(a, r); + } } diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/TreeAware.java similarity index 62% copy from oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java copy to oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/TreeAware.java index 221dffa693..db24b0f8dd 100644 --- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java +++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/TreeAware.java @@ -6,7 +6,7 @@ * (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 + * 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, @@ -14,7 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("3.2.1") package org.apache.jackrabbit.oak.plugins.tree; -import org.osgi.annotation.versioning.Version; +import org.apache.jackrabbit.oak.api.Tree; +import org.jetbrains.annotations.NotNull; + +/** + * Oak internal utility interface to avoid repeated retrieval of an underlying {@link Tree}. + * Note, that is is the responsibility of the caller to make user that the content session and root + * used to retrieve {@link TreeAware} object remains the same. + */ +public interface TreeAware { + + @NotNull + Tree getTree(); + +} \ No newline at end of file diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java index 221dffa693..6141ac0312 100644 --- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java +++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/plugins/tree/package-info.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("3.2.1") +@Version("3.3.0") package org.apache.jackrabbit.oak.plugins.tree; import org.osgi.annotation.versioning.Version; diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeAction.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeAction.java index 3efcbade9b..014e953000 100644 --- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeAction.java +++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeAction.java @@ -21,7 +21,9 @@ import javax.jcr.nodetype.ConstraintViolationException; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.namepath.NamePathMapper; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.spi.security.user.UserConstants; import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil; import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; @@ -55,7 +57,8 @@ public class PasswordChangeAction extends AbstractAuthorizableAction { //------------------------------------------------------------< private >--- @Nullable - private String getPasswordHash(@NotNull Root root, @NotNull User user) throws RepositoryException { - return TreeUtil.getString(root.getTree(user.getPath()), UserConstants.REP_PASSWORD); + private static String getPasswordHash(@NotNull Root root, @NotNull User user) throws RepositoryException { + Tree tree = (user instanceof TreeAware) ? ((TreeAware)user).getTree() : root.getTree(user.getPath()); + return TreeUtil.getString(tree, UserConstants.REP_PASSWORD); } } diff --git a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeActionTest.java b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeActionTest.java index 784712e57a..aaf0567f68 100644 --- a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeActionTest.java +++ b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordChangeActionTest.java @@ -21,6 +21,7 @@ import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; +import org.apache.jackrabbit.oak.plugins.tree.TreeAware; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.user.UserConstants; @@ -28,19 +29,23 @@ import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil; import org.jetbrains.annotations.Nullable; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import javax.jcr.nodetype.ConstraintViolationException; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; public class PasswordChangeActionTest { private static final String USER_PATH = "/userpath"; - private final NamePathMapper namePathMapper = Mockito.mock(NamePathMapper.class); + private final NamePathMapper namePathMapper = mock(NamePathMapper.class); private PasswordChangeAction pwChangeAction; @@ -49,19 +54,19 @@ public class PasswordChangeActionTest { @Before public void before() throws Exception { pwChangeAction = new PasswordChangeAction(); - pwChangeAction.init(Mockito.mock(SecurityProvider.class), ConfigurationParameters.EMPTY); + pwChangeAction.init(mock(SecurityProvider.class), ConfigurationParameters.EMPTY); - user = Mockito.mock(User.class); + user = mock(User.class); when(user.getPath()).thenReturn(USER_PATH); } private static Root createRoot(@Nullable String pw) throws Exception { - Tree userTree = Mockito.mock(Tree.class); + Tree userTree = mock(Tree.class); if (pw != null) { String pwHash = PasswordUtil.buildPasswordHash(pw); when(userTree.getProperty(UserConstants.REP_PASSWORD)).thenReturn(PropertyStates.createProperty(UserConstants.REP_PASSWORD, pwHash)); } - Root root = Mockito.mock(Root.class); + Root root = mock(Root.class); when(root.getTree(USER_PATH)).thenReturn(userTree); return root; } @@ -89,4 +94,20 @@ public class PasswordChangeActionTest { verify(user).getPath(); verifyNoMoreInteractions(user); } + + @Test + public void testUserIsTreeAware() throws Exception { + Root r = createRoot("pw"); + Tree t = r.getTree(USER_PATH); + + User u = mock(User.class, withSettings().extraInterfaces(TreeAware.class)); + when(((TreeAware) u).getTree()).thenReturn(t); + + pwChangeAction.onPasswordChange(u, "changedPassword", r, namePathMapper); + + verify(u, never()).getPath(); + verify(((TreeAware) u)).getTree(); + verify(r).getTree(USER_PATH); + verifyNoMoreInteractions(r, u); + } }
