From a9e54bd08cc5bd62dd8c1cb8c7683bde28110921 Mon Sep 17 00:00:00 2001 From: Denis Ungureanu Date: Tue, 12 Jan 2021 11:41:23 +0200 Subject: [PATCH] ACS-1043 : Camel upgrade to 3.7.0 (#235) ACS-1043: Upgrade Camel version --- .../SpringAwareUserTransaction.java | 9 +- .../util/BaseApplicationContextHelper.java | 37 +- packaging/war/pom.xml | 5 - pom.xml | 47 +- remote-api/pom.xml | 5 + .../repo/web/util/HttpRangeProcessorTest.java | 148 +-- .../repo/webdav/GetMethodRegressionTest.java | 614 ++++----- .../alfresco/repo/webdav/MoveMethodTest.java | 1124 ++++++++--------- .../repo/webdav/UnlockMethodTest.java | 762 +++++------ .../repo/webdav/WebDAVHelperTest.java | 194 +-- .../webdav/WebDAVLockServiceImplTest.java | 462 +++---- .../repo/webdav/WebDAVMethodTest.java | 1056 ++++++++-------- .../alfresco/rest/api/tests/ProbeApiTest.java | 2 +- .../rest/api/tests/QueriesPeopleApiTest.java | 1036 ++++++++------- repository/pom.xml | 148 +-- .../camel/SpringContextRouteLoader.java | 5 +- .../ConnectionFactoryConfiguration.java | 7 + .../routes/OnContentUpdateRenditionRoute.java | 4 +- .../routes/RepoNodeEventsRouteBuilder.java | 14 +- .../routes/TransformRequestConsumer.java | 4 +- .../Messaging/default/messaging-context.xml | 2 +- .../messaging/camel/CamelRoutesTest.java | 14 +- .../camel/routes/TestingRouteBuilder.java | 7 +- .../event2/AbstractContextAwareRepoEvent.java | 5 +- .../RenditionEventProcessorTest.java | 3 +- .../TransformationOptionsConverterTest.java | 2 +- 26 files changed, 2821 insertions(+), 2895 deletions(-) diff --git a/core/src/main/java/org/alfresco/util/transaction/SpringAwareUserTransaction.java b/core/src/main/java/org/alfresco/util/transaction/SpringAwareUserTransaction.java index 3ad66f6b4e..476890ecf5 100644 --- a/core/src/main/java/org/alfresco/util/transaction/SpringAwareUserTransaction.java +++ b/core/src/main/java/org/alfresco/util/transaction/SpringAwareUserTransaction.java @@ -18,9 +18,10 @@ */ package org.alfresco.util.transaction; +import static java.util.Collections.emptyList; + import java.lang.reflect.Method; import java.util.Collection; -import java.util.Collections; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; @@ -138,8 +139,8 @@ public class SpringAwareUserTransaction /** make sure that we clean up the thread transaction stack properly */ private boolean finalized = false; - private Collection labels = Collections.emptyList(); - + private Collection labels = emptyList(); + /** * Creates a user transaction that defaults to {@link TransactionDefinition#PROPAGATION_REQUIRED}. * @@ -212,7 +213,7 @@ public class SpringAwareUserTransaction public void setLabels(Collection labels) { this.labels = labels; } - + @Override public Collection getLabels() { diff --git a/data-model/src/main/java/org/alfresco/util/BaseApplicationContextHelper.java b/data-model/src/main/java/org/alfresco/util/BaseApplicationContextHelper.java index 1666a33e69..cdd8a4a0e3 100644 --- a/data-model/src/main/java/org/alfresco/util/BaseApplicationContextHelper.java +++ b/data-model/src/main/java/org/alfresco/util/BaseApplicationContextHelper.java @@ -100,26 +100,25 @@ public abstract class BaseApplicationContextHelper classpath[i] = resources[i].getURL(); } // Let's give our classloader 'child-first' resource loading qualities! - ClassLoader classLoader = new URLClassLoader(classpath, Thread.currentThread().getContextClassLoader()) - { - @Override - public URL getResource(String name) - { - URL ret = findResource(name); - return ret == null ? super.getResource(name) : ret; - } + return new URLClassLoader(classpath, Thread.currentThread().getContextClassLoader()) + { + @Override + public URL getResource(String name) + { + URL ret = findResource(name); + return ret == null ? super.getResource(name) : ret; + } - @SuppressWarnings("rawtypes") - @Override - public Enumeration getResources(String name) throws IOException - { - Enumeration[] tmp = new Enumeration[2]; - tmp[0] = findResources(name); - tmp[1] = super.getResources(name); - return new CompoundEnumeration(tmp); - } - }; - return classLoader; + @SuppressWarnings("rawtypes") + @Override + public Enumeration getResources(String name) throws IOException + { + Enumeration[] tmp = new Enumeration[2]; + tmp[0] = findResources(name); + tmp[1] = super.getResources(name); + return new CompoundEnumeration(tmp); + } + }; } /** diff --git a/packaging/war/pom.xml b/packaging/war/pom.xml index 3268fc78cd..06e35315a9 100644 --- a/packaging/war/pom.xml +++ b/packaging/war/pom.xml @@ -95,11 +95,6 @@ tests test - - - commons-lang - commons-lang - org.springframework spring-test diff --git a/pom.xml b/pom.xml index 2b37b488c6..339b0447ac 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 5.3.2 3.5.2 2.12.1 - 2.11.2 + ${dependency.jackson.version} 3.4.2 1.0.0 8.15 @@ -82,7 +82,7 @@ 1.4 12.0.1 3.4.1.Final - 2.25.3 + 3.7.0 5.16.0 1.2.5 4.0.3 @@ -243,11 +243,6 @@ commons-digester 2.1 - - commons-lang - commons-lang - 2.6 - commons-fileupload commons-fileupload @@ -637,6 +632,44 @@ gson ${dependency.gson.version} + + org.apache.camel + camel-spring + ${dependency.camel.version} + + + org.apache.camel + camel-amqp + ${dependency.camel.version} + + + + org.apache.geronimo.specs + geronimo-jms_2.0_spec + + + + + org.apache.camel + camel-jackson + ${dependency.camel.version} + + + org.apache.camel + camel-directvm + ${dependency.camel.version} + + + org.apache.camel + camel-direct + ${dependency.camel.version} + + + org.apache.camel + camel-mock + ${dependency.camel.version} + test + diff --git a/remote-api/pom.xml b/remote-api/pom.xml index b8d52d5aad..dc7f40e68c 100644 --- a/remote-api/pom.xml +++ b/remote-api/pom.xml @@ -207,6 +207,11 @@ + + org.apache.camel + camel-mock + test + diff --git a/remote-api/src/test/java/org/alfresco/repo/web/util/HttpRangeProcessorTest.java b/remote-api/src/test/java/org/alfresco/repo/web/util/HttpRangeProcessorTest.java index ab93f69753..b87a0c7d5d 100644 --- a/remote-api/src/test/java/org/alfresco/repo/web/util/HttpRangeProcessorTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/web/util/HttpRangeProcessorTest.java @@ -23,77 +23,77 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.repo.web.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - -import java.io.IOException; - -import javax.servlet.http.HttpServletResponse; - -import org.alfresco.service.cmr.repository.ContentReader; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.mock.web.MockHttpServletResponse; - -/** - * Tests for the HttpRangeProcessor class. - * - * @author Ray Gauss II - */ -@RunWith(MockitoJUnitRunner.class) -public class HttpRangeProcessorTest -{ - private HttpRangeProcessor httpRangeProcessor; - private @Mock ContentReader reader; - - @Before - public void setUp() throws Exception - { - httpRangeProcessor = new HttpRangeProcessor(null); - when(reader.getMimetype()).thenReturn("image/jpeg"); - when(reader.getSize()).thenReturn(19133L); - when(reader.getContentInputStream()).thenReturn(this.getClass().getResourceAsStream("/test.jpg")); - } - - @Test - public void testValidRange() throws IOException - { - testRange("700-800", HttpServletResponse.SC_PARTIAL_CONTENT); - } - - @Test - public void testStartOnlyRange() throws IOException - { - testRange("19000-", HttpServletResponse.SC_PARTIAL_CONTENT); - } - - @Test - public void testNegativeRange() throws IOException - { - testRange("800-700", HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - } - - @Test - public void testBeyondLengthRange() throws IOException - { - testRange("20000-", HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - } - - protected void testRange(String range, int expectedStatus) throws IOException - { - MockHttpServletResponse response = new MockHttpServletResponse(); - - boolean result = httpRangeProcessor.processRange(response, reader, range, null, null, null, null); - - assertTrue(result); - assertEquals(expectedStatus, response.getStatus()); - reader.getContentInputStream().close(); - } - -} +package org.alfresco.repo.web.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.cmr.repository.ContentReader; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * Tests for the HttpRangeProcessor class. + * + * @author Ray Gauss II + */ +@RunWith(MockitoJUnitRunner.class) +public class HttpRangeProcessorTest +{ + private HttpRangeProcessor httpRangeProcessor; + private @Mock ContentReader reader; + + @Before + public void setUp() throws Exception + { + httpRangeProcessor = new HttpRangeProcessor(null); + when(reader.getMimetype()).thenReturn("image/jpeg"); + when(reader.getSize()).thenReturn(19133L); + when(reader.getContentInputStream()).thenReturn(this.getClass().getResourceAsStream("/test.jpg")); + } + + @Test + public void testValidRange() throws IOException + { + testRange("700-800", HttpServletResponse.SC_PARTIAL_CONTENT); + } + + @Test + public void testStartOnlyRange() throws IOException + { + testRange("19000-", HttpServletResponse.SC_PARTIAL_CONTENT); + } + + @Test + public void testNegativeRange() throws IOException + { + testRange("800-700", HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + } + + @Test + public void testBeyondLengthRange() throws IOException + { + testRange("20000-", HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + } + + protected void testRange(String range, int expectedStatus) throws IOException + { + MockHttpServletResponse response = new MockHttpServletResponse(); + + boolean result = httpRangeProcessor.processRange(response, reader, range, null, null, null, null); + + assertTrue(result); + assertEquals(expectedStatus, response.getStatus()); + reader.getContentInputStream().close(); + } + +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/GetMethodRegressionTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/GetMethodRegressionTest.java index 51d62d0f07..71ccdbc37c 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/GetMethodRegressionTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/GetMethodRegressionTest.java @@ -1,307 +1,307 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ -package org.alfresco.repo.webdav; - -import java.io.Serializable; -import java.net.HttpURLConnection; -import java.util.Map; - -import javax.transaction.Status; -import javax.transaction.UserTransaction; - -import junit.framework.TestCase; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.audit.model.AuditModelRegistryImpl; -import org.alfresco.repo.node.archive.NodeArchiveService; -import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.audit.AuditQueryParameters; -import org.alfresco.service.cmr.audit.AuditService; -import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.testing.category.LuceneTests; -import org.apache.chemistry.opencmis.commons.spi.Holder; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -/** - * Tests {@link GetMethod} in real environment, using {@link Mock} HTTP request and {@link Mock} HTTP response - * - * @author Dmitry Velichkevich - */ -@RunWith(MockitoJUnitRunner.class) -@Category(LuceneTests.class) -public class GetMethodRegressionTest extends TestCase -{ - private static final int DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST = 25; - - - private static final String HTTP_METHOD_GET = "GET"; - - private static final String TEST_ENCODING = "UTF-8"; - - private static final String TEST_MIMETYPE = "text/plain"; - - private static final String TEST_WEBDAV_URL_PREFIX = "/"; - - private static final String AUDIT_REGISTRY_BEAN_NAME = "Audit"; - - private static final String PROP_AUDIT_ALFRESCO_ACCESS_ENABLED = "audit.alfresco-access.enabled"; - - private static final String ROOT_TEST_FOLDER_NAME = "TestFolder-" + System.currentTimeMillis(); - - private static final String TEST_DOCUMENT_NAME_PATTERN = "TestDocument-%d-%d.pdf"; - - private static final String TEXT_DOCUMENT_CONTENT_PATTERN = "Text content for '%s' document"; - - - private ApplicationContext applicationContext; - - private WebDAVHelper davHelper; - - private AuditService auditService; - - private FileFolderService fileFolderService; - - private AuditModelRegistryImpl auditRegistry; - - private TransactionService transactionService; - - - private UserTransaction transaction; - - private GetMethod testingMethod; - - private NodeRef companyHomeNodeRef; - - private NodeRef rootTestFolder; - - private MockHttpServletResponse mockResponse; - - - @Before - public void setUp() throws Exception - { - applicationContext = ApplicationContextHelper.getApplicationContext(); - ServiceRegistry registry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); - davHelper = (WebDAVHelper) applicationContext.getBean(WebDAVHelper.BEAN_NAME); - auditRegistry = (AuditModelRegistryImpl) applicationContext.getBean(AUDIT_REGISTRY_BEAN_NAME); - - auditService = registry.getAuditService(); - fileFolderService = registry.getFileFolderService(); - transactionService = registry.getTransactionService(); - - testingMethod = new GetMethod(); - mockResponse = new MockHttpServletResponse(); - - restartTransaction(TransactionActionEnum.ACTION_NONE); - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - - companyHomeNodeRef = registry.getNodeLocatorService().getNode(CompanyHomeNodeLocator.NAME, null, null); - rootTestFolder = fileFolderService.create(companyHomeNodeRef, ROOT_TEST_FOLDER_NAME, ContentModel.TYPE_FOLDER).getNodeRef(); - } - - @After - public void tearDown() throws Exception - { - if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) - { - transaction.rollback(); - } - - AuthenticationUtil.clearCurrentSecurityContext(); - } - - /** - * Test for MNT-10820 - * - * @throws Exception - */ - @Test - public void testAuditRecordsAdditionAsbsence() throws Exception - { - String url = new StringBuilder(TEST_WEBDAV_URL_PREFIX).append(ROOT_TEST_FOLDER_NAME).toString(); - MockHttpServletRequest mockRequest = new MockHttpServletRequest(HTTP_METHOD_GET, url); - testingMethod.setDetails(mockRequest, mockResponse, davHelper, companyHomeNodeRef); - - boolean auditEnabled = auditService.isAuditEnabled(); - - if (!auditEnabled) - { - auditService.setAuditEnabled(true); - } - - boolean alfrescoAccessEnabled = Boolean.valueOf(auditRegistry.getProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED)); - - if (!alfrescoAccessEnabled) - { - setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.TRUE.toString()); - } - - try - { - createTestContent(rootTestFolder, DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST); - - restartTransaction(TransactionActionEnum.ACTION_COMMIT); - - Long expectedLastTime = getLastAuditRecordTime(); - - testingMethod.executeImpl(); - assertEquals(HttpURLConnection.HTTP_OK, mockResponse.getStatus()); - - String contentAsString = mockResponse.getContentAsString(); - assertNotNull("WebDAV 'GET' method response is empty!", contentAsString); - assertTrue(contentAsString.contains(ROOT_TEST_FOLDER_NAME)); - - restartTransaction(TransactionActionEnum.ACTION_COMMIT); - - Long actualLastTime = getLastAuditRecordTime(); - - if (null == expectedLastTime) - { - assertNull("Audit entry table is not empty after 'GetMethod.executeImpl()' invocation. But it is expected to be empty!", actualLastTime); - } - else - { - assertEquals(expectedLastTime, actualLastTime); - } - } - finally - { - if (!alfrescoAccessEnabled) - { - setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.FALSE.toString()); - } - - if (!auditEnabled) - { - auditService.setAuditEnabled(false); - } - } - } - - private void setAuditRegistryProperty(String propertyName, String value) - { - assertTrue(("'" + propertyName + "' is not updatable!"), auditRegistry.isUpdateable(propertyName)); - - auditRegistry.stop(); - auditRegistry.setProperty(propertyName, value); - auditRegistry.start(); - } - - private void createTestContent(NodeRef parentNode, int documentsAmount) - { - for (int i = 0; i < documentsAmount; i++) - { - String testDocumentName = String.format(TEST_DOCUMENT_NAME_PATTERN, i, System.currentTimeMillis()); - FileInfo testDocument = fileFolderService.create(parentNode, testDocumentName, ContentModel.TYPE_CONTENT); - ContentWriter writer = fileFolderService.getWriter(testDocument.getNodeRef()); - writer.putContent(String.format(TEXT_DOCUMENT_CONTENT_PATTERN, testDocumentName)); - writer.setMimetype(TEST_MIMETYPE); - writer.setEncoding(TEST_ENCODING); - } - } - - private enum TransactionActionEnum - { - ACTION_NONE, - - ACTION_COMMIT, - - ACTION_ROLLBACK - } - - /** - * Commits or rolls back or does nothing with the current transaction and begins a new {@link UserTransaction} - * - * @param transactionAction - one of the {@link TransactionActionEnum} values which specifies action to be done for the current transaction - * @throws Exception - */ - private void restartTransaction(TransactionActionEnum transactionAction) throws Exception - { - if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) - { - if (TransactionActionEnum.ACTION_COMMIT == transactionAction) - { - transaction.commit(); - } - else if (TransactionActionEnum.ACTION_ROLLBACK == transactionAction) - { - transaction.rollback(); - } - } - - transaction = transactionService.getUserTransaction(); - transaction.begin(); - } - - private Long getLastAuditRecordTime() - { - final Holder lastTime = new Holder(); - - AuditQueryParameters parameters = new AuditQueryParameters(); - parameters.setForward(false); - - auditService.auditQuery(new AuditQueryCallback() - { - @Override - public boolean valuesRequired() - { - return false; - } - - @Override - public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error) - { - return false; - } - - @Override - public boolean handleAuditEntry(Long entryId, String applicationName, String user, long time, Map values) - { - lastTime.setValue(time); - return false; - } - }, parameters, 1); - - return lastTime.getValue(); - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ +package org.alfresco.repo.webdav; + +import java.io.Serializable; +import java.net.HttpURLConnection; +import java.util.Map; + +import javax.transaction.Status; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.audit.model.AuditModelRegistryImpl; +import org.alfresco.repo.node.archive.NodeArchiveService; +import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.audit.AuditQueryParameters; +import org.alfresco.service.cmr.audit.AuditService; +import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.testing.category.LuceneTests; +import org.apache.chemistry.opencmis.commons.spi.Holder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * Tests {@link GetMethod} in real environment, using {@link Mock} HTTP request and {@link Mock} HTTP response + * + * @author Dmitry Velichkevich + */ +@RunWith(MockitoJUnitRunner.class) +@Category(LuceneTests.class) +public class GetMethodRegressionTest extends TestCase +{ + private static final int DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST = 25; + + + private static final String HTTP_METHOD_GET = "GET"; + + private static final String TEST_ENCODING = "UTF-8"; + + private static final String TEST_MIMETYPE = "text/plain"; + + private static final String TEST_WEBDAV_URL_PREFIX = "/"; + + private static final String AUDIT_REGISTRY_BEAN_NAME = "Audit"; + + private static final String PROP_AUDIT_ALFRESCO_ACCESS_ENABLED = "audit.alfresco-access.enabled"; + + private static final String ROOT_TEST_FOLDER_NAME = "TestFolder-" + System.currentTimeMillis(); + + private static final String TEST_DOCUMENT_NAME_PATTERN = "TestDocument-%d-%d.pdf"; + + private static final String TEXT_DOCUMENT_CONTENT_PATTERN = "Text content for '%s' document"; + + + private ApplicationContext applicationContext; + + private WebDAVHelper davHelper; + + private AuditService auditService; + + private FileFolderService fileFolderService; + + private AuditModelRegistryImpl auditRegistry; + + private TransactionService transactionService; + + + private UserTransaction transaction; + + private GetMethod testingMethod; + + private NodeRef companyHomeNodeRef; + + private NodeRef rootTestFolder; + + private MockHttpServletResponse mockResponse; + + + @Before + public void setUp() throws Exception + { + applicationContext = ApplicationContextHelper.getApplicationContext(); + ServiceRegistry registry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + davHelper = (WebDAVHelper) applicationContext.getBean(WebDAVHelper.BEAN_NAME); + auditRegistry = (AuditModelRegistryImpl) applicationContext.getBean(AUDIT_REGISTRY_BEAN_NAME); + + auditService = registry.getAuditService(); + fileFolderService = registry.getFileFolderService(); + transactionService = registry.getTransactionService(); + + testingMethod = new GetMethod(); + mockResponse = new MockHttpServletResponse(); + + restartTransaction(TransactionActionEnum.ACTION_NONE); + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + companyHomeNodeRef = registry.getNodeLocatorService().getNode(CompanyHomeNodeLocator.NAME, null, null); + rootTestFolder = fileFolderService.create(companyHomeNodeRef, ROOT_TEST_FOLDER_NAME, ContentModel.TYPE_FOLDER).getNodeRef(); + } + + @After + public void tearDown() throws Exception + { + if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) + { + transaction.rollback(); + } + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + /** + * Test for MNT-10820 + * + * @throws Exception + */ + @Test + public void testAuditRecordsAdditionAsbsence() throws Exception + { + String url = new StringBuilder(TEST_WEBDAV_URL_PREFIX).append(ROOT_TEST_FOLDER_NAME).toString(); + MockHttpServletRequest mockRequest = new MockHttpServletRequest(HTTP_METHOD_GET, url); + testingMethod.setDetails(mockRequest, mockResponse, davHelper, companyHomeNodeRef); + + boolean auditEnabled = auditService.isAuditEnabled(); + + if (!auditEnabled) + { + auditService.setAuditEnabled(true); + } + + boolean alfrescoAccessEnabled = Boolean.valueOf(auditRegistry.getProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED)); + + if (!alfrescoAccessEnabled) + { + setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.TRUE.toString()); + } + + try + { + createTestContent(rootTestFolder, DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST); + + restartTransaction(TransactionActionEnum.ACTION_COMMIT); + + Long expectedLastTime = getLastAuditRecordTime(); + + testingMethod.executeImpl(); + assertEquals(HttpURLConnection.HTTP_OK, mockResponse.getStatus()); + + String contentAsString = mockResponse.getContentAsString(); + assertNotNull("WebDAV 'GET' method response is empty!", contentAsString); + assertTrue(contentAsString.contains(ROOT_TEST_FOLDER_NAME)); + + restartTransaction(TransactionActionEnum.ACTION_COMMIT); + + Long actualLastTime = getLastAuditRecordTime(); + + if (null == expectedLastTime) + { + assertNull("Audit entry table is not empty after 'GetMethod.executeImpl()' invocation. But it is expected to be empty!", actualLastTime); + } + else + { + assertEquals(expectedLastTime, actualLastTime); + } + } + finally + { + if (!alfrescoAccessEnabled) + { + setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.FALSE.toString()); + } + + if (!auditEnabled) + { + auditService.setAuditEnabled(false); + } + } + } + + private void setAuditRegistryProperty(String propertyName, String value) + { + assertTrue(("'" + propertyName + "' is not updatable!"), auditRegistry.isUpdateable(propertyName)); + + auditRegistry.stop(); + auditRegistry.setProperty(propertyName, value); + auditRegistry.start(); + } + + private void createTestContent(NodeRef parentNode, int documentsAmount) + { + for (int i = 0; i < documentsAmount; i++) + { + String testDocumentName = String.format(TEST_DOCUMENT_NAME_PATTERN, i, System.currentTimeMillis()); + FileInfo testDocument = fileFolderService.create(parentNode, testDocumentName, ContentModel.TYPE_CONTENT); + ContentWriter writer = fileFolderService.getWriter(testDocument.getNodeRef()); + writer.putContent(String.format(TEXT_DOCUMENT_CONTENT_PATTERN, testDocumentName)); + writer.setMimetype(TEST_MIMETYPE); + writer.setEncoding(TEST_ENCODING); + } + } + + private enum TransactionActionEnum + { + ACTION_NONE, + + ACTION_COMMIT, + + ACTION_ROLLBACK + } + + /** + * Commits or rolls back or does nothing with the current transaction and begins a new {@link UserTransaction} + * + * @param transactionAction - one of the {@link TransactionActionEnum} values which specifies action to be done for the current transaction + * @throws Exception + */ + private void restartTransaction(TransactionActionEnum transactionAction) throws Exception + { + if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) + { + if (TransactionActionEnum.ACTION_COMMIT == transactionAction) + { + transaction.commit(); + } + else if (TransactionActionEnum.ACTION_ROLLBACK == transactionAction) + { + transaction.rollback(); + } + } + + transaction = transactionService.getUserTransaction(); + transaction.begin(); + } + + private Long getLastAuditRecordTime() + { + final Holder lastTime = new Holder(); + + AuditQueryParameters parameters = new AuditQueryParameters(); + parameters.setForward(false); + + auditService.auditQuery(new AuditQueryCallback() + { + @Override + public boolean valuesRequired() + { + return false; + } + + @Override + public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error) + { + return false; + } + + @Override + public boolean handleAuditEntry(Long entryId, String applicationName, String user, long time, Map values) + { + lastTime.setValue(time); + return false; + } + }, parameters, 1); + + return lastTime.getValue(); + } +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/MoveMethodTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/MoveMethodTest.java index 09696b905a..1ba3d44eb3 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/MoveMethodTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/MoveMethodTest.java @@ -1,562 +1,562 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ -package org.alfresco.repo.webdav; - -import static org.junit.Assert.fail; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.List; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.model.Repository; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.permissions.AccessDeniedException; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; -import org.alfresco.service.cmr.repository.ContentReader; -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.search.ResultSet; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.GUID; -import org.alfresco.util.testing.category.LuceneTests; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -/** - * Tests for the {@link MoveMethod} class. - * - * @author Matt Ward - */ -@RunWith(MockitoJUnitRunner.class) -@Category(LuceneTests.class) -public class MoveMethodTest -{ - private static ApplicationContext ctx; - - private MoveMethod moveMethod; - private @Mock WebDAVHelper davHelper; - private MockHttpServletRequest req; - private MockHttpServletResponse resp; - private NodeRef rootNode; - private @Mock FileFolderService mockFileFolderService; - private @Mock WebDAVLockService davLockService; - private @Mock ServiceRegistry mockServiceRegistry; - private @Mock ContentService mockContentService; - private String destPath; - private String sourcePath; - private FileInfo sourceFileInfo; - private NodeRef sourceParentNodeRef; - private NodeRef destParentNodeRef; - private NodeRef sourceNodeRef; - - private SearchService searchService; - private FileFolderService fileFolderService; - private NodeService nodeService; - private TransactionService transactionService; - private ContentService contentService; - private WebDAVHelper webDAVHelper; - - private Repository repositoryHelper; - private NodeRef companyHomeNodeRef; - - @BeforeClass - public static void setUpBeforeClass() throws Exception - { - ctx = ApplicationContextHelper.getApplicationContext(new String[] - { - "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", - "classpath:alfresco/remote-api-context.xml" - }); - } - - @After - public void tearDown() - { - moveMethod = null; - req = null; - resp = null; - - AuthenticationUtil.clearCurrentSecurityContext(); - } - - @Before - public void setUp() throws Exception - { - req = new MockHttpServletRequest(); - resp = new MockHttpServletResponse(); - rootNode = new NodeRef("workspace://SpacesStore/node1"); - moveMethod = new MoveMethod() - { - @Override - protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) - throws WebDAVServerException - { - return new LockInfoImpl(); - } - - @Override - protected LockInfo checkNode(FileInfo fileInfo) throws WebDAVServerException - { - return new LockInfoImpl(); - } - }; - moveMethod.setDetails(req, resp, davHelper, rootNode); - - sourceFileInfo = Mockito.mock(FileInfo.class); - when(sourceFileInfo.isFolder()).thenReturn(true); - - destPath = "/path/to/dest.doc"; - moveMethod.m_strDestinationPath = destPath; - - sourcePath = "/path/to/source.doc"; - moveMethod.m_strPath = sourcePath; - - when(davHelper.getFileFolderService()).thenReturn(mockFileFolderService); - - List sourcePathSplit = Arrays.asList("path", "to", "source.doc"); - when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); - - - List destPathSplit = Arrays.asList("path", "to", "dest.doc"); - when(davHelper.splitAllPaths(destPath)).thenReturn(destPathSplit); - - - when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(sourceFileInfo); - - FileInfo destFileInfo = Mockito.mock(FileInfo.class); - when(mockFileFolderService.resolveNamePath(rootNode, destPathSplit)).thenReturn(destFileInfo); - - sourceParentNodeRef = new NodeRef("workspace://SpacesStore/parent"); - destParentNodeRef = new NodeRef("workspace://SpacesStore/parent"); - - - sourceNodeRef = new NodeRef("workspace://SpacesStore/sourcefile"); - - when(davHelper.getLockService()).thenReturn(davLockService); - - searchService = ctx.getBean("SearchService", SearchService.class); - fileFolderService = ctx.getBean("FileFolderService", FileFolderService.class); - nodeService = ctx.getBean("NodeService", NodeService.class); - transactionService = ctx.getBean("transactionService", TransactionService.class); - contentService = ctx.getBean("contentService", ContentService.class); - webDAVHelper = ctx.getBean("webDAVHelper", WebDAVHelper.class); - - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - - repositoryHelper = (Repository)ctx.getBean("repositoryHelper"); - companyHomeNodeRef = repositoryHelper.getCompanyHome(); - } - - - @Test - public void canRenameFolders() throws Exception - { - moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); - - verify(mockFileFolderService).rename(sourceNodeRef, "dest.doc"); - // sourceNodeRef is not locked, so unlock should not be called after rename - verify(davLockService, never()).unlock(sourceNodeRef); - verify(mockFileFolderService, never()).create(destParentNodeRef, "dest.doc", ContentModel.TYPE_CONTENT); - } - - - @Test - public void canRenameFoldersWhenNewNameMatchesShufflePattern() throws Exception - { - when(davHelper.isRenameShuffle(destPath)).thenReturn(true); - when(davHelper.isRenameShuffle(sourcePath)).thenReturn(false); - - // Test: Perform the rename - moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); - - verify(mockFileFolderService).rename(sourceNodeRef, "dest.doc"); - // sourceNodeRef is not locked, so unlock should not be called after rename - verify(davLockService, never()).unlock(sourceNodeRef); - verify(mockFileFolderService, never()).create(destParentNodeRef, "dest.doc", ContentModel.TYPE_CONTENT); - } - - @Test - public void canMoveFileUnlock() throws Exception - { - moveMethod = new MoveMethod() - { - @Override - protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException - { - LockInfoImpl lockInfo = new LockInfoImpl(); - lockInfo.setExclusiveLockToken("opaque-lock-token"); - lockInfo.setDepth(WebDAV.INFINITY); - lockInfo.setScope(WebDAV.XML_EXCLUSIVE); - return lockInfo; - } - - @Override - protected LockInfo checkNode(FileInfo fileInfo) throws WebDAVServerException - { - return checkNode(fileInfo, false, false); - } - }; - - moveMethod.setDetails(req, resp, davHelper, rootNode); - - sourceFileInfo = Mockito.mock(FileInfo.class); - when(sourceFileInfo.isFolder()).thenReturn(true); - - destPath = "/path/to/test.doc"; - moveMethod.m_strDestinationPath = destPath; - - sourcePath = "/path/from/test.doc"; - moveMethod.m_strPath = sourcePath; - - when(davHelper.getServiceRegistry()).thenReturn(mockServiceRegistry); - when(mockServiceRegistry.getContentService()).thenReturn(mockContentService); - - List sourcePathSplit = Arrays.asList("path", "from", "test.doc"); - when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); - - List destPathSplit = Arrays.asList("path", "to", "dest.doc"); - when(davHelper.splitAllPaths(destPath)).thenReturn(destPathSplit); - - when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(sourceFileInfo); - - FileInfo destFileInfo = Mockito.mock(FileInfo.class); - when(mockFileFolderService.resolveNamePath(rootNode, destPathSplit)).thenReturn(destFileInfo); - - sourceParentNodeRef = new NodeRef("workspace://SpacesStore/parent1"); - destParentNodeRef = new NodeRef("workspace://SpacesStore/parent2"); - sourceNodeRef = new NodeRef("workspace://SpacesStore/sourcefile"); - - moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "test.doc"); - - verify(mockFileFolderService).moveFrom(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "test.doc"); - verify(davLockService).unlock(sourceNodeRef); - } - - @Test - public void testMNT_13144() throws Exception - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - FileInfo dwgFI = null; - String fileName = "source-" + GUID.generate(); - String sourceFileName = fileName + ".dwg"; - - FileInfo atmpFI = null; - String destFileName = "atmp1234"; - - FileInfo tmpFI = null; - String tmpFileName = fileName + ".tmp"; - - String bakFileName = fileName + ".bak"; - - String content = "Some dwg content."; - String tmpContent = "Change dwg content."; - - try - { - dwgFI = fileFolderService.create(companyHomeNodeRef, sourceFileName, ContentModel.TYPE_CONTENT); - ContentWriter writer = contentService.getWriter(dwgFI.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.setMimetype(MimetypeMap.MIMETYPE_APP_DWG); - writer.setEncoding("UTF-8"); - writer.putContent(content); - - tmpFI = fileFolderService.create(companyHomeNodeRef, tmpFileName, ContentModel.TYPE_CONTENT); - writer = contentService.getWriter(tmpFI.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.setMimetype(MimetypeMap.MIMETYPE_APP_DWG); - writer.setEncoding("UTF-8"); - writer.putContent(tmpContent); - - atmpFI = fileFolderService.create(companyHomeNodeRef, destFileName, ContentModel.TYPE_CONTENT); - - sourcePath = "/" + sourceFileName; - moveMethod.m_strPath = sourcePath; - - destPath = "/" + destFileName; - moveMethod.m_strDestinationPath = destPath; - - List sourcePathSplit = Arrays.asList(sourceFileName); - when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); - - when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(dwgFI); - when(davHelper.isRenameShuffle(destPath)).thenReturn(true); - when(davHelper.isRenameShuffle(sourcePath)).thenReturn(false); - - when(mockFileFolderService.create(companyHomeNodeRef, destFileName, ContentModel.TYPE_CONTENT)).thenReturn(atmpFI); - - ServiceRegistry mockServiceRegistry = Mockito.mock(ServiceRegistry.class); - when(davHelper.getServiceRegistry()).thenReturn(mockServiceRegistry); - when(davHelper.getServiceRegistry().getContentService()).thenReturn(contentService); - - // move webdav method dwg copy to atmp1234 - moveMethod.moveOrCopy(dwgFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, destFileName); - - ContentReader reader = contentService.getReader(atmpFI.getNodeRef(), ContentModel.PROP_CONTENT); - assertNotNull(reader); - assertEquals(content, reader.getContentString()); - - // move webdav method atmp1234 rename to bak - sourcePath = "/" + destFileName; - moveMethod.m_strPath = sourcePath; - - destPath = "/" + bakFileName; - moveMethod.m_strDestinationPath = destPath; - - sourcePathSplit = Arrays.asList(destFileName); - when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); - - when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(atmpFI); - when(davHelper.isRenameShuffle(destPath)).thenReturn(true); - when(davHelper.isRenameShuffle(sourcePath)).thenReturn(true); - - moveMethod.moveOrCopy(atmpFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, bakFileName); - - verify(mockFileFolderService).rename(atmpFI.getNodeRef(), bakFileName); - verify(mockFileFolderService, never()).create(destParentNodeRef, bakFileName, ContentModel.TYPE_CONTENT); - - // move webdav method tmp copy content to dwg - sourcePath = "/" + tmpFileName; - moveMethod.m_strPath = sourcePath; - - destPath = "/" + sourceFileName; - moveMethod.m_strDestinationPath = destPath; - - sourcePathSplit = Arrays.asList(tmpFileName); - when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); - - when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(tmpFI); - when(davHelper.isRenameShuffle(destPath)).thenReturn(false); - when(davHelper.isRenameShuffle(sourcePath)).thenReturn(true); - - moveMethod.moveOrCopy(atmpFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, bakFileName); - - reader = contentService.getReader(dwgFI.getNodeRef(), ContentModel.PROP_CONTENT); - assertNotNull(reader); - assertEquals(tmpContent, reader.getContentString()); - } - finally - { - if (dwgFI != null) - { - nodeService.deleteNode(dwgFI.getNodeRef()); - } - - if (atmpFI != null) - { - nodeService.deleteNode(atmpFI.getNodeRef()); - } - } - - return null; - } - }); - } - - @Test(expected=AccessDeniedException.class) - public void testMNT_10380_ThrowAccessDeniedExceptionWhenUserLacksPermissions() throws Exception - { - when(mockFileFolderService.rename(sourceNodeRef, "dest.doc")). - thenThrow(new AccessDeniedException("Access denied in test by mockFileFolderService")); - - moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); - } - - @Test - public void testMNT_9662() - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - // create test folder with name that doesn't match getDAVHelper().isRenameShuffle() - FileInfo testFileInfo = fileFolderService.create(companyHomeNodeRef, "folder-" + GUID.generate().substring(29), ContentModel.TYPE_FOLDER); - - req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + testFileInfo.getName()); - resp = new MockHttpServletResponse(); - req.setServerPort(8080); - req.setContextPath("/alfresco"); - req.setServletPath("/webdav"); - - moveMethod = new MoveMethod(); - moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); - - // generate new name that matches getDAVHelper().isRenameShuffle() - String newName = GUID.generate().substring(28); - req.addHeader(WebDAV.HEADER_DESTINATION, "http://localhost:8080/alfresco/webdav/" + newName); - - try - { - moveMethod.execute(); - - assertTrue(nodeService.exists(testFileInfo.getNodeRef())); - assertEquals(newName, nodeService.getProperty(testFileInfo.getNodeRef(), ContentModel.PROP_NAME)); - } - catch (WebDAVServerException e) - { - fail("Fail to rename folder: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); - } - finally - { - nodeService.deleteNode(testFileInfo.getNodeRef()); - } - return null; - } - }); - } - - @Test - public void testMNT_6480() - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - // create test file with name that doesn't match getDAVHelper().isRenameShuffle() - String originalFileName = "content-" + GUID.generate() + ".txt"; - FileInfo testFileInfo = fileFolderService.create(companyHomeNodeRef, originalFileName, ContentModel.TYPE_CONTENT); - - // rename source file to file with upper case name - String newFileName = originalFileName.toUpperCase(); - - req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + testFileInfo.getName()); - req.setServerPort(8080); - req.setContextPath("/alfresco"); - req.setServletPath("/webdav"); - req.addHeader(WebDAV.HEADER_DESTINATION, "http://localhost:8080/alfresco/webdav/" + newFileName); - - resp = new MockHttpServletResponse(); - - moveMethod = new MoveMethod(); - moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); - - try - { - moveMethod.execute(); - - // MNT-6480 - File should be renamed but not deleted - assertTrue(nodeService.exists(testFileInfo.getNodeRef())); - assertEquals(newFileName, nodeService.getProperty(testFileInfo.getNodeRef(), ContentModel.PROP_NAME)); - } - catch (WebDAVServerException e) - { - fail("Fail to rename node: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); - } - finally - { - nodeService.deleteNode(testFileInfo.getNodeRef()); - } - return null; - } - }); - } - - @Test - public void testMNT_9777() - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - // create test file with name that does match getDAVHelper().isRenameShuffle() - String originalFileName = "tempfile-" + GUID.generate() + ".tmp"; - - // destination within same folder - String newFileName = "destfile-" + GUID.generate() + ".txt"; - - FileInfo sourceFileInfo = fileFolderService.create(companyHomeNodeRef, originalFileName, ContentModel.TYPE_CONTENT); - FileInfo newFileInfo = fileFolderService.create(companyHomeNodeRef, newFileName, ContentModel.TYPE_CONTENT); - - String newContent = GUID.generate(); - ContentWriter writer; - writer = contentService.getWriter(sourceFileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.putContent(newContent); - - req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + sourceFileInfo.getName()); - resp = new MockHttpServletResponse(); - req.setServerPort(8080); - req.setContextPath("/alfresco"); - req.setServletPath("/webdav"); - - moveMethod = new MoveMethod(); - moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); - - String destPath = "http://localhost:8080/alfresco/webdav/" + newFileName; - req.addHeader(WebDAV.HEADER_DESTINATION, destPath); - - try - { - moveMethod.execute(); - - // MNT-9777 - Source node should be deleted - assertTrue(!nodeService.exists(sourceFileInfo.getNodeRef())); - - // Content should be updated - ContentReader reader = contentService.getReader(newFileInfo.getNodeRef(), ContentModel.PROP_CONTENT); - assertEquals(newContent, reader.getContentString()); - } - catch (WebDAVServerException e) - { - fail("Fail to move node: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); - } - finally - { - nodeService.deleteNode(newFileInfo.getNodeRef()); - } - return null; - } - }); - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ +package org.alfresco.repo.webdav; + +import static org.junit.Assert.fail; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.model.Repository; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.repository.ContentReader; +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.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.GUID; +import org.alfresco.util.testing.category.LuceneTests; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * Tests for the {@link MoveMethod} class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +@Category(LuceneTests.class) +public class MoveMethodTest +{ + private static ApplicationContext ctx; + + private MoveMethod moveMethod; + private @Mock WebDAVHelper davHelper; + private MockHttpServletRequest req; + private MockHttpServletResponse resp; + private NodeRef rootNode; + private @Mock FileFolderService mockFileFolderService; + private @Mock WebDAVLockService davLockService; + private @Mock ServiceRegistry mockServiceRegistry; + private @Mock ContentService mockContentService; + private String destPath; + private String sourcePath; + private FileInfo sourceFileInfo; + private NodeRef sourceParentNodeRef; + private NodeRef destParentNodeRef; + private NodeRef sourceNodeRef; + + private SearchService searchService; + private FileFolderService fileFolderService; + private NodeService nodeService; + private TransactionService transactionService; + private ContentService contentService; + private WebDAVHelper webDAVHelper; + + private Repository repositoryHelper; + private NodeRef companyHomeNodeRef; + + @BeforeClass + public static void setUpBeforeClass() throws Exception + { + ctx = ApplicationContextHelper.getApplicationContext(new String[] + { + "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/remote-api-context.xml" + }); + } + + @After + public void tearDown() + { + moveMethod = null; + req = null; + resp = null; + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + @Before + public void setUp() throws Exception + { + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + rootNode = new NodeRef("workspace://SpacesStore/node1"); + moveMethod = new MoveMethod() + { + @Override + protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) + throws WebDAVServerException + { + return new LockInfoImpl(); + } + + @Override + protected LockInfo checkNode(FileInfo fileInfo) throws WebDAVServerException + { + return new LockInfoImpl(); + } + }; + moveMethod.setDetails(req, resp, davHelper, rootNode); + + sourceFileInfo = Mockito.mock(FileInfo.class); + when(sourceFileInfo.isFolder()).thenReturn(true); + + destPath = "/path/to/dest.doc"; + moveMethod.m_strDestinationPath = destPath; + + sourcePath = "/path/to/source.doc"; + moveMethod.m_strPath = sourcePath; + + when(davHelper.getFileFolderService()).thenReturn(mockFileFolderService); + + List sourcePathSplit = Arrays.asList("path", "to", "source.doc"); + when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); + + + List destPathSplit = Arrays.asList("path", "to", "dest.doc"); + when(davHelper.splitAllPaths(destPath)).thenReturn(destPathSplit); + + + when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(sourceFileInfo); + + FileInfo destFileInfo = Mockito.mock(FileInfo.class); + when(mockFileFolderService.resolveNamePath(rootNode, destPathSplit)).thenReturn(destFileInfo); + + sourceParentNodeRef = new NodeRef("workspace://SpacesStore/parent"); + destParentNodeRef = new NodeRef("workspace://SpacesStore/parent"); + + + sourceNodeRef = new NodeRef("workspace://SpacesStore/sourcefile"); + + when(davHelper.getLockService()).thenReturn(davLockService); + + searchService = ctx.getBean("SearchService", SearchService.class); + fileFolderService = ctx.getBean("FileFolderService", FileFolderService.class); + nodeService = ctx.getBean("NodeService", NodeService.class); + transactionService = ctx.getBean("transactionService", TransactionService.class); + contentService = ctx.getBean("contentService", ContentService.class); + webDAVHelper = ctx.getBean("webDAVHelper", WebDAVHelper.class); + + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + repositoryHelper = (Repository)ctx.getBean("repositoryHelper"); + companyHomeNodeRef = repositoryHelper.getCompanyHome(); + } + + + @Test + public void canRenameFolders() throws Exception + { + moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); + + verify(mockFileFolderService).rename(sourceNodeRef, "dest.doc"); + // sourceNodeRef is not locked, so unlock should not be called after rename + verify(davLockService, never()).unlock(sourceNodeRef); + verify(mockFileFolderService, never()).create(destParentNodeRef, "dest.doc", ContentModel.TYPE_CONTENT); + } + + + @Test + public void canRenameFoldersWhenNewNameMatchesShufflePattern() throws Exception + { + when(davHelper.isRenameShuffle(destPath)).thenReturn(true); + when(davHelper.isRenameShuffle(sourcePath)).thenReturn(false); + + // Test: Perform the rename + moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); + + verify(mockFileFolderService).rename(sourceNodeRef, "dest.doc"); + // sourceNodeRef is not locked, so unlock should not be called after rename + verify(davLockService, never()).unlock(sourceNodeRef); + verify(mockFileFolderService, never()).create(destParentNodeRef, "dest.doc", ContentModel.TYPE_CONTENT); + } + + @Test + public void canMoveFileUnlock() throws Exception + { + moveMethod = new MoveMethod() + { + @Override + protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException + { + LockInfoImpl lockInfo = new LockInfoImpl(); + lockInfo.setExclusiveLockToken("opaque-lock-token"); + lockInfo.setDepth(WebDAV.INFINITY); + lockInfo.setScope(WebDAV.XML_EXCLUSIVE); + return lockInfo; + } + + @Override + protected LockInfo checkNode(FileInfo fileInfo) throws WebDAVServerException + { + return checkNode(fileInfo, false, false); + } + }; + + moveMethod.setDetails(req, resp, davHelper, rootNode); + + sourceFileInfo = Mockito.mock(FileInfo.class); + when(sourceFileInfo.isFolder()).thenReturn(true); + + destPath = "/path/to/test.doc"; + moveMethod.m_strDestinationPath = destPath; + + sourcePath = "/path/from/test.doc"; + moveMethod.m_strPath = sourcePath; + + when(davHelper.getServiceRegistry()).thenReturn(mockServiceRegistry); + when(mockServiceRegistry.getContentService()).thenReturn(mockContentService); + + List sourcePathSplit = Arrays.asList("path", "from", "test.doc"); + when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); + + List destPathSplit = Arrays.asList("path", "to", "dest.doc"); + when(davHelper.splitAllPaths(destPath)).thenReturn(destPathSplit); + + when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(sourceFileInfo); + + FileInfo destFileInfo = Mockito.mock(FileInfo.class); + when(mockFileFolderService.resolveNamePath(rootNode, destPathSplit)).thenReturn(destFileInfo); + + sourceParentNodeRef = new NodeRef("workspace://SpacesStore/parent1"); + destParentNodeRef = new NodeRef("workspace://SpacesStore/parent2"); + sourceNodeRef = new NodeRef("workspace://SpacesStore/sourcefile"); + + moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "test.doc"); + + verify(mockFileFolderService).moveFrom(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "test.doc"); + verify(davLockService).unlock(sourceNodeRef); + } + + @Test + public void testMNT_13144() throws Exception + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + FileInfo dwgFI = null; + String fileName = "source-" + GUID.generate(); + String sourceFileName = fileName + ".dwg"; + + FileInfo atmpFI = null; + String destFileName = "atmp1234"; + + FileInfo tmpFI = null; + String tmpFileName = fileName + ".tmp"; + + String bakFileName = fileName + ".bak"; + + String content = "Some dwg content."; + String tmpContent = "Change dwg content."; + + try + { + dwgFI = fileFolderService.create(companyHomeNodeRef, sourceFileName, ContentModel.TYPE_CONTENT); + ContentWriter writer = contentService.getWriter(dwgFI.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_APP_DWG); + writer.setEncoding("UTF-8"); + writer.putContent(content); + + tmpFI = fileFolderService.create(companyHomeNodeRef, tmpFileName, ContentModel.TYPE_CONTENT); + writer = contentService.getWriter(tmpFI.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_APP_DWG); + writer.setEncoding("UTF-8"); + writer.putContent(tmpContent); + + atmpFI = fileFolderService.create(companyHomeNodeRef, destFileName, ContentModel.TYPE_CONTENT); + + sourcePath = "/" + sourceFileName; + moveMethod.m_strPath = sourcePath; + + destPath = "/" + destFileName; + moveMethod.m_strDestinationPath = destPath; + + List sourcePathSplit = Arrays.asList(sourceFileName); + when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); + + when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(dwgFI); + when(davHelper.isRenameShuffle(destPath)).thenReturn(true); + when(davHelper.isRenameShuffle(sourcePath)).thenReturn(false); + + when(mockFileFolderService.create(companyHomeNodeRef, destFileName, ContentModel.TYPE_CONTENT)).thenReturn(atmpFI); + + ServiceRegistry mockServiceRegistry = Mockito.mock(ServiceRegistry.class); + when(davHelper.getServiceRegistry()).thenReturn(mockServiceRegistry); + when(davHelper.getServiceRegistry().getContentService()).thenReturn(contentService); + + // move webdav method dwg copy to atmp1234 + moveMethod.moveOrCopy(dwgFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, destFileName); + + ContentReader reader = contentService.getReader(atmpFI.getNodeRef(), ContentModel.PROP_CONTENT); + assertNotNull(reader); + assertEquals(content, reader.getContentString()); + + // move webdav method atmp1234 rename to bak + sourcePath = "/" + destFileName; + moveMethod.m_strPath = sourcePath; + + destPath = "/" + bakFileName; + moveMethod.m_strDestinationPath = destPath; + + sourcePathSplit = Arrays.asList(destFileName); + when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); + + when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(atmpFI); + when(davHelper.isRenameShuffle(destPath)).thenReturn(true); + when(davHelper.isRenameShuffle(sourcePath)).thenReturn(true); + + moveMethod.moveOrCopy(atmpFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, bakFileName); + + verify(mockFileFolderService).rename(atmpFI.getNodeRef(), bakFileName); + verify(mockFileFolderService, never()).create(destParentNodeRef, bakFileName, ContentModel.TYPE_CONTENT); + + // move webdav method tmp copy content to dwg + sourcePath = "/" + tmpFileName; + moveMethod.m_strPath = sourcePath; + + destPath = "/" + sourceFileName; + moveMethod.m_strDestinationPath = destPath; + + sourcePathSplit = Arrays.asList(tmpFileName); + when(davHelper.splitAllPaths(sourcePath)).thenReturn(sourcePathSplit); + + when(mockFileFolderService.resolveNamePath(rootNode, sourcePathSplit)).thenReturn(tmpFI); + when(davHelper.isRenameShuffle(destPath)).thenReturn(false); + when(davHelper.isRenameShuffle(sourcePath)).thenReturn(true); + + moveMethod.moveOrCopy(atmpFI.getNodeRef(), companyHomeNodeRef, companyHomeNodeRef, bakFileName); + + reader = contentService.getReader(dwgFI.getNodeRef(), ContentModel.PROP_CONTENT); + assertNotNull(reader); + assertEquals(tmpContent, reader.getContentString()); + } + finally + { + if (dwgFI != null) + { + nodeService.deleteNode(dwgFI.getNodeRef()); + } + + if (atmpFI != null) + { + nodeService.deleteNode(atmpFI.getNodeRef()); + } + } + + return null; + } + }); + } + + @Test(expected=AccessDeniedException.class) + public void testMNT_10380_ThrowAccessDeniedExceptionWhenUserLacksPermissions() throws Exception + { + when(mockFileFolderService.rename(sourceNodeRef, "dest.doc")). + thenThrow(new AccessDeniedException("Access denied in test by mockFileFolderService")); + + moveMethod.moveOrCopy(sourceNodeRef, sourceParentNodeRef, destParentNodeRef, "dest.doc"); + } + + @Test + public void testMNT_9662() + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + // create test folder with name that doesn't match getDAVHelper().isRenameShuffle() + FileInfo testFileInfo = fileFolderService.create(companyHomeNodeRef, "folder-" + GUID.generate().substring(29), ContentModel.TYPE_FOLDER); + + req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + testFileInfo.getName()); + resp = new MockHttpServletResponse(); + req.setServerPort(8080); + req.setContextPath("/alfresco"); + req.setServletPath("/webdav"); + + moveMethod = new MoveMethod(); + moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); + + // generate new name that matches getDAVHelper().isRenameShuffle() + String newName = GUID.generate().substring(28); + req.addHeader(WebDAV.HEADER_DESTINATION, "http://localhost:8080/alfresco/webdav/" + newName); + + try + { + moveMethod.execute(); + + assertTrue(nodeService.exists(testFileInfo.getNodeRef())); + assertEquals(newName, nodeService.getProperty(testFileInfo.getNodeRef(), ContentModel.PROP_NAME)); + } + catch (WebDAVServerException e) + { + fail("Fail to rename folder: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); + } + finally + { + nodeService.deleteNode(testFileInfo.getNodeRef()); + } + return null; + } + }); + } + + @Test + public void testMNT_6480() + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + // create test file with name that doesn't match getDAVHelper().isRenameShuffle() + String originalFileName = "content-" + GUID.generate() + ".txt"; + FileInfo testFileInfo = fileFolderService.create(companyHomeNodeRef, originalFileName, ContentModel.TYPE_CONTENT); + + // rename source file to file with upper case name + String newFileName = originalFileName.toUpperCase(); + + req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + testFileInfo.getName()); + req.setServerPort(8080); + req.setContextPath("/alfresco"); + req.setServletPath("/webdav"); + req.addHeader(WebDAV.HEADER_DESTINATION, "http://localhost:8080/alfresco/webdav/" + newFileName); + + resp = new MockHttpServletResponse(); + + moveMethod = new MoveMethod(); + moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); + + try + { + moveMethod.execute(); + + // MNT-6480 - File should be renamed but not deleted + assertTrue(nodeService.exists(testFileInfo.getNodeRef())); + assertEquals(newFileName, nodeService.getProperty(testFileInfo.getNodeRef(), ContentModel.PROP_NAME)); + } + catch (WebDAVServerException e) + { + fail("Fail to rename node: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); + } + finally + { + nodeService.deleteNode(testFileInfo.getNodeRef()); + } + return null; + } + }); + } + + @Test + public void testMNT_9777() + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + // create test file with name that does match getDAVHelper().isRenameShuffle() + String originalFileName = "tempfile-" + GUID.generate() + ".tmp"; + + // destination within same folder + String newFileName = "destfile-" + GUID.generate() + ".txt"; + + FileInfo sourceFileInfo = fileFolderService.create(companyHomeNodeRef, originalFileName, ContentModel.TYPE_CONTENT); + FileInfo newFileInfo = fileFolderService.create(companyHomeNodeRef, newFileName, ContentModel.TYPE_CONTENT); + + String newContent = GUID.generate(); + ContentWriter writer; + writer = contentService.getWriter(sourceFileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.putContent(newContent); + + req = new MockHttpServletRequest(WebDAV.METHOD_MOVE, "/alfresco/webdav/" + sourceFileInfo.getName()); + resp = new MockHttpServletResponse(); + req.setServerPort(8080); + req.setContextPath("/alfresco"); + req.setServletPath("/webdav"); + + moveMethod = new MoveMethod(); + moveMethod.setDetails(req, resp, webDAVHelper, companyHomeNodeRef); + + String destPath = "http://localhost:8080/alfresco/webdav/" + newFileName; + req.addHeader(WebDAV.HEADER_DESTINATION, destPath); + + try + { + moveMethod.execute(); + + // MNT-9777 - Source node should be deleted + assertTrue(!nodeService.exists(sourceFileInfo.getNodeRef())); + + // Content should be updated + ContentReader reader = contentService.getReader(newFileInfo.getNodeRef(), ContentModel.PROP_CONTENT); + assertEquals(newContent, reader.getContentString()); + } + catch (WebDAVServerException e) + { + fail("Fail to move node: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage())); + } + finally + { + nodeService.deleteNode(newFileInfo.getNodeRef()); + } + return null; + } + }); + } +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java index 60b30c58e2..3e0a58f2f2 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java @@ -1,381 +1,381 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ -package org.alfresco.repo.webdav; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import java.io.Serializable; -import java.util.Collections; - -import javax.servlet.http.HttpServletResponse; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.coci.CheckOutCheckInService; -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.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -@RunWith(MockitoJUnitRunner.class) -public class UnlockMethodTest -{ - private UnlockMethod unlockMethod; - private LockMethod lockMethod; - private MockHttpServletRequest request; - private MockHttpServletResponse response; - private @Mock WebDAVHelper davHelper; - ApplicationContext appContext; - - /** - * Services used by the tests - */ - private NodeService nodeService; - private CheckOutCheckInService cociService; - private ContentService contentService; - private MutableAuthenticationService authenticationService; - private AuthenticationComponent authenticationComponent; - private TransactionService transactionService; - private PermissionService permissionService; - - /** - * Data used by the tests - */ - private StoreRef storeRef; - private NodeRef rootNodeRef; - private String userNodeRef; - private NodeRef folderNodeRef; - private NodeRef fileNodeRef; - private NodeRef fileWorkingCopyNodeRef; - - /** - * 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"; - - /** - * User details - */ - private String userName; - private static final String PWD = "password"; - - @Before - public void setUp() throws Exception - { - request = new MockHttpServletRequest(); - response = new MockHttpServletResponse(); - unlockMethod = new UnlockMethod(); - unlockMethod.setDetails(request, response, davHelper, null); - lockMethod = new LockMethod(); - lockMethod.setDetails(request, null, davHelper, null); - } - - /** - * Set up preconditions for unlock a checked out node - */ - protected void setUpPreconditionForCheckedOutTest() throws Exception - { - appContext = ApplicationContextHelper.getApplicationContext(new String[] - { - "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", - "classpath:alfresco/remote-api-context.xml" - }); - - // Set the services - this.cociService = (CheckOutCheckInService) appContext.getBean("checkOutCheckInService"); - this.contentService = (ContentService) appContext.getBean("contentService"); - this.authenticationService = (MutableAuthenticationService) appContext.getBean("authenticationService"); - this.permissionService = (PermissionService) appContext.getBean("permissionService"); - this.transactionService = (TransactionService) appContext.getBean("TransactionService"); - this.nodeService = (NodeService) appContext.getBean("NodeService"); - // Authenticate as system to create initial test data set - this.authenticationComponent = (AuthenticationComponent) appContext.getBean("authenticationComponent"); - 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 = "webdavUnlockTest" + GUID.generate(); - TestWithUserUtils.createUser(userName, PWD, rootNodeRef, nodeService, authenticationService); - permissionService.setPermission(rootNodeRef, userName, PermissionService.ALL_PERMISSIONS, true); - TestWithUserUtils.authenticateUser(userName, PWD, rootNodeRef, authenticationService); - userNodeRef = TestWithUserUtils.getCurrentUser(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); - - // Check out test file - fileWorkingCopyNodeRef = cociService.checkout(fileNodeRef); - assertNotNull(fileWorkingCopyNodeRef); - assertEquals(userNodeRef, nodeService.getProperty(fileNodeRef, ContentModel.PROP_LOCK_OWNER)); - - return null; - } - - }; - this.transactionService.getRetryingTransactionHelper().doInTransaction(createTestFileCallback); - } - - @Test - public void parseValidLockTokenHeader() throws WebDAVServerException - { - String lockToken = "976e2f82-40ab-4852-a867-986e9ce11f82:admin"; - String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; - request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); - unlockMethod.parseRequestHeaders(); - - assertEquals(lockToken, unlockMethod.getLockToken()); - } - - @Test - public void parseInvalidLockTokenHeader() - { - String lockToken = "976e2f82-40ab-4852-a867-986e9ce11f82:admin"; - String lockHeaderValue = ""; - request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); - try - { - unlockMethod.parseRequestHeaders(); - fail("Exception should have been thrown, but wasn't."); - } - catch (WebDAVServerException e) - { - assertEquals(HttpServletResponse.SC_BAD_REQUEST, e.getHttpStatusCode()); - } - } - - @Test - public void parseMissingLockTokenHeader() - { - // Note: we're not adding the lock token header - try - { - unlockMethod.parseRequestHeaders(); - fail("Exception should have been thrown, but wasn't."); - } - catch (WebDAVServerException e) - { - assertEquals(HttpServletResponse.SC_BAD_REQUEST, e.getHttpStatusCode()); - } - } - - /** - * Test MNT-9680: Working copies are open in read-only mode when using Webdav online edit - * - * @throws Exception - */ - @Test - public void unlockWorkingCopy() throws Exception - { - setUpPreconditionForCheckedOutTest(); - try - { - String workingCopyName = nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_NAME).toString(); - String lockToken = fileWorkingCopyNodeRef.getId() + WebDAV.LOCK_TOKEN_SEPERATOR + this.userName; - String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; - final WebDAVHelper davHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); - - request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); - request.setRequestURI("/" + workingCopyName); - String content = "" - + "" - + "" - + ""; - - request.setContent(content.getBytes("UTF-8")); - - lockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); - lockMethod.parseRequestHeaders(); - lockMethod.parseRequestBody(); - - RetryingTransactionCallback lockExecuteImplCallBack = new RetryingTransactionCallback() - { - - @Override - public Void execute() throws Throwable - { - lockMethod.executeImpl(); - return null; - } - - }; - this.transactionService.getRetryingTransactionHelper().doInTransaction(lockExecuteImplCallBack); - - unlockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); - unlockMethod.parseRequestHeaders(); - - RetryingTransactionCallback unlockExecuteImplCallBack = new RetryingTransactionCallback() - { - - @Override - public Void execute() throws Throwable - { - unlockMethod.executeImpl(); - return null; - } - - }; - this.transactionService.getRetryingTransactionHelper().doInTransaction(unlockExecuteImplCallBack); - - assertNull("lockType property should be deleted on unlock", nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_LOCK_TYPE)); - assertNull("lockOwner property should be deleted on unlock", nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_LOCK_OWNER)); - - } - finally - { - // 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 that it is impossible to unlock a checked out node - * - * @throws Exception - */ - @Test - public void unlockCheckedOutNode() throws Exception - { - setUpPreconditionForCheckedOutTest(); - try - { - String lockToken = fileNodeRef.getId() + WebDAV.LOCK_TOKEN_SEPERATOR + this.userName; - String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; - request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); - request.setRequestURI("/" + TEST_FILE_NAME); - - WebDAVHelper davHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); - unlockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); - unlockMethod.parseRequestHeaders(); - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - unlockMethod.executeImpl(); - return null; - } - }); - - fail("Exception should have been thrown, but wasn't."); - } - catch (AlfrescoRuntimeException e) - { - if (e.getCause() instanceof WebDAVServerException) - { - WebDAVServerException ee = (WebDAVServerException) e.getCause(); - assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, ee.getHttpStatusCode()); - } - else - { - fail("Incorrect exception thrown."); - } - } - catch (WebDAVServerException e) - { - assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, e.getHttpStatusCode()); - } - finally - { - // 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); - } - } - -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ +package org.alfresco.repo.webdav; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.io.Serializable; +import java.util.Collections; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +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.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +@RunWith(MockitoJUnitRunner.class) +public class UnlockMethodTest +{ + private UnlockMethod unlockMethod; + private LockMethod lockMethod; + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private @Mock WebDAVHelper davHelper; + ApplicationContext appContext; + + /** + * Services used by the tests + */ + private NodeService nodeService; + private CheckOutCheckInService cociService; + private ContentService contentService; + private MutableAuthenticationService authenticationService; + private AuthenticationComponent authenticationComponent; + private TransactionService transactionService; + private PermissionService permissionService; + + /** + * Data used by the tests + */ + private StoreRef storeRef; + private NodeRef rootNodeRef; + private String userNodeRef; + private NodeRef folderNodeRef; + private NodeRef fileNodeRef; + private NodeRef fileWorkingCopyNodeRef; + + /** + * 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"; + + /** + * User details + */ + private String userName; + private static final String PWD = "password"; + + @Before + public void setUp() throws Exception + { + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + unlockMethod = new UnlockMethod(); + unlockMethod.setDetails(request, response, davHelper, null); + lockMethod = new LockMethod(); + lockMethod.setDetails(request, null, davHelper, null); + } + + /** + * Set up preconditions for unlock a checked out node + */ + protected void setUpPreconditionForCheckedOutTest() throws Exception + { + appContext = ApplicationContextHelper.getApplicationContext(new String[] + { + "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/remote-api-context.xml" + }); + + // Set the services + this.cociService = (CheckOutCheckInService) appContext.getBean("checkOutCheckInService"); + this.contentService = (ContentService) appContext.getBean("contentService"); + this.authenticationService = (MutableAuthenticationService) appContext.getBean("authenticationService"); + this.permissionService = (PermissionService) appContext.getBean("permissionService"); + this.transactionService = (TransactionService) appContext.getBean("TransactionService"); + this.nodeService = (NodeService) appContext.getBean("NodeService"); + // Authenticate as system to create initial test data set + this.authenticationComponent = (AuthenticationComponent) appContext.getBean("authenticationComponent"); + 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 = "webdavUnlockTest" + GUID.generate(); + TestWithUserUtils.createUser(userName, PWD, rootNodeRef, nodeService, authenticationService); + permissionService.setPermission(rootNodeRef, userName, PermissionService.ALL_PERMISSIONS, true); + TestWithUserUtils.authenticateUser(userName, PWD, rootNodeRef, authenticationService); + userNodeRef = TestWithUserUtils.getCurrentUser(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); + + // Check out test file + fileWorkingCopyNodeRef = cociService.checkout(fileNodeRef); + assertNotNull(fileWorkingCopyNodeRef); + assertEquals(userNodeRef, nodeService.getProperty(fileNodeRef, ContentModel.PROP_LOCK_OWNER)); + + return null; + } + + }; + this.transactionService.getRetryingTransactionHelper().doInTransaction(createTestFileCallback); + } + + @Test + public void parseValidLockTokenHeader() throws WebDAVServerException + { + String lockToken = "976e2f82-40ab-4852-a867-986e9ce11f82:admin"; + String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; + request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); + unlockMethod.parseRequestHeaders(); + + assertEquals(lockToken, unlockMethod.getLockToken()); + } + + @Test + public void parseInvalidLockTokenHeader() + { + String lockToken = "976e2f82-40ab-4852-a867-986e9ce11f82:admin"; + String lockHeaderValue = ""; + request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); + try + { + unlockMethod.parseRequestHeaders(); + fail("Exception should have been thrown, but wasn't."); + } + catch (WebDAVServerException e) + { + assertEquals(HttpServletResponse.SC_BAD_REQUEST, e.getHttpStatusCode()); + } + } + + @Test + public void parseMissingLockTokenHeader() + { + // Note: we're not adding the lock token header + try + { + unlockMethod.parseRequestHeaders(); + fail("Exception should have been thrown, but wasn't."); + } + catch (WebDAVServerException e) + { + assertEquals(HttpServletResponse.SC_BAD_REQUEST, e.getHttpStatusCode()); + } + } + + /** + * Test MNT-9680: Working copies are open in read-only mode when using Webdav online edit + * + * @throws Exception + */ + @Test + public void unlockWorkingCopy() throws Exception + { + setUpPreconditionForCheckedOutTest(); + try + { + String workingCopyName = nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_NAME).toString(); + String lockToken = fileWorkingCopyNodeRef.getId() + WebDAV.LOCK_TOKEN_SEPERATOR + this.userName; + String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; + final WebDAVHelper davHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); + + request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); + request.setRequestURI("/" + workingCopyName); + String content = "" + + "" + + "" + + ""; + + request.setContent(content.getBytes("UTF-8")); + + lockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); + lockMethod.parseRequestHeaders(); + lockMethod.parseRequestBody(); + + RetryingTransactionCallback lockExecuteImplCallBack = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + lockMethod.executeImpl(); + return null; + } + + }; + this.transactionService.getRetryingTransactionHelper().doInTransaction(lockExecuteImplCallBack); + + unlockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); + unlockMethod.parseRequestHeaders(); + + RetryingTransactionCallback unlockExecuteImplCallBack = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + unlockMethod.executeImpl(); + return null; + } + + }; + this.transactionService.getRetryingTransactionHelper().doInTransaction(unlockExecuteImplCallBack); + + assertNull("lockType property should be deleted on unlock", nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_LOCK_TYPE)); + assertNull("lockOwner property should be deleted on unlock", nodeService.getProperty(fileWorkingCopyNodeRef, ContentModel.PROP_LOCK_OWNER)); + + } + finally + { + // 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 that it is impossible to unlock a checked out node + * + * @throws Exception + */ + @Test + public void unlockCheckedOutNode() throws Exception + { + setUpPreconditionForCheckedOutTest(); + try + { + String lockToken = fileNodeRef.getId() + WebDAV.LOCK_TOKEN_SEPERATOR + this.userName; + String lockHeaderValue = "<" + WebDAV.OPAQUE_LOCK_TOKEN + lockToken + ">"; + request.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockHeaderValue); + request.setRequestURI("/" + TEST_FILE_NAME); + + WebDAVHelper davHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); + unlockMethod.setDetails(request, new MockHttpServletResponse(), davHelper, folderNodeRef); + unlockMethod.parseRequestHeaders(); + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + unlockMethod.executeImpl(); + return null; + } + }); + + fail("Exception should have been thrown, but wasn't."); + } + catch (AlfrescoRuntimeException e) + { + if (e.getCause() instanceof WebDAVServerException) + { + WebDAVServerException ee = (WebDAVServerException) e.getCause(); + assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, ee.getHttpStatusCode()); + } + else + { + fail("Incorrect exception thrown."); + } + } + catch (WebDAVServerException e) + { + assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, e.getHttpStatusCode()); + } + finally + { + // 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); + } + } + +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVHelperTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVHelperTest.java index c61514ac9f..25a2ae351d 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVHelperTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVHelperTest.java @@ -23,100 +23,100 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.repo.webdav; - -import static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.mock.web.MockHttpServletRequest; - -/** - * Tests for the WebDAVHelper class. - * - * @see RenameShuffleDetectionTest - * @author Matt Ward - */ -@RunWith(MockitoJUnitRunner.class) -public class WebDAVHelperTest -{ - private WebDAVHelper davHelper; - - @Before - public void setUp() throws Exception - { - davHelper = new WebDAVHelper(); - } - - @Test - public void canGetUrlPathPrefixWhenExplicitlySet() - { - // Path prefix explicitly set on helper. - davHelper.setUrlPathPrefix("/my/prefix"); - MockHttpServletRequest request = new MockHttpServletRequest("GET", "/my/prefix/folder/filename.txt"); - String prefix = davHelper.getUrlPathPrefix(request); - assertEquals("/my/prefix/", prefix); - } - - @Test - public void canGetUrlPathPrefixFromServletPath() - { - // Path prefix not explicitly set on helper. - davHelper.setUrlPathPrefix(""); - MockHttpServletRequest request = new MockHttpServletRequest("GET", "/before/the-servlet/folder/filename.txt"); - // Servlet path will be used to determine path prefix. - request.setServletPath("/the-servlet"); - String prefix = davHelper.getUrlPathPrefix(request); - assertEquals("/before/the-servlet/", prefix); - } - - @Test - public void canGetDestinationPathWhenNoServletName() - { - assertPathForURL("/the-tenant.com/the-site/path/to/file", - "http://webdav.alfresco.com/the-tenant.com/the-site/path/to/file"); - - } - - /** - * THOR-1459: WebDAV: site names cannot start with 'webdav'. - *

- * /webdav-test begins with servlet path /webdav - */ - @Test - public void canGetDestinationPathWhenPathElementStartsWithServletPath() - { - assertPathForURL("/t/webdav-test/path/to/file", - "http://webdav.alfresco.com/t/webdav-test/path/to/file"); - - // Looks like /contextPath/servletName in URL's path prefix, but isn't - assertPathForURL("/alfresco/webdav-test/path/to/file", - "http://webdav.alfresco.com/alfresco/webdav-test/path/to/file"); - } - - @Test - public void canGetDestinationPathWhenPrefixedWithContextPathAndServletName() - { - assertPathForURL("/path/to/file", - "http://webdav.alfresco.com/alfresco/webdav/path/to/file"); - - assertPathForURL("/alfresco/webdav/path/to/file", - "http://webdav.alfresco.com/alfresco/webdav/alfresco/webdav/path/to/file"); - - assertPathForURL("/my/folder/alfresco/webdav/path/to/file", - "http://webdav.alfresco.com/alfresco/webdav/my/folder/alfresco/webdav/path/to/file"); - } - - /** - * Check that the expected path was extracted from a given URL. - * - * @param path The expected path. - * @param url URL to extract the path from. - */ - private void assertPathForURL(String path, String url) - { - assertEquals(path, davHelper.getDestinationPath("/alfresco", "/webdav", url)); - } -} +package org.alfresco.repo.webdav; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * Tests for the WebDAVHelper class. + * + * @see RenameShuffleDetectionTest + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class WebDAVHelperTest +{ + private WebDAVHelper davHelper; + + @Before + public void setUp() throws Exception + { + davHelper = new WebDAVHelper(); + } + + @Test + public void canGetUrlPathPrefixWhenExplicitlySet() + { + // Path prefix explicitly set on helper. + davHelper.setUrlPathPrefix("/my/prefix"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/my/prefix/folder/filename.txt"); + String prefix = davHelper.getUrlPathPrefix(request); + assertEquals("/my/prefix/", prefix); + } + + @Test + public void canGetUrlPathPrefixFromServletPath() + { + // Path prefix not explicitly set on helper. + davHelper.setUrlPathPrefix(""); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/before/the-servlet/folder/filename.txt"); + // Servlet path will be used to determine path prefix. + request.setServletPath("/the-servlet"); + String prefix = davHelper.getUrlPathPrefix(request); + assertEquals("/before/the-servlet/", prefix); + } + + @Test + public void canGetDestinationPathWhenNoServletName() + { + assertPathForURL("/the-tenant.com/the-site/path/to/file", + "http://webdav.alfresco.com/the-tenant.com/the-site/path/to/file"); + + } + + /** + * THOR-1459: WebDAV: site names cannot start with 'webdav'. + *

+ * /webdav-test begins with servlet path /webdav + */ + @Test + public void canGetDestinationPathWhenPathElementStartsWithServletPath() + { + assertPathForURL("/t/webdav-test/path/to/file", + "http://webdav.alfresco.com/t/webdav-test/path/to/file"); + + // Looks like /contextPath/servletName in URL's path prefix, but isn't + assertPathForURL("/alfresco/webdav-test/path/to/file", + "http://webdav.alfresco.com/alfresco/webdav-test/path/to/file"); + } + + @Test + public void canGetDestinationPathWhenPrefixedWithContextPathAndServletName() + { + assertPathForURL("/path/to/file", + "http://webdav.alfresco.com/alfresco/webdav/path/to/file"); + + assertPathForURL("/alfresco/webdav/path/to/file", + "http://webdav.alfresco.com/alfresco/webdav/alfresco/webdav/path/to/file"); + + assertPathForURL("/my/folder/alfresco/webdav/path/to/file", + "http://webdav.alfresco.com/alfresco/webdav/my/folder/alfresco/webdav/path/to/file"); + } + + /** + * Check that the expected path was extracted from a given URL. + * + * @param path The expected path. + * @param url URL to extract the path from. + */ + private void assertPathForURL(String path, String url) + { + assertEquals(path, davHelper.getDestinationPath("/alfresco", "/webdav", url)); + } +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVLockServiceImplTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVLockServiceImplTest.java index c6cc5cd723..f0ea5137b0 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVLockServiceImplTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVLockServiceImplTest.java @@ -23,234 +23,234 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.repo.webdav; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import javax.servlet.http.HttpSession; - -import org.alfresco.repo.lock.mem.Lifetime; -import org.alfresco.repo.lock.mem.LockState; -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.lock.LockType; -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 HttpSession session; - private @Mock List> 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 LockState lockState1; - private LockInfoImpl lockInfo2; - private LockState lockState2; - - @SuppressWarnings("unchecked") - @Before - public void setUp() throws Exception - { - davLockService = new WebDAVLockServiceImpl(); - 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(); - lockState1 = LockState.createLock(nodeRef1, LockType.WRITE_LOCK, "user1", null, Lifetime.EPHEMERAL, null); - Mockito.when(lockService.getLockState(nodeRef1)).thenReturn(lockState1); - nodeRef2 = new NodeRef("workspace://SpacesStore/a6a4371c-99b9-4618-8cd2-e71d7d96aa87"); - lockInfo2 = new LockInfoImplTest.LockInfoImplEx(); - lockInfo2.setExclusiveLockToken("a-random-token"); - lockInfo2.setDepth("infinity"); - lockInfo2.setScope(WebDAV.XML_EXCLUSIVE); - lockState2 = LockState.createLock(nodeRef2, LockType.WRITE_LOCK, "user2", new Date(999L), Lifetime.EPHEMERAL, lockInfo2.toJSON()); - Mockito.when(lockService.getLockState(nodeRef2)).thenReturn(lockState2); - - // 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 callback = (RetryingTransactionCallback) args[0]; - callback.execute(); - return null; - } - - }); - Mockito.when(transactionService.getRetryingTransactionHelper()).thenReturn(txHelper); - davLockService.setTransactionService(transactionService); - } - - - @Test - public void testSessionDestroyed() - { - List> lockedNodes = new ArrayList>(2); - lockedNodes.add(new Pair("some_user_name", nodeRef1)); - lockedNodes.add(new Pair("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); - - // nodeRef2 is not unlocked - Mockito.verify(lockService, Mockito.never()).unlock(nodeRef2); - } - - @Test - public void lockLessThan24Hours() - { - lockInfo1.setTimeoutSeconds(100); - - davLockService.lock(nodeRef1, lockInfo1); - - Mockito.verify(lockService).lock(nodeRef1, LockType.WRITE_LOCK, 100, Lifetime.EPHEMERAL, lockInfo1.toJSON()); - // 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(lockService).lock(nodeRef1, LockType.WRITE_LOCK, WebDAV.TIMEOUT_24_HOURS, Lifetime.EPHEMERAL, lockInfo1.toJSON()); - Mockito.verify(sessionList).add(new Pair("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(lockService).lock(nodeRef1, LockType.WRITE_LOCK, WebDAV.TIMEOUT_24_HOURS, Lifetime.EPHEMERAL, lockInfo1.toJSON()); - Mockito.verify(sessionList).add(new Pair("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 unlocked. - Mockito.verify(lockService).unlock(nodeRef1); - // Node should have been removed from the list in the user's session. - Mockito.verify(sessionList).remove(new Pair("some_user_name", nodeRef1)); - } - - @Test - public void canGetLockInfo() - { - NodeRef nodeRef3 = new NodeRef("workspace://SpacesStore/a6a4371c-99b9-4618-8cd2-e71d28374859"); - Mockito.when(lockService.getLockState(nodeRef1)).thenReturn(lockState1); - Mockito.when(lockService.getLockState(nodeRef2)).thenReturn(lockState2); - Mockito.when(lockService.getLockState(nodeRef3)).thenReturn(null); - - // nodeRef1 - LockInfo lockInfo = davLockService.getLockInfo(nodeRef1); - assertEquals(null, lockInfo.getExpires()); - assertEquals("user1", lockInfo.getOwner()); - - // nodeRef2 - lockInfo = davLockService.getLockInfo(nodeRef2); - assertEquals(new Date(999L), lockInfo.getExpires()); - assertEquals("user2", lockInfo.getOwner()); - assertEquals("a-random-token", lockInfo.getExclusiveLockToken()); - assertEquals("infinity", lockInfo.getDepth()); - assertEquals(WebDAV.XML_EXCLUSIVE, lockInfo.getScope()); - - // nodeRef3 - lockInfo = davLockService.getLockInfo(nodeRef3); - assertEquals(null, lockInfo); - } - - @Test - public void mnt13183LockInfo() - { - // CIFS lock node to 1 hour - lockService.lock(nodeRef1, LockType.WRITE_LOCK, 3600, Lifetime.EPHEMERAL, "lock_info_that_is_not_from_webdav"); - - // WebDAV get lock info - LockInfo lockInfoNodeRef1 = davLockService.getLockInfo(nodeRef1); - assertNull("exclusiveLockToken is null", lockInfoNodeRef1.getExclusiveLockToken()); - - String user = AuthenticationUtil.getFullyAuthenticatedUser(); - - // WebDav lock, check marker - davLockService.lock(nodeRef2, user, 3600); - - LockState lockState2 = lockService.getLockState(nodeRef2); - assertNotNull("lockState is not null", lockState2); - - String additionalInfo2 = lockState2.getAdditionalInfo(); - assertNotNull("additionalInfo is not null", additionalInfo2); - assertTrue("Check WEBDAV_LOCK marker", additionalInfo2.startsWith(LockInfoImpl.ADDINFO_WEBDAV_MARKER)); - } -} +package org.alfresco.repo.webdav; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpSession; + +import org.alfresco.repo.lock.mem.Lifetime; +import org.alfresco.repo.lock.mem.LockState; +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.lock.LockType; +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.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +@RunWith(MockitoJUnitRunner.class) +public class WebDAVLockServiceImplTest +{ + private WebDAVLockServiceImpl davLockService; + private @Mock HttpSession session; + private @Mock List> 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 LockState lockState1; + private LockInfoImpl lockInfo2; + private LockState lockState2; + + @SuppressWarnings("unchecked") + @Before + public void setUp() throws Exception + { + davLockService = new WebDAVLockServiceImpl(); + 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(); + lockState1 = LockState.createLock(nodeRef1, LockType.WRITE_LOCK, "user1", null, Lifetime.EPHEMERAL, null); + Mockito.when(lockService.getLockState(nodeRef1)).thenReturn(lockState1); + nodeRef2 = new NodeRef("workspace://SpacesStore/a6a4371c-99b9-4618-8cd2-e71d7d96aa87"); + lockInfo2 = new LockInfoImplTest.LockInfoImplEx(); + lockInfo2.setExclusiveLockToken("a-random-token"); + lockInfo2.setDepth("infinity"); + lockInfo2.setScope(WebDAV.XML_EXCLUSIVE); + lockState2 = LockState.createLock(nodeRef2, LockType.WRITE_LOCK, "user2", new Date(999L), Lifetime.EPHEMERAL, lockInfo2.toJSON()); + Mockito.when(lockService.getLockState(nodeRef2)).thenReturn(lockState2); + + // 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 callback = (RetryingTransactionCallback) args[0]; + callback.execute(); + return null; + } + + }); + Mockito.when(transactionService.getRetryingTransactionHelper()).thenReturn(txHelper); + davLockService.setTransactionService(transactionService); + } + + + @Test + public void testSessionDestroyed() + { + List> lockedNodes = new ArrayList>(2); + lockedNodes.add(new Pair("some_user_name", nodeRef1)); + lockedNodes.add(new Pair("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); + + // nodeRef2 is not unlocked + Mockito.verify(lockService, Mockito.never()).unlock(nodeRef2); + } + + @Test + public void lockLessThan24Hours() + { + lockInfo1.setTimeoutSeconds(100); + + davLockService.lock(nodeRef1, lockInfo1); + + Mockito.verify(lockService).lock(nodeRef1, LockType.WRITE_LOCK, 100, Lifetime.EPHEMERAL, lockInfo1.toJSON()); + // 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(lockService).lock(nodeRef1, LockType.WRITE_LOCK, WebDAV.TIMEOUT_24_HOURS, Lifetime.EPHEMERAL, lockInfo1.toJSON()); + Mockito.verify(sessionList).add(new Pair("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(lockService).lock(nodeRef1, LockType.WRITE_LOCK, WebDAV.TIMEOUT_24_HOURS, Lifetime.EPHEMERAL, lockInfo1.toJSON()); + Mockito.verify(sessionList).add(new Pair("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 unlocked. + Mockito.verify(lockService).unlock(nodeRef1); + // Node should have been removed from the list in the user's session. + Mockito.verify(sessionList).remove(new Pair("some_user_name", nodeRef1)); + } + + @Test + public void canGetLockInfo() + { + NodeRef nodeRef3 = new NodeRef("workspace://SpacesStore/a6a4371c-99b9-4618-8cd2-e71d28374859"); + Mockito.when(lockService.getLockState(nodeRef1)).thenReturn(lockState1); + Mockito.when(lockService.getLockState(nodeRef2)).thenReturn(lockState2); + Mockito.when(lockService.getLockState(nodeRef3)).thenReturn(null); + + // nodeRef1 + LockInfo lockInfo = davLockService.getLockInfo(nodeRef1); + assertEquals(null, lockInfo.getExpires()); + assertEquals("user1", lockInfo.getOwner()); + + // nodeRef2 + lockInfo = davLockService.getLockInfo(nodeRef2); + assertEquals(new Date(999L), lockInfo.getExpires()); + assertEquals("user2", lockInfo.getOwner()); + assertEquals("a-random-token", lockInfo.getExclusiveLockToken()); + assertEquals("infinity", lockInfo.getDepth()); + assertEquals(WebDAV.XML_EXCLUSIVE, lockInfo.getScope()); + + // nodeRef3 + lockInfo = davLockService.getLockInfo(nodeRef3); + assertEquals(null, lockInfo); + } + + @Test + public void mnt13183LockInfo() + { + // CIFS lock node to 1 hour + lockService.lock(nodeRef1, LockType.WRITE_LOCK, 3600, Lifetime.EPHEMERAL, "lock_info_that_is_not_from_webdav"); + + // WebDAV get lock info + LockInfo lockInfoNodeRef1 = davLockService.getLockInfo(nodeRef1); + assertNull("exclusiveLockToken is null", lockInfoNodeRef1.getExclusiveLockToken()); + + String user = AuthenticationUtil.getFullyAuthenticatedUser(); + + // WebDav lock, check marker + davLockService.lock(nodeRef2, user, 3600); + + LockState lockState2 = lockService.getLockState(nodeRef2); + assertNotNull("lockState is not null", lockState2); + + String additionalInfo2 = lockState2.getAdditionalInfo(); + assertNotNull("additionalInfo is not null", additionalInfo2); + assertTrue("Check WEBDAV_LOCK marker", additionalInfo2.startsWith(LockInfoImpl.ADDINFO_WEBDAV_MARKER)); + } +} diff --git a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVMethodTest.java b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVMethodTest.java index e637de3f5a..cbb6a625a9 100644 --- a/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVMethodTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/webdav/WebDAVMethodTest.java @@ -1,528 +1,528 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ -package org.alfresco.repo.webdav; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.io.Serializable; -import java.util.Collections; -import java.util.List; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.tenant.TenantAdminService; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.repo.tenant.TenantUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -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.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; -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.testing.category.IntermittentlyFailingTests; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -import com.ibm.icu.impl.Assert; - -/** - * Tests for the WebDAVMethod class. - * - * @author Matt Ward - */ -@RunWith(MockitoJUnitRunner.class) -public class WebDAVMethodTest -{ - private WebDAVMethod method; - private MockHttpServletRequest req; - private MockHttpServletResponse resp; - private @Mock WebDAVHelper davHelper; - - private NodeService nodeService; - private SearchService searchService; - private NamespaceService namespaceService; - private TenantService tenantService; - private TransactionService transactionService; - private WebDAVHelper webDAVHelper; - private TenantAdminService tenantAdminService; - - private @Mock LockMethod lockMethod; - private @Mock PutMethod putMethod; - private @Mock DeleteMethod deleteMethod; - private @Mock UnlockMethod unlockMethod; - - private static Log logger = LogFactory.getLog(WebDAVMethodTest.class); - - public static final String TEST_RUN = System.currentTimeMillis()+""; - public static final String TEST_TENANT_DOMAIN = TEST_RUN+".my.test"; - public static final String DEFAULT_ADMIN_PW = "admin"; - - private Level saveLogLevel; - - protected void setUpApplicationContext() - { - ApplicationContext appContext = ApplicationContextHelper.getApplicationContext(new String[] - { - "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", - "classpath:alfresco/remote-api-context.xml" - }); - - this.nodeService = (NodeService) appContext.getBean("NodeService"); - this.searchService = (SearchService) appContext.getBean("SearchService"); - this.namespaceService = (NamespaceService) appContext.getBean("NamespaceService"); - this.tenantService = (TenantService) appContext.getBean("tenantService"); - this.transactionService = (TransactionService) appContext.getBean("transactionService"); - this.webDAVHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); - this.tenantAdminService = (TenantAdminService) appContext.getBean("tenantAdminService"); - - // Authenticate as system to create initial test data set - AuthenticationComponent authenticationComponent = (AuthenticationComponent) appContext.getBean("authenticationComponent"); - authenticationComponent.setSystemUserAsCurrentUser(); - } - - private void checkLockedNodeTestWork() throws WebDAVServerException - { - req = new MockHttpServletRequest(); - resp = new MockHttpServletResponse(); - - String rootPath = "/app:company_home"; - String storeName = "workspace://SpacesStore"; - StoreRef storeRef = new StoreRef(storeName); - NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); - List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); - NodeRef defaultRootNode = nodeRefs.get(0); - - lockMethod = new LockMethod(); - NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); - String strPath = "/" + "testLockedNode" + GUID.generate(); - - lockMethod.createExclusive = true; - lockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - lockMethod.m_strPath = strPath; - - // Lock the node (will create a new one). - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable { - lockMethod.executeImpl(); - return null; - } - }); - - // Prepare for PUT - req.addHeader(WebDAV.HEADER_IF, "(<" + lockMethod.lockToken + ">)"); - putMethod = new PutMethod(); - putMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - putMethod.parseRequestHeaders(); - putMethod.m_strPath = strPath; - String content = "test content stream"; - req.setContent(content.getBytes()); - - // Issue a put request - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - putMethod.executeImpl(); - return null; - } - }); - } - - /** - * Call the org.alfresco.repo.webdav.WebDAVMethod#checkNode(org.alfresco.service.cmr.model.FileInfo, boolean, boolean) - * for a write locked node for tenant and non-tenant. - * See ALF-19915. - */ - @Test - public void checkLockedNodeTest() throws Exception - { - setUpApplicationContext(); - - // Create a tenant domain - TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { - public Object doWork() throws Exception { - if (!tenantAdminService.existsTenant(TEST_TENANT_DOMAIN)) - { - tenantAdminService.createTenant(TEST_TENANT_DOMAIN, (DEFAULT_ADMIN_PW + " " + TEST_TENANT_DOMAIN).toCharArray(), null); - } - return null; - } - }, TenantService.DEFAULT_DOMAIN); - - // run as admin - try - { - TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() - { - @Override - public Object doWork() throws Exception - { - checkLockedNodeTestWork(); - return null; - } - }, AuthenticationUtil.getAdminUserName(), TenantService.DEFAULT_DOMAIN); - } - catch (Exception e) - { - fail("Failed to lock and put content as admin with error: " + e.getCause()); - } - - // run as tenant admin - try - { - TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() - { - @Override - public Object doWork() throws Exception - { - checkLockedNodeTestWork(); - return null; - } - }, AuthenticationUtil.getAdminUserName(), TEST_TENANT_DOMAIN); - } - catch (Exception e) - { - fail("Failed to lock and put content as tenant admin with error: " + e.getCause()); - } - } - - private void checkLockedNodeTestTenantWork() throws Exception - { - req = new MockHttpServletRequest(); - resp = new MockHttpServletResponse(); - - String rootPath = "/app:company_home"; - String storeName = "workspace://SpacesStore"; - StoreRef storeRef = new StoreRef(storeName); - NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); - List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); - NodeRef defaultRootNode = nodeRefs.get(0); - - lockMethod = new LockMethod(); - NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); - String strPath = "/" + "testLockedNode" + GUID.generate(); - - lockMethod.createExclusive = true; - lockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - lockMethod.m_strPath = strPath; - - // Lock the node (will create a new one). - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable { - lockMethod.executeImpl(); - return null; - } - }); - - // Prepare for DELETE - String corruptedLockToken = lockMethod.lockToken + "corr"; - req.addHeader(WebDAV.HEADER_IF, "(<" + corruptedLockToken + ">)"); - deleteMethod = new DeleteMethod(); - deleteMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - deleteMethod.parseRequestHeaders(); - deleteMethod.m_strPath = strPath; - - // can't be deleted with corrupted lockTocken - try - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - deleteMethod.executeImpl(); - return null; - } - }); - fail("Locked node shouldn't be deleted"); - } - catch(Exception e) - { - if (!(e.getCause() instanceof WebDAVServerException)) - { - throw e; - } - } - - req = new MockHttpServletRequest(); - req.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockMethod.lockToken); - - unlockMethod = new UnlockMethod(); - unlockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - unlockMethod.parseRequestHeaders(); - unlockMethod.m_strPath = strPath; - // unlock the node - try - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - unlockMethod.executeImpl(); - return null; - } - }); - } - catch(Exception e) - { - fail("Locked node should be unlocked with correct lockTocken " + e.getCause()); - } - - // Lock it again - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable { - lockMethod.executeImpl(); - return null; - } - }); - - req.addHeader(WebDAV.HEADER_IF, "(<" + lockMethod.lockToken + ">)"); - deleteMethod = new DeleteMethod(); - deleteMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); - deleteMethod.parseRequestHeaders(); - deleteMethod.m_strPath = strPath; - - // can be deleted with correct lockTocken - try - { - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - deleteMethod.executeImpl(); - return null; - } - }); - } - catch(Exception e) - { - fail("Locked node should be deleted with correct lockTocken " + e.getCause()); - } - - } - - /* CLOUD-2204 Test */ - @Test - public void checkLockedNodeTenantTest() - { - setUpApplicationContext(); - - // Create a tenant domain - TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { - public Object doWork() throws Exception { - if (!tenantAdminService.existsTenant(TEST_TENANT_DOMAIN)) - { - tenantAdminService.createTenant(TEST_TENANT_DOMAIN, (DEFAULT_ADMIN_PW + " " + TEST_TENANT_DOMAIN).toCharArray(), null); - } - return null; - } - }, TenantService.DEFAULT_DOMAIN); - - TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() - { - @Override - public Object doWork() throws Exception - { - checkLockedNodeTestTenantWork(); - return null; - } - }, AuthenticationUtil.getAdminUserName(), TEST_TENANT_DOMAIN); - } - - @Test - public void canGetStatusForAccessDeniedException() - { - // Initially Mac OS X Finder uses a different UA string than for subsequent requests. - assertStatusCode(500, "WebDAVLib/1.3"); - - // Current UA string at time of writing test. - assertStatusCode(500, "WebDAVFS/1.9.0 (01908000) Darwin/11.4.0 (x86_64)"); - - // A fictitious version number long in the future. - assertStatusCode(500, "WebDAVFS/100.10.5 (01908000) Darwin/11.4.0 (x86_64)"); - - // Other processor architectures, e.g. x86_32 should work too. - assertStatusCode(500, "WebDAVFS/100.10.5 (01908000) Darwin/109.6.3 (some_other_processor_arch)"); - - // Other clients should give 403. - assertStatusCode(403, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6; en-us)"); - // Mozilla-based Windows browser. - assertStatusCode(403, "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12)"); - assertStatusCode(403, "SomeBrowser/1.0 (Macintosh; U; Intel Mac OS X 10_6; en-us)"); - assertStatusCode(403, "SomeBrowser/1.9.0 (01908000) Darwin/11.4.0 (x86_64)"); - assertStatusCode(403, "Cyberduck/4.2.1 (Mac OS X/10.7.4) (i386)"); - // Chrome - assertStatusCode(403, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5"); - // Safari - assertStatusCode(403, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"); - } - - /* MNT-10555 Test */ - @Category(IntermittentlyFailingTests.class) // ACS-959 - @Test - public void expiryLockTest() - { - // ACE-4347 extra debug logging just for this test so we can see what's going on when it next fails - Level repoWebdavSaveLogLevel = Logger.getLogger("org.alfresco.repo.webdav").getLevel(); - Logger.getLogger("org.alfresco.repo.webdav").setLevel(Level.ALL); - Level webdavProtocolSaveLogLevel = Logger.getLogger("org.alfresco.webdav.protocol").getLevel(); - Logger.getLogger("org.alfresco.webdav.protocol").setLevel(Level.ALL); - try - { - setUpApplicationContext(); - - req = new MockHttpServletRequest(); - resp = new MockHttpServletResponse(); - - String rootPath = "/app:company_home"; - StoreRef storeRef = new StoreRef("workspace://SpacesStore"); - NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); - List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); - NodeRef defaultRootNode = nodeRefs.get(0); - - NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); - - // Create test folder. - NodeRef folderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_FOLDER, - Collections. singletonMap(ContentModel.PROP_NAME, "WebDavMethodExpiryLockTest" + System.currentTimeMillis())).getChildRef(); - - // Create test document. - NodeRef nodeRef = nodeService.createNode(folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_CONTENT, - Collections. singletonMap(ContentModel.PROP_NAME, "text.txt")).getChildRef(); - - lockMethod = new LockMethod(); - lockMethod.createExclusive = true; - lockMethod.m_timeoutDuration = 1; - lockMethod.setDetails(req, resp, webDAVHelper, nodeRef); - - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Object execute() throws Throwable - { - try - { - // LOCK document. - lockMethod.executeImpl(); - - //wait for the lock to expire up to 5 seconds - int timeout = 5; - while( timeout > 0 && !lockMethod.lockInfo.isExpired()) - { - Thread.sleep(1000); - timeout--; - } - - // LOCK against an expired lock. - lockMethod.executeImpl(); - } - catch (WebDAVServerException e) - { - logger.debug(e); - Assert.fail("Document was not locked again, when lock has expired."); - } - return null; - } - }); - - // Remove test folder. - nodeService.deleteNode(folderNodeRef); - } - finally - { - Logger.getLogger("org.alfresco.webdav.protocol").setLevel(webdavProtocolSaveLogLevel); - Logger.getLogger("org.alfresco.repo.webdav").setLevel(repoWebdavSaveLogLevel); - } - } - - private void assertStatusCode(int expectedStatusCode, String userAgent) - { - // Fresh objects needed for each status code test. - createRequestObjects(); - req.addHeader("User-Agent", userAgent); - method.setDetails(req, resp, davHelper, null); - - int statusCode = method.getStatusForAccessDeniedException(); - - assertEquals("Incorrect status code for user-agent string \"" + userAgent + "\"", - expectedStatusCode, - statusCode); - } - - private void createRequestObjects() - { - method = new TestWebDAVMethod(); - req = new MockHttpServletRequest(); - resp = new MockHttpServletResponse(); - } - - - /** - * Empty subclass of abstract base class for testing base class' behaviour. - */ - private static class TestWebDAVMethod extends WebDAVMethod - { - @Override - protected void executeImpl() throws WebDAVServerException, Exception - { - } - - @Override - protected void parseRequestBody() throws WebDAVServerException - { - } - - @Override - protected void parseRequestHeaders() throws WebDAVServerException - { - } - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ +package org.alfresco.repo.webdav; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantAdminService; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +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.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +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.testing.category.IntermittentlyFailingTests; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import com.ibm.icu.impl.Assert; + +/** + * Tests for the WebDAVMethod class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class WebDAVMethodTest +{ + private WebDAVMethod method; + private MockHttpServletRequest req; + private MockHttpServletResponse resp; + private @Mock WebDAVHelper davHelper; + + private NodeService nodeService; + private SearchService searchService; + private NamespaceService namespaceService; + private TenantService tenantService; + private TransactionService transactionService; + private WebDAVHelper webDAVHelper; + private TenantAdminService tenantAdminService; + + private @Mock LockMethod lockMethod; + private @Mock PutMethod putMethod; + private @Mock DeleteMethod deleteMethod; + private @Mock UnlockMethod unlockMethod; + + private static Log logger = LogFactory.getLog(WebDAVMethodTest.class); + + public static final String TEST_RUN = System.currentTimeMillis()+""; + public static final String TEST_TENANT_DOMAIN = TEST_RUN+".my.test"; + public static final String DEFAULT_ADMIN_PW = "admin"; + + private Level saveLogLevel; + + protected void setUpApplicationContext() + { + ApplicationContext appContext = ApplicationContextHelper.getApplicationContext(new String[] + { + "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/remote-api-context.xml" + }); + + this.nodeService = (NodeService) appContext.getBean("NodeService"); + this.searchService = (SearchService) appContext.getBean("SearchService"); + this.namespaceService = (NamespaceService) appContext.getBean("NamespaceService"); + this.tenantService = (TenantService) appContext.getBean("tenantService"); + this.transactionService = (TransactionService) appContext.getBean("transactionService"); + this.webDAVHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); + this.tenantAdminService = (TenantAdminService) appContext.getBean("tenantAdminService"); + + // Authenticate as system to create initial test data set + AuthenticationComponent authenticationComponent = (AuthenticationComponent) appContext.getBean("authenticationComponent"); + authenticationComponent.setSystemUserAsCurrentUser(); + } + + private void checkLockedNodeTestWork() throws WebDAVServerException + { + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + + String rootPath = "/app:company_home"; + String storeName = "workspace://SpacesStore"; + StoreRef storeRef = new StoreRef(storeName); + NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); + List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); + NodeRef defaultRootNode = nodeRefs.get(0); + + lockMethod = new LockMethod(); + NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); + String strPath = "/" + "testLockedNode" + GUID.generate(); + + lockMethod.createExclusive = true; + lockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + lockMethod.m_strPath = strPath; + + // Lock the node (will create a new one). + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable { + lockMethod.executeImpl(); + return null; + } + }); + + // Prepare for PUT + req.addHeader(WebDAV.HEADER_IF, "(<" + lockMethod.lockToken + ">)"); + putMethod = new PutMethod(); + putMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + putMethod.parseRequestHeaders(); + putMethod.m_strPath = strPath; + String content = "test content stream"; + req.setContent(content.getBytes()); + + // Issue a put request + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + putMethod.executeImpl(); + return null; + } + }); + } + + /** + * Call the org.alfresco.repo.webdav.WebDAVMethod#checkNode(org.alfresco.service.cmr.model.FileInfo, boolean, boolean) + * for a write locked node for tenant and non-tenant. + * See ALF-19915. + */ + @Test + public void checkLockedNodeTest() throws Exception + { + setUpApplicationContext(); + + // Create a tenant domain + TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { + public Object doWork() throws Exception { + if (!tenantAdminService.existsTenant(TEST_TENANT_DOMAIN)) + { + tenantAdminService.createTenant(TEST_TENANT_DOMAIN, (DEFAULT_ADMIN_PW + " " + TEST_TENANT_DOMAIN).toCharArray(), null); + } + return null; + } + }, TenantService.DEFAULT_DOMAIN); + + // run as admin + try + { + TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() + { + @Override + public Object doWork() throws Exception + { + checkLockedNodeTestWork(); + return null; + } + }, AuthenticationUtil.getAdminUserName(), TenantService.DEFAULT_DOMAIN); + } + catch (Exception e) + { + fail("Failed to lock and put content as admin with error: " + e.getCause()); + } + + // run as tenant admin + try + { + TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() + { + @Override + public Object doWork() throws Exception + { + checkLockedNodeTestWork(); + return null; + } + }, AuthenticationUtil.getAdminUserName(), TEST_TENANT_DOMAIN); + } + catch (Exception e) + { + fail("Failed to lock and put content as tenant admin with error: " + e.getCause()); + } + } + + private void checkLockedNodeTestTenantWork() throws Exception + { + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + + String rootPath = "/app:company_home"; + String storeName = "workspace://SpacesStore"; + StoreRef storeRef = new StoreRef(storeName); + NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); + List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); + NodeRef defaultRootNode = nodeRefs.get(0); + + lockMethod = new LockMethod(); + NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); + String strPath = "/" + "testLockedNode" + GUID.generate(); + + lockMethod.createExclusive = true; + lockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + lockMethod.m_strPath = strPath; + + // Lock the node (will create a new one). + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable { + lockMethod.executeImpl(); + return null; + } + }); + + // Prepare for DELETE + String corruptedLockToken = lockMethod.lockToken + "corr"; + req.addHeader(WebDAV.HEADER_IF, "(<" + corruptedLockToken + ">)"); + deleteMethod = new DeleteMethod(); + deleteMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + deleteMethod.parseRequestHeaders(); + deleteMethod.m_strPath = strPath; + + // can't be deleted with corrupted lockTocken + try + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + deleteMethod.executeImpl(); + return null; + } + }); + fail("Locked node shouldn't be deleted"); + } + catch(Exception e) + { + if (!(e.getCause() instanceof WebDAVServerException)) + { + throw e; + } + } + + req = new MockHttpServletRequest(); + req.addHeader(WebDAV.HEADER_LOCK_TOKEN, lockMethod.lockToken); + + unlockMethod = new UnlockMethod(); + unlockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + unlockMethod.parseRequestHeaders(); + unlockMethod.m_strPath = strPath; + // unlock the node + try + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + unlockMethod.executeImpl(); + return null; + } + }); + } + catch(Exception e) + { + fail("Locked node should be unlocked with correct lockTocken " + e.getCause()); + } + + // Lock it again + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable { + lockMethod.executeImpl(); + return null; + } + }); + + req.addHeader(WebDAV.HEADER_IF, "(<" + lockMethod.lockToken + ">)"); + deleteMethod = new DeleteMethod(); + deleteMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + deleteMethod.parseRequestHeaders(); + deleteMethod.m_strPath = strPath; + + // can be deleted with correct lockTocken + try + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + deleteMethod.executeImpl(); + return null; + } + }); + } + catch(Exception e) + { + fail("Locked node should be deleted with correct lockTocken " + e.getCause()); + } + + } + + /* CLOUD-2204 Test */ + @Test + public void checkLockedNodeTenantTest() + { + setUpApplicationContext(); + + // Create a tenant domain + TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { + public Object doWork() throws Exception { + if (!tenantAdminService.existsTenant(TEST_TENANT_DOMAIN)) + { + tenantAdminService.createTenant(TEST_TENANT_DOMAIN, (DEFAULT_ADMIN_PW + " " + TEST_TENANT_DOMAIN).toCharArray(), null); + } + return null; + } + }, TenantService.DEFAULT_DOMAIN); + + TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() + { + @Override + public Object doWork() throws Exception + { + checkLockedNodeTestTenantWork(); + return null; + } + }, AuthenticationUtil.getAdminUserName(), TEST_TENANT_DOMAIN); + } + + @Test + public void canGetStatusForAccessDeniedException() + { + // Initially Mac OS X Finder uses a different UA string than for subsequent requests. + assertStatusCode(500, "WebDAVLib/1.3"); + + // Current UA string at time of writing test. + assertStatusCode(500, "WebDAVFS/1.9.0 (01908000) Darwin/11.4.0 (x86_64)"); + + // A fictitious version number long in the future. + assertStatusCode(500, "WebDAVFS/100.10.5 (01908000) Darwin/11.4.0 (x86_64)"); + + // Other processor architectures, e.g. x86_32 should work too. + assertStatusCode(500, "WebDAVFS/100.10.5 (01908000) Darwin/109.6.3 (some_other_processor_arch)"); + + // Other clients should give 403. + assertStatusCode(403, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6; en-us)"); + // Mozilla-based Windows browser. + assertStatusCode(403, "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12)"); + assertStatusCode(403, "SomeBrowser/1.0 (Macintosh; U; Intel Mac OS X 10_6; en-us)"); + assertStatusCode(403, "SomeBrowser/1.9.0 (01908000) Darwin/11.4.0 (x86_64)"); + assertStatusCode(403, "Cyberduck/4.2.1 (Mac OS X/10.7.4) (i386)"); + // Chrome + assertStatusCode(403, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5"); + // Safari + assertStatusCode(403, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"); + } + + /* MNT-10555 Test */ + @Category(IntermittentlyFailingTests.class) // ACS-959 + @Test + public void expiryLockTest() + { + // ACE-4347 extra debug logging just for this test so we can see what's going on when it next fails + Level repoWebdavSaveLogLevel = Logger.getLogger("org.alfresco.repo.webdav").getLevel(); + Logger.getLogger("org.alfresco.repo.webdav").setLevel(Level.ALL); + Level webdavProtocolSaveLogLevel = Logger.getLogger("org.alfresco.webdav.protocol").getLevel(); + Logger.getLogger("org.alfresco.webdav.protocol").setLevel(Level.ALL); + try + { + setUpApplicationContext(); + + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + + String rootPath = "/app:company_home"; + StoreRef storeRef = new StoreRef("workspace://SpacesStore"); + NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); + List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); + NodeRef defaultRootNode = nodeRefs.get(0); + + NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); + + // Create test folder. + NodeRef folderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_FOLDER, + Collections. singletonMap(ContentModel.PROP_NAME, "WebDavMethodExpiryLockTest" + System.currentTimeMillis())).getChildRef(); + + // Create test document. + NodeRef nodeRef = nodeService.createNode(folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("test"), ContentModel.TYPE_CONTENT, + Collections. singletonMap(ContentModel.PROP_NAME, "text.txt")).getChildRef(); + + lockMethod = new LockMethod(); + lockMethod.createExclusive = true; + lockMethod.m_timeoutDuration = 1; + lockMethod.setDetails(req, resp, webDAVHelper, nodeRef); + + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + try + { + // LOCK document. + lockMethod.executeImpl(); + + //wait for the lock to expire up to 5 seconds + int timeout = 5; + while( timeout > 0 && !lockMethod.lockInfo.isExpired()) + { + Thread.sleep(1000); + timeout--; + } + + // LOCK against an expired lock. + lockMethod.executeImpl(); + } + catch (WebDAVServerException e) + { + logger.debug(e); + Assert.fail("Document was not locked again, when lock has expired."); + } + return null; + } + }); + + // Remove test folder. + nodeService.deleteNode(folderNodeRef); + } + finally + { + Logger.getLogger("org.alfresco.webdav.protocol").setLevel(webdavProtocolSaveLogLevel); + Logger.getLogger("org.alfresco.repo.webdav").setLevel(repoWebdavSaveLogLevel); + } + } + + private void assertStatusCode(int expectedStatusCode, String userAgent) + { + // Fresh objects needed for each status code test. + createRequestObjects(); + req.addHeader("User-Agent", userAgent); + method.setDetails(req, resp, davHelper, null); + + int statusCode = method.getStatusForAccessDeniedException(); + + assertEquals("Incorrect status code for user-agent string \"" + userAgent + "\"", + expectedStatusCode, + statusCode); + } + + private void createRequestObjects() + { + method = new TestWebDAVMethod(); + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + } + + + /** + * Empty subclass of abstract base class for testing base class' behaviour. + */ + private static class TestWebDAVMethod extends WebDAVMethod + { + @Override + protected void executeImpl() throws WebDAVServerException, Exception + { + } + + @Override + protected void parseRequestBody() throws WebDAVServerException + { + } + + @Override + protected void parseRequestHeaders() throws WebDAVServerException + { + } + } +} diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/ProbeApiTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/ProbeApiTest.java index 9bfd0469d8..afad7aa219 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/ProbeApiTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/ProbeApiTest.java @@ -35,7 +35,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import static org.alfresco.rest.api.probes.ProbeEntityResource.*; import static org.junit.Assert.assertEquals; diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/QueriesPeopleApiTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/QueriesPeopleApiTest.java index a00703f5b9..6a1932e6ac 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/QueriesPeopleApiTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/QueriesPeopleApiTest.java @@ -1,519 +1,517 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2017 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ -package org.alfresco.rest.api.tests; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.rest.AbstractSingleNetworkSiteTest; -import org.alfresco.rest.api.Queries; -import org.alfresco.rest.api.tests.client.HttpResponse; -import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; -import org.alfresco.rest.api.tests.client.data.Company; -import org.alfresco.rest.api.tests.client.data.Person; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.search.SearchParameters; -import org.alfresco.util.testing.category.LuceneTests; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.runners.MockitoJUnitRunner; - -import javax.transaction.HeuristicMixedException; -import javax.transaction.HeuristicRollbackException; -import javax.transaction.NotSupportedException; -import javax.transaction.RollbackException; -import javax.transaction.SystemException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringJoiner; - -import static org.alfresco.rest.api.Queries.PARAM_FIRSTNAME; -import static org.alfresco.rest.api.Queries.PARAM_LASTNAME; -import static org.alfresco.rest.api.Queries.PARAM_PERSON_ID; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** -* V1 REST API tests for pre-defined 'live' search Queries on People - * - *
    - *
  • {@literal :/alfresco/api//public/alfresco/versions/1/queries/people}
  • - *
- * - * @author Alan Davis - */ -@RunWith(MockitoJUnitRunner.class) -public class QueriesPeopleApiTest extends AbstractSingleNetworkSiteTest -{ - private static final String URL_QUERIES_LSP = "queries/people"; - - private static String TEST_TERM_PREFIX = Long.toString(System.currentTimeMillis()/1000); - - // TODO Would like to use @BeforeClass and @AfterClass. But creating and - // deleting users is hard from from static methods. For the moment do it - // in the first and last tests, but we have to get the TEST count right! - // If we don't, a test fails or the users get left behind (not too bad). - private static int TEST_COUNT = 22; - private static int testCounter = 0; - - // Test usernames - private static final String USER0 = TEST_TERM_PREFIX+"user0"; - private static final String USER1 = TEST_TERM_PREFIX+"user1"; - private static final String USER2 = TEST_TERM_PREFIX+"user2"; - private static final String USER3 = TEST_TERM_PREFIX+"user3"; - private static final String USER4 = TEST_TERM_PREFIX+"user4"; - private static final String USER5 = TEST_TERM_PREFIX+"user5"; - - // Test firstnames - private static final String FIRST_A = TEST_TERM_PREFIX+"FirstA"; - private static final String FIRST_B = TEST_TERM_PREFIX+"FirstB"; - private static final String FIRST_C = TEST_TERM_PREFIX+"FirstC"; - - // Test Lastnames - private static final String LAST_A = TEST_TERM_PREFIX+"LastA"; - private static final String LAST_B = TEST_TERM_PREFIX+"LastB"; - private static final String LAST_C = TEST_TERM_PREFIX+"LastC"; - - private static final List testUsernames = new ArrayList<>(); - private static final List testPersons = new ArrayList<>(); - private static final List testPersonNodeRefs = new ArrayList<>(); - private static final String[][] userProperties = new String[][] - { - {USER0, FIRST_A, LAST_A}, - {USER1, FIRST_A, LAST_B}, - {USER2, FIRST_B, LAST_A}, - {USER3, FIRST_C,}, - {USER4, null , LAST_A}, - {USER5, null, LAST_C}, - }; - - // inputs - private String term = ""; - private String orderBy = null; - private String fields = null; - private Paging paging; - - // available for extra tests after call. - private Map params; - private HttpResponse response; - private List people; - - @Before - @Override - @SuppressWarnings("deprecation") - public void setup() throws Exception - { - super.setup(); - - if (testCounter++ == 0) - { - createTestUsers(); - } - - paging = getPaging(0, 100); - params = new HashMap<>(); - term = TEST_TERM_PREFIX; - orderBy = null; - fields = null; - - setRequestContext(user1); - } - - @After - @Override - public void tearDown() throws Exception - { - super.tearDown(); - - if (testCounter == TEST_COUNT) - { - deleteTestUsers(); - } - } - - // Helper method to create users. These are deleted on tearDown. - private void createTestUsers() throws IllegalArgumentException, SystemException, NotSupportedException, HeuristicRollbackException, HeuristicMixedException, RollbackException - { - AuthenticationUtil.setFullyAuthenticatedUser(user1); - for (String[] properties: userProperties) - { - int l = properties.length; - if (l > 0) - { - PersonInfo personInfo = newPersonInfo(properties); - String originalUsername = personInfo.getUsername(); - String id = createUser(personInfo, networkOne); - Person person = new Person( - id, - null, // Not set to originalUsername, as the returned JSON does not set it - true, // enabled - personInfo.getFirstName(), - personInfo.getLastName(), - personInfo.getCompany(), - personInfo.getSkype(), - personInfo.getLocation(), - personInfo.getTel(), - personInfo.getMob(), - personInfo.getInstantmsg(), - personInfo.getGoogle(), - null); // description - testUsernames.add(originalUsername); - testPersons.add(person); - - // The following call to personService.getPerson(id) returns a NodeRef like: - // workspace://SpacesStore/9db76769-96de-4de4-bdb4-a127130af362 - // We call tenantService.getName(nodeRef) to get a fully qualified NodeRef as Solr returns this. - // They look like: - // workspace://@org.alfresco.rest.api.tests.queriespeopleapitest@SpacesStore/9db76769-96de-4de4-bdb4-a127130af362 - NodeRef nodeRef = personService.getPerson(id); - nodeRef = tenantService.getName(nodeRef); - testPersonNodeRefs.add(nodeRef); - } - } - } - - private void deleteTestUsers() - { - for (String id: testUsernames) - { - try - { - deleteUser(id, null); - } - catch (Exception e) - { - System.err.println("Failed to delete test user "+id); - } - } - testPersons.clear(); - } - - // Helper method to create a PersonInfo object - // first 3 parameters are username, firstname, lastname unlike PersonInfo - // password defaults to "password" - private static PersonInfo newPersonInfo(String... properties) throws IllegalArgumentException - { - int l = properties.length; - if (l > 17) - { - throw new IllegalArgumentException("Too many properties supplied for "+properties); - } - return new PersonInfo( - (l <= 1 ? null : properties[ 1]), // firstName - (l <= 2 ? null : properties[ 2]), // lastName - (l <= 0 ? null : properties[ 0]), // username - - (l <= 3 || properties[ 3] == null - ? "password" : properties[ 3]), // password - (l <= 4 ? null : new Company( - properties[ 4], // organization - (l <= 5 ? null : properties[ 5]), // address1 - (l <= 6 ? null : properties[ 6]), // address2 - (l <= 7 ? null : properties[ 7]), // address3 - (l <= 8 ? null : properties[ 8]), // postcode - (l <= 9 ? null : properties[ 9]), // telephone - (l <= 10 ? null : properties[10]), // fax - (l <= 11 ? null : properties[11]))),// email - (l <= 12 ? null : properties[12]), // skype - (l <= 13 ? null : properties[13]), // location - (l <= 14 ? null : properties[14]), // tel - (l <= 15 ? null : properties[15]), // mob - (l <= 16 ? null : properties[16]), // instantmsg - (l <= 17 ? null : properties[17])); // google - } - - private void checkApiCall(String term, String orderBy, String fields, Paging paging, - int expectedStatus, - List expectedPeople, int... userIds) throws Exception - { - createParamIdNotNull(Queries.PARAM_TERM, term); - createParamIdNotNull(Queries.PARAM_ORDERBY, orderBy); - createParamIdNotNull(Queries.PARAM_FIELDS, fields); - - dummySearchServiceQueryNodeRefs.clear(); - for (int i: userIds) - { - NodeRef nodeRef = testPersonNodeRefs.get(i); - dummySearchServiceQueryNodeRefs.add(nodeRef); - } - - response = getAll(URL_QUERIES_LSP, paging, params, expectedStatus); - - if (expectedStatus == 200) - { - String termWithEscapedAsterisks = term.replaceAll("\\*", "\\\\*"); - String expectedQuery = "TYPE:\"{http://www.alfresco.org/model/content/1.0}person\" AND (\"*"+ termWithEscapedAsterisks +"*\")"; - ArgumentCaptor searchParametersCaptor = ArgumentCaptor.forClass(SearchParameters.class); - verify(mockSearchService, times(++callCountToMockSearchService)).query(searchParametersCaptor.capture()); - SearchParameters parameters = searchParametersCaptor.getValue(); - assertEquals("Query", expectedQuery, parameters.getQuery()); - - people = Person.parsePeople(response.getJsonResponse()).getList(); - - if (!expectedPeople.isEmpty()) - { - StringJoiner actual = new StringJoiner("\n"); - StringJoiner expected = new StringJoiner("\n"); - for (String people : expectedPeople) - { - expected.add(people); - } - for (Person person : people) - { - actual.add(person.toString()); - } - String exp = expected.toString().replaceAll(TEST_TERM_PREFIX, ""); - String act = actual.toString().replaceAll(TEST_TERM_PREFIX, ""); - assertEquals(exp, act); - } - } - } - - private void createParamIdNotNull(String param, String value) - { - if (value != null && params != null) - { - params.put(param, value); - } - } - - private List expectedPeople(int... userIds) - { - List list = new ArrayList<>(); - for (int i : userIds) - { - Person person = testPersons.get(i); - String string = person.toString(); - list.add(string); - } - return list; - } - - @Test - @SuppressWarnings("deprecation") - public void testUnauthenticated() throws Exception - { - setRequestContext(null); - - checkApiCall(term, orderBy, fields, paging, 401, null); - } - - @Test - public void testOnlyTestUsersAndDefaultOrder() throws Exception - { - // Checks only test users are found as a result of using TEST_TERM_PREFIX. - - // Also checks the default sort order (firstname lastname): - // 4 A - // 5 C - // 0 A A - // 1 A B - // 2 B A - // 3 C - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 5, 0, 1, 2, 3), 4, 5, 0, 1, 2, 3); - } - - @Test - public void testSearchFirstname() throws Exception - { - checkApiCall(FIRST_A, orderBy, fields, paging, 200, expectedPeople(0, 1), 0, 1); - } - - @Test - public void testSearchLastName() throws Exception - { - checkApiCall(LAST_A, orderBy, fields, paging, 200, expectedPeople(4, 0, 2), 4, 0, 2); - } - - @Test - public void testSearchUsername() throws Exception - { - checkApiCall(USER0, orderBy, fields, paging, 200, expectedPeople(0), 0); - } - - @Test - public void testNoParams() throws Exception - { - params = null; - checkApiCall(term, orderBy, fields, paging, 400, null); - } - - @Test - public void testNoTerm() throws Exception - { - checkApiCall(null, orderBy, fields, paging, 400, null); - } - - @Test - public void testTermShorterThan2() throws Exception - { - checkApiCall("X", orderBy, fields, paging, 400, null); - } - - @Test - public void testOrderbySameAsDefault() throws Exception - { - orderBy = "firstName asc, lastName"; // same as default (asc is default order) - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 5, 0, 1, 2, 3), 4, 5, 0, 1, 2, 3); - } - - @Test - public void testOrderbyDescAndAsc() throws Exception - { - // 4 C - // 3 B A - // 1 A A - // 2 A B - // 5 A - // 6 C - orderBy = "firstName desc, lastName"; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(3, 2, 0, 1, 4, 5), 3, 2, 0, 1, 4, 5); - } - - @Test - public void testOrderbyDescAndDesc() throws Exception - { - // 4 C - // 3 B A - // 2 A B - // 1 A A - // 6 C - // 5 A - orderBy = "firstName desc, lastName desc"; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(3, 2, 1, 0, 5, 4), 3, 2, 1, 0, 5, 4); - } - - @Test - public void testOrderbyId() throws Exception - { - orderBy = PARAM_PERSON_ID; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0, 1, 2, 3, 4, 5), 0, 1, 2, 3, 4, 5); - } - - @Test - public void testBadOrderByField() throws Exception - { - orderBy = "rubbish"; - checkApiCall(term, orderBy, fields, paging, 400, null); - } - - @Test - public void testFieldsFirstLast() throws Exception - { - fields = PARAM_FIRSTNAME+","+PARAM_LASTNAME; - term = LAST_A; - List expectedPeople = Arrays.asList( - "Person [" + "lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 - "Person [" + "firstName=FirstA, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 - "Person [" + "firstName=FirstB, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 - ); - - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); - } - - @Test - public void testFieldsId() throws Exception - { - fields = PARAM_PERSON_ID; - String tenantSuffix = (useDefaultNetwork ? "" : "@"+networkOne.getId()); - List expectedPeople = Arrays.asList( - "Person [id=user4"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 - "Person [id=user0"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 - "Person [id=user2"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 - ); - - checkApiCall(LAST_A, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); - } - - @Test - public void testSearchFirstnameWithWildcard() throws Exception - { - term = FIRST_A.substring(0,FIRST_A.length()-3) + "*A"; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0, 1), 0, 1); - } - - @Test - public void testSearchLastNameWithWildcard() throws Exception - { - term = LAST_A; - term = term.substring(0,term.length()-3) + "*A"; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 0, 2), 4, 0, 2); - } - - @Test - public void testSearchUsernameWithWildcard() throws Exception - { - term = TEST_TERM_PREFIX+"us*1"; - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0), 0); - } - - @Test - public void testOrderbyDescAndAscWithWildcard() throws Exception - { - // 3 B A - // 1 A A - // 5 A - term = TEST_TERM_PREFIX+"la*A"; - orderBy = "firstName desc,lastName"; - - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(2, 0, 4), 2, 0, 4); - } - - @Test - public void testOnlyWildcard() throws Exception - { - checkApiCall("*", orderBy, fields, paging, 400, null); - } - - @Test - public void testBadOrderByDirection() throws Exception - { - // note: also tested generically in RecognizedParamsExtractorTest - orderBy = "firstName rubbish, lastName asc"; - checkApiCall(term, orderBy, fields, paging, 400, null); - } - - @Test - public void testFieldsWithSpace() throws Exception - { - fields = PARAM_FIRSTNAME+", "+PARAM_LASTNAME; - term = LAST_A; - List expectedPeople = Arrays.asList( - "Person ["+ "lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 - "Person ["+"firstName=FirstA, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 - "Person ["+"firstName=FirstB, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 - ); - - checkApiCall(term, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ +package org.alfresco.rest.api.tests; + +import static org.alfresco.rest.api.Queries.PARAM_FIRSTNAME; +import static org.alfresco.rest.api.Queries.PARAM_LASTNAME; +import static org.alfresco.rest.api.Queries.PARAM_PERSON_ID; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; + +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.SystemException; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.rest.AbstractSingleNetworkSiteTest; +import org.alfresco.rest.api.Queries; +import org.alfresco.rest.api.tests.client.HttpResponse; +import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; +import org.alfresco.rest.api.tests.client.data.Company; +import org.alfresco.rest.api.tests.client.data.Person; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.SearchParameters; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.MockitoJUnitRunner; + +/** +* V1 REST API tests for pre-defined 'live' search Queries on People + * + *
    + *
  • {@literal :/alfresco/api//public/alfresco/versions/1/queries/people}
  • + *
+ * + * @author Alan Davis + */ +@RunWith(MockitoJUnitRunner.class) +public class QueriesPeopleApiTest extends AbstractSingleNetworkSiteTest +{ + private static final String URL_QUERIES_LSP = "queries/people"; + + private static String TEST_TERM_PREFIX = Long.toString(System.currentTimeMillis()/1000); + + // TODO Would like to use @BeforeClass and @AfterClass. But creating and + // deleting users is hard from from static methods. For the moment do it + // in the first and last tests, but we have to get the TEST count right! + // If we don't, a test fails or the users get left behind (not too bad). + private static int TEST_COUNT = 22; + private static int testCounter = 0; + + // Test usernames + private static final String USER0 = TEST_TERM_PREFIX+"user0"; + private static final String USER1 = TEST_TERM_PREFIX+"user1"; + private static final String USER2 = TEST_TERM_PREFIX+"user2"; + private static final String USER3 = TEST_TERM_PREFIX+"user3"; + private static final String USER4 = TEST_TERM_PREFIX+"user4"; + private static final String USER5 = TEST_TERM_PREFIX+"user5"; + + // Test firstnames + private static final String FIRST_A = TEST_TERM_PREFIX+"FirstA"; + private static final String FIRST_B = TEST_TERM_PREFIX+"FirstB"; + private static final String FIRST_C = TEST_TERM_PREFIX+"FirstC"; + + // Test Lastnames + private static final String LAST_A = TEST_TERM_PREFIX+"LastA"; + private static final String LAST_B = TEST_TERM_PREFIX+"LastB"; + private static final String LAST_C = TEST_TERM_PREFIX+"LastC"; + + private static final List testUsernames = new ArrayList<>(); + private static final List testPersons = new ArrayList<>(); + private static final List testPersonNodeRefs = new ArrayList<>(); + private static final String[][] userProperties = new String[][] + { + {USER0, FIRST_A, LAST_A}, + {USER1, FIRST_A, LAST_B}, + {USER2, FIRST_B, LAST_A}, + {USER3, FIRST_C,}, + {USER4, null , LAST_A}, + {USER5, null, LAST_C}, + }; + + // inputs + private String term = ""; + private String orderBy = null; + private String fields = null; + private Paging paging; + + // available for extra tests after call. + private Map params; + private HttpResponse response; + private List people; + + @Before + @Override + @SuppressWarnings("deprecation") + public void setup() throws Exception + { + super.setup(); + + if (testCounter++ == 0) + { + createTestUsers(); + } + + paging = getPaging(0, 100); + params = new HashMap<>(); + term = TEST_TERM_PREFIX; + orderBy = null; + fields = null; + + setRequestContext(user1); + } + + @After + @Override + public void tearDown() throws Exception + { + super.tearDown(); + + if (testCounter == TEST_COUNT) + { + deleteTestUsers(); + } + } + + // Helper method to create users. These are deleted on tearDown. + private void createTestUsers() throws IllegalArgumentException, SystemException, NotSupportedException, HeuristicRollbackException, HeuristicMixedException, RollbackException + { + AuthenticationUtil.setFullyAuthenticatedUser(user1); + for (String[] properties: userProperties) + { + int l = properties.length; + if (l > 0) + { + PersonInfo personInfo = newPersonInfo(properties); + String originalUsername = personInfo.getUsername(); + String id = createUser(personInfo, networkOne); + Person person = new Person( + id, + null, // Not set to originalUsername, as the returned JSON does not set it + true, // enabled + personInfo.getFirstName(), + personInfo.getLastName(), + personInfo.getCompany(), + personInfo.getSkype(), + personInfo.getLocation(), + personInfo.getTel(), + personInfo.getMob(), + personInfo.getInstantmsg(), + personInfo.getGoogle(), + null); // description + testUsernames.add(originalUsername); + testPersons.add(person); + + // The following call to personService.getPerson(id) returns a NodeRef like: + // workspace://SpacesStore/9db76769-96de-4de4-bdb4-a127130af362 + // We call tenantService.getName(nodeRef) to get a fully qualified NodeRef as Solr returns this. + // They look like: + // workspace://@org.alfresco.rest.api.tests.queriespeopleapitest@SpacesStore/9db76769-96de-4de4-bdb4-a127130af362 + NodeRef nodeRef = personService.getPerson(id); + nodeRef = tenantService.getName(nodeRef); + testPersonNodeRefs.add(nodeRef); + } + } + } + + private void deleteTestUsers() + { + for (String id: testUsernames) + { + try + { + deleteUser(id, null); + } + catch (Exception e) + { + System.err.println("Failed to delete test user "+id); + } + } + testPersons.clear(); + } + + // Helper method to create a PersonInfo object + // first 3 parameters are username, firstname, lastname unlike PersonInfo + // password defaults to "password" + private static PersonInfo newPersonInfo(String... properties) throws IllegalArgumentException + { + int l = properties.length; + if (l > 17) + { + throw new IllegalArgumentException("Too many properties supplied for "+properties); + } + return new PersonInfo( + (l <= 1 ? null : properties[ 1]), // firstName + (l <= 2 ? null : properties[ 2]), // lastName + (l <= 0 ? null : properties[ 0]), // username + + (l <= 3 || properties[ 3] == null + ? "password" : properties[ 3]), // password + (l <= 4 ? null : new Company( + properties[ 4], // organization + (l <= 5 ? null : properties[ 5]), // address1 + (l <= 6 ? null : properties[ 6]), // address2 + (l <= 7 ? null : properties[ 7]), // address3 + (l <= 8 ? null : properties[ 8]), // postcode + (l <= 9 ? null : properties[ 9]), // telephone + (l <= 10 ? null : properties[10]), // fax + (l <= 11 ? null : properties[11]))),// email + (l <= 12 ? null : properties[12]), // skype + (l <= 13 ? null : properties[13]), // location + (l <= 14 ? null : properties[14]), // tel + (l <= 15 ? null : properties[15]), // mob + (l <= 16 ? null : properties[16]), // instantmsg + (l <= 17 ? null : properties[17])); // google + } + + private void checkApiCall(String term, String orderBy, String fields, Paging paging, + int expectedStatus, + List expectedPeople, int... userIds) throws Exception + { + createParamIdNotNull(Queries.PARAM_TERM, term); + createParamIdNotNull(Queries.PARAM_ORDERBY, orderBy); + createParamIdNotNull(Queries.PARAM_FIELDS, fields); + + dummySearchServiceQueryNodeRefs.clear(); + for (int i: userIds) + { + NodeRef nodeRef = testPersonNodeRefs.get(i); + dummySearchServiceQueryNodeRefs.add(nodeRef); + } + + response = getAll(URL_QUERIES_LSP, paging, params, expectedStatus); + + if (expectedStatus == 200) + { + String termWithEscapedAsterisks = term.replaceAll("\\*", "\\\\*"); + String expectedQuery = "TYPE:\"{http://www.alfresco.org/model/content/1.0}person\" AND (\"*"+ termWithEscapedAsterisks +"*\")"; + ArgumentCaptor searchParametersCaptor = ArgumentCaptor.forClass(SearchParameters.class); + verify(mockSearchService, times(++callCountToMockSearchService)).query(searchParametersCaptor.capture()); + SearchParameters parameters = searchParametersCaptor.getValue(); + assertEquals("Query", expectedQuery, parameters.getQuery()); + + people = Person.parsePeople(response.getJsonResponse()).getList(); + + if (!expectedPeople.isEmpty()) + { + StringJoiner actual = new StringJoiner("\n"); + StringJoiner expected = new StringJoiner("\n"); + for (String people : expectedPeople) + { + expected.add(people); + } + for (Person person : people) + { + actual.add(person.toString()); + } + String exp = expected.toString().replaceAll(TEST_TERM_PREFIX, ""); + String act = actual.toString().replaceAll(TEST_TERM_PREFIX, ""); + assertEquals(exp, act); + } + } + } + + private void createParamIdNotNull(String param, String value) + { + if (value != null && params != null) + { + params.put(param, value); + } + } + + private List expectedPeople(int... userIds) + { + List list = new ArrayList<>(); + for (int i : userIds) + { + Person person = testPersons.get(i); + String string = person.toString(); + list.add(string); + } + return list; + } + + @Test + @SuppressWarnings("deprecation") + public void testUnauthenticated() throws Exception + { + setRequestContext(null); + + checkApiCall(term, orderBy, fields, paging, 401, null); + } + + @Test + public void testOnlyTestUsersAndDefaultOrder() throws Exception + { + // Checks only test users are found as a result of using TEST_TERM_PREFIX. + + // Also checks the default sort order (firstname lastname): + // 4 A + // 5 C + // 0 A A + // 1 A B + // 2 B A + // 3 C + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 5, 0, 1, 2, 3), 4, 5, 0, 1, 2, 3); + } + + @Test + public void testSearchFirstname() throws Exception + { + checkApiCall(FIRST_A, orderBy, fields, paging, 200, expectedPeople(0, 1), 0, 1); + } + + @Test + public void testSearchLastName() throws Exception + { + checkApiCall(LAST_A, orderBy, fields, paging, 200, expectedPeople(4, 0, 2), 4, 0, 2); + } + + @Test + public void testSearchUsername() throws Exception + { + checkApiCall(USER0, orderBy, fields, paging, 200, expectedPeople(0), 0); + } + + @Test + public void testNoParams() throws Exception + { + params = null; + checkApiCall(term, orderBy, fields, paging, 400, null); + } + + @Test + public void testNoTerm() throws Exception + { + checkApiCall(null, orderBy, fields, paging, 400, null); + } + + @Test + public void testTermShorterThan2() throws Exception + { + checkApiCall("X", orderBy, fields, paging, 400, null); + } + + @Test + public void testOrderbySameAsDefault() throws Exception + { + orderBy = "firstName asc, lastName"; // same as default (asc is default order) + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 5, 0, 1, 2, 3), 4, 5, 0, 1, 2, 3); + } + + @Test + public void testOrderbyDescAndAsc() throws Exception + { + // 4 C + // 3 B A + // 1 A A + // 2 A B + // 5 A + // 6 C + orderBy = "firstName desc, lastName"; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(3, 2, 0, 1, 4, 5), 3, 2, 0, 1, 4, 5); + } + + @Test + public void testOrderbyDescAndDesc() throws Exception + { + // 4 C + // 3 B A + // 2 A B + // 1 A A + // 6 C + // 5 A + orderBy = "firstName desc, lastName desc"; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(3, 2, 1, 0, 5, 4), 3, 2, 1, 0, 5, 4); + } + + @Test + public void testOrderbyId() throws Exception + { + orderBy = PARAM_PERSON_ID; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0, 1, 2, 3, 4, 5), 0, 1, 2, 3, 4, 5); + } + + @Test + public void testBadOrderByField() throws Exception + { + orderBy = "rubbish"; + checkApiCall(term, orderBy, fields, paging, 400, null); + } + + @Test + public void testFieldsFirstLast() throws Exception + { + fields = PARAM_FIRSTNAME+","+PARAM_LASTNAME; + term = LAST_A; + List expectedPeople = Arrays.asList( + "Person [" + "lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 + "Person [" + "firstName=FirstA, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 + "Person [" + "firstName=FirstB, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 + ); + + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); + } + + @Test + public void testFieldsId() throws Exception + { + fields = PARAM_PERSON_ID; + String tenantSuffix = (useDefaultNetwork ? "" : "@"+networkOne.getId()); + List expectedPeople = Arrays.asList( + "Person [id=user4"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 + "Person [id=user0"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 + "Person [id=user2"+tenantSuffix+", company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 + ); + + checkApiCall(LAST_A, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); + } + + @Test + public void testSearchFirstnameWithWildcard() throws Exception + { + term = FIRST_A.substring(0,FIRST_A.length()-3) + "*A"; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0, 1), 0, 1); + } + + @Test + public void testSearchLastNameWithWildcard() throws Exception + { + term = LAST_A; + term = term.substring(0,term.length()-3) + "*A"; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(4, 0, 2), 4, 0, 2); + } + + @Test + public void testSearchUsernameWithWildcard() throws Exception + { + term = TEST_TERM_PREFIX+"us*1"; + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(0), 0); + } + + @Test + public void testOrderbyDescAndAscWithWildcard() throws Exception + { + // 3 B A + // 1 A A + // 5 A + term = TEST_TERM_PREFIX+"la*A"; + orderBy = "firstName desc,lastName"; + + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople(2, 0, 4), 2, 0, 4); + } + + @Test + public void testOnlyWildcard() throws Exception + { + checkApiCall("*", orderBy, fields, paging, 400, null); + } + + @Test + public void testBadOrderByDirection() throws Exception + { + // note: also tested generically in RecognizedParamsExtractorTest + orderBy = "firstName rubbish, lastName asc"; + checkApiCall(term, orderBy, fields, paging, 400, null); + } + + @Test + public void testFieldsWithSpace() throws Exception + { + fields = PARAM_FIRSTNAME+", "+PARAM_LASTNAME; + term = LAST_A; + List expectedPeople = Arrays.asList( + "Person ["+ "lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER4 + "Person ["+"firstName=FirstA, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]", // USER0 + "Person ["+"firstName=FirstB, lastName=LastA, company=Company [address1=null, address2=null, address3=null, postcode=null, telephone=null, fax=null, email=null], ]" // USER2 + ); + + checkApiCall(term, orderBy, fields, paging, 200, expectedPeople, 4, 0, 2); + } +} diff --git a/repository/pom.xml b/repository/pom.xml index 0075e4571b..a7c7e72d77 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -630,34 +630,6 @@ gytheio-messaging-camel ${dependency.gytheio.version} - - commons-logging - commons-logging - - - commons-io - commons-io - - - commons-lang - commons-lang - - - commons-pool - commons-pool - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - - - org.apache.tika - tika-core - org.apache.camel camel-core @@ -671,92 +643,32 @@ org.apache.camel camel-spring - ${dependency.camel.version} - - - org.springframework - spring-context - - - org.springframework - spring-aop - - - org.springframework - spring-tx - - - org.springframework - spring-core - - - org.springframework - spring-beans - - - org.springframework - spring-expression - - org.apache.camel camel-amqp - ${dependency.camel.version} - - - org.springframework - spring-core - - - org.springframework - spring-tx - - - org.springframework - spring-beans - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - - - - org.apache.geronimo.specs - geronimo-jms_2.0_spec - - org.apache.camel camel-jackson - ${dependency.camel.version} - - - - jakarta.activation - jakarta.activation-api - - + + + org.apache.camel + camel-directvm + + + org.apache.camel + camel-direct + + + org.apache.camel + camel-mock + test org.apache.activemq activemq-client ${dependency.activemq.version} - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - - org.apache.activemq @@ -764,30 +676,10 @@ ${dependency.activemq.version} - org.apache.activemq - activemq-camel - ${dependency.activemq.version} + org.apache.camel + camel-activemq + ${dependency.camel.version} - - org.springframework - spring-beans - - - commons-logging - commons-logging - - - commons-pool - commons-pool - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - org.apache.geronimo.specs @@ -800,14 +692,6 @@ activemq-pool ${dependency.activemq.version} - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - org.apache.geronimo.specs diff --git a/repository/src/main/java/org/alfresco/messaging/camel/SpringContextRouteLoader.java b/repository/src/main/java/org/alfresco/messaging/camel/SpringContextRouteLoader.java index 20f077d637..62c96faddc 100644 --- a/repository/src/main/java/org/alfresco/messaging/camel/SpringContextRouteLoader.java +++ b/repository/src/main/java/org/alfresco/messaging/camel/SpringContextRouteLoader.java @@ -27,6 +27,7 @@ package org.alfresco.messaging.camel; import java.util.ArrayList; +import org.apache.camel.CamelContext; import org.apache.camel.model.ModelCamelContext; import org.apache.camel.model.RouteDefinition; import org.springframework.beans.BeansException; @@ -65,7 +66,9 @@ public class SpringContextRouteLoader implements ApplicationContextAware, Initia @SuppressWarnings("unchecked") public void addRoutesToCamelContext() throws Exception { - ModelCamelContext modelCamelContext = (ModelCamelContext) applicationContext.getBean(camelContextId); + ModelCamelContext modelCamelContext = applicationContext + .getBean(camelContextId, CamelContext.class) + .adapt(ModelCamelContext.class); ArrayList routeDefinitions = (ArrayList) applicationContext.getBean(routeContextId); modelCamelContext.addRouteDefinitions(routeDefinitions); } diff --git a/repository/src/main/java/org/alfresco/messaging/camel/configuration/ConnectionFactoryConfiguration.java b/repository/src/main/java/org/alfresco/messaging/camel/configuration/ConnectionFactoryConfiguration.java index 14843e2a68..1d20fabf46 100644 --- a/repository/src/main/java/org/alfresco/messaging/camel/configuration/ConnectionFactoryConfiguration.java +++ b/repository/src/main/java/org/alfresco/messaging/camel/configuration/ConnectionFactoryConfiguration.java @@ -33,6 +33,7 @@ import javax.jms.ConnectionFactory; import org.alfresco.encryption.AlfrescoKeyStore; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQSslConnectionFactory; +import org.apache.camel.component.jms.JmsComponent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -80,6 +81,12 @@ public class ConnectionFactoryConfiguration return createConnectionFactory(); } + @Bean + public JmsComponent jms() + { + return JmsComponent.jmsComponent(activeMqConnectionFactory()); + } + protected ConnectionFactory createConnectionFactory() { return new ActiveMQConnectionFactory(username, password, brokerUrl); diff --git a/repository/src/main/java/org/alfresco/messaging/camel/routes/OnContentUpdateRenditionRoute.java b/repository/src/main/java/org/alfresco/messaging/camel/routes/OnContentUpdateRenditionRoute.java index 982abdcef2..2b6d8fa410 100644 --- a/repository/src/main/java/org/alfresco/messaging/camel/routes/OnContentUpdateRenditionRoute.java +++ b/repository/src/main/java/org/alfresco/messaging/camel/routes/OnContentUpdateRenditionRoute.java @@ -39,7 +39,7 @@ import org.alfresco.repo.rawevents.types.OnContentUpdatePolicyEvent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.GUID; -import org.apache.camel.spring.SpringRouteBuilder; +import org.apache.camel.builder.RouteBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -52,7 +52,7 @@ import org.springframework.stereotype.Component; * @author Cristian Turlica */ @Component -public class OnContentUpdateRenditionRoute extends SpringRouteBuilder +public class OnContentUpdateRenditionRoute extends RouteBuilder { private static Log logger = LogFactory.getLog(OnContentUpdateRenditionRoute.class); diff --git a/repository/src/main/java/org/alfresco/messaging/camel/routes/RepoNodeEventsRouteBuilder.java b/repository/src/main/java/org/alfresco/messaging/camel/routes/RepoNodeEventsRouteBuilder.java index e75d6d3b55..67e6d91109 100644 --- a/repository/src/main/java/org/alfresco/messaging/camel/routes/RepoNodeEventsRouteBuilder.java +++ b/repository/src/main/java/org/alfresco/messaging/camel/routes/RepoNodeEventsRouteBuilder.java @@ -25,7 +25,7 @@ */ package org.alfresco.messaging.camel.routes; -import org.apache.camel.spring.SpringRouteBuilder; +import org.apache.camel.builder.RouteBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Value; @@ -33,11 +33,11 @@ import org.springframework.stereotype.Component; /** * Route builder for Repo node events - * + * * @author sglover */ @Component -public class RepoNodeEventsRouteBuilder extends SpringRouteBuilder +public class RepoNodeEventsRouteBuilder extends RouteBuilder { private static Log logger = LogFactory.getLog(RepoNodeEventsRouteBuilder.class); @@ -60,8 +60,10 @@ public class RepoNodeEventsRouteBuilder extends SpringRouteBuilder logger.debug("targetTopic is "+targetTopic); } - from(sourceQueue).routeId("alfresco.events -> topic:alfresco.repo.events") - .marshal("defaultDataFormat").to(targetTopic) - .end(); + from(sourceQueue) + .routeId("alfresco.events -> topic:alfresco.repo.events") + .marshal("defaultDataFormat") + .to(targetTopic) + .end(); } } diff --git a/repository/src/main/java/org/alfresco/messaging/camel/routes/TransformRequestConsumer.java b/repository/src/main/java/org/alfresco/messaging/camel/routes/TransformRequestConsumer.java index cd43b74c12..f7cc9276f8 100644 --- a/repository/src/main/java/org/alfresco/messaging/camel/routes/TransformRequestConsumer.java +++ b/repository/src/main/java/org/alfresco/messaging/camel/routes/TransformRequestConsumer.java @@ -26,7 +26,7 @@ package org.alfresco.messaging.camel.routes; import org.apache.camel.Processor; -import org.apache.camel.spring.SpringRouteBuilder; +import org.apache.camel.builder.RouteBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -43,7 +43,7 @@ import java.util.concurrent.Executors; * @author aepure */ @Component -public class TransformRequestConsumer extends SpringRouteBuilder +public class TransformRequestConsumer extends RouteBuilder { private static Log logger = LogFactory.getLog(TransformRequestConsumer.class); diff --git a/repository/src/main/resources/alfresco/subsystems/Messaging/default/messaging-context.xml b/repository/src/main/resources/alfresco/subsystems/Messaging/default/messaging-context.xml index 0272da70a4..853a80f7ab 100644 --- a/repository/src/main/resources/alfresco/subsystems/Messaging/default/messaging-context.xml +++ b/repository/src/main/resources/alfresco/subsystems/Messaging/default/messaging-context.xml @@ -71,7 +71,7 @@ - +