diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/audit/AuditEvents.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/audit/AuditEvents.java index 31d05ecece..37e89ee91d 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/audit/AuditEvents.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/audit/AuditEvents.java @@ -41,7 +41,11 @@ public enum AuditEvents DELETE_USER_GROUP("Delete User Group", "Delete User Group"), ADD_TO_USER_GROUP("Add To User Group", "Add To User Group"), REMOVE_FROM_USER_GROUP("Remove From User Group", "Remove From User Group"), - LOGIN_UNSUCCESSFUL("Login.Failure", "Login Unsuccessful"); + LOGIN_UNSUCCESSFUL("Login.Failure", "Login Unsuccessful"), + CREATE_HOLD("Create Hold", "Create Hold"), + DELETE_HOLD("Delete Hold", "Delete Hold"), + ADD_TO_HOLD("Add To Hold", "Add To Hold"), + REMOVE_FROM_HOLD("Remove From Hold", "Remove From Hold"); /** event audited */ public final String event; diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java new file mode 100644 index 0000000000..da0c855b69 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java @@ -0,0 +1,302 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.community.audit; + +import static java.util.Arrays.asList; + +import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION; +import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON; +import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_HOLD; +import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix; +import static org.alfresco.utility.data.RandomData.getRandomName; +import static org.alfresco.utility.report.log.Step.STEP; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.fail; + +import java.util.Collections; +import java.util.List; + +import org.alfresco.dataprep.CMISUtil; +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.audit.AuditEntry; +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.rm.community.model.user.UserPermissions; +import org.alfresco.rest.rm.community.model.user.UserRoles; +import org.alfresco.rest.v0.HoldsAPI; +import org.alfresco.rest.v0.RMAuditAPI; +import org.alfresco.rest.v0.service.RoleService; +import org.alfresco.test.AlfrescoTest; +import org.alfresco.utility.constants.UserRole; +import org.alfresco.utility.model.FileModel; +import org.alfresco.utility.model.SiteModel; +import org.alfresco.utility.model.UserModel; +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 the tests that check the add to hold event is audited + * + * @author Claudia Agache + * @since 3.3 + */ +@AlfrescoTest (jira = "RM-6859") +public class AuditAddToHoldTests extends BaseRMRestTest +{ + private final String PREFIX = generateTestPrefix(AuditAddToHoldTests.class); + private final String HOLD1 = PREFIX + "hold1"; + private final String HOLD2 = PREFIX + "hold2"; + + @Autowired + private RMAuditAPI rmAuditAPI; + @Autowired + private HoldsAPI holdsAPI; + @Autowired + private RoleService roleService; + + private UserModel rmAdmin, rmManagerNoRightsOnHold, rmManagerNoRightsOnNode; + private SiteModel privateSite; + private RecordCategory recordCategory; + private RecordCategoryChild recordFolder; + private List auditEntries; + private List holdsList = asList(HOLD1, HOLD2); + private AuditEntry auditEntry; + + @BeforeClass (alwaysRun = true) + public void preconditionForAuditAddToHoldTests() throws Exception + { + STEP("Create 2 holds."); + String hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), + getAdminUser().getPassword(), HOLD1, HOLD_REASON, HOLD_DESCRIPTION); + holdsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Create a new record category with a record folder."); + recordCategory = createRootCategory(getRandomName("recordCategory")); + recordFolder = createRecordFolder(recordCategory.getId(), PREFIX + "recFolder"); + + STEP("Create an user with full rights to add content to a hold."); + rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId); + + STEP("Create a collaboration site."); + privateSite = dataSite.usingUser(rmAdmin).createPrivateRandomSite(); + + STEP("Create users without rights to add content to a hold."); + rmManagerNoRightsOnHold = roleService.createUserWithSiteRoleRMRoleAndPermission(privateSite, + UserRole.SiteManager, recordCategory.getId(), UserRoles.ROLE_RM_MANAGER, UserPermissions.PERMISSION_FILING); + rmManagerNoRightsOnNode = roleService.createUserWithRMRoleAndRMNodePermission(UserRoles.ROLE_RM_MANAGER.roleId, + hold1NodeRef, UserPermissions.PERMISSION_FILING); + } + + /** + * Data provider with valid nodes that can be added to a hold + * + * @return the node id and the node name + * @throws Exception + */ + @DataProvider (name = "validNodesForAddToHold") + public Object[][] getValidNodesForAddToHold() throws Exception + { + FileModel contentToBeAdded = dataContent.usingAdmin().usingSite(privateSite) + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + RecordCategoryChild recordFolderToBeAdded = createRecordFolder(recordCategory.getId(), PREFIX + "recFolderToBeAdded"); + Record recordToBeAdded = createElectronicRecord(recordFolder.getId(), PREFIX + "record"); + + return new String[][] + { + // a record folder + { recordFolderToBeAdded.getId(), recordFolderToBeAdded.getName() }, + // a record + { recordToBeAdded.getId(), recordToBeAdded.getName() }, + //an active content, + { contentToBeAdded.getNodeRefWithoutVersion(), contentToBeAdded.getName() } + }; + } + + /** + * Data provider with invalid users that can not add content to a hold + * + * @return the userModel + */ + @DataProvider (name = "invalidUsersForAddToHold") + public Object[][] getInvalidUsersForAddToHold() + { + return new UserModel[][] + { + { rmManagerNoRightsOnHold }, + { rmManagerNoRightsOnNode } + }; + } + + /** + * Given a document/record/record folder is added to a hold + * When I view the audit log + * Then an entry has been created in the audit log that contains the following: + * name of the hold + * name of the document/record/record folder added + * user who added the content + * date the content was added + */ + @Test (dataProvider = "validNodesForAddToHold") + public void addToHoldEventIsAudited(String nodeId, String nodeName) + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Add node to hold."); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD1); + + STEP("Get the list of audit entries for the add to hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + ADD_TO_HOLD.event); + + STEP("Check the audit log contains the entry for the add to hold."); + assertFalse("The list of events should contain Add To Hold entry ", auditEntries.isEmpty()); + auditEntry = auditEntries.get(0); + assertTrue("The list of events is not filtered by Add To Hold", + auditEntry.getEvent().equals(ADD_TO_HOLD.eventDisplayName)); + assertTrue("The hold name value for the add to hold is not audited.", + auditEntry.getNodeName().equals(HOLD1)); + assertTrue("The user who added the node to the hold is not audited.", + auditEntry.getUserName().equals(rmAdmin.getUsername())); + assertFalse("The date when the add to hold occurred is not audited.", auditEntry.getTimestamp().isEmpty()); + //TODO check content name + } + + /** + * Given an unsuccessful add to hold action + * When I view the audit log + * Then the add to hold event isn't audited + */ + @Test + public void unsuccessfulAddToHoldIsNotAudited() throws Exception + { + STEP("Create a new record"); + Record recordToBeAdded = createElectronicRecord(recordFolder.getId(), PREFIX + "record"); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Try to add the record to a hold by an user with no rights."); + try + { + holdsAPI.addItemToHold(rmManagerNoRightsOnHold.getUsername(), rmManagerNoRightsOnHold.getPassword(), + recordToBeAdded.getId(), HOLD1); + fail("Add to hold action was successful."); + } + catch (Exception e) + { + STEP("Get the list of audit entries for the add to hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + ADD_TO_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the unsuccessful add to hold."); + assertTrue("The list of events should not contain Add to Hold entry ", auditEntries.isEmpty()); + } + } + + /** + * Given a not empty record folder is added to a hold + * When I view the audit log + * Then only an entry has been created in the audit log for the record folder added + */ + @Test + public void addToHoldIsNotAuditedForRecordFolderChildren() throws Exception + { + STEP("Create a new record folder with a record inside"); + RecordCategoryChild notEmptyRecFolder = createRecordFolder(recordCategory.getId(), PREFIX + "notEmptyRecFolder"); + createElectronicRecord(notEmptyRecFolder.getId(), PREFIX + "record"); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Add record folder to hold."); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1); + + STEP("Get the list of audit entries for the add to hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + ADD_TO_HOLD.event); + + STEP("Check the audit log contains only an entry for add to hold."); + assertEquals("The list of events should not contain Add to Hold entry for the record", 1, auditEntries.size()); + //TODO check content name + } + + /** + * Given a document/record/record folder is added to multiple holds + * When I view the audit log + * Then multiple entries have been created in the audit log for each add to hold event + */ + @Test + public void addToHoldIsAuditedInBulkAddition() throws Exception + { + STEP("Create a new record"); + Record recordToBeAdded = createElectronicRecord(recordFolder.getId(), PREFIX + "record"); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Add record to multiple holds."); + holdsAPI.addItemsToHolds(rmAdmin.getUsername(), rmAdmin.getPassword(), + Collections.singletonList(recordToBeAdded.getId()), holdsList); + + STEP("Get the list of audit entries for the add to hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + ADD_TO_HOLD.event); + + STEP("Check the audit log contains entries for both additions."); + assertEquals("The list of events should contain Add to Hold entries for both holds", 2, auditEntries.size()); + assertTrue("The hold name value for the first add to hold is not audited.", + auditEntries.stream().anyMatch(entry -> entry.getNodeName().equals(HOLD1))); + assertTrue("The hold name value for the second add to hold is not audited.", + auditEntries.stream().anyMatch(entry -> entry.getNodeName().equals(HOLD2))); + } + + /** + * Given a document/record/record folder is added to a hold + * When I view the audit log as an user with no Read permissions over the hold or the node + * Then the add to hold entry isn't visible + */ + @Test (dataProvider = "invalidUsersForAddToHold") + public void addToHoldAuditEntryNotVisible(UserModel user) + { + STEP("Create a new file"); + FileModel contentToBeAdded = dataContent.usingAdmin().usingSite(privateSite) + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Add file to hold."); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1); + + STEP("Get the list of audit entries for the add to hold event as an user with no Read permissions."); + auditEntries = rmAuditAPI.getRMAuditLog(user.getUsername(), user.getPassword(), 100, ADD_TO_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the add to hold event."); + assertTrue("The list of events should not contain Add to Hold entry ", auditEntries.isEmpty()); + } + + @AfterClass (alwaysRun = true) + public void cleanUpAuditHoldTests() + { + holdsList.forEach(hold -> holdsAPI.deleteHold(getAdminUser().getUsername(), getAdminUser().getPassword(), hold)); + dataSite.usingAdmin().deleteSite(privateSite); + asList(rmAdmin, rmManagerNoRightsOnHold, rmManagerNoRightsOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user)); + getRestAPIFactory().getRecordCategoryAPI().deleteRecordCategory(recordCategory.getId()); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditCreateHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditCreateHoldTests.java new file mode 100644 index 0000000000..9ef62b20ee --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditCreateHoldTests.java @@ -0,0 +1,195 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.community.audit; + +import static java.util.Arrays.asList; + +import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION; +import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON; +import static org.alfresco.rest.rm.community.model.audit.AuditEvents.CREATE_HOLD; +import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix; +import static org.alfresco.utility.report.log.Step.STEP; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.List; + +import com.google.common.collect.ImmutableMap; + +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.audit.AuditEntry; +import org.alfresco.rest.rm.community.model.user.UserRoles; +import org.alfresco.rest.v0.HoldsAPI; +import org.alfresco.rest.v0.RMAuditAPI; +import org.alfresco.rest.v0.service.RoleService; +import org.alfresco.test.AlfrescoTest; +import org.alfresco.utility.model.UserModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * This class contains the tests that check the create hold event is audited + * + * @author Claudia Agache + * @since 3.3 + */ +@AlfrescoTest (jira = "RM-6859") +public class AuditCreateHoldTests extends BaseRMRestTest +{ + private final String PREFIX = generateTestPrefix(AuditCreateHoldTests.class); + private final String HOLD1 = PREFIX + "createHold"; + private final String HOLD2 = PREFIX + "createHold2"; + private final String HOLD3 = PREFIX + "createHold3"; + + @Autowired + private RMAuditAPI rmAuditAPI; + @Autowired + private HoldsAPI holdsAPI; + @Autowired + private RoleService roleService; + + private UserModel rmAdmin, rmManager; + private List auditEntries; + + @BeforeClass (alwaysRun = true) + public void preconditionForAuditCreateHoldTests() + { + STEP("Create test users."); + rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId); + rmManager = roleService.createUserWithRMRole(UserRoles.ROLE_RM_MANAGER.roleId); + } + + /** + * Given a new hold is created + * When I view the audit log + * Then an entry has been created in the audit log which contains the following: + * name of the hold + * reason for hold + * user who created the hold + * date the creation occurred + */ + @Test + public void createHoldEventIsAuditedForNewHold() + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD1, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Get the list of audit entries for the create hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + CREATE_HOLD.event); + + STEP("Check the audit log contains the entry for the created hold with the hold details."); + assertFalse("The list of events should contain Create Hold entry ", auditEntries.isEmpty()); + AuditEntry auditEntry = auditEntries.get(0); + assertTrue("The list of events is not filtered by Create Hold", + auditEntry.getEvent().equals(CREATE_HOLD.eventDisplayName)); + assertTrue("The hold name value for the hold created is not audited.", auditEntry.getNodeName().equals(HOLD1)); + assertTrue("The hold reason value for the hold created is not audited.", + auditEntry.getChangedValues().contains( + ImmutableMap.of("new", HOLD_REASON, "previous", "", "name", "Hold Reason"))); + assertTrue("The user who created the hold is not audited.", + auditEntry.getUserName().equals(rmAdmin.getUsername())); + assertFalse("The date when the hold creation occurred is not audited.", auditEntry.getTimestamp().isEmpty()); + } + + /** + * Given an unsuccessful create hold action + * When I view the audit log + * Then the create hold event isn't audited + */ + @Test + public void createHoldEventIsNotAuditedForExistingHold() + { + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Try to create again the same hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Get the list of audit entries for the create hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + CREATE_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the second create hold event."); + assertTrue("The list of events should not contain Create Hold entry ", auditEntries.isEmpty()); + } + + /** + * Given a new hold is created and then deleted + * When I view the audit log + * Then the create hold entry still contains the initial details + */ + @Test + public void createHoldAuditEntryIsNotLost() + { + final String holdName = PREFIX + "holdToBeDeleted"; + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Get the list of audit entries for the create hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + CREATE_HOLD.event); + + STEP("Delete the created hold."); + holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName); + + STEP("Get again the list of audit entries for the create hold event."); + List auditEntriesAfterDelete = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), + getAdminUser().getPassword(), 100, CREATE_HOLD.event); + + STEP("Check that the audit entry for the created hold didn't change after hold deletion."); + assertEquals("The list of events is not filtered by Create Hold", + auditEntries, auditEntriesAfterDelete); + } + + /** + * Given a new hold is created + * When I view the audit log as an user with no Read permissions over the created hold + * Then the create hold entry isn't visible + */ + @Test + public void createHoldAuditEntryNotVisible() + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD3, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Get the list of audit entries for the create hold event as an user with no Read permissions over the hold."); + auditEntries = rmAuditAPI.getRMAuditLog(rmManager.getUsername(), rmManager.getPassword(), 100, + CREATE_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the create hold event."); + assertTrue("The list of events should not contain Create Hold entry ", auditEntries.isEmpty()); + } + + @AfterClass (alwaysRun = true) + public void cleanUpAuditHoldTests() + { + asList(HOLD1, HOLD2, HOLD3).forEach(hold -> + holdsAPI.deleteHold(getAdminUser().getUsername(), getAdminUser().getPassword(), hold)); + asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user)); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditDeleteHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditDeleteHoldTests.java new file mode 100644 index 0000000000..fdbada737e --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditDeleteHoldTests.java @@ -0,0 +1,169 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.community.audit; + +import static java.util.Arrays.asList; + +import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION; +import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON; +import static org.alfresco.rest.rm.community.model.audit.AuditEvents.DELETE_HOLD; +import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix; +import static org.alfresco.utility.report.log.Step.STEP; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.fail; + +import java.util.List; + +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.audit.AuditEntry; +import org.alfresco.rest.rm.community.model.user.UserRoles; +import org.alfresco.rest.v0.HoldsAPI; +import org.alfresco.rest.v0.RMAuditAPI; +import org.alfresco.rest.v0.service.RoleService; +import org.alfresco.test.AlfrescoTest; +import org.alfresco.utility.model.UserModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * This class contains the tests that check the delete hold event is audited + * + * @author Claudia Agache + * @since 3.3 + */ +@AlfrescoTest (jira = "RM-6859") +public class AuditDeleteHoldTests extends BaseRMRestTest +{ + private final String PREFIX = generateTestPrefix(AuditDeleteHoldTests.class); + private final String HOLD = PREFIX + "holdToBeDeleted"; + private final String HOLD2 = PREFIX + "deleteHold"; + + @Autowired + private RMAuditAPI rmAuditAPI; + @Autowired + private HoldsAPI holdsAPI; + @Autowired + private RoleService roleService; + + private UserModel rmAdmin, rmManager; + private List auditEntries; + + @BeforeClass (alwaysRun = true) + public void preconditionForAuditDeleteHoldTests() + { + STEP("Create a new hold."); + holdsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Create 2 users with different permissions for the created hold."); + rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId); + rmManager = roleService.createUserWithRMRole(UserRoles.ROLE_RM_MANAGER.roleId); + } + + /** + * Given a hold is deleted + * When I view the audit log + * Then an entry has been created in the audit log which contains the following: + * name of the hold + * user who deleted the hold + * date the delete occurred + */ + @Test + public void deleteHoldEventIsAudited() + { + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Delete the created hold."); + holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2); + + STEP("Get the list of audit entries for the delete hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + DELETE_HOLD.event); + + STEP("Check the audit log contains the entry for the deleted hold with the hold details."); + assertFalse("The list of events should contain Delete Hold entry ", auditEntries.isEmpty()); + AuditEntry auditEntry = auditEntries.get(0); + assertTrue("The list of events is not filtered by Delete Hold", + auditEntry.getEvent().equals(DELETE_HOLD.eventDisplayName)); + assertTrue("The hold name value for the deleted hold is not audited.", + auditEntry.getNodeName().equals(HOLD2)); + assertTrue("The user who deleted the hold is not audited.", + auditEntry.getUserName().equals(rmAdmin.getUsername())); + assertFalse("The date when the hold deletion occurred is not audited.", auditEntry.getTimestamp().isEmpty()); + } + + /** + * Given an unsuccessful delete hold action + * When I view the audit log + * Then the delete hold event isn't audited + */ + @Test + public void unsuccessfulDeleteHoldIsNotAudited() + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Try to delete a hold by an user with no Read permissions over the hold."); + try + { + holdsAPI.deleteHold(rmManager.getUsername(), rmManager.getPassword(), HOLD); + fail("Delete hold action was successful."); + } + catch (Exception e) + { + STEP("Get the list of audit entries for the delete hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + DELETE_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the unsuccessful delete hold."); + assertTrue("The list of events should not contain Delete Hold entry ", auditEntries.isEmpty()); + } + } + + /** + * Given a hold is deleted + * When I view the audit log as an user with no Read permissions over the deleted hold + * Then the delete hold entry isn't visible + */ + @Test + public void deleteHoldAuditEntryNotVisible() + { + STEP("Create a new hold."); + holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Delete the created hold."); + holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2); + + STEP("Get the list of audit entries for the delete hold event as an user with no Read permissions over the hold."); + auditEntries = rmAuditAPI.getRMAuditLog(rmManager.getUsername(), rmManager.getPassword(), 100, + DELETE_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the delete hold event."); + assertTrue("The list of events should not contain Delete Hold entry ", auditEntries.isEmpty()); + } + + @AfterClass (alwaysRun = true) + public void cleanUpAuditHoldTests() + { + holdsAPI.deleteHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD); + asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user)); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java new file mode 100644 index 0000000000..e7448a8471 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java @@ -0,0 +1,337 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.community.audit; + +import static java.util.Arrays.asList; + +import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION; +import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON; +import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_HOLD; +import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix; +import static org.alfresco.utility.data.RandomData.getRandomName; +import static org.alfresco.utility.report.log.Step.STEP; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.fail; + +import java.util.Collections; +import java.util.List; + +import org.alfresco.dataprep.CMISUtil; +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.audit.AuditEntry; +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.rm.community.model.user.UserPermissions; +import org.alfresco.rest.rm.community.model.user.UserRoles; +import org.alfresco.rest.v0.HoldsAPI; +import org.alfresco.rest.v0.RMAuditAPI; +import org.alfresco.rest.v0.service.RoleService; +import org.alfresco.test.AlfrescoTest; +import org.alfresco.utility.constants.UserRole; +import org.alfresco.utility.model.FileModel; +import org.alfresco.utility.model.SiteModel; +import org.alfresco.utility.model.UserModel; +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 the tests that check the remove from hold event is audited + * + * @author Claudia Agache + * @since 3.3 + */ +@AlfrescoTest (jira = "RM-6859") +public class AuditRemoveFromHoldTests extends BaseRMRestTest +{ + private final String PREFIX = generateTestPrefix(AuditRemoveFromHoldTests.class); + private final String HOLD1 = PREFIX + "hold1"; + private final String HOLD2 = PREFIX + "hold2"; + private final String HOLD3 = PREFIX + "hold3"; + private final String HOLD_TO_BE_DELETED = PREFIX + "holdToBeDeleted"; + + @Autowired + private RMAuditAPI rmAuditAPI; + @Autowired + private HoldsAPI holdsAPI; + @Autowired + private RoleService roleService; + + private UserModel rmAdmin, rmManagerNoRightsOnHold, rmManagerNoRightsOnNode; + private SiteModel privateSite; + private RecordCategory recordCategory; + private RecordCategoryChild recordFolder, heldRecordFolder; + private Record heldRecord; + private List auditEntries; + private List holdsList = asList(HOLD1, HOLD2, HOLD3); + private AuditEntry auditEntry; + private FileModel heldContent; + + @BeforeClass (alwaysRun = true) + public void createAuditHoldTestsPrecondition() throws Exception + { + STEP("Create an user with full rights to remove content from a hold."); + rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId); + + STEP("Create a collaboration site."); + privateSite = dataSite.usingUser(rmAdmin).createPrivateRandomSite(); + + STEP("Create new holds."); + String hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), + HOLD1, HOLD_REASON, HOLD_DESCRIPTION); + holdsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION); + holdsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD3, HOLD_REASON, HOLD_DESCRIPTION); + holdsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD_TO_BE_DELETED, + HOLD_REASON, HOLD_DESCRIPTION); + + STEP("Create a new record category with a record folder."); + recordCategory = createRootCategory(getRandomName("recordCategory")); + recordFolder = createRecordFolder(recordCategory.getId(), getRandomName("recFolder")); + + STEP("Create some held items"); + heldContent = dataContent.usingAdmin().usingSite(privateSite) + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + heldRecordFolder = createRecordFolder(recordCategory.getId(), PREFIX + "heldRecFolder"); + heldRecord = createElectronicRecord(recordFolder.getId(), PREFIX + "record"); + + holdsAPI.addItemsToHolds(getAdminUser().getUsername(), getAdminUser().getPassword(), + asList(heldContent.getNodeRefWithoutVersion(), heldRecordFolder.getId(), heldRecord.getId()), + holdsList); + + STEP("Create users without rights to remove content from a hold."); + rmManagerNoRightsOnHold = roleService.createUserWithSiteRoleRMRoleAndPermission(privateSite, + UserRole.SiteManager, recordCategory.getId(), UserRoles.ROLE_RM_MANAGER, UserPermissions.PERMISSION_FILING); + rmManagerNoRightsOnNode = roleService.createUserWithRMRoleAndRMNodePermission(UserRoles.ROLE_RM_MANAGER.roleId, + hold1NodeRef, UserPermissions.PERMISSION_FILING); + } + + /** + * Data provider with valid nodes that can be removed from a hold + * + * @return the node id and the node name + * @throws Exception + */ + @DataProvider (name = "validNodesForRemoveFromHold") + public Object[][] getValidNodesForRemoveFromHold() + { + return new String[][] + { + // a record folder + { heldRecordFolder.getId(), heldRecordFolder.getName() }, + // a record + { heldRecord.getId(), heldRecord.getName() }, + //an active content, + { heldContent.getNodeRefWithoutVersion(), heldContent.getName() } + }; + } + + /** + * Data provider with invalid users that can not remove content from a hold + * + * @return the userModel + */ + @DataProvider (name = "invalidUsersForRemoveFromHold") + public Object[][] getInvalidUsersForRemoveFromHold() + { + return new UserModel[][] + { + { rmManagerNoRightsOnHold }, + { rmManagerNoRightsOnNode } + }; + } + + /** + * Given a document/record/record folder is removed from a hold + * When I view the audit log + * Then an entry has been created in the audit log that contains the following: + * name of the hold + * name of the document/record/record folder removed + * user who removed the content + * date the content was removed + */ + @Test (dataProvider = "validNodesForRemoveFromHold") + public void removeFromHoldEventIsAudited(String nodeId, String nodeName) + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Remove node from hold."); + holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD3); + + STEP("Get the list of audit entries for the remove from hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + REMOVE_FROM_HOLD.event); + + STEP("Check the audit log contains the entry for the remove from hold."); + assertFalse("The list of events should contain Remove From Hold entry ", auditEntries.isEmpty()); + auditEntry = auditEntries.get(0); + assertTrue("The list of events is not filtered by Remove From Hold", + auditEntry.getEvent().equals(REMOVE_FROM_HOLD.eventDisplayName)); + assertTrue("The hold name value for the remove from hold is not audited.", + auditEntry.getNodeName().equals(HOLD3)); + assertTrue("The user who removed the node from the hold is not audited.", + auditEntry.getUserName().equals(rmAdmin.getUsername())); + assertFalse("The date when the add to hold occurred is not audited.", auditEntry.getTimestamp().isEmpty()); + //TODO check content name + } + + /** + * Given a not empty hold is deleted + * When I view the audit log + * Then an entry has been created in the audit log for each item removed from that hold + */ + @Test + public void removeFromHoldAuditedWhenHoldIsDeleted() + { + STEP("Add a file to the hold that will be deleted"); + holdsAPI.addItemToHold(getAdminUser().getUsername(), getAdminUser().getPassword(), + heldContent.getNodeRefWithoutVersion(), HOLD_TO_BE_DELETED); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Delete the hold."); + holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD_TO_BE_DELETED); + + STEP("Get the list of audit entries for the remove from hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + REMOVE_FROM_HOLD.event); + + STEP("Check the audit log contains the entry for the remove from hold."); + assertFalse("The list of events should contain Remove From Hold entry ", auditEntries.isEmpty()); + assertTrue("The hold name value for the remove from hold is not audited.", + auditEntries.get(0).getNodeName().equals(HOLD_TO_BE_DELETED)); + } + + /** + * Given an unsuccessful remove from hold action + * When I view the audit log + * Then the remove from hold event isn't audited + */ + @Test + public void unsuccessfulRemoveFromHoldIsNotAudited() + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Try to remove the record from a hold by an user with no rights."); + try + { + holdsAPI.removeItemFromHold(rmManagerNoRightsOnHold.getUsername(), rmManagerNoRightsOnHold.getPassword(), + heldRecord.getId(), HOLD1); + fail("Remove from hold action was successful."); + } + catch (Exception e) + { + STEP("Get the list of audit entries for the remove from hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + REMOVE_FROM_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the unsuccessful remove from hold."); + assertTrue("The list of events should not contain remove from hold entry ", auditEntries.isEmpty()); + } + } + + /** + * Given a not empty record folder is removed from a hold + * When I view the audit log + * Then only an entry has been created in the audit log for the record folder removed + */ + @Test + public void removeFromHoldNotAuditedForRecordFolderChildren() throws Exception + { + STEP("Create a new record folder with a record inside"); + RecordCategoryChild notEmptyRecFolder = createRecordFolder(recordCategory.getId(), PREFIX + "notEmptyRecFolder"); + createElectronicRecord(notEmptyRecFolder.getId(), PREFIX + "record"); + + STEP("Add the record folder to a hold."); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1); + + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Remove record folder from hold."); + holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1); + + STEP("Get the list of audit entries for the remove from hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + REMOVE_FROM_HOLD.event); + + STEP("Check the audit log contains only an entry for remove from hold."); + assertEquals("The list of events should not contain Remove from Hold entry for the record", 1, + auditEntries.size()); + //TODO check content name + } + + /** + * Given a document/record/record folder is removed from multiple holds + * When I view the audit log + * Then multiple entries have been created in the audit log for each remove from hold event + */ + @Test + public void removeFromHoldIsAuditedInBulkRemoval() + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Remove record folder from multiple holds."); + holdsAPI.removeItemsFromHolds(rmAdmin.getUsername(), rmAdmin.getPassword(), + Collections.singletonList(heldRecordFolder.getId()), asList(HOLD1, HOLD2)); + + STEP("Get the list of audit entries for the remove from hold event."); + auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword(), 100, + REMOVE_FROM_HOLD.event); + + STEP("Check the audit log contains entries for both removal."); + assertEquals("The list of events should contain remove from Hold entries for both holds", 2, + auditEntries.size()); + assertTrue("The hold name value for the first remove from hold is not audited.", + auditEntries.stream().anyMatch(entry -> entry.getNodeName().equals(HOLD1))); + assertTrue("The hold name value for the second remove from hold is not audited.", + auditEntries.stream().anyMatch(entry -> entry.getNodeName().equals(HOLD2))); + } + + /** + * Given a document/record/record folder is removed from a hold + * When I view the audit log as an user with no Read permissions over the hold or the node + * Then the remove from hold entry isn't visible + */ + @Test (dataProvider = "invalidUsersForRemoveFromHold") + public void removeFromHoldAuditEntryNotVisible(UserModel user) + { + STEP("Clean audit logs."); + rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword()); + + STEP("Remove held content from a hold."); + holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldContent.getNodeRefWithoutVersion(), HOLD1); + + STEP("Get the list of audit entries for the remove from hold event as an user with no Read permissions."); + auditEntries = rmAuditAPI.getRMAuditLog(user.getUsername(), user.getPassword(), 100, REMOVE_FROM_HOLD.event); + + STEP("Check the audit log doesn't contain the entry for the remove from hold event."); + assertTrue("The list of events should not contain Remove from Hold entry ", auditEntries.isEmpty()); + } + + @AfterClass (alwaysRun = true) + public void cleanUpAuditHoldTests() + { + holdsList.forEach(hold -> holdsAPI.deleteHold(getAdminUser().getUsername(), getAdminUser().getPassword(), hold)); + dataSite.usingAdmin().deleteSite(privateSite); + asList(rmAdmin, rmManagerNoRightsOnHold, rmManagerNoRightsOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user)); + getRestAPIFactory().getRecordCategoryAPI().deleteRecordCategory(recordCategory.getId()); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditUserEventsTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditUserEventsTests.java index a71094bcd7..6f29159520 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditUserEventsTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditUserEventsTests.java @@ -66,7 +66,7 @@ public class AuditUserEventsTests extends BaseRMRestTest */ @Test @AlfrescoTest(jira = "RM-6223") - public void createUserEventIsAudited() throws Exception + public void createUserEventIsAudited() { STEP("Create a new user."); String userName = "auditCreateUser" + PREFIX; diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/hold/AddToHoldsTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/hold/AddToHoldsTests.java index 2476370482..636c453077 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/hold/AddToHoldsTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/hold/AddToHoldsTests.java @@ -108,7 +108,7 @@ public class AddToHoldsTests extends BaseRMRestTest private ContentActions contentActions; @BeforeClass (alwaysRun = true) - public void preconditionForAddContentToHold() throws Exception + public void preconditionForAddContentToHold() { STEP("Create a hold."); holdNodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getUsername(), @@ -174,7 +174,7 @@ public class AddToHoldsTests extends BaseRMRestTest * Valid nodes to be added to hold */ @DataProvider (name = "validNodesForAddToHold") - public Object[][] getValidNodesForAddToHold() throws Exception + public Object[][] getValidNodesForAddToHold() { //create electronic and nonElectronic record in record folder RecordCategoryChild recordFolder = createCategoryFolderInFilePlan(); @@ -354,7 +354,7 @@ public class AddToHoldsTests extends BaseRMRestTest } @AfterClass (alwaysRun = true) - public void cleanUpAddContentToHold() throws Exception + public void cleanUpAddContentToHold() { holdsAPI.deleteHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD); dataSite.usingAdmin().deleteSite(testSite);