001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.kernel.impl.services; 007 008import static org.junit.Assert.assertEquals; 009import static org.mockito.ArgumentMatchers.any; 010import static org.mockito.Mockito.times; 011import static org.mockito.Mockito.verify; 012import static org.mockito.Mockito.when; 013import static org.springframework.test.util.ReflectionTestUtils.setField; 014 015import java.util.List; 016import java.util.Optional; 017import java.util.UUID; 018 019import javax.inject.Inject; 020 021import org.fcrepo.kernel.api.ContainmentIndex; 022import org.fcrepo.kernel.api.Transaction; 023import org.fcrepo.kernel.api.auth.ACLHandle; 024import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 025import org.fcrepo.kernel.api.identifiers.FedoraId; 026import org.fcrepo.kernel.api.models.Binary; 027import org.fcrepo.kernel.api.models.Container; 028import org.fcrepo.kernel.api.models.NonRdfSourceDescription; 029import org.fcrepo.kernel.api.models.ResourceFactory; 030import org.fcrepo.kernel.api.models.ResourceHeaders; 031import org.fcrepo.kernel.api.models.WebacAcl; 032import org.fcrepo.kernel.api.observer.EventAccumulator; 033import org.fcrepo.kernel.api.services.MembershipService; 034import org.fcrepo.kernel.api.services.ReferenceService; 035import org.fcrepo.kernel.impl.TestTransactionHelper; 036import org.fcrepo.kernel.impl.operations.DeleteResourceOperation; 037import org.fcrepo.kernel.impl.operations.DeleteResourceOperationFactoryImpl; 038import org.fcrepo.persistence.api.PersistentStorageSession; 039import org.fcrepo.persistence.api.PersistentStorageSessionManager; 040import org.fcrepo.search.api.SearchIndex; 041 042import org.junit.After; 043import org.junit.Before; 044import org.junit.Test; 045import org.junit.runner.RunWith; 046import org.mockito.ArgumentCaptor; 047import org.mockito.Captor; 048import org.mockito.InjectMocks; 049import org.mockito.Mock; 050import org.mockito.MockitoAnnotations; 051import org.springframework.test.context.ContextConfiguration; 052import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 053 054import com.github.benmanes.caffeine.cache.Cache; 055 056/** 057 * DeleteResourceServiceTest 058 * 059 * @author dbernstein 060 */ 061@RunWith(SpringJUnit4ClassRunner.class) 062@ContextConfiguration("/containmentIndexTest.xml") 063public class DeleteResourceServiceImplTest { 064 065 private static final String USER = "fedoraAdmin"; 066 067 private Transaction tx; 068 069 @Mock 070 private EventAccumulator eventAccumulator; 071 072 @Mock 073 private PersistentStorageSession pSession; 074 075 @Inject 076 private ContainmentIndex containmentIndex; 077 078 @Mock 079 private SearchIndex searchIndex; 080 081 @Mock 082 private PersistentStorageSessionManager psManager; 083 084 @Mock 085 private ResourceFactory resourceFactory; 086 087 @Mock 088 private Container container; 089 090 @Mock 091 private Container childContainer; 092 093 @Mock 094 private Binary binary; 095 096 @Mock 097 private WebacAcl acl; 098 099 @Mock 100 private NonRdfSourceDescription binaryDesc; 101 102 @Mock 103 private ReferenceService referenceService; 104 105 @Mock 106 private MembershipService membershipService; 107 108 @Mock 109 private ResourceHeaders resourceHeaders; 110 @Mock 111 private ResourceHeaders childHeaders; 112 @Mock 113 private ResourceHeaders descHeaders; 114 @Mock 115 private ResourceHeaders aclHeaders; 116 117 @Mock 118 private Cache<String, Optional<ACLHandle>> authHandleCache; 119 120 @Captor 121 private ArgumentCaptor<DeleteResourceOperation> operationCaptor; 122 123 @InjectMocks 124 private DeleteResourceServiceImpl service; 125 126 private static final FedoraId RESOURCE_ID = FedoraId.create("test-resource"); 127 private static final FedoraId CHILD_RESOURCE_ID = FedoraId.create("test-resource-child"); 128 private static final FedoraId RESOURCE_DESCRIPTION_ID = 129 FedoraId.create("test-resource-description"); 130 private static final FedoraId RESOURCE_ACL_ID = FedoraId.create("test-resource-acl"); 131 132 @Before 133 public void setup() { 134 MockitoAnnotations.openMocks(this); 135 final String txId = UUID.randomUUID().toString(); 136 tx = TestTransactionHelper.mockTransaction(txId, false); 137 when(psManager.getSession(any(Transaction.class))).thenReturn(pSession); 138 final DeleteResourceOperationFactoryImpl factoryImpl = new DeleteResourceOperationFactoryImpl(); 139 setField(service, "deleteResourceFactory", factoryImpl); 140 setField(service, "containmentIndex", containmentIndex); 141 setField(service, "eventAccumulator", eventAccumulator); 142 setField(service, "referenceService", referenceService); 143 setField(service, "membershipService", membershipService); 144 setField(service, "searchIndex", searchIndex); 145 when(container.getFedoraId()).thenReturn(RESOURCE_ID); 146 147 when(pSession.getHeaders(RESOURCE_ID, null)).thenReturn(resourceHeaders); 148 when(pSession.getHeaders(CHILD_RESOURCE_ID, null)).thenReturn(childHeaders); 149 when(pSession.getHeaders(RESOURCE_DESCRIPTION_ID, null)).thenReturn(descHeaders); 150 when(pSession.getHeaders(RESOURCE_ACL_ID, null)).thenReturn(aclHeaders); 151 } 152 153 @After 154 public void cleanUp() { 155 containmentIndex.reset(); 156 } 157 158 @Test 159 public void testContainerDelete() throws Exception { 160 when(container.isAcl()).thenReturn(false); 161 when(container.getAcl()).thenReturn(null); 162 163 service.perform(tx, container, USER); 164 containmentIndex.commitTransaction(tx); 165 verifyResourceOperation(RESOURCE_ID, operationCaptor, pSession); 166 } 167 168 @Test 169 public void testRecursiveDelete() throws Exception { 170 when(container.isAcl()).thenReturn(false); 171 when(container.getAcl()).thenReturn(null); 172 when(childContainer.getFedoraId()).thenReturn(CHILD_RESOURCE_ID); 173 when(childContainer.isAcl()).thenReturn(false); 174 when(childContainer.getAcl()).thenReturn(null); 175 176 when(resourceFactory.getResource(tx, CHILD_RESOURCE_ID)).thenReturn(childContainer); 177 containmentIndex.addContainedBy(tx, container.getFedoraId(), childContainer.getFedoraId()); 178 179 when(container.isAcl()).thenReturn(false); 180 when(container.getAcl()).thenReturn(null); 181 182 assertEquals(1, containmentIndex.getContains(tx, RESOURCE_ID).count()); 183 service.perform(tx, container, USER); 184 185 verify(pSession, times(2)).persist(operationCaptor.capture()); 186 final List<DeleteResourceOperation> operations = operationCaptor.getAllValues(); 187 assertEquals(2, operations.size()); 188 189 assertEquals(CHILD_RESOURCE_ID, operations.get(0).getResourceId()); 190 assertEquals(RESOURCE_ID, operations.get(1).getResourceId()); 191 192 assertEquals(0, containmentIndex.getContains(tx, RESOURCE_ID).count()); 193 194 verify(tx).lockResource(RESOURCE_ID); 195 verify(tx).lockResource(CHILD_RESOURCE_ID); 196 } 197 198 private void verifyResourceOperation(final FedoraId fedoraID, 199 final ArgumentCaptor<DeleteResourceOperation> captor, 200 final PersistentStorageSession pSession) throws Exception { 201 verify(pSession).persist(captor.capture()); 202 final DeleteResourceOperation containerOperation = captor.getValue(); 203 assertEquals(fedoraID, containerOperation.getResourceId()); 204 } 205 206 @Test 207 public void testAclDelete() throws Exception { 208 when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID); 209 when(acl.isAcl()).thenReturn(true); 210 service.perform(tx, acl, USER); 211 verifyResourceOperation(RESOURCE_ACL_ID, operationCaptor, pSession); 212 } 213 214 @Test(expected = RepositoryRuntimeException.class) 215 public void testBinaryDescriptionDelete() throws Exception { 216 when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID); 217 service.perform(tx, binaryDesc, USER); 218 } 219 220 @Test 221 public void testBinaryDeleteWithAcl() throws Exception { 222 when(binary.getFedoraId()).thenReturn(RESOURCE_ID); 223 when(binary.isAcl()).thenReturn(false); 224 when(binary.getDescription()).thenReturn(binaryDesc); 225 when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID); 226 when(binary.getAcl()).thenReturn(acl); 227 when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID); 228 229 service.perform(tx, binary, USER); 230 231 verify(pSession, times(3)).persist(operationCaptor.capture()); 232 final List<DeleteResourceOperation> operations = operationCaptor.getAllValues(); 233 assertEquals(3, operations.size()); 234 235 assertEquals(RESOURCE_DESCRIPTION_ID, operations.get(0).getResourceId()); 236 assertEquals(RESOURCE_ACL_ID, operations.get(1).getResourceId()); 237 assertEquals(RESOURCE_ID, operations.get(2).getResourceId()); 238 239 verify(tx).lockResource(RESOURCE_ID); 240 verify(tx).lockResource(RESOURCE_DESCRIPTION_ID); 241 verify(tx).lockResource(RESOURCE_ACL_ID); 242 } 243 244}