Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud)

65603: Merged V4.2-BUG-FIX (4.2.2) to HEAD-BUG-FIX (4.3/Cloud)
      65504: Merged DEV to V4.2-BUG-FIX (4.2.2)
         64017 : MNT-10908 : WebDAV lock refresh calls are not processed
            - LOCK method was modified to update lock expiry date correctly.
            - PROPFIND method should not generated lock discovery response for expired locks
         64152 : MNT-10908 : WebDAV lock refresh calls are not processed
            - Unit tests to prove the fix. 


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@66255 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2014-04-02 21:59:20 +00:00
parent 265620433f
commit afcd38825f
4 changed files with 295 additions and 1 deletions

View File

@@ -459,6 +459,7 @@ public class LockMethod extends WebDAVMethod
{ {
// Update the expiry for the lock // Update the expiry for the lock
lockInfo.setTimeoutSeconds(getLockTimeout()); lockInfo.setTimeoutSeconds(getLockTimeout());
getDAVLockService().lock(lockNode.getNodeRef(), lockInfo);
} }
} }

View File

@@ -922,7 +922,7 @@ public class PropFindMethod extends WebDAVMethod
{ {
// Output the lock status response // Output the lock status response
LockInfo lockInfo = getNodeLockInfo(nodeInfo); LockInfo lockInfo = getNodeLockInfo(nodeInfo);
if (lockInfo.isLocked()) if (lockInfo.isLocked() && !lockInfo.isExpired())
{ {
generateLockDiscoveryXML(xml, nodeInfo, lockInfo); generateLockDiscoveryXML(xml, nodeInfo, lockInfo);
} }

View File

@@ -71,6 +71,7 @@ public class RemoteApi01TestSuite extends TestSuite
{ {
suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.MoveMethodTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.MoveMethodTest.class));
suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.UnlockMethodTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.UnlockMethodTest.class));
suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.LockMethodTest.class));
suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.WebDAVHelperIntegrationTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.WebDAVHelperIntegrationTest.class));
suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.WebDAVMethodTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.WebDAVMethodTest.class));
suite.addTestSuite(org.alfresco.repo.webservice.CMLUtilTest.class); suite.addTestSuite(org.alfresco.repo.webservice.CMLUtilTest.class);

View File

