From 0034f53b5f71fb285a1605d8c70e48b99f379409 Mon Sep 17 00:00:00 2001 From: mpichura <41297682+mpichura@users.noreply.github.com> Date: Fri, 10 Dec 2021 16:06:54 +0100 Subject: [PATCH] ACS-2336 POST endpoints for archive/archive-restore content (#826) * ACS-2200: Java API for archive/archive-restore content + unit tests. * Bump restapi from 1.64 to 1.65 (#795) * Bump utility from 3.0.45 to 3.0.47 (#794) * ACS-2200: Applying review comments. * ACS-2200: Applying review comments. * ACS-2200: Adding new unit test to suite. * ACS-2200: Adding optional archive params to archive operation. * ACS-2236: Archive + archive-restore operations and unit tests. * ACS-2236: Addressing review comments. Small refactor in unit tests. --- .../rest/api/ContentStorageInformation.java | 26 +++ .../impl/ContentStorageInformationImpl.java | 33 ++++ .../rest/api/model/ArchiveContentRequest.java | 63 +++++++ .../model/RestoreArchivedContentRequest.java | 55 ++++++ .../api/nodes/NodeStorageInfoRelation.java | 50 +++++- .../alfresco/AppContextExtraTestSuite.java | 2 + .../ContentStorageInformationImplTest.java | 151 ++++++++++++++--- .../nodes/NodeStorageInfoRelationTest.java | 158 ++++++++++++++++++ .../cmr/repository/ContentService.java | 2 +- 9 files changed, 514 insertions(+), 26 deletions(-) create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/model/ArchiveContentRequest.java create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/model/RestoreArchivedContentRequest.java create mode 100644 remote-api/src/test/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelationTest.java diff --git a/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java b/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java index 454dc8ea68..4b142750f4 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java @@ -26,7 +26,9 @@ package org.alfresco.rest.api; +import org.alfresco.rest.api.model.ArchiveContentRequest; import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.api.model.RestoreArchivedContentRequest; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.service.Experimental; @@ -41,6 +43,7 @@ public interface ContentStorageInformation { /** * Note: Currently marked as experimental and subject to change. + * * @param nodeId Identifier of the node * @param contentPropName Qualified name of content property (e.g. 'cm_content') * @param parameters {@link Parameters} object to get the parameters passed into the request @@ -48,4 +51,27 @@ public interface ContentStorageInformation */ @Experimental ContentStorageInfo getStorageInfo(String nodeId, String contentPropName, Parameters parameters); + + /** + * Note: Currently marked as experimental and subject to change. + * + * @param nodeId Identifier of the node + * @param contentPropName Qualified name of content property (e.g. 'cm_content') + * @param archiveContentRequest {@link ArchiveContentRequest} object holding parameters for archive content request + * @return true when request successful, false when unsuccessful + */ + @Experimental + boolean requestArchiveContent(String nodeId, String contentPropName, ArchiveContentRequest archiveContentRequest); + + /** + * Note: Currently marked as experimental and subject to change. + * + * @param nodeId Identifier of the node + * @param contentPropName Qualified name of content property (e.g. 'cm_content') + * @param restoreArchivedContentRequest {@link RestoreArchivedContentRequest} object holding parameters for restore from archive request + * @return true when request successful, false when unsuccessful + */ + @Experimental + boolean requestRestoreContentFromArchive(String nodeId, String contentPropName, + RestoreArchivedContentRequest restoreArchivedContentRequest); } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java index 164b0927a4..c3faabe29d 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java @@ -26,8 +26,11 @@ package org.alfresco.rest.api.impl; +import org.alfresco.repo.content.ContentRestoreParams; import org.alfresco.rest.api.ContentStorageInformation; +import org.alfresco.rest.api.model.ArchiveContentRequest; import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.api.model.RestoreArchivedContentRequest; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.repository.ContentService; @@ -36,7 +39,10 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import java.io.Serializable; +import java.util.Collections; import java.util.Map; + /** * Default implementation for {@link ContentStorageInformation} * Note: Currently marked as experimental and subject to change. @@ -74,6 +80,33 @@ public class ContentStorageInformationImpl implements ContentStorageInformation return storageInfo; } + /** + * {@inheritDoc} + */ + @Override + public boolean requestArchiveContent(String nodeId, String contentPropName, + ArchiveContentRequest archiveContentRequest) + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + final QName propQName = getQName(contentPropName); + return contentService.requestSendContentToArchive(nodeRef, propQName, archiveContentRequest.getArchiveParams()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean requestRestoreContentFromArchive(String nodeId, String contentPropName, + RestoreArchivedContentRequest restoreArchivedContentRequest) + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + final QName propQName = getQName(contentPropName); + final Map restoreParams = restoreArchivedContentRequest.getRestorePriority() == null ? + Collections.emptyMap() : + Map.of(ContentRestoreParams.RESTORE_PRIORITY.name(), restoreArchivedContentRequest.getRestorePriority()); + return contentService.requestRestoreContentFromArchive(nodeRef, propQName, restoreParams); + } + private QName getQName(final String contentPropName) { final String properContentPropName = contentPropName.replace(PREFIX_SEPARATOR, QName.NAMESPACE_PREFIX); diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/ArchiveContentRequest.java b/remote-api/src/main/java/org/alfresco/rest/api/model/ArchiveContentRequest.java new file mode 100644 index 0000000000..7e44e03c13 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/ArchiveContentRequest.java @@ -0,0 +1,63 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.model; + +import org.alfresco.service.Experimental; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Request for content archive. + * Marked as experimental and subject to change. + * + * @author mpichura + */ +@Experimental +public class ArchiveContentRequest +{ + /** + * A map (String-Serializable) of parameters specific for request to archive content. + * This object is optional. + */ + private Map archiveParams; + + public Map getArchiveParams() + { + if (archiveParams == null) + { + archiveParams = new HashMap<>(); + } + return archiveParams; + } + + public void setArchiveParams(Map archiveParams) + { + this.archiveParams = archiveParams; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/RestoreArchivedContentRequest.java b/remote-api/src/main/java/org/alfresco/rest/api/model/RestoreArchivedContentRequest.java new file mode 100644 index 0000000000..3746a8df50 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/RestoreArchivedContentRequest.java @@ -0,0 +1,55 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.model; + +import org.alfresco.service.Experimental; + +/** + * Request for restore content from archive. + * Marked as experimental and subject to change. + * + * @author mpichura + */ +@Experimental +public class RestoreArchivedContentRequest +{ + /** + * Restore priority. Possible values: Standard/High. + * This field is optional. + */ + private String restorePriority; + + public String getRestorePriority() + { + return restorePriority; + } + + public void setRestorePriority(String restorePriority) + { + this.restorePriority = restorePriority; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java index 78dca635f0..c0fc223e3e 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java @@ -27,12 +27,18 @@ package org.alfresco.rest.api.nodes; import org.alfresco.rest.api.ContentStorageInformation; +import org.alfresco.rest.api.model.ArchiveContentRequest; import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.api.model.RestoreArchivedContentRequest; +import org.alfresco.rest.framework.Operation; import org.alfresco.rest.framework.WebApiDescription; +import org.alfresco.rest.framework.WebApiParam; +import org.alfresco.rest.framework.core.ResourceParameter; import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.rest.framework.webscripts.WithResponse; import org.alfresco.service.Experimental; import org.alfresco.util.PropertyCheck; import org.springframework.beans.factory.InitializingBean; @@ -61,10 +67,10 @@ public class NodeStorageInfoRelation implements RelationshipResourceAction.ReadB description = "Retrieves storage properties for given node's content", successStatus = HttpServletResponse.SC_OK) @Override - public ContentStorageInfo readById(String entityResourceId, String id, Parameters parameters) + public ContentStorageInfo readById(String nodeId, String contentPropName, Parameters parameters) throws RelationshipResourceNotFoundException { - return storageInformation.getStorageInfo(entityResourceId, id, parameters); + return storageInformation.getStorageInfo(nodeId, contentPropName, parameters); } @Override @@ -72,4 +78,44 @@ public class NodeStorageInfoRelation implements RelationshipResourceAction.ReadB { PropertyCheck.mandatory(this, "storageInformation", storageInformation); } + + @Experimental + @Operation("archive") + @WebApiParam(name = "archiveContentRequest", title = "Request for archive content", + description = "Optional parameters for archive content", kind = ResourceParameter.KIND.HTTP_BODY_OBJECT) + @WebApiDescription(title = "Request send content to archive", + description = "Submits a request to send content to archive", + successStatus = HttpServletResponse.SC_OK) + public void requestArchiveContent(String nodeId, String contentPropName, ArchiveContentRequest archiveContentRequest, Parameters parameters, + WithResponse withResponse) + { + final boolean result = storageInformation.requestArchiveContent(nodeId, contentPropName, archiveContentRequest); + if (result) + { + withResponse.setStatus(HttpServletResponse.SC_OK); + } else + { + withResponse.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + } + } + + @Experimental + @Operation("archive-restore") + @WebApiParam(name = "restoreArchivedContentRequest", title = "Request for restore content from archive", + description = "Optional parameters for restore content from archive", kind = ResourceParameter.KIND.HTTP_BODY_OBJECT) + @WebApiDescription(title = "Request restore content from archive", + description = "Submits a request to restore content from archive", + successStatus = HttpServletResponse.SC_ACCEPTED) + public void requestRestoreContentFromArchive(String nodeId, String contentPropName, RestoreArchivedContentRequest restoreArchivedContentRequest, + Parameters parameters, WithResponse withResponse) + { + final boolean result = storageInformation.requestRestoreContentFromArchive(nodeId, contentPropName, restoreArchivedContentRequest); + if (result) + { + withResponse.setStatus(HttpServletResponse.SC_ACCEPTED); + } else + { + withResponse.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + } + } } diff --git a/remote-api/src/test/java/org/alfresco/AppContextExtraTestSuite.java b/remote-api/src/test/java/org/alfresco/AppContextExtraTestSuite.java index 2452955e0e..318b398a7c 100644 --- a/remote-api/src/test/java/org/alfresco/AppContextExtraTestSuite.java +++ b/remote-api/src/test/java/org/alfresco/AppContextExtraTestSuite.java @@ -47,6 +47,8 @@ import org.junit.runners.Suite; org.alfresco.repo.webdav.RenameShuffleDetectionTest.class, org.alfresco.repo.webdav.WebDAVHelperTest.class, org.alfresco.repo.webdav.WebDAVLockServiceImplTest.class, + org.alfresco.rest.api.impl.ContentStorageInformationImplTest.class, + org.alfresco.rest.api.nodes.NodeStorageInfoRelationTest.class, org.alfresco.rest.api.search.ResultMapperTests.class, org.alfresco.rest.api.search.SearchApiWebscriptTests.class, org.alfresco.rest.api.search.SearchMapperTests.class, diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java index bddec6f0ca..47d67aa3be 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java @@ -26,26 +26,39 @@ package org.alfresco.rest.api.impl; +import org.alfresco.repo.content.ContentRestoreParams; +import org.alfresco.rest.api.model.ArchiveContentRequest; import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.api.model.RestoreArchivedContentRequest; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.NamespaceService; -import org.junit.Assert; +import org.alfresco.service.namespace.QName; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Map; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + @RunWith(MockitoJUnitRunner.class) public class ContentStorageInformationImplTest { + private static final String DUMMY_NODE_ID = "dummy-node-id"; + private static final String CONTENT_PROP_NAME = "cm:content"; + private static final String STANDARD_PRIORITY = "Standard"; + @Mock private ContentService contentService; @Mock @@ -57,40 +70,132 @@ public class ContentStorageInformationImplTest @Test public void shouldReturnStorageInfoResponseWithNonEmptyStorageProps() { - - final String nodeId = "dummy-node-id"; - final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); - final String contentPropName = "cm:content"; + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); final Map storageProps = Map.of("x-amz-storage-class", "INTELLIGENT_TIERING", "x-alf-archived", "false"); - Mockito.when(contentService.getStorageProperties(Mockito.eq(nodeRef), Mockito.any())).thenReturn(storageProps); - Mockito.when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)) - .thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); - Mockito.when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) + when(contentService.getStorageProperties(eq(nodeRef), any())).thenReturn(storageProps); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) .thenReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX)); - final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(nodeId, contentPropName, null); + final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(DUMMY_NODE_ID, CONTENT_PROP_NAME, null); - Assert.assertEquals(storageProps, storageInfo.getStorageProperties()); - Assert.assertEquals(storageInfo.getId(), contentPropName); + assertEquals(storageProps, storageInfo.getStorageProperties()); + assertEquals(CONTENT_PROP_NAME, storageInfo.getId()); } @Test public void shouldReturnStorageInfoResponseWithEmptyStorageProps() { - final String nodeId = "dummy-node-id"; - final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); - final String contentPropName = "cm:content"; + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); - Mockito.when(contentService.getStorageProperties(Mockito.eq(nodeRef), Mockito.any())).thenCallRealMethod(); - Mockito.when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)) - .thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); - Mockito.when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) + when(contentService.getStorageProperties(eq(nodeRef), any())).thenCallRealMethod(); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) .thenReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX)); - final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(nodeId, contentPropName, null); + final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(DUMMY_NODE_ID, CONTENT_PROP_NAME, null); - Assert.assertEquals(Collections.emptyMap(), storageInfo.getStorageProperties()); - Assert.assertEquals(storageInfo.getId(), contentPropName); + assertEquals(Collections.emptyMap(), storageInfo.getStorageProperties()); + assertEquals(CONTENT_PROP_NAME, storageInfo.getId()); + } + + @Test + public void shouldSucceedOnArchiveContent() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map archiveProps = Collections.emptyMap(); + final ArchiveContentRequest archiveParamsRequest = new ArchiveContentRequest(); + archiveParamsRequest.setArchiveParams(archiveProps); + final boolean expectedResult = true; + + when(contentService.requestSendContentToArchive(eq(nodeRef), any(QName.class), eq(archiveProps))).thenReturn(expectedResult); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + final boolean requestArchiveContent = objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveParamsRequest); + + assertEquals(expectedResult, requestArchiveContent); + } + + @Test + public void shouldNotSucceedOnArchiveContent() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map archiveProps = Collections.emptyMap(); + final ArchiveContentRequest archiveParamsRequest = new ArchiveContentRequest(); + archiveParamsRequest.setArchiveParams(archiveProps); + final boolean expectedResult = false; + + when(contentService.requestSendContentToArchive(eq(nodeRef), any(QName.class), eq(archiveProps))).thenReturn(expectedResult); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + final boolean requestArchiveContent = objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveParamsRequest); + + assertEquals(expectedResult, requestArchiveContent); + } + + @Test + public void shouldThrowExceptionOnArchiveContent() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map archiveProps = Collections.emptyMap(); + final ArchiveContentRequest archiveParamsRequest = new ArchiveContentRequest(); + archiveParamsRequest.setArchiveParams(archiveProps); + + when(contentService.requestSendContentToArchive(eq(nodeRef), any(QName.class), eq(archiveProps))).thenCallRealMethod(); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + assertThrows(UnsupportedOperationException.class, + () -> objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveParamsRequest)); + } + + @Test + public void shouldSucceedOnRestoreContentFromArchive() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map restoreParams = Map.of(ContentRestoreParams.RESTORE_PRIORITY.name(), STANDARD_PRIORITY); + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + restoreArchivedContentRequest.setRestorePriority(STANDARD_PRIORITY); + final boolean expectedResult = true; + + when(contentService.requestRestoreContentFromArchive(eq(nodeRef), any(QName.class), eq(restoreParams))).thenReturn(expectedResult); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + final boolean requestArchiveContent = objectUnderTest.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest); + + assertEquals(expectedResult, requestArchiveContent); + } + + @Test + public void shouldNotSucceedOnRestoreContentFromArchive() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map restoreParams = Map.of(ContentRestoreParams.RESTORE_PRIORITY.name(), STANDARD_PRIORITY); + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + restoreArchivedContentRequest.setRestorePriority(STANDARD_PRIORITY); + final boolean expectedResult = false; + + when(contentService.requestRestoreContentFromArchive(eq(nodeRef), any(QName.class), eq(restoreParams))).thenReturn(expectedResult); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + final boolean requestArchiveContent = objectUnderTest.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest); + + assertEquals(expectedResult, requestArchiveContent); + } + + @Test + public void shouldThrowExceptionRestoreContentFromArchive() + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID); + final Map restoreParams = Map.of(ContentRestoreParams.RESTORE_PRIORITY.name(), STANDARD_PRIORITY); + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + restoreArchivedContentRequest.setRestorePriority(STANDARD_PRIORITY); + final boolean expectedResult = false; + + when(contentService.requestRestoreContentFromArchive(eq(nodeRef), any(QName.class), eq(restoreParams))).thenCallRealMethod(); + when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + + assertThrows(UnsupportedOperationException.class, + () -> objectUnderTest.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest)); } } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelationTest.java b/remote-api/src/test/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelationTest.java new file mode 100644 index 0000000000..1ca31c77c6 --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelationTest.java @@ -0,0 +1,158 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.nodes; + +import junit.framework.TestCase; +import org.alfresco.rest.api.ContentStorageInformation; +import org.alfresco.rest.api.model.ArchiveContentRequest; +import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.api.model.RestoreArchivedContentRequest; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.rest.framework.webscripts.WithResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class NodeStorageInfoRelationTest extends TestCase +{ + private static final String DUMMY_NODE_ID = "dummy-node-id"; + private static final String CONTENT_PROP_NAME = "cm:content"; + + @Mock + private ContentStorageInformation storageInformation; + @Mock + private Parameters params; + @Mock + private WithResponse withResponse; + + @InjectMocks + private NodeStorageInfoRelation objectUnderTest; + + + @Test + public void shouldProperlyReturnStorageInfo() + { + final ContentStorageInfo expectedStorageInfo = new ContentStorageInfo(); + final Map storageProps = Map.of("x-amz-storage-class", "INTELLIGENT_TIERING", "x-alf-archived", "false"); + expectedStorageInfo.setStorageProperties(storageProps); + expectedStorageInfo.setId(CONTENT_PROP_NAME); + + when(storageInformation.getStorageInfo(DUMMY_NODE_ID, CONTENT_PROP_NAME, params)).thenReturn(expectedStorageInfo); + + final ContentStorageInfo storageInfo = objectUnderTest.readById(DUMMY_NODE_ID, CONTENT_PROP_NAME, params); + + Assert.assertEquals(storageProps, storageInfo.getStorageProperties()); + Assert.assertEquals(CONTENT_PROP_NAME, storageInfo.getId()); + } + + @Test + public void shouldProperlyRequestArchiveContent() + { + final ArchiveContentRequest archiveContentRequest = new ArchiveContentRequest(); + when(storageInformation.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest)).thenReturn(true); + + objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest, params, withResponse); + + verify(withResponse, times(1)).setStatus(HttpServletResponse.SC_OK); + } + + @Test + public void shouldFailsOnRequestArchiveContent() + { + final ArchiveContentRequest archiveContentRequest = new ArchiveContentRequest(); + when(storageInformation.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest)).thenReturn(false); + + objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest, params, withResponse); + + verify(withResponse, times(1)).setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + } + + @Test + public void shouldThrowExceptionOnRequestArchiveContent() + { + final ArchiveContentRequest archiveContentRequest = new ArchiveContentRequest(); + when(storageInformation.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest)) + .thenThrow(UnsupportedOperationException.class); + + assertThrows(UnsupportedOperationException.class, + () -> objectUnderTest.requestArchiveContent(DUMMY_NODE_ID, CONTENT_PROP_NAME, archiveContentRequest, params, withResponse)); + verify(withResponse, never()).setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + verify(withResponse, never()).setStatus(HttpServletResponse.SC_OK); + } + + @Test + public void shouldProperlyRequestRestoreContentFromArchive() + { + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + when(storageInformation.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest)) + .thenReturn(true); + + objectUnderTest + .requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest, params, withResponse); + + verify(withResponse, times(1)).setStatus(HttpServletResponse.SC_ACCEPTED); + } + + @Test + public void shouldFailsOnRequestRestoreContentFromArchive() + { + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + when(storageInformation.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest)) + .thenReturn(false); + + objectUnderTest + .requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest, params, withResponse); + + verify(withResponse, times(1)).setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + } + + @Test + public void shouldThrowExceptionOnRequestRestoreContentFromArchive() + { + final RestoreArchivedContentRequest restoreArchivedContentRequest = new RestoreArchivedContentRequest(); + when(storageInformation.requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest)) + .thenThrow(UnsupportedOperationException.class); + + assertThrows(UnsupportedOperationException.class, () -> objectUnderTest + .requestRestoreContentFromArchive(DUMMY_NODE_ID, CONTENT_PROP_NAME, restoreArchivedContentRequest, params, withResponse)); + verify(withResponse, never()).setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + verify(withResponse, never()).setStatus(HttpServletResponse.SC_ACCEPTED); + } +} diff --git a/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java b/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java index 4fdc8e21f2..c39a29dfc1 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java @@ -278,7 +278,7 @@ public interface ContentService * @return true when request successful, false when unsuccessful. * @throws UnsupportedOperationException when method not implemented */ - @Auditable(parameters = {"nodeRef", "propertyQName"}) + @Auditable(parameters = {"nodeRef", "propertyQName", "archiveParams"}) @Experimental default boolean requestSendContentToArchive(NodeRef nodeRef, QName propertyQName, Map archiveParams)