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 = RESOURCE_ID.resolve("test-resource-child"); 128 private static final FedoraId RESOURCE_DESCRIPTION_ID = RESOURCE_ID.resolve("fcr:metadata"); 129 private static final FedoraId RESOURCE_ACL_ID = RESOURCE_ID.resolve("fcr:acl"); 130 131 @Before 132 public void setup() { 133 MockitoAnnotations.openMocks(this); 134 final String txId = UUID.randomUUID().toString(); 135 tx = TestTransactionHelper.mockTransaction(txId, false); 136 when(psManager.getSession(any(Transaction.class))).thenReturn(pSession); 137 final DeleteResourceOperationFactoryImpl factoryImpl = new DeleteResourceOperationFactoryImpl(); 138 setField(service, "deleteResourceFactory", factoryImpl); 139 setField(service, "containmentIndex", containmentIndex); 140 setField(service, "eventAccumulator", eventAccumulator); 141 setField(service, "referenceService", referenceService); 142 setField(service, "membershipService", membershipService); 143 setField(service, "searchIndex", searchIndex); 144 when(container.getFedoraId()).thenReturn(RESOURCE_ID); 145 146 when(pSession.getHeaders(RESOURCE_ID, null)).thenReturn(resourceHeaders); 147 when(pSession.getHeaders(CHILD_RESOURCE_ID, null)).thenReturn(childHeaders); 148 when(pSession.getHeaders(RESOURCE_DESCRIPTION_ID, null)).thenReturn(descHeaders); 149 when(pSession.getHeaders(RESOURCE_ACL_ID, null)).thenReturn(aclHeaders); 150 } 151 152 @After 153 public void cleanUp() { 154 containmentIndex.reset(); 155 } 156 157 @Test 158 public void testContainerDelete() throws Exception { 159 when(container.isAcl()).thenReturn(false); 160 when(container.getAcl()).thenReturn(null); 161 162 service.perform(tx, container, USER); 163 containmentIndex.commitTransaction(tx); 164 verifyResourceOperation(RESOURCE_ID, operationCaptor, pSession); 165 } 166 167 @Test 168 public void testRecursiveDelete() throws Exception { 169 when(container.isAcl()).thenReturn(false); 170 when(container.getAcl()).thenReturn(null); 171 when(childContainer.getFedoraId()).thenReturn(CHILD_RESOURCE_ID); 172 when(childContainer.isAcl()).thenReturn(false); 173 when(childContainer.getAcl()).thenReturn(null); 174 175 when(resourceFactory.getResource(tx, CHILD_RESOURCE_ID)).thenReturn(childContainer); 176 containmentIndex.addContainedBy(tx, container.getFedoraId(), childContainer.getFedoraId()); 177 178 assertEquals(1, containmentIndex.getContains(tx, RESOURCE_ID).count()); 179 service.perform(tx, container, USER); 180 181 verify(pSession, times(2)).persist(operationCaptor.capture()); 182 final List<DeleteResourceOperation> operations = operationCaptor.getAllValues(); 183 assertEquals(2, operations.size()); 184 185 assertEquals(CHILD_RESOURCE_ID, operations.get(0).getResourceId()); 186 assertEquals(RESOURCE_ID, operations.get(1).getResourceId()); 187 188 assertEquals(0, containmentIndex.getContains(tx, RESOURCE_ID).count()); 189 190 verify(tx).lockResource(RESOURCE_ID); 191 verify(tx).lockResource(CHILD_RESOURCE_ID); 192 } 193 194 private void verifyResourceOperation(final FedoraId fedoraID, 195 final ArgumentCaptor<DeleteResourceOperation> captor, 196 final PersistentStorageSession pSession) throws Exception { 197 verify(pSession).persist(captor.capture()); 198 final DeleteResourceOperation containerOperation = captor.getValue(); 199 assertEquals(fedoraID, containerOperation.getResourceId()); 200 } 201 202 @Test 203 public void testAclDelete() throws Exception { 204 when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID); 205 when(acl.isAcl()).thenReturn(true); 206 service.perform(tx, acl, USER); 207 verifyResourceOperation(RESOURCE_ACL_ID, operationCaptor, pSession); 208 } 209 210 @Test(expected = RepositoryRuntimeException.class) 211 public void testBinaryDescriptionDelete() throws Exception { 212 when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID); 213 service.perform(tx, binaryDesc, USER); 214 } 215 216 @Test 217 public void testBinaryDeleteWithAcl() throws Exception { 218 when(binary.getFedoraId()).thenReturn(RESOURCE_ID); 219 when(binary.isAcl()).thenReturn(false); 220 when(binary.getDescription()).thenReturn(binaryDesc); 221 when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID); 222 when(binary.getAcl()).thenReturn(acl); 223 when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID); 224 225 service.perform(tx, binary, USER); 226 227 verify(pSession, times(3)).persist(operationCaptor.capture()); 228 final List<DeleteResourceOperation> operations = operationCaptor.getAllValues(); 229 assertEquals(3, operations.size()); 230 231 assertEquals(RESOURCE_DESCRIPTION_ID, operations.get(0).getResourceId()); 232 assertEquals(RESOURCE_ACL_ID, operations.get(1).getResourceId()); 233 assertEquals(RESOURCE_ID, operations.get(2).getResourceId()); 234 235 verify(tx).lockResource(RESOURCE_ID); 236 verify(tx).lockResource(RESOURCE_DESCRIPTION_ID); 237 verify(tx).lockResource(RESOURCE_ACL_ID); 238 } 239 240}