ALF-13028: Sharepoint broken by changes to WebDAV

Integrated fix for ALF-11777 so that locks are not kept for more than 24 hours and 24 hour or infinite locks are dropped on user's session destruction.

Extracted interface from WebDAVLockService and moved the implementation to WebDAVLockServiceImpl. Modified WebDAVLockServiceImpl to use the LockStore in-memory locking. WebDAV and SPP use WebDAVLockService instead of directly using LockStore.

 


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@35486 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Matt Ward
2012-04-20 14:33:19 +00:00
parent 617e6486cc
commit 004b2c5e60
12 changed files with 854 additions and 358 deletions

View File

@@ -0,0 +1,184 @@
package org.alfresco.repo.webdav;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.Pair;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
@RunWith(MockitoJUnitRunner.class)
public class WebDAVLockServiceImplTest
{
private WebDAVLockServiceImpl davLockService;
private @Mock LockStore lockStore;
private @Mock HttpSession session;
private @Mock List<Pair<String, NodeRef>> sessionList;
private @Mock AuthenticationUtil authenticationUtil;
private @Mock TransactionService transactionService;
private @Mock RetryingTransactionHelper txHelper;
private @Mock NodeService nodeService;
private @Mock LockService lockService;
private @Mock CheckOutCheckInService cociService;
private NodeRef nodeRef1;
private NodeRef nodeRef2;
private LockInfoImpl lockInfo1;
private LockInfoImpl lockInfo2;
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception
{
davLockService = new WebDAVLockServiceImpl();
LockStoreFactory lockStoreFactory = Mockito.mock(LockStoreFactory.class);
Mockito.when(lockStoreFactory.getLockStore()).thenReturn(lockStore);
davLockService.setLockStoreFactory(lockStoreFactory);
davLockService.setNodeService(nodeService);
davLockService.setCheckOutCheckInService(cociService);
davLockService.setCurrentSession(session);
davLockService.setLockService(lockService);
// Train the mock LockStore to respond to get() requests for certain noderefs.
nodeRef1 = new NodeRef("workspace://SpacesStore/f6e3f82a-cfef-445b-9fca-7986a14181cc");
lockInfo1 = new LockInfoImplTest.LockInfoImplEx();
Mockito.when(lockStore.get(nodeRef1)).thenReturn(lockInfo1);
nodeRef2 = new NodeRef("workspace://SpacesStore/a6a4371c-99b9-4618-8cd2-e71d7d96aa87");
lockInfo2 = new LockInfoImplTest.LockInfoImplEx();
Mockito.when(lockStore.get(nodeRef2)).thenReturn(lockInfo2);
// The mock HttpSession should return the mock session list.
Mockito.when(session.getAttribute("_webdavLockedResources")).thenReturn(sessionList);
// Provide a user name for our fictional user.
authenticationUtil = new AuthenticationUtil();
authenticationUtil.afterPropertiesSet();
AuthenticationUtil.setFullyAuthenticatedUser("some_user_name");
Mockito.when(txHelper.doInTransaction(any(RetryingTransactionCallback.class), anyBoolean())).thenAnswer(new Answer()
{
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
Object[] args = invocation.getArguments();
RetryingTransactionCallback<Void> callback = (RetryingTransactionCallback<Void>) args[0];
callback.execute();
return null;
}
});
Mockito.when(transactionService.getRetryingTransactionHelper()).thenReturn(txHelper);
davLockService.setTransactionService(transactionService);
}
@Test
public void testSessionDestroyed()
{
List<Pair<String, NodeRef>> lockedNodes = new ArrayList<Pair<String, NodeRef>>(2);
lockedNodes.add(new Pair<String, NodeRef>("some_user_name", nodeRef1));
lockedNodes.add(new Pair<String, NodeRef>("another_user_name", nodeRef2));
Mockito.when(sessionList.size()).thenReturn(2);
Mockito.when(sessionList.iterator()).thenReturn(lockedNodes.iterator());
Mockito.when(nodeService.exists(nodeRef1)).thenReturn(true);
Mockito.when(nodeService.exists(nodeRef2)).thenReturn(true);
Mockito.when(lockService.getLockStatus(nodeRef1)).thenReturn(LockStatus.LOCKED);
Mockito.when(lockService.getLockStatus(nodeRef2)).thenReturn(LockStatus.LOCKED);
// We're not going to do anything with nodeRef2
NodeRef wcNodeRef2 = new NodeRef("workspace://SpacesStore/a6e3f82a-cfef-363d-9fca-3986a14180a0");
Mockito.when(cociService.getWorkingCopy(nodeRef2)).thenReturn(wcNodeRef2);
davLockService.sessionDestroyed();
// nodeRef1 is unlocked
Mockito.verify(lockService).unlock(nodeRef1);
Mockito.verify(lockStore).remove(nodeRef1);
// nodeRef2 is not unlocked
Mockito.verify(lockService, Mockito.never()).unlock(nodeRef2);
Mockito.verify(lockStore, Mockito.never()).remove(nodeRef2);
}
@Test
public void lockLessThan24Hours()
{
lockInfo1.setTimeoutSeconds(100);
davLockService.lock(nodeRef1, lockInfo1);
Mockito.verify(lockStore).put(nodeRef1, lockInfo1);
// 100 seconds (in millis) should have been added to the date/time stamp.
assertEquals(86500000, lockInfo1.getExpires().getTime());
}
@Test
public void lockGreaterThan24Hours()
{
int timeout25hours = WebDAV.TIMEOUT_24_HOURS + 3600;
lockInfo1.setTimeoutSeconds(timeout25hours);
davLockService.lock(nodeRef1, lockInfo1);
Mockito.verify(lockStore).put(nodeRef1, lockInfo1);
Mockito.verify(sessionList).add(new Pair<String, NodeRef>("some_user_name", nodeRef1));
// Timeout should be capped at 24 hours.
assertEquals(WebDAV.TIMEOUT_24_HOURS, lockInfo1.getRemainingTimeoutSeconds());
}
@Test
public void lockForInfinityTime()
{
lockInfo1.setTimeoutSeconds(WebDAV.TIMEOUT_INFINITY);
davLockService.lock(nodeRef1, lockInfo1);
Mockito.verify(lockStore).put(nodeRef1, lockInfo1);
Mockito.verify(sessionList).add(new Pair<String, NodeRef>("some_user_name", nodeRef1));
// Timeout should be capped at 24 hours.
assertEquals(WebDAV.TIMEOUT_24_HOURS, lockInfo1.getRemainingTimeoutSeconds());
}
@Test
public void canUnlock()
{
davLockService.unlock(nodeRef1);
// NodeRef should have been removed from the LockStore
Mockito.verify(lockStore).remove(nodeRef1);
// Node should have been removed from the list in the user's session.
Mockito.verify(sessionList).remove(new Pair<String, NodeRef>("some_user_name", nodeRef1));
}
@Test
public void canGetLockInfo()
{
// Sanity check that what we're putting in, is what we're getting out.
assertNull("LockInfo should be null", davLockService.getLockInfo(null));
assertEquals(lockInfo1, davLockService.getLockInfo(nodeRef1));
assertEquals(lockInfo2, davLockService.getLockInfo(nodeRef2));
}
}