From afcd38825f1c480b5a00ea2b2ff267415689d2b5 Mon Sep 17 00:00:00 2001 From: Alan Davis Date: Wed, 2 Apr 2014 21:59:20 +0000 Subject: [PATCH] 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 --- .../org/alfresco/repo/webdav/LockMethod.java | 1 + .../alfresco/repo/webdav/PropFindMethod.java | 2 +- .../org/alfresco/RemoteApi01TestSuite.java | 1 + .../alfresco/repo/webdav/LockMethodTest.java | 292 ++++++++++++++++++ 4 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 source/test-java/org/alfresco/repo/webdav/LockMethodTest.java diff --git a/source/java/org/alfresco/repo/webdav/LockMethod.java b/source/java/org/alfresco/repo/webdav/LockMethod.java index 6e67240046..505b707873 100644 --- a/source/java/org/alfresco/repo/webdav/LockMethod.java +++ b/source/java/org/alfresco/repo/webdav/LockMethod.java @@ -459,6 +459,7 @@ public class LockMethod extends WebDAVMethod { // Update the expiry for the lock lockInfo.setTimeoutSeconds(getLockTimeout()); + getDAVLockService().lock(lockNode.getNodeRef(), lockInfo); } } diff --git a/source/java/org/alfresco/repo/webdav/PropFindMethod.java b/source/java/org/alfresco/repo/webdav/PropFindMethod.java index 181dc007bf..cf50979bb7 100644 --- a/source/java/org/alfresco/repo/webdav/PropFindMethod.java +++ b/source/java/org/alfresco/repo/webdav/PropFindMethod.java @@ -922,7 +922,7 @@ public class PropFindMethod extends WebDAVMethod { // Output the lock status response LockInfo lockInfo = getNodeLockInfo(nodeInfo); - if (lockInfo.isLocked()) + if (lockInfo.isLocked() && !lockInfo.isExpired()) { generateLockDiscoveryXML(xml, nodeInfo, lockInfo); } diff --git a/source/test-java/org/alfresco/RemoteApi01TestSuite.java b/source/test-java/org/alfresco/RemoteApi01TestSuite.java index 96430a8dc2..9f2619ae52 100644 --- a/source/test-java/org/alfresco/RemoteApi01TestSuite.java +++ b/source/test-java/org/alfresco/RemoteApi01TestSuite.java @@ -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.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.WebDAVMethodTest.class)); suite.addTestSuite(org.alfresco.repo.webservice.CMLUtilTest.class); diff --git a/source/test-java/org/alfresco/repo/webdav/LockMethodTest.java b/source/test-java/org/alfresco/repo/webdav/LockMethodTest.java new file mode 100644 index 0000000000..8e24812cbb --- /dev/null +++ b/source/test-java/org/alfresco/repo/webdav/LockMethodTest.java @@ -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 . + */ +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 createTestFileCallback = new RetryingTransactionCallback() + { + @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. singletonMap(ContentModel.PROP_NAME, "folder")).getChildRef(); + fileNodeRef = nodeService.createNode(folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_CONTENT, + Collections. 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 deleteStoreCallback = new RetryingTransactionCallback() + { + @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 = "" + + "" + + "" + userName + ""; + + lockRequest.setContent(content.getBytes("UTF-8")); + + lockMethod.setDetails(lockRequest, new MockHttpServletResponse(), davHelper, folderNodeRef); + lockMethod.parseRequestHeaders(); + lockMethod.parseRequestBody(); + + RetryingTransactionCallback lockExecuteImplCallBack = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + lockMethod.executeImpl(); + return null; + } + }; + + // lock node for 5 seconds + this.transactionService.getRetryingTransactionHelper().doInTransaction(lockExecuteImplCallBack); + + RetryingTransactionCallback getNodeLockInfoCallBack = new RetryingTransactionCallback() + { + @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 = "" + + ""; + + propFindRequest.setContent(content.getBytes("UTF-8")); + + MockHttpServletResponse propfindResponse = new MockHttpServletResponse(); + propFindMethod.setDetails(propFindRequest, propfindResponse, davHelper, folderNodeRef); + + propFindMethod.parseRequestHeaders(); + propFindMethod.parseRequestBody(); + + RetryingTransactionCallback propfindExecuteImplCallBack = new RetryingTransactionCallback() + { + @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); + } +}