@@ -0,0 +1,292 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.webdav;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.util.Collections;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.model.FileFolderService;
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.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.GUID;
import org.alfresco.util.TestWithUserUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests for the {@link LockMethod} class.
*
* @author pavel.yurkevich
*/
public class LockMethodTest
{
private LockMethod lockMethod;
private PropFindMethod propFindMethod;
private ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(new String[]
{
"classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml",
"classpath:alfresco/remote-api-context.xml"
});
/**
* Services used by the tests
*/
private WebDAVHelper davHelper;
private TransactionService transactionService;
private AuthenticationComponent authenticationComponent;
private NodeService nodeService;
private MutableAuthenticationService authenticationService;
private PermissionService permissionService;
private ContentService contentService;
private FileFolderService fileFolderService;
/**
* Types and properties used by the tests
*/
private static final String CONTENT_1 = "This is some content";
private static final String TEST_STORE_IDENTIFIER = "test_store-" + System.currentTimeMillis();
private static final String TEST_FILE_NAME = "file";
/**
* Data used by the tests
*/
private StoreRef storeRef;
private NodeRef rootNodeRef;
private NodeRef folderNodeRef;
private NodeRef fileNodeRef;
/**
* User details
*/
private String userName;
private static final String PWD = "password";
@Before
public void setUp() throws Exception
{
lockMethod = new LockMethod();
propFindMethod = new PropFindMethod();
this.transactionService = (TransactionService) applicationContext.getBean("TransactionService");
this.davHelper = (WebDAVHelper) applicationContext.getBean("webDAVHelper");
this.authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
this.nodeService = (NodeService) applicationContext.getBean("NodeService");
this.authenticationService = (MutableAuthenticationService) applicationContext.getBean("authenticationService");
this.permissionService = (PermissionService) applicationContext.getBean("permissionService");
this.contentService = (ContentService) applicationContext.getBean("contentService");
this.fileFolderService = (FileFolderService) applicationContext.getBean("fileFolderService");
this.authenticationComponent.setSystemUserAsCurrentUser();
RetryingTransactionCallback<Void> createTestFileCallback = new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
// Create the store and get the root node reference
storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, TEST_STORE_IDENTIFIER);
if (!nodeService.exists(storeRef))
{
storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, TEST_STORE_IDENTIFIER);
}
rootNodeRef = nodeService.getRootNode(storeRef);
// Create and authenticate the user
userName = "webdavLockTest" + GUID.generate();
TestWithUserUtils.createUser(userName, PWD, rootNodeRef, nodeService, authenticationService);
permissionService.setPermission(rootNodeRef, userName, PermissionService.ALL_PERMISSIONS, true);
TestWithUserUtils.authenticateUser(userName, PWD, rootNodeRef, authenticationService);
// create test file in test folder
folderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("test"), ContentModel.TYPE_FOLDER,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, "folder")).getChildRef();
fileNodeRef = nodeService.createNode(folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_CONTENT,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, TEST_FILE_NAME)).getChildRef();
ContentWriter contentWriter = contentService.getWriter(fileNodeRef, ContentModel.PROP_CONTENT, true);
contentWriter.setMimetype("text/plain");
contentWriter.setEncoding("UTF-8");
contentWriter.putContent(CONTENT_1);
return null;
}
};
this.transactionService.getRetryingTransactionHelper().doInTransaction(createTestFileCallback);
}
@After
public void tearDown()
{
lockMethod = null;
propFindMethod = null;
// clear context for current user
this.authenticationComponent.clearCurrentSecurityContext();
// delete test store as system user
this.authenticationComponent.setSystemUserAsCurrentUser();
RetryingTransactionCallback<Void> deleteStoreCallback = new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (nodeService.exists(storeRef))
{
nodeService.deleteStore(storeRef);
}
return null;
}
};
this.transactionService.getRetryingTransactionHelper().doInTransaction(deleteStoreCallback);
}
@Test
public void testRefreshLock() throws Exception
{
MockHttpServletRequest lockRequest = new MockHttpServletRequest();
lockRequest.addHeader(WebDAV.HEADER_TIMEOUT, WebDAV.SECOND + 5);
lockRequest.setRequestURI("/" + TEST_FILE_NAME);
String content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><D:lockinfo xmlns:D=\"DAV:\"><D:lockscope xmlns:D=\"DAV:\">" +
"<D:exclusive xmlns:D=\"DAV:\"/></D:lockscope><D:locktype xmlns:D=\"DAV:\"><D:write xmlns:D=\"DAV:\"/></D:locktype>" +
"<D:owner xmlns:D=\"DAV:\">" + userName + "</D:owner></D:lockinfo>";
lockRequest.setContent(content.getBytes("UTF-8"));
lockMethod.setDetails(lockRequest, new MockHttpServletResponse(), davHelper, folderNodeRef);
lockMethod.parseRequestHeaders();
lockMethod.parseRequestBody();
RetryingTransactionCallback<Void> lockExecuteImplCallBack = new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
lockMethod.executeImpl();
return null;
}
};
// lock node for 5 seconds
this.transactionService.getRetryingTransactionHelper().doInTransaction(lockExecuteImplCallBack);
RetryingTransactionCallback<LockInfo> getNodeLockInfoCallBack = new RetryingTransactionCallback<LockInfo>()
{
@Override
public LockInfo execute() throws Throwable
{
return lockMethod.getNodeLockInfo(fileFolderService.getFileInfo(fileNodeRef));
}
};
// get lock info
LockInfo lockInfo = this.transactionService.getRetryingTransactionHelper().doInTransaction(getNodeLockInfoCallBack);
assertNotNull(lockInfo);
// wait for 1 second
Thread.sleep(1000);
String lockToken = fileNodeRef.getId() + WebDAV.LOCK_TOKEN_SEPERATOR + this.userName;
String lockHeaderValue = "(<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">)";
lockRequest.addHeader(WebDAV.HEADER_IF, lockHeaderValue);
lockMethod.parseRequestHeaders();
// update lock for another 5 seconds
this.transactionService.getRetryingTransactionHelper().doInTransaction(lockExecuteImplCallBack);
// get updated lock info
LockInfo updatedLockInfo = this.transactionService.getRetryingTransactionHelper().doInTransaction(getNodeLockInfoCallBack);
assertNotNull(updatedLockInfo);
assertEquals("Lock owner should not change after lock refresh.", lockInfo.getOwner(), updatedLockInfo.getOwner());
assertEquals("Lock token should not change after lock refresh.", lockInfo.getExclusiveLockToken(), updatedLockInfo.getExclusiveLockToken());
assertFalse("Expires was not updated.", lockInfo.getExpires().equals(updatedLockInfo.getExpires()));
assertTrue("Expires was updated incorrectly.", lockInfo.getExpires().before(updatedLockInfo.getExpires()));
// prepare propfind method
MockHttpServletRequest propFindRequest = new MockHttpServletRequest();
propFindRequest.setRequestURI("/" + TEST_FILE_NAME);
propFindRequest.addHeader(WebDAV.HEADER_DEPTH, "1");
content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><D:propfind xmlns:D=\"DAV:\"><D:prop><D:getlastmodified/>" +
"<D:getcontentlength/><D:resourcetype/><D:supportedlock/><D:lockdiscovery/></D:prop></D:propfind>";
propFindRequest.setContent(content.getBytes("UTF-8"));
MockHttpServletResponse propfindResponse = new MockHttpServletResponse();
propFindMethod.setDetails(propFindRequest, propfindResponse, davHelper, folderNodeRef);
propFindMethod.parseRequestHeaders();
propFindMethod.parseRequestBody();
RetryingTransactionCallback<Void> propfindExecuteImplCallBack = new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
propFindMethod.executeImpl();
return null;
}
};
// make propfind method call for locked resource
this.transactionService.getRetryingTransactionHelper().doInTransaction(propfindExecuteImplCallBack);
String response = propfindResponse.getContentAsString();
assertFalse("Propfind response should contain lock informarion.", response.indexOf("lockdiscovery") == -1);
// wait for lock expiration
Thread.sleep(6000);
propfindResponse = new MockHttpServletResponse();
propFindMethod.setDetails(propFindRequest, propfindResponse, davHelper, folderNodeRef);
// make another propfind call on resource with expired lock
this.transactionService.getRetryingTransactionHelper().doInTransaction(propfindExecuteImplCallBack);
response = propfindResponse.getContentAsString();
// check that lock information is not there for expired lock
assertTrue("Propfind response should not conatain information about expired lock", response.indexOf("lockdiscovery") == -1);
}
}