diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/ExportAPI.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/ExportAPI.java
new file mode 100644
index 0000000000..12d322fdb2
--- /dev/null
+++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/ExportAPI.java
@@ -0,0 +1,103 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * 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.v0;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.alfresco.rest.core.v0.BaseAPI;
+import org.apache.http.HttpResponse;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.springframework.stereotype.Component;
+
+/**
+ * Methods to make API requests using v0 API for Exporting Items
+ *
+ * @author Shubham Jain
+ * @since 7.1.0
+ */
+
+@Component
+public class ExportAPI extends BaseAPI
+{
+ /**
+ * The URI to export an item
+ */
+ private static final String EXPORT_API = "{0}rma/admin/export";
+
+ /**
+ * Export a single Record/Record Folder/Record Category using V0 Export API
+ *
+ * @param user User performing the export
+ * @param password User's Password
+ * @param expectedStatusCode Expected Response Code
+ * @param nodeID ID of the Node(Record/RecordFolder) to be exported
+ * @return HTTP Response
+ */
+ public HttpResponse exportRMNode(String user, String password, int expectedStatusCode, String nodeID)
+ {
+ return export(user, password, expectedStatusCode, Collections.singletonList(getNodeRefSpacesStore() + nodeID));
+ }
+
+ /**
+ * Export a list of nodes using V0 Export API
+ *
+ * @param user User performing the export
+ * @param password User's Password
+ * @param expectedStatusCode Expected Response Code
+ * @param nodeIDList List of the nodes to be exported
+ * @return HTTP Response
+ */
+ public HttpResponse exportRMNodes(String user, String password, int expectedStatusCode, List nodeIDList)
+ {
+
+ List nodeRefs =
+ nodeIDList.stream().map(nodeID -> getNodeRefSpacesStore() + nodeID).collect(Collectors.toList());
+
+ return export(user, password, expectedStatusCode, nodeRefs);
+ }
+
+ /**
+ * Export API function to perform Export Operation on items with given noderefs using V0 Export Rest API
+ *
+ * @param user User performing the export
+ * @param password User's Password
+ * @param expectedStatusCode Expected Response Code
+ * @param nodeRefs list of the noderefs for the items to be exported
+ * @return Rest API Post Request
+ */
+ public HttpResponse export(String user, String password, int expectedStatusCode, List nodeRefs)
+ {
+ final JSONObject requestParams = new JSONObject();
+
+ requestParams.put("nodeRefs", new JSONArray(nodeRefs));
+
+ return doPostJsonRequest(user, password, expectedStatusCode, requestParams, EXPORT_API);
+ }
+}
diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ExportRecordsTests.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ExportRecordsTests.java
new file mode 100644
index 0000000000..d3e7bde53f
--- /dev/null
+++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ExportRecordsTests.java
@@ -0,0 +1,136 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * 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.rm.community.records;
+
+import static java.util.Arrays.asList;
+
+import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.CONTENT_TYPE;
+import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createTempFile;
+import static org.alfresco.utility.data.RandomData.getRandomName;
+import static org.alfresco.utility.report.log.Step.STEP;
+import static org.apache.http.HttpStatus.SC_OK;
+
+import org.alfresco.rest.rm.community.base.BaseRMRestTest;
+import org.alfresco.rest.rm.community.model.record.Record;
+import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
+import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
+import org.alfresco.rest.v0.ExportAPI;
+import org.alfresco.test.AlfrescoTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * This class contains tests for testing the Export functionality on RM site
+ *
+ * @author Shubham Jain
+ * @since 7.1.0
+ */
+public class ExportRecordsTests extends BaseRMRestTest
+{
+ private RecordCategory rootCategory;
+
+ private RecordCategoryChild recordFolder;
+
+ @Autowired
+ private ExportAPI exportAPI;
+
+ @BeforeClass (alwaysRun = true)
+ public void exportRecordsTestsBeforeClass()
+ {
+ STEP("Create root level category");
+ rootCategory = createRootCategory(getRandomName("Category"));
+
+ STEP("Create the record folder inside the rootCategory");
+ recordFolder = createRecordFolder(rootCategory.getId(), getRandomName("Folder"));
+
+ }
+
+ @DataProvider (name = "CreateRMNodes")
+ public Object[][] getRMNodeID()
+ {
+ return new String[][] {
+ { createRecord("Record_4MB", 4).getId() },
+ { createRecord("Record_200MB", 200).getId() },
+ { recordFolder.getId() }
+ };
+ }
+
+ /**
+ * Given a record with size > 4 MB
+ * When I export the record using API
+ * Then the request is successful
+ */
+ @Test (description = "Testing the RM Export functionality for records of size >4MB and Record " +
+ "Folder containing records with size >4MB",
+ dataProvider = "CreateRMNodes")
+ @AlfrescoTest (jira = "APPS-986")
+ public void exportRMNodeTest(String nodeID)
+ {
+ STEP("Export the created record/record folder with size greater than 4 MB and verifying the expected response" +
+ " code");
+ exportAPI.exportRMNode(getAdminUser().getUsername(), getAdminUser().getPassword(), SC_OK, nodeID);
+ }
+
+ /**
+ * I would change this to
+ * Given a list of records with a size > 4MB
+ * When I export the records
+ * Then the request is succesfull
+ */
+ @Test (description = "Testing the RM Export functionality using API for a list of Records at once with " +
+ "collective size of more than 4MB")
+ public void exportRecordsTest()
+ {
+ STEP("Export all the created records at once and verifying the expected response code");
+ exportAPI.exportRMNodes(getAdminUser().getUsername(), getAdminUser().getPassword(),
+ SC_OK, asList(createRecord("Record_2MB", 2).getId(), createRecord("Record_3MB", 3).getId()));
+ }
+
+ /**
+ * Create a Record with a specific size in RM Site inside already created Record Folder
+ *
+ * @param recordName Name of the record to be created
+ * @param sizeInMegaBytes Size of the record to be created in MegaBytes
+ * @return Created record with defined size
+ */
+ public Record createRecord(String recordName, int sizeInMegaBytes)
+ {
+ return getRestAPIFactory().getRecordFolderAPI().createRecord(Record.builder().name(recordName)
+ .nodeType(CONTENT_TYPE).build(), recordFolder.getId(),
+ createTempFile("TempFile", sizeInMegaBytes));
+ }
+
+ @AfterClass (alwaysRun = true)
+ public void exportRecordsTestsAfter()
+ {
+ STEP("Delete the created rootCategory along with corresponding record folders/records present in it");
+ getRestAPIFactory().getRecordCategoryAPI().deleteRecordCategory(rootCategory.getId());
+ }
+}
diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/FilePlanComponentsUtil.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/FilePlanComponentsUtil.java
index 56dd5da2bb..fe91643217 100644
--- a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/FilePlanComponentsUtil.java
+++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/FilePlanComponentsUtil.java
@@ -41,6 +41,7 @@ import static org.testng.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
+import java.io.RandomAccessFile;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.record.RecordProperties;
@@ -66,13 +67,19 @@ public class FilePlanComponentsUtil
// Intentionally blank
}
- /** Name of the image resource file to be used for records body */
+ /**
+ * Name of the image resource file to be used for records body
+ */
public static final String IMAGE_FILE = "money.JPG";
- /** Title prefix for record category children */
+ /**
+ * Title prefix for record category children
+ */
public static final String TITLE_PREFIX = "Title for ";
- /** Description prefix for record category children */
+ /**
+ * Description prefix for record category children
+ */
public static final String DESCRIPTION_PREFIX = "This is the description for";
@@ -87,7 +94,7 @@ public class FilePlanComponentsUtil
}
/**
- * Creates a record model with the given type and a random name (with "Record " prefix)
+ * Creates a record model with the given type and a random name (with "Record " prefix)
*
* @param nodeType The node type
* @return The {@link Record} with for the given node type
@@ -95,9 +102,9 @@ public class FilePlanComponentsUtil
private static Record createRecordModel(String nodeType)
{
return Record.builder()
- .name("Record " + getRandomAlphanumeric())
- .nodeType(nodeType)
- .build();
+ .name("Record " + getRandomAlphanumeric())
+ .nodeType(nodeType)
+ .build();
}
/**
@@ -133,22 +140,22 @@ public class FilePlanComponentsUtil
/**
* Creates an unfiled records container child record model with the given name and type
*
- * @param name The name of the unfiled records container child
+ * @param name The name of the unfiled records container child
* @param nodeType The type of the record category child
* @return The {@link UnfiledContainerChild} with the given details
*/
public static UnfiledContainerChild createUnfiledContainerChildRecordModel(String name, String nodeType)
{
return UnfiledContainerChild.builder()
- .name(name)
- .nodeType(nodeType)
- .build();
+ .name(name)
+ .nodeType(nodeType)
+ .build();
}
/**
* Creates a nonElectronic container child record model with all available properties for the non electronic records
*
- * @param name The name of the unfiled records container child
+ * @param name The name of the unfiled records container child
* @param nodeType The type of the record category child
* @return The {@link UnfiledContainerChild} with the given details
*/
@@ -156,19 +163,19 @@ public class FilePlanComponentsUtil
String shelf, String storageLocation, Integer numberOfCopies, Integer physicalSize)
{
return UnfiledContainerChild.builder()
- .name(name)
- .nodeType(NON_ELECTRONIC_RECORD_TYPE)
- .properties(UnfiledContainerChildProperties.builder()
- .title(title)
- .description(description)
- .box(box)
- .file(file)
- .shelf(shelf)
- .storageLocation(storageLocation)
- .numberOfCopies(numberOfCopies)
- .physicalSize(physicalSize)
- .build())
- .build();
+ .name(name)
+ .nodeType(NON_ELECTRONIC_RECORD_TYPE)
+ .properties(UnfiledContainerChildProperties.builder()
+ .title(title)
+ .description(description)
+ .box(box)
+ .file(file)
+ .shelf(shelf)
+ .storageLocation(storageLocation)
+ .numberOfCopies(numberOfCopies)
+ .physicalSize(physicalSize)
+ .build())
+ .build();
}
/**
@@ -190,110 +197,110 @@ public class FilePlanComponentsUtil
String shelf, String storageLocation, Integer numberOfCopies, Integer physicalSize)
{
return Record.builder()
- .name(name)
- .nodeType(NON_ELECTRONIC_RECORD_TYPE)
- .properties(RecordProperties.builder()
- .title(title)
- .description(description)
- .box(box)
- .file(file)
- .shelf(shelf)
- .storageLocation(storageLocation)
- .numberOfCopies(numberOfCopies)
- .physicalSize(physicalSize)
- .build())
- .build();
+ .name(name)
+ .nodeType(NON_ELECTRONIC_RECORD_TYPE)
+ .properties(RecordProperties.builder()
+ .title(title)
+ .description(description)
+ .box(box)
+ .file(file)
+ .shelf(shelf)
+ .storageLocation(storageLocation)
+ .numberOfCopies(numberOfCopies)
+ .physicalSize(physicalSize)
+ .build())
+ .build();
}
/**
* Creates a record model with the given name, description and title
*
- * @param name The name of the record
+ * @param name The name of the record
* @param description The description of the record
- * @param title The title of the record
+ * @param title The title of the record
* @return The {@link Record} with the given details
*/
public static Record createRecordModel(String name, String description, String title)
{
return Record.builder()
- .name(name)
- .properties(RecordProperties.builder()
- .description(description)
- .title(title)
- .build())
- .build();
+ .name(name)
+ .properties(RecordProperties.builder()
+ .description(description)
+ .title(title)
+ .build())
+ .build();
}
/**
* Creates a record category child model with the given name and type
*
- * @param name The name of the record category child
+ * @param name The name of the record category child
* @param nodeType The type of the record category child
* @return The {@link RecordCategoryChild} with the given details
*/
public static RecordCategoryChild createRecordCategoryChildModel(String name, String nodeType)
{
return RecordCategoryChild.builder()
- .name(name)
- .nodeType(nodeType)
- .properties(RecordCategoryChildProperties.builder()
- .title(TITLE_PREFIX + name)
- .build())
- .build();
+ .name(name)
+ .nodeType(nodeType)
+ .properties(RecordCategoryChildProperties.builder()
+ .title(TITLE_PREFIX + name)
+ .build())
+ .build();
}
/**
* Creates a record category model with the given name and title
*
- * @param name The name of the record category
+ * @param name The name of the record category
* @param title The title of the record category
* @return The {@link RecordCategory} with the given details
*/
public static RecordCategory createRecordCategoryModel(String name, String title)
{
return RecordCategory.builder()
- .name(name)
- .nodeType(RECORD_CATEGORY_TYPE)
- .properties(RecordCategoryProperties.builder()
- .title(title)
- .build())
- .build();
+ .name(name)
+ .nodeType(RECORD_CATEGORY_TYPE)
+ .properties(RecordCategoryProperties.builder()
+ .title(title)
+ .build())
+ .build();
}
/**
* Creates a record folder model with the given name and title
*
- * @param name The name of the record folder
+ * @param name The name of the record folder
* @param title The title of the record folder
* @return The {@link RecordFolder} with the given details
*/
public static RecordFolder createRecordFolderModel(String name, String title)
{
return RecordFolder.builder()
- .name(name)
- .nodeType(RECORD_FOLDER_TYPE)
- .properties(RecordFolderProperties.builder()
- .title(title)
- .build())
- .build();
+ .name(name)
+ .nodeType(RECORD_FOLDER_TYPE)
+ .properties(RecordFolderProperties.builder()
+ .title(title)
+ .build())
+ .build();
}
/**
* Creates an unfiled records container child model with the given name and type
*
- * @param name The name of the unfiled records container child
+ * @param name The name of the unfiled records container child
* @param nodeType The type of the record category child
* @return The {@link UnfiledContainerChild} with the given details
*/
public static UnfiledContainerChild createUnfiledContainerChildModel(String name, String nodeType)
{
return UnfiledContainerChild.builder()
- .name(name)
- .nodeType(nodeType)
- .properties(UnfiledContainerChildProperties.builder()
- .title(TITLE_PREFIX + name)
- .build())
- .build();
+ .name(name)
+ .nodeType(nodeType)
+ .properties(UnfiledContainerChildProperties.builder()
+ .title(TITLE_PREFIX + name)
+ .build())
+ .build();
}
/**
@@ -324,6 +331,32 @@ public class FilePlanComponentsUtil
}
}
+ /**
+ * Method to create a temporary file with specific size
+ *
+ * @param name file name
+ * @param sizeInMegaBytes size
+ * @return temporary file
+ */
+ public static File createTempFile(final String name, long sizeInMegaBytes)
+ {
+ try
+ {
+ // Create file
+ final File file = File.createTempFile(name, ".txt");
+
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.setLength(sizeInMegaBytes * 1024 * 1024);
+ raf.close();
+
+ return file;
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException("Unable to create test file.", exception);
+ }
+ }
+
/**
* Helper method to verify all properties of a nonElectronic record
*