diff --git a/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java b/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
index 8d7b54d07d..b32ccaf972 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
@@ -23,7 +23,7 @@
* along with Alfresco. If not, see .
* #L%
*/
-package org.alfresco.repo.domain.permissions;
+package org.alfresco.repo.domain.permissions;
import java.io.Serializable;
import java.util.ArrayList;
@@ -392,8 +392,20 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
{
return;
}
- else
- {
+ else
+ {
+ // When node is copied when the aspect is applied, the sharedACLtoReplace will not match the children's ACLS
+ // to replace, we need to use the current one.
+ Long currentAcl = nodeDAO.getNodeAclId(nodeId);
+
+ if (nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
+ {
+ // If node has a pending acl, retrieve the sharedAclToReplace from node property. When the job calls
+ // this, it already does it but on move and copy operations, it uses the new parents old ACL.
+ sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
+
+ }
+
// Lazily retrieve/create the shared ACL
if (mergeFrom == null)
{
@@ -405,33 +417,26 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
nodeDAO.setNodeAclId(nodeId, mergeFrom);
}
- List children = nodeDAO.getPrimaryChildrenAcls(nodeId);
-
- if(children.size() > 0)
- {
- nodeDAO.setPrimaryChildrenSharedAclId(nodeId, sharedAclToReplace, mergeFrom);
- }
+ List children = nodeDAO.getPrimaryChildrenAcls(nodeId);
if (!propagateOnChildren)
{
return;
- }
+ }
+
for (NodeIdAndAclId child : children)
- {
- Long acl = child.getAclId();
-
+ {
+ //Use the current ACL instead of the stored value, it could've been changed meanwhile
+ Long acl = nodeDAO.getNodeAclId(child.getId());
+
if (acl == null)
{
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
}
else
{
-// if(acl.equals(mergeFrom))
-// {
-// setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false);
-// }
// Still has old shared ACL or already replaced
- if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom))
+ if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom) || acl.equals(currentAcl))
{
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
}
@@ -456,7 +461,22 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
}
}
}
- }
+ }
+
+ // By doing an eager update of the direct children we canot see if another thread has changed the ACL
+ // between the time we get the child nodes and we update them. By updating the direct children last it is
+ // possible to verify if any child has changed meanwhile.
+ if(children.size() > 0)
+ {
+ nodeDAO.setPrimaryChildrenSharedAclId(nodeId, sharedAclToReplace, mergeFrom);
+ }
+
+ // When this is not executed triggered by the job, but a move or copy operation occures on a pending
+ // node, we don't want to apply the OLD ACL that was pending
+ if(nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
+ {
+ removePendingAclAspect(nodeId);
+ }
}
}
@@ -509,25 +529,45 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
}
// set ASPECT_PENDING_FIX_ACL aspect on node to be later on processed with FixedAclUpdater amd switch flag
// FIXED_ACL_ASYNC_REQUIRED_KEY
- addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom);
+ addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom, mergeFrom);
AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY, true);
// stop propagating on children nodes
return false;
}
- private void addFixedAclPendingAspect(Long nodeId, Long sharedAclToReplace, Long inheritFrom)
- {
- Set aspect = new HashSet<>();
- aspect.add(ContentModel.ASPECT_PENDING_FIX_ACL);
- nodeDAO.addNodeAspects(nodeId, aspect);
- Map pendingAclProperties = new HashMap<>();
- pendingAclProperties.put(ContentModel.PROP_SHARED_ACL_TO_REPLACE, sharedAclToReplace);
- pendingAclProperties.put(ContentModel.PROP_INHERIT_FROM_ACL, inheritFrom);
- nodeDAO.addNodeProperties(nodeId, pendingAclProperties);
- if (log.isDebugEnabled())
- {
- log.debug("Set Fixed Acl Pending : " + nodeId + " " + nodeDAO.getNodePair(nodeId).getSecond());
+ private void addFixedAclPendingAspect(Long nodeId, Long sharedAclToReplace, Long inheritFrom, Long mergeFrom)
+ {
+ //If the node already has the pending ACL aspect, just update the new inheritFrom value
+ if (nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
+ {
+ Map pendingAclProperties = new HashMap<>();
+ pendingAclProperties.put(ContentModel.PROP_INHERIT_FROM_ACL, inheritFrom);
+ nodeDAO.addNodeProperties(nodeId, pendingAclProperties);
+ return;
+ }
+
+ Set aspect = new HashSet<>();
+ aspect.add(ContentModel.ASPECT_PENDING_FIX_ACL);
+ nodeDAO.addNodeAspects(nodeId, aspect);
+ Map pendingAclProperties = new HashMap<>();
+ pendingAclProperties.put(ContentModel.PROP_SHARED_ACL_TO_REPLACE, sharedAclToReplace);
+ pendingAclProperties.put(ContentModel.PROP_INHERIT_FROM_ACL, inheritFrom);
+ nodeDAO.addNodeProperties(nodeId, pendingAclProperties);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Set Fixed Acl Pending : " + nodeId + " " + nodeDAO.getNodePair(nodeId).getSecond());
}
+ }
+
+ public void removePendingAclAspect(Long nodeId)
+ {
+ Set aspects = new HashSet<>(1);
+ aspects.add(ContentModel.ASPECT_PENDING_FIX_ACL);
+ Set pendingFixAclProperties = new HashSet<>();
+ pendingFixAclProperties.add(ContentModel.PROP_SHARED_ACL_TO_REPLACE);
+ pendingFixAclProperties.add(ContentModel.PROP_INHERIT_FROM_ACL);
+ nodeDAO.removeNodeAspects(nodeId, aspects);
+ nodeDAO.removeNodeProperties(nodeId, pendingFixAclProperties);
}
/**
diff --git a/repository/src/main/java/org/alfresco/repo/domain/permissions/AccessControlListDAO.java b/repository/src/main/java/org/alfresco/repo/domain/permissions/AccessControlListDAO.java
index e5ac53fbf3..700f280c80 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/permissions/AccessControlListDAO.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/permissions/AccessControlListDAO.java
@@ -105,5 +105,7 @@ public interface AccessControlListDAO
public void updateInheritance(Long childNodeId, Long oldParentAclId, Long newParentAclId);
- public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List changes, boolean set);
+ public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List changes, boolean set);
+
+ public void removePendingAclAspect(Long nodeId);
}
diff --git a/repository/src/main/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java b/repository/src/main/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java
index bfbaa5d336..8812ff5028 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java
@@ -53,7 +53,6 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeRef.Status;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -93,8 +92,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
private int maxItemBatchSize = 100;
private int numThreads = 4;
- private ClassPolicyDelegate onInheritPermissionsDisabledDelegate;
- private PolicyComponent policyComponent;
+ private ClassPolicyDelegate onInheritPermissionsDisabledDelegate;
+ private PolicyComponent policyComponent;
private PolicyIgnoreUtil policyIgnoreUtil;
public void setNumThreads(int numThreads)
@@ -137,8 +136,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
{
this.lockTimeToLive = lockTimeToLive;
this.lockRefreshTime = lockTimeToLive / 2;
- }
-
+ }
+
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
@@ -151,7 +150,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
public void init()
{
- onInheritPermissionsDisabledDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class);
+ onInheritPermissionsDisabledDelegate = policyComponent
+ .registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class);
}
private class GetNodesWithAspects
@@ -264,35 +264,34 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
{
log.debug(String.format("Processing node %s", nodeRef));
}
+
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do not
// process
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
{
- nodeDAO.removeNodeAspects(nodeId, aspects);
- nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS);
+ accessControlListDAO.removePendingAclAspect(nodeId);
return null;
}
// retrieve acl properties from node
- Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId,
- ContentModel.PROP_INHERIT_FROM_ACL);
- Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId,
- ContentModel.PROP_SHARED_ACL_TO_REPLACE);
+ Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
+ Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
// set inheritance using retrieved prop
- accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace,
- true);
+ accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true);
+
+ // Remove aspect
+ accessControlListDAO.removePendingAclAspect(nodeId);
- nodeDAO.removeNodeAspects(nodeId, aspects);
- nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS);
-
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
{
- boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
+ boolean transformedToAsyncOperation = toBoolean(
+ (Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
- OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate.get(ContentModel.TYPE_BASE);
+ OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
+ .get(ContentModel.TYPE_BASE);
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
}
@@ -406,12 +405,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
AclWorkProvider provider = new AclWorkProvider();
AclWorker worker = new AclWorker();
- BatchProcessor bp = new BatchProcessor<>(
- "FixedAclUpdater",
- transactionService.getRetryingTransactionHelper(),
- provider,
- numThreads, maxItemBatchSize,
- applicationContext,
+ BatchProcessor bp = new BatchProcessor<>("FixedAclUpdater",
+ transactionService.getRetryingTransactionHelper(), provider, numThreads, maxItemBatchSize, applicationContext,
log, 100);
int count = bp.process(worker, true);
return count;
@@ -424,7 +419,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
finally
{
jobLockRefreshCallback.isActive.set(false);
- if(lockToken != null)
+ if (lockToken != null)
{
jobLockService.releaseLock(lockToken, lockQName);
}
diff --git a/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java b/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
index 8bd6ecaa78..5c62103894 100644
--- a/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
+++ b/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
@@ -27,29 +27,43 @@ package org.alfresco.repo.domain.permissions;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
import org.alfresco.repo.model.Repository;
-import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent;
-import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.coci.CheckOutCheckInService;
+import org.alfresco.service.cmr.lock.LockService;
+import org.alfresco.service.cmr.lock.LockType;
+import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.model.FileNotFoundException;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.security.AuthorityService;
+import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
+import org.springframework.dao.ConcurrencyFailureException;
import junit.framework.TestCase;
@@ -68,15 +82,22 @@ public class FixedAclUpdaterTest extends TestCase
private FileFolderService fileFolderService;
private Repository repository;
private FixedAclUpdater fixedAclUpdater;
- private NodeRef folderAsyncCallNodeRef;
- private NodeRef folderSyncCallNodeRef;
- private NodeRef folderAsyncCallWithCreateNodeRef;
- private NodeRef folderAsyncCallWithDeleteNodeRef;
private PermissionsDaoComponent permissionsDaoComponent;
private PermissionService permissionService;
private NodeDAO nodeDAO;
private NodeRef homeFolderNodeRef;
- private NodeArchiveService nodeArchiveService;
+ private LockService lockService;
+ private CheckOutCheckInService checkOutCheckInService;
+ private ContentService contentService;
+ private AuthorityService authorityService;
+ private static final long MAX_TRANSACTION_TIME_DEFAULT = 50;
+ private static final int[] filesPerLevelMoreFolders = { 5, 3, 1, 50 };
+ private static final int[] filesPerLevelMoreFiles = { 5, 100 };
+ private long maxTransactionTime;
+ private static HashMap> errors;
+ private static String TEST_GROUP_NAME = "FixedACLUpdaterTest";
+ private static String TEST_GROUP_NAME_FULL = PermissionService.GROUP_PREFIX + TEST_GROUP_NAME;
+ private static String DEFAULT_PERMISSION = PermissionService.CONTRIBUTOR;
@Override
public void setUp() throws Exception
@@ -90,37 +111,1128 @@ public class FixedAclUpdaterTest extends TestCase
permissionsDaoComponent = (PermissionsDaoComponent) ctx.getBean("admPermissionsDaoComponent");
permissionService = (PermissionService) ctx.getBean("permissionService");
nodeDAO = (NodeDAO) ctx.getBean("nodeDAO");
- nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService");
-
+ lockService = (LockService) ctx.getBean("lockService");
+ checkOutCheckInService = (CheckOutCheckInService) ctx.getBean("checkOutCheckInService");
+ contentService = (ContentService) ctx.getBean("contentService");
+ authorityService = (AuthorityService) ctx.getBean("authorityService");
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
- NodeRef home = repository.getCompanyHome();
- // create a folder hierarchy for which will change permission inheritance
- int[] filesPerLevel = { 5, 5, 5, 5 };
+ homeFolderNodeRef = repository.getCompanyHome();
+ maxTransactionTime = MAX_TRANSACTION_TIME_DEFAULT;
+ setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
+ }
- //Test folder for Async Call test
- RetryingTransactionCallback cb1 = createFolderHierchyCallback(home, fileFolderService, "rootFolderAsyncCall",
- filesPerLevel);
- folderAsyncCallNodeRef = txnHelper.doInTransaction(cb1);
+ @Override
+ public void tearDown() throws Exception
+ {
+ AuthenticationUtil.clearCurrentSecurityContext();
+ }
- //Test folder for Sync Call test
- RetryingTransactionCallback cb2 = createFolderHierchyCallback(home, fileFolderService, "rootFolderSyncCall",
- filesPerLevel);
- folderSyncCallNodeRef = txnHelper.doInTransaction(cb2);
+ /*
+ * Test setting permissions having the maxTransactionTime set to 24H, disabling the need for the job
+ */
+ @Test
+ public void testSyncNoTimeOut()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testSyncNoTimeOutFolder");
+ ACLComparator aclComparator = new ACLComparator(folderRef);
- //Test folder for Asyc Call test with node creation
- RetryingTransactionCallback cb3 = createFolderHierchyCallback(home, fileFolderService,
- "rootFolderAsyncWithCreateCall", filesPerLevel);
- folderAsyncCallWithCreateNodeRef = txnHelper.doInTransaction(cb3);
-
- //Test folder for Asyc Call test with node deletion
- RetryingTransactionCallback cb4 = createFolderHierchyCallback(home, fileFolderService,
- "rootFolderAsyncWithDeleteCall", filesPerLevel);
- folderAsyncCallWithDeleteNodeRef = txnHelper.doInTransaction(cb4);
+ try
+ {
+ maxTransactionTime = 86400000;
+ setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
+ setPermissionsOnTree(folderRef, false, false);
+ aclComparator.compareACLs();
- // change setFixedAclMaxTransactionTime to lower value so setInheritParentPermissions on created folder
- // hierarchy require async call
- setFixedAclMaxTransactionTime(permissionsDaoComponent, home, 50);
+ assertEquals("There are nodes pending", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Test setting permissions explicitly as sync, but the operaration times out
+ */
+ @Test
+ public void testSyncTimeOut()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testSyncTimeOutFolder");
+ ACLComparator aclComparator = new ACLComparator(folderRef);
+
+ try
+ {
+ setPermissionsOnTree(folderRef, false, true);
+
+ // Get current ACLS on non pending nodes and validate
+ aclComparator.updateCurrentACLs();
+ assertTrue("Permissions not applied", aclComparator.parentHasOriginalPermission());
+
+ // Validate values in pending ACL node
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ ACLComparator aclComparatorForPending = new ACLComparator(folderWithPendingAcl);
+ assertEquals("Pending inheritFrom value should be the parent ACL id", aclComparator.getParentAcl(),
+ aclComparatorForPending.getPendingInheritFromAcl());
+ assertFalse("Permissions not expected to be applied on a pending node before job",
+ aclComparatorForPending.firstChildHasOriginalPermission());
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Verify if ACLs where applied correctly
+ aclComparator.updateCurrentACLs();
+ aclComparatorForPending.updateCurrentACLs();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertEquals("Processed Pending ACL children doesn't have correct ACL", aclComparator.getChildAcl(),
+ aclComparatorForPending.getChildAcl());
+ assertTrue("Permissions not applied on pending nodes", aclComparatorForPending.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Test setting permissions explicitly as async
+ */
+ @Test
+ public void testAsync()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncFolder");
+ ACLComparator aclComparator = new ACLComparator(folderRef);
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ // Get current ACLS on non pending nodes and validate
+ aclComparator.updateCurrentACLs();
+ assertTrue("Permissions not applied", aclComparator.parentHasOriginalPermission());
+
+ // Validate values in pending ACL node
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+ ACLComparator aclComparatorForPending = new ACLComparator(folderWithPendingAcl);
+ assertEquals("Pending inheritFrom value should be the parent ACL id", aclComparator.getParentAcl(),
+ aclComparatorForPending.getPendingInheritFromAcl());
+ assertFalse("Permissions not expected to be applied on a pending node before job",
+ aclComparatorForPending.firstChildHasOriginalPermission());
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Verify if ACLs where applied correctly
+ aclComparator.updateCurrentACLs();
+ aclComparatorForPending.updateCurrentACLs();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertEquals("Processed Pending ACL children doesn't have correct ACL", aclComparator.getChildAcl(),
+ aclComparatorForPending.getChildAcl());
+ assertTrue("Pending nodes doesn't have same permission as parent",
+ aclComparatorForPending.parentHasOriginalPermission());
+ assertTrue("Children of Pending nodes doesn't have same permission as parent",
+ aclComparatorForPending.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * MNT-21847 - Create a new content in folder that has the aspect applied
+ */
+ @Test
+ public void testAsyncWithNodeCreation()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCreationFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ createFile(fileFolderService, folderWithPendingAcl, "NewFile", ContentModel.TYPE_CONTENT);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * MNT-22009 - Delete node that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeDeletion()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeDeletionFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ fileFolderService.delete(folderWithPendingAcl);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Copy node with no timeout and no pending nodes
+ */
+ @Test
+ public void testSyncCopyNoTimeOut() throws FileExistsException, FileNotFoundException
+ {
+ NodeRef originalRef = createFolderHierarchyInRootForFolderTests("originFolder");
+ NodeRef targetRef = createFolderHierarchyInRootForFolderTests("targetFolder");
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorOrigin = new ACLComparator(originalRef);
+
+ try
+ {
+ maxTransactionTime = 86400000;
+ setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
+
+ // Set Shared permissions on origin
+ permissionService.setInheritParentPermissions(originalRef, true, false);
+ permissionService.setPermission(originalRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorOrigin.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+
+ // Set Shared permissions on target and inherit permissions from parent
+ permissionService.setInheritParentPermissions(targetRef, true, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+
+ // Copy the nodes
+ NodeRef copiedNode = fileFolderService.copy(originalRef, targetRef, null).getNodeRef();
+ ACLComparator aclComparatorCopied = new ACLComparator(copiedNode);
+ aclComparatorOrigin.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+
+ // Validate the results - Permissions should merge on copied node
+ assertEquals("There are nodes pending", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Copied node did not inherit permissions from target",
+ aclComparatorCopied.hasPermission(TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION));
+ assertTrue("Child of Copied node did not inherit permissions from target",
+ aclComparatorCopied.firstChildHasPermission(TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION));
+ assertTrue("Copied node did not keep original permissions", aclComparatorCopied.parentHasOriginalPermission());
+ assertTrue("Child of Copied node did not keep original permissions",
+ aclComparatorCopied.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(originalRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * MNT-22040 - Copy node that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeCopy()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
+ NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeCopyTargetFolder",
+ ContentModel.TYPE_FOLDER);
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
+
+ try
+ {
+ // Set permissions on target folder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(targetRef, false, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+ return null;
+ }, false, true);
+
+ assertTrue("Target Folder does not have correct permission", aclComparatorTarget.parentHasOriginalPermission());
+
+ // Set permissions async on origin folder and inherit permissions from parent
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, true, false);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+ return null;
+ }, false, true);
+
+ // Find a pending ACL folder to copy
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ // copy folder with pending acl to target
+ fileFolderService.copy(folderWithPendingAcl, targetRef, "copyOfFolder");
+ return null;
+ }, false, true);
+
+ NodeRef copiedChild = fileFolderService.searchSimple(targetRef, "copyOfFolder");
+ ACLComparator aclComparatorCopiedPendingChild = new ACLComparator(copiedChild);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results - ACL's aren't suppose to merge as the Copied folder doesn't have any ACL's directly
+ // applied to them and should just inherit from whatever parent they have
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending Copied node did not inherit permissions from target",
+ aclComparatorCopiedPendingChild.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending Copied node did not inherit permissions from target",
+ aclComparatorCopiedPendingChild.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertFalse("Pending Copied node kept original permissions",
+ aclComparatorCopiedPendingChild.parentHasOriginalPermission());
+ assertFalse("Child of Pending Copied node kept original permissions",
+ aclComparatorCopiedPendingChild.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * Copy node that has the aspect to another folder that also has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeCopyToPendingFolder()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
+ NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
+
+ try
+ {
+ // Set permissions on target folder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(targetRef, false, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+ return null;
+ }, false, true);
+
+ assertTrue("Target Folder does not have correct permission", aclComparatorTarget.parentHasOriginalPermission());
+
+ // Get target Folder with a pending ACL to copy the pending folder to
+ NodeRef targetFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, targetRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", targetFolderWithPendingAcl);
+ ACLComparator aclComparatorTargetPendingChild = new ACLComparator(targetFolderWithPendingAcl);
+ aclComparatorTargetPendingChild.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+
+ // Set permissions on origin folder and get a pending folder to copy
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, true, false);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+ return null;
+ }, false, true);
+
+ // Find a pending ACL folder to copy
+ NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
+
+ // copy one pending folder into the other
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ // copy folder with pending acl to target
+ fileFolderService.copy(originFolderWithPendingAcl, targetFolderWithPendingAcl, "copyOfFolder");
+ return null;
+ }, false, true);
+
+ NodeRef copiedChild = fileFolderService.searchSimple(targetFolderWithPendingAcl, "copyOfFolder");
+ ACLComparator aclComparatorCopiedPendingChild = new ACLComparator(copiedChild);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results - ACL's aren't suppose to merge as the Copied folder doesn't have any ACL's directly
+ // applied to them and should just inherit from whatever parent they have
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending Copied node did not inherit permissions from target",
+ aclComparatorCopiedPendingChild.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of PendingCopied node did not inherit permissions from target",
+ aclComparatorCopiedPendingChild.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertFalse("Pending Copied kept original permissions",
+ aclComparatorCopiedPendingChild.parentHasOriginalPermission());
+ assertFalse("Child of Pending Copied node kept original permissions",
+ aclComparatorCopiedPendingChild.firstChildHasOriginalPermission());
+ assertTrue("Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.parentHasOriginalPermission());
+ assertTrue("Child of Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * Copy parent of node that has the aspect to a child folder of a folder that also has the aspect applied before job
+ * runs
+ */
+ @Test
+ public void testAsyncWithNodeCopyParentToChildPendingFolder()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
+ NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
+
+ try
+ {
+ // Set permissions on target folder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(targetRef, false, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+ return null;
+ }, false, true);
+
+ assertTrue("Target Folder does not have correct permission", aclComparatorTarget.parentHasOriginalPermission());
+
+ // Get target Folder with a pending ACL to copy the pending folder to
+ NodeRef targetFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, targetRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", targetFolderWithPendingAcl);
+ NodeRef targetFolderWithPendingAclChild = nodeDAO
+ .getNodePair(getChild(nodeDAO.getNodePair(targetFolderWithPendingAcl).getFirst())).getSecond();
+ ACLComparator aclComparatorTargetPendingChild = new ACLComparator(targetFolderWithPendingAclChild);
+ aclComparatorTargetPendingChild.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+
+ // Set permissions on origin folder and get a pending folder to copy
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, true, false);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+ return null;
+ }, false, true);
+
+ // Find a pending ACL folder and copy its parent
+ NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
+ NodeRef originFolderWithPendingAclParent = nodeDAO
+ .getPrimaryParentAssoc(nodeDAO.getNodePair(originFolderWithPendingAcl).getFirst()).getSecond().getParentRef();
+
+ // copy one pending folder into the other
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ // copy folder with pending acl to target
+ fileFolderService.copy(originFolderWithPendingAclParent, targetFolderWithPendingAcl, "copyOfFolder");
+ return null;
+ }, false, true);
+
+ NodeRef copiedChild = fileFolderService.searchSimple(targetFolderWithPendingAcl, "copyOfFolder");
+ ACLComparator aclComparatorCopiedPendingParent = new ACLComparator(copiedChild);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results - ACL's aren't suppose to merge as the Copied folder doesn't have any ACL's directly
+ // applied to them and should just inherit from whatever parent they have
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Copied Parent node did not inherit permissions from target",
+ aclComparatorCopiedPendingParent.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Pending Node copied with parent node did not inherit permissions from target",
+ aclComparatorCopiedPendingParent.firstChildHasPermission(TEST_GROUP_NAME_FULL,
+ PermissionService.COORDINATOR));
+
+ // Depending on when the time runs out of the transaction, the parent node we copied may be the node we
+ // actually set permission on. In this case, if this parent node is copied, it is expected to keep the
+ // permissions we set directly on it
+ if (originFolderWithPendingAclParent.equals(folderRef))
+ {
+ assertTrue("Copied Parent (from original node where permissions were set) did not keep original permissions",
+ aclComparatorCopiedPendingParent.parentHasOriginalPermission());
+ assertTrue("Pending Node copied with parent node did not keep original permissions",
+ aclComparatorCopiedPendingParent.firstChildHasOriginalPermission());
+ }
+ else
+ {
+ assertFalse("Copied Parent kept original permissions",
+ aclComparatorCopiedPendingParent.parentHasOriginalPermission());
+ assertFalse("Pending Node copied with parent node kept original permissions",
+ aclComparatorCopiedPendingParent.firstChildHasOriginalPermission());
+ }
+
+ assertTrue("Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.parentHasOriginalPermission());
+ assertTrue("Child of Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * MNT-22040 - Move node that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeMove()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
+ NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeMoveTargetFolder",
+ ContentModel.TYPE_FOLDER);
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
+
+ try
+ {
+ // Set permissions on target folder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(targetRef, false, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+ return null;
+ }, false, true);
+
+ assertTrue("Target Folder does not have correct permission", aclComparatorTarget.parentHasOriginalPermission());
+
+ // Set permissions async on origin folder and inherit permissions from parent
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, true, false);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+ return null;
+ }, false, true);
+
+ // Find a pending ACL folder to move
+ NodeRef folderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
+ ACLComparator aclComparatorOriginPendingChild = new ACLComparator(folderWithPendingAcl);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ // move folder with pending acl to target
+ fileFolderService.move(folderWithPendingAcl, targetRef, "moveOfFolder");
+ return null;
+ }, false, true);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results - ACL's aren't suppose to merge as the Moved folder doesn't have any ACL's directly
+ // applied to them and should just inherit from whatever parent they have
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending Moved node did not inherit permissions from target",
+ aclComparatorOriginPendingChild.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending Moved node did not inherit permissions from target",
+ aclComparatorOriginPendingChild.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertFalse("Pending Moved node kept original permissions",
+ aclComparatorOriginPendingChild.parentHasOriginalPermission());
+ assertFalse("Child of Pending Moved node kept original permissions",
+ aclComparatorOriginPendingChild.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * Move node that has the aspect to another folder that also has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeMoveToPendingFolder()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
+ NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
+
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
+
+ try
+ {
+ // Set permissions on target folder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(targetRef, false, false);
+ permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+ return null;
+ }, false, true);
+
+ assertTrue("Target Folder does not have correct permission", aclComparatorTarget.parentHasOriginalPermission());
+
+ // Get target Folder with a pending ACL to move the pending folder to
+ NodeRef targetFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, targetRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", targetFolderWithPendingAcl);
+ ACLComparator aclComparatorTargetPendingChild = new ACLComparator(targetFolderWithPendingAcl);
+ aclComparatorTargetPendingChild.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
+
+ // Set permissions on origin folder and get a pending folder to move
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, true, false);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
+ return null;
+ }, false, true);
+
+ // Find a pending ACL folder to move
+ NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
+ ACLComparator aclComparatorOriginPendingChild = new ACLComparator(originFolderWithPendingAcl);
+
+ // move one pending folder into the other
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ // move folder with pending acl to target
+ fileFolderService.move(originFolderWithPendingAcl, targetFolderWithPendingAcl, "movedFolder");
+ return null;
+ }, false, true);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results - ACL's aren't suppose to merge as the Moved folder doesn't have any ACL's directly
+ // applied to them and should just inherit from whatever parent they have
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending Moved node did not inherit permissions from target",
+ aclComparatorOriginPendingChild.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of PendingMoved node did not inherit permissions from target",
+ aclComparatorOriginPendingChild.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertFalse("Pending Moved kept original permissions", aclComparatorOriginPendingChild.parentHasOriginalPermission());
+ assertFalse("Child of Pending Moved node kept original permissions",
+ aclComparatorOriginPendingChild.firstChildHasOriginalPermission());
+ assertTrue("Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.parentHasOriginalPermission());
+ assertTrue("Child of Pending target node does not have parent's permissions",
+ aclComparatorTargetPendingChild.firstChildHasOriginalPermission());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ deleteNodes(targetRef);
+ }
+ }
+
+ /*
+ * Lock node that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeLock()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFileTests("testAsyncWithNodeLockFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_CONTENT);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ lockService.lock(nodeWithPendingAcl, LockType.READ_ONLY_LOCK);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Checkout a node for editing that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeCheckout()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFileTests("testAsyncWithNodeCheckoutFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_CONTENT);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ NodeRef workingCopy = checkOutCheckInService.checkout(nodeWithPendingAcl);
+ assertNotNull("Working copy is null", workingCopy);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Update the permissions of a node that has the aspect applied (new permissions: fixed)
+ */
+ @Test
+ public void testAsyncWithNodeUpdatePermissionsFixed()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeUpdatePermissionsFixedFolder");
+ ACLComparator aclComparatorTop = new ACLComparator(folderRef);
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+ aclComparatorTop.updateCurrentACLs();
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+ ACLComparator aclComparator = new ACLComparator(nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(nodeWithPendingAcl, false, false);
+ permissionService.setPermission(nodeWithPendingAcl, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ return null;
+ }, false, true);
+ aclComparator.updateCurrentACLs();
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertFalse("Pending node is not expected to have old permission", aclComparator.parentHasOriginalPermission());
+ assertFalse("Child of Pending node is not expected to have old permission",
+ aclComparator.firstChildHasOriginalPermission());
+ assertTrue("Pending node is expected to have new permission",
+ aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending node is expected to have new permission",
+ aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Update the permissions of a node that has the aspect applied (new permissions: shared)
+ */
+ @Test
+ public void testAsyncWithNodeUpdatePermissionsShared()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeUpdatePermissionsSharedFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+ ACLComparator aclComparator = new ACLComparator(nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(nodeWithPendingAcl, true, false);
+ permissionService.setPermission(nodeWithPendingAcl, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending node is expected to have old permission", aclComparator.parentHasOriginalPermission());
+ assertTrue("Child of Pending node is expected to have old permission",
+ aclComparator.firstChildHasOriginalPermission());
+ assertTrue("Pending node is expected to have new permission",
+ aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending node is expected to have new permission",
+ aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Update the permissions of the parent of a node that has the aspect applied (new permissions: fixed)
+ */
+ @Test
+ public void testAsyncWithParentUpdatePermissionsFixed()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithParentUpdatePermissionsFixedFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+ ACLComparator aclComparator = new ACLComparator(nodeWithPendingAcl);
+
+ NodeRef parentRef = nodeDAO.getPrimaryParentAssoc(nodeDAO.getNodePair(nodeWithPendingAcl).getFirst()).getSecond()
+ .getParentRef();
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(parentRef, false, false);
+ permissionService.setPermission(parentRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertFalse("Pending node is not expected to have old permission", aclComparator.parentHasOriginalPermission());
+ assertFalse("Child of Pending node is not expected to have old permission",
+ aclComparator.firstChildHasOriginalPermission());
+ assertTrue("Pending node is expected to have new permission",
+ aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending node is expected to have new permission",
+ aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Update the permissions of the parent of a node that has the aspect applied (new permissions: shared)
+ */
+ @Test
+ public void testAsyncWithParentUpdatePermissionsShared()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithParentUpdatePermissionsSharedFolder");
+
+ try
+ {
+
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+ ACLComparator aclComparator = new ACLComparator(nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ NodeRef parentRef = nodeDAO.getPrimaryParentAssoc(nodeDAO.getNodePair(nodeWithPendingAcl).getFirst()).getSecond()
+ .getParentRef();
+ permissionService.setInheritParentPermissions(parentRef, true, false);
+ permissionService.setPermission(parentRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Pending node is expected to have old permission", aclComparator.parentHasOriginalPermission());
+ assertTrue("Child of Pending node is expected to have old permission",
+ aclComparator.firstChildHasOriginalPermission());
+ assertTrue("Pending node is expected to have new permission",
+ aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ assertTrue("Child of Pending node is expected to have new permission",
+ aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ @Test
+ public void testAsyncCascadeUpdatePermissions()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncCascadeUpdatePermissionsFolder");
+ List subFolders = fileFolderService.listFolders(folderRef);
+ NodeRef subFolder1 = subFolders.get(0).getNodeRef();
+ // Get ACLS for later comparison
+ ACLComparator aclComparatorBase = new ACLComparator(folderRef);
+ ACLComparator aclComparatorSubfolder1 = new ACLComparator(subFolder1);
+
+ try
+ {
+
+ // Set permissions First Subfolder - should put ACL on subfolder and add aspect to child
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(subFolder1, false, true);
+ permissionService.setPermission(subFolder1, TEST_GROUP_NAME_FULL, PermissionService.CONTRIBUTOR, true);
+ aclComparatorSubfolder1.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.CONTRIBUTOR);
+ return null;
+ }, false, true);
+
+ // Set permissions on base folder - should put ACL on base folder and add aspect to the previous subfolder
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ permissionService.setInheritParentPermissions(folderRef, false, true);
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
+ aclComparatorBase.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.CONSUMER);
+ return null;
+ }, false, true);
+
+ assertTrue("There are no nodes to process", getNodesCountWithPendingFixedAclAspect() > 0);
+
+ // Trigger job
+ triggerFixedACLJob();
+
+ // Validate results
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ assertTrue("Base Folder permissions are incorrect",
+ aclComparatorBase.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.CONSUMER));
+ assertTrue("First Sub-Folder permissions are incorrect",
+ aclComparatorSubfolder1.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.CONTRIBUTOR));
+ assertTrue("Child of First Sub-Folder permissions are incorrect",
+ aclComparatorSubfolder1.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.CONTRIBUTOR));
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Update the content of a node that has the aspect applied before job runs
+ */
+ @Test
+ public void testAsyncWithNodeContentUpdate()
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFileTests("testAsyncWithNodeContentUpdateFolder");
+
+ try
+ {
+ setPermissionsOnTree(folderRef, true, true);
+
+ NodeRef nodeWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_CONTENT);
+ assertNotNull("No children files were found with pendingFixACl aspect", nodeWithPendingAcl);
+
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ ContentWriter contentWriter = contentService.getWriter(nodeWithPendingAcl, ContentModel.PROP_CONTENT, true);
+ contentWriter.setEncoding("UTF-8");
+ contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ contentWriter.putContent("Updated content for file");
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Test setting permissions concurrently to actually cause the expected concurrency exception
+ */
+ @Test
+ public void testAsyncConcurrentPermissionsUpdate() throws Throwable
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncConcurrentPermissionsUpdateFolder");
+ List subFolders = fileFolderService.listFolders(folderRef);
+ String group_prefix = "TEST_";
+ int concurrentUpdates = 5;
+
+ try
+ {
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ Set zones = new HashSet(2, 1.0f);
+ zones.add(AuthorityService.ZONE_APP_DEFAULT);
+ for (int i = 0; i < concurrentUpdates; i++)
+ {
+ if (!authorityService.authorityExists(PermissionService.GROUP_PREFIX + group_prefix + i))
+ {
+ authorityService.createAuthority(AuthorityType.GROUP, group_prefix + i, group_prefix + i, zones);
+ }
+ }
+ return null;
+ }, false, true);
+
+ final Runnable[] runnables = new Runnable[concurrentUpdates];
+ final List threads = new ArrayList();
+ errors = new HashMap>();
+
+ // First thread is setting permissions on top folder
+ runnables[0] = createRunnableToSetPermissions(folderRef, group_prefix + 0, 0);
+ Thread threadBase = new Thread(runnables[0]);
+ threads.add(threadBase);
+ threadBase.start();
+
+ // All remaining threads will set permissions on sub-folders
+ for (int i = 1; i < runnables.length; i++)
+ {
+ NodeRef nodeRef = subFolders.get(i - 1).getNodeRef();
+ runnables[i] = createRunnableToSetPermissions(nodeRef, group_prefix + i, i);
+ Thread thread = new Thread(runnables[i]);
+ threads.add(thread);
+ thread.start();
+ }
+
+ // Wait for the threads to finish
+ for (Thread t : threads)
+ {
+ t.join();
+ }
+
+ // There should only be ConcurrencyFailureException
+ for (Map.Entry> error : errors.entrySet())
+ {
+ assertEquals("Unexpected error on Concurrent Update", ConcurrencyFailureException.class, error.getValue());
+ }
+
+ triggerFixedACLJob();
+ // We expect at least one error to occur when threads were running
+ assertTrue("There were no concurrency errors", errors.entrySet().size() > 0);
+
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ /*
+ * Test setting permissions concurrently as the job runs at the same time to actually cause the expected concurrency
+ * exception but the job should be able to recover
+ */
+ @Test
+ public void testAsyncConcurrentUpdateAndJob() throws Throwable
+ {
+ NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncConcurrentUpdateAndJobFolder");
+ List subFolders = fileFolderService.listFolders(folderRef);
+ String group_prefix = "TEST_";
+ int concurrentUpdates = 5;
+
+ try
+ {
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ Set zones = new HashSet(2, 1.0f);
+ zones.add(AuthorityService.ZONE_APP_DEFAULT);
+ for (int i = 0; i < concurrentUpdates; i++)
+ {
+ if (!authorityService.authorityExists(PermissionService.GROUP_PREFIX + group_prefix + i))
+ {
+ authorityService.createAuthority(AuthorityType.GROUP, group_prefix + i, group_prefix + i, zones);
+ }
+
+ }
+ return null;
+ }, false, true);
+
+ final Runnable[] runnables = new Runnable[concurrentUpdates];
+ final List threads = new ArrayList();
+ errors = new HashMap>();
+
+ // Set permissions on top folder
+ setPermissionsOnTree(folderRef, true, true);
+
+ // First thread runs job to process setting permissions on top folder.
+ runnables[0] = createRunnableToRunJob();
+ Thread threadBase = new Thread(runnables[0]);
+ threads.add(threadBase);
+ threadBase.start();
+
+ // Meanwhile other threads are updating permissions on subfolders as the job runs
+ for (int i = 1; i < runnables.length; i++)
+ {
+ NodeRef nodeRef = subFolders.get(i - 1).getNodeRef();
+ runnables[i] = createRunnableToSetPermissions(nodeRef, group_prefix + i, i);
+ Thread thread = new Thread(runnables[i]);
+ threads.add(thread);
+ thread.start();
+ }
+
+ // Wait for the threads to finish
+ for (Thread t : threads)
+ {
+ t.join();
+ }
+
+ // Verify that we only have errors of type ConcurrencyFailureException
+ for (Map.Entry> error : errors.entrySet())
+ {
+ assertEquals("Unexpected error on Concurrent Update", ConcurrencyFailureException.class, error.getValue());
+ }
+ triggerFixedACLJob();
+ assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ }
+ finally
+ {
+ deleteNodes(folderRef);
+ }
+ }
+
+ private Long getChild(Long parentId)
+ {
+ List children = fileFolderService.list(nodeDAO.getNodePair(parentId).getSecond());
+ if (children.size() > 0)
+ {
+ NodeRef childRef = children.get(0).getNodeRef();
+ return nodeDAO.getNodePair(childRef).getFirst();
+ }
+
+ return null;
+ }
+
+ private Long getAclOfFirstChild(Long nodeId)
+ {
+ Long firstChild = getChild(nodeId);
+ if (firstChild != null)
+ {
+ return nodeDAO.getNodeAclId(firstChild);
+ }
+ return null;
+ }
+
+ private void setFixedPermissionsForTestGroup(NodeRef folderRef, String authName, int thread)
+ {
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ try
+ {
+ Thread.sleep(200);
+ permissionService.setInheritParentPermissions(folderRef, false, true);
+ permissionService.setPermission(folderRef, authName, PermissionService.COORDINATOR, true);
+ }
+ catch (Exception e)
+ {
+ errors.put(thread, e.getClass());
+ throw e;
+ }
+
+ return null;
+ }, false, true);
+ }
+
+ private Runnable createRunnableToSetPermissions(NodeRef folderRef, String authName, int thread) throws Throwable
+ {
+ return new Runnable()
+ {
+ @Override
+ public synchronized void run()
+ {
+ setFixedPermissionsForTestGroup(folderRef, authName, thread);
+ }
+ };
+
+ }
+
+ private Runnable createRunnableToRunJob() throws Throwable
+ {
+ return new Runnable()
+ {
+ @Override
+ public synchronized void run()
+ {
+ triggerFixedACLJob();
+ }
+ };
}
@@ -138,44 +1250,23 @@ public class FixedAclUpdaterTest extends TestCase
}
}
- private static RetryingTransactionCallback createFolderHierchyCallback(final NodeRef root,
- final FileFolderService fileFolderService, final String rootName, final int[] filesPerLevel)
+ private NodeRef createFolderHierarchyInRoot(String folderName, int[] filesPerLevel)
{
- RetryingTransactionCallback cb = new RetryingTransactionCallback()
- {
- @Override
- public NodeRef execute() throws Throwable
- {
- NodeRef parent = createFile(fileFolderService, root, rootName, ContentModel.TYPE_FOLDER);
- createFolderHierchy(fileFolderService, parent, 0, filesPerLevel);
- return parent;
- }
- };
- return cb;
+ return txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ NodeRef parent = createFile(fileFolderService, homeFolderNodeRef, folderName, ContentModel.TYPE_FOLDER);
+ createFolderHierchy(fileFolderService, parent, 0, filesPerLevel);
+ return parent;
+ }, false, true);
}
- @Override
- public void tearDown() throws Exception
+ private NodeRef createFolderHierarchyInRootForFolderTests(String folderName)
{
- // delete created folder hierarchy
- try
- {
- txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
- Set aspect = new HashSet<>();
- aspect.add(ContentModel.ASPECT_TEMPORARY);
- nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderAsyncCallNodeRef).getFirst(), aspect);
- nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderSyncCallNodeRef).getFirst(), aspect);
- nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderAsyncCallWithCreateNodeRef).getFirst(), aspect);
- fileFolderService.delete(folderAsyncCallNodeRef);
- fileFolderService.delete(folderSyncCallNodeRef);
- fileFolderService.delete(folderAsyncCallWithCreateNodeRef);
- return null;
- }, false, true);
- }
- catch (Exception e)
- {
- }
- AuthenticationUtil.clearCurrentSecurityContext();
+ return createFolderHierarchyInRoot(folderName, filesPerLevelMoreFolders);
+ }
+
+ private NodeRef createFolderHierarchyInRootForFileTests(String folderName)
+ {
+ return createFolderHierarchyInRoot(folderName, filesPerLevelMoreFiles);
}
private static NodeRef createFile(FileFolderService fileFolderService, NodeRef parent, String name, QName type)
@@ -197,162 +1288,216 @@ public class FixedAclUpdaterTest extends TestCase
}, true, true);
}
- @Test
- public void testSyncTimeOut()
+ private void setPermissionsOnTree(NodeRef folderRef, boolean asyncCall, boolean shouldHaveNodesPending)
{
- testWork(folderSyncCallNodeRef, false);
- }
-
- @Test
- public void testAsync()
- {
- testWork(folderAsyncCallNodeRef, true);
- }
-
- @Test
- public void testAsyncWithNodeCreation()
- {
- testWorkWithNodeCreation(folderAsyncCallWithCreateNodeRef, true);
- }
-
- @Test
- public void testAsyncWithNodeDeletion()
- {
- testWorkWithNodeDeletion(folderAsyncCallWithDeleteNodeRef, true);
- }
-
- private void testWork(NodeRef folderRef, boolean asyncCall)
- {
- try
- {
- setPermissionsOnTree(folderRef, asyncCall);
- triggerFixedACLJob(folderRef);
- }
- finally
- {
- removeNodesWithPendingAcl(folderRef);
- }
- }
-
- private void testWorkWithNodeCreation(NodeRef folderRef, boolean asyncCall)
- {
- try
- {
- setPermissionsOnTree(folderRef, asyncCall);
-
- // MNT-21847 - Create a new content in folder that has the aspect applied
- txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
- NodeRef folderWithPendingAcl = getFirstFolderWithAclPending(folderRef);
- assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
- createFile(fileFolderService, folderWithPendingAcl, "NewFile", ContentModel.TYPE_CONTENT);
- return null;
- }, false, true);
-
- triggerFixedACLJob(folderRef);
- }
- finally
- {
- removeNodesWithPendingAcl(folderRef);
- }
- }
-
- private void testWorkWithNodeDeletion(NodeRef folderRef, boolean asyncCall)
- {
- try
- {
- setPermissionsOnTree(folderRef, asyncCall);
-
- // MNT-22009 - Delete node that has the aspect applied before job runs
- txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
- NodeRef folderWithPendingAcl = getFirstFolderWithAclPending(folderRef);
- assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
- fileFolderService.delete(folderWithPendingAcl);
- return null;
- }, false, true);
-
- triggerFixedACLJob(folderRef);
-
- }
- finally
- {
- removeNodesWithPendingAcl(folderRef);
- }
- }
-
- private void setPermissionsOnTree(NodeRef folderRef, boolean asyncCall)
- {
- // kick it off by setting inherit parent permissions == false
txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+
+ // create a group for tests
+ Set zones = new HashSet(2, 1.0f);
+ zones.add(AuthorityService.ZONE_APP_DEFAULT);
+ if (!authorityService.authorityExists(TEST_GROUP_NAME_FULL))
+ {
+ authorityService.createAuthority(AuthorityType.GROUP, TEST_GROUP_NAME, TEST_GROUP_NAME, zones);
+ }
+ // kick it off by setting inherit parent permissions == false
permissionService.setInheritParentPermissions(folderRef, false, asyncCall);
- assertTrue("asyncCallRequired should be true", isFixedAclAsyncRequired());
+ permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
return null;
}, false, true);
// Assert that there are nodes with aspect ASPECT_PENDING_FIX_ACL to be processed
- txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
- assertTrue("There are no nodes to process", getNodesCountWithPendingFixedAclAspect() > 0);
- return null;
- }, false, true);
+ int pendingNodes = getNodesCountWithPendingFixedAclAspect();
+ if (shouldHaveNodesPending)
+ {
+ assertTrue("There are no nodes to process", pendingNodes > 0);
+ }
+ else
+ {
+ assertEquals("There are nodes to process", pendingNodes, 0);
+ }
}
- private void triggerFixedACLJob(NodeRef folder)
+ private void triggerFixedACLJob()
{
// run the fixedAclUpdater until there is nothing more to fix (running the updater may create more to fix up) or
- // the count doesn't change, meaning we have a problem.
+ // the count doesn't change for 3 cycles, meaning we have a problem.
txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
int count = 0;
int previousCount = 0;
+ int rounds = 0;
do
{
previousCount = count;
count = fixedAclUpdater.execute();
- } while (count > 0 && previousCount != count);
- assertEquals("Not all nodes were processed", 0, count);
+ if (count == previousCount)
+ {
+ rounds++;
+ }
+ } while (count > 0 && rounds <= 3);
return null;
}, false, true);
}
- private NodeRef getFirstFolderWithAclPending(NodeRef parentNodeRef)
+ private NodeRef getFirstNodeWithAclPending(QName nodeType, NodeRef parentRef)
{
- final GetNodesWithAspectCallback getNodesCallback = new GetNodesWithAspectCallback();
- nodeDAO.getNodesWithAspects(Collections.singleton(ContentModel.ASPECT_PENDING_FIX_ACL), 0l, null, getNodesCallback);
- List nodesWithAclPendingAspect = getNodesCallback.getNodes();
- for (int i = 0; i < nodesWithAclPendingAspect.size(); i++)
- {
- NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
- if (nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(ContentModel.TYPE_FOLDER))
- {
- return nodeRef;
- }
- }
- return null;
- }
-
- private void removeNodesWithPendingAcl(NodeRef folder)
- {
- txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
- Set aspect = new HashSet<>();
- aspect.add(ContentModel.ASPECT_TEMPORARY);
- nodeDAO.addNodeAspects(nodeDAO.getNodePair(folder).getFirst(), aspect);
- fileFolderService.delete(folder);
-
- // Delete any remaining nodes with aspect
+ return txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
final GetNodesWithAspectCallback getNodesCallback = new GetNodesWithAspectCallback();
nodeDAO.getNodesWithAspects(Collections.singleton(ContentModel.ASPECT_PENDING_FIX_ACL), 0l, null, getNodesCallback);
- getNodesCallback.getNodes().forEach(node -> {
- nodeArchiveService.purgeArchivedNode(node);
- });
+ List nodesWithAclPendingAspect = getNodesCallback.getNodes();
+ for (int i = 0; i < nodesWithAclPendingAspect.size(); i++)
+ {
+ NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
+ boolean isDescendent = false;
+ List path = fileFolderService.getNamePath(homeFolderNodeRef, nodeRef);
+ for (FileInfo element : path)
+ {
+ if (element.getNodeRef().equals(parentRef))
+ {
+ isDescendent = true;
+ }
+ }
+ if (isDescendent && nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
+ {
+ return nodeRef;
+ }
+ }
+ return null;
+ }, false, true);
+
+ }
+
+ private NodeRef getFirstNodeWithAclPending(QName nodeType)
+ {
+ return txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ final GetNodesWithAspectCallback getNodesCallback = new GetNodesWithAspectCallback();
+ nodeDAO.getNodesWithAspects(Collections.singleton(ContentModel.ASPECT_PENDING_FIX_ACL), 0l, null, getNodesCallback);
+ List nodesWithAclPendingAspect = getNodesCallback.getNodes();
+ for (int i = 0; i < nodesWithAclPendingAspect.size(); i++)
+ {
+ NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
+ if (nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
+ {
+ return nodeRef;
+ }
+ }
+ return null;
+ }, false, true);
+
+ }
+
+ private void deleteNodes(NodeRef folder)
+ {
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ if (nodeDAO.exists(folder))
+ {
+ Set aspect = new HashSet<>();
+ aspect.add(ContentModel.ASPECT_TEMPORARY);
+ nodeDAO.addNodeAspects(nodeDAO.getNodePair(folder).getFirst(), aspect);
+ fileFolderService.delete(folder);
+ }
return null;
}, false, true);
}
- private static boolean isFixedAclAsyncRequired()
+ private class ACLComparator
{
- if (AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY) == null)
+ Long parentId;
+ Long oParentACL;
+ Long oFirstChildACL;
+ Long tParentACL;
+ Long tFirstChildACL;
+ String originalPermission = DEFAULT_PERMISSION;
+ String originalAuthority = TEST_GROUP_NAME_FULL;
+ Long pendingInheritFrom = 0L;
+
+ public ACLComparator(NodeRef nodeRef)
{
- return false;
+ Long parentId = nodeDAO.getNodePair(nodeRef).getFirst();
+ this.parentId = parentId;
+ this.oParentACL = nodeDAO.getNodeAclId(parentId);
+ this.oFirstChildACL = getAclOfFirstChild(parentId);
+ updateCurrentACLs();
+ }
+
+ public void updateCurrentACLs()
+ {
+ this.tParentACL = nodeDAO.getNodeAclId(parentId);
+ this.tFirstChildACL = getAclOfFirstChild(parentId);
+
+ if (nodeDAO.hasNodeAspect(parentId, ContentModel.ASPECT_PENDING_FIX_ACL))
+ {
+ this.pendingInheritFrom = (Long) nodeDAO.getNodeProperty(parentId, ContentModel.PROP_INHERIT_FROM_ACL);
+ }
+ else
+ {
+ this.pendingInheritFrom = 0L;
+ }
+ }
+
+ public void compareACLs()
+ {
+ updateCurrentACLs();
+ assertTrue("Permissions were not changed on top folder", !oParentACL.equals(tParentACL));
+ assertTrue("Permissions were not changed on child", !oFirstChildACL.equals(tFirstChildACL));
+ }
+
+ public void setOriginalPermission(String originalAuthority, String originalPermission)
+ {
+ this.originalPermission = originalPermission;
+ this.originalAuthority = originalAuthority;
+ }
+
+ public boolean hasPermission(String authority, String permission)
+ {
+ return hasPermission(parentId, authority, permission);
+ }
+
+ public boolean hasPermission(Long nodeId, String authority, String permission)
+ {
+ boolean hasExpectedPermission = false;
+ Set permissions = permissionService.getAllSetPermissions(nodeDAO.getNodePair(nodeId).getSecond());
+ for (Iterator iterator = permissions.iterator(); iterator.hasNext();)
+ {
+ AccessPermission accessPermission = (AccessPermission) iterator.next();
+ if (accessPermission.getPermission().equalsIgnoreCase(permission)
+ && accessPermission.getAuthority().equalsIgnoreCase(authority))
+ {
+ hasExpectedPermission = true;
+ break;
+ }
+ }
+ return hasExpectedPermission;
+ }
+
+ public boolean firstChildHasPermission(String authority, String permission)
+ {
+ return hasPermission(getChild(parentId), authority, permission);
+ }
+
+ public boolean firstChildHasOriginalPermission()
+ {
+ return hasPermission(getChild(parentId), originalAuthority, originalPermission);
+ }
+
+ public boolean parentHasOriginalPermission()
+ {
+ return hasPermission(originalAuthority, originalPermission);
+ }
+
+ private Long getParentAcl()
+ {
+ return tParentACL;
+ }
+
+ private Long getChildAcl()
+ {
+ return tFirstChildACL;
+ }
+
+ private Long getPendingInheritFromAcl()
+ {
+ return pendingInheritFrom;
}
- return (Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY);
}
private static class GetNodesCountWithAspectCallback implements NodeRefQueryCallback
@@ -409,7 +1554,7 @@ public class FixedAclUpdaterTest extends TestCase
int numFiles = filesPerLevel[level];
for (int i = 0; i < numFiles; i++)
{
- NodeRef node = createFile(fileFolderService, parent, "LVL" + level + i, ContentModel.TYPE_FOLDER);
+ NodeRef node = createFile(fileFolderService, parent, "-LVL" + level + i, ContentModel.TYPE_FOLDER);
createFolderHierchy(fileFolderService, node, level + 1, filesPerLevel);
}
}
@@ -419,7 +1564,7 @@ public class FixedAclUpdaterTest extends TestCase
int numFiles = filesPerLevel[level];
for (int i = 0; i < numFiles; i++)
{
- createFile(fileFolderService, parent, "File" + i, ContentModel.TYPE_CONTENT);
+ createFile(fileFolderService, parent, "-File" + i, ContentModel.TYPE_CONTENT);
}
}
}