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.fcrepo.kernel.api.FedoraTypes.FEDORA_ID_PREFIX;
009import static org.junit.Assert.assertEquals;
010import static org.mockito.ArgumentMatchers.any;
011import static org.mockito.Mockito.times;
012import static org.mockito.Mockito.verify;
013import static org.mockito.Mockito.when;
014import static org.springframework.test.util.ReflectionTestUtils.setField;
015
016import java.util.List;
017import java.util.Optional;
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.impl.TestTransactionHelper;
034import org.fcrepo.kernel.impl.operations.DeleteResourceOperationFactoryImpl;
035import org.fcrepo.kernel.impl.operations.PurgeResourceOperation;
036import org.fcrepo.persistence.api.PersistentStorageSession;
037import org.fcrepo.persistence.api.PersistentStorageSessionManager;
038
039import org.junit.Before;
040import org.junit.Test;
041import org.junit.runner.RunWith;
042import org.mockito.ArgumentCaptor;
043import org.mockito.Captor;
044import org.mockito.InjectMocks;
045import org.mockito.Mock;
046import org.mockito.MockitoAnnotations;
047import org.springframework.test.context.ContextConfiguration;
048import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
049
050import com.github.benmanes.caffeine.cache.Cache;
051
052/**
053 * PurgeResourceServiceTest
054 *
055 * Copy of DeleteResourceServiceTest
056 *
057 * @author dbernstein
058 * @author whikloj
059 */
060@RunWith(SpringJUnit4ClassRunner.class)
061@ContextConfiguration("/containmentIndexTest.xml")
062public class PurgeResourceServiceImplTest {
063
064    private static final String USER = "fedoraAdmin";
065
066    private Transaction tx;
067
068    @Mock
069    private EventAccumulator eventAccumulator;
070
071    @Mock
072    private PersistentStorageSession pSession;
073
074    @Inject
075    private ContainmentIndex containmentIndex;
076
077    @Mock
078    private PersistentStorageSessionManager psManager;
079
080    @Mock
081    private ResourceFactory resourceFactory;
082
083    @Mock
084    private Container container;
085
086    @Mock
087    private Container childContainer;
088
089    @Mock
090    private Binary binary;
091
092    @Mock
093    private WebacAcl acl;
094
095    @Mock
096    private NonRdfSourceDescription binaryDesc;
097
098    @Mock
099    private ResourceHeaders resourceHeaders;
100    @Mock
101    private ResourceHeaders childHeaders;
102    @Mock
103    private ResourceHeaders descHeaders;
104    @Mock
105    private ResourceHeaders aclHeaders;
106    @Mock
107    private Cache<String, Optional<ACLHandle>> authHandleCache;
108
109    @Captor
110    private ArgumentCaptor<PurgeResourceOperation> operationCaptor;
111
112    @InjectMocks
113    private PurgeResourceServiceImpl service;
114
115    private static final FedoraId RESOURCE_ID =  FedoraId.create("test-resource");
116    private static final FedoraId CHILD_RESOURCE_ID = RESOURCE_ID.resolve("test-resource-child");
117    private static final FedoraId RESOURCE_DESCRIPTION_ID =
118            FedoraId.create(FEDORA_ID_PREFIX + "test-resource-description");
119    private static final FedoraId RESOURCE_ACL_ID = FedoraId.create("test-resource-acl");
120    private static final String TX_ID = "tx-1234";
121
122    @Before
123    public void setup() {
124        MockitoAnnotations.openMocks(this);
125        tx = TestTransactionHelper.mockTransaction(TX_ID, false);
126        when(psManager.getSession(any(Transaction.class))).thenReturn(pSession);
127        final DeleteResourceOperationFactoryImpl factoryImpl = new DeleteResourceOperationFactoryImpl();
128        setField(service, "deleteResourceFactory", factoryImpl);
129        setField(service, "containmentIndex", containmentIndex);
130        setField(service, "eventAccumulator", eventAccumulator);
131        when(container.getFedoraId()).thenReturn(RESOURCE_ID);
132
133        when(pSession.getHeaders(RESOURCE_ID, null)).thenReturn(resourceHeaders);
134        when(pSession.getHeaders(CHILD_RESOURCE_ID, null)).thenReturn(childHeaders);
135        when(pSession.getHeaders(RESOURCE_DESCRIPTION_ID, null)).thenReturn(descHeaders);
136        when(pSession.getHeaders(RESOURCE_ACL_ID, null)).thenReturn(aclHeaders);
137    }
138
139    @Test
140    public void testContainerPurge() throws Exception {
141        when(container.isAcl()).thenReturn(false);
142        when(container.getAcl()).thenReturn(null);
143
144        service.perform(tx, container, USER);
145        verifyResourceOperation(RESOURCE_ID, operationCaptor, pSession);
146    }
147
148    @Test
149    public void testRecursivePurge() throws Exception {
150        when(container.isAcl()).thenReturn(false);
151        when(container.getAcl()).thenReturn(null);
152        when(childContainer.getFedoraId()).thenReturn(CHILD_RESOURCE_ID);
153        when(childContainer.isAcl()).thenReturn(false);
154        when(childContainer.getAcl()).thenReturn(null);
155
156        when(resourceFactory.getResource(tx, CHILD_RESOURCE_ID)).thenReturn(childContainer);
157        containmentIndex.addContainedBy(tx, container.getFedoraId(), childContainer.getFedoraId());
158        containmentIndex.commitTransaction(tx);
159        containmentIndex.removeContainedBy(tx, container.getFedoraId(), childContainer.getFedoraId());
160
161        when(container.isAcl()).thenReturn(false);
162        when(container.getAcl()).thenReturn(null);
163
164        service.perform(tx, container, USER);
165
166        verify(pSession, times(2)).persist(operationCaptor.capture());
167        final List<PurgeResourceOperation> operations = operationCaptor.getAllValues();
168        assertEquals(2, operations.size());
169
170        assertEquals(CHILD_RESOURCE_ID, operations.get(0).getResourceId());
171        assertEquals(RESOURCE_ID, operations.get(1).getResourceId());
172
173        assertEquals(0, containmentIndex.getContains(tx, RESOURCE_ID).count());
174
175        verify(tx).lockResource(RESOURCE_ID);
176        verify(tx).lockResource(CHILD_RESOURCE_ID);
177    }
178
179    private void verifyResourceOperation(final FedoraId fedoraID,
180                                         final ArgumentCaptor<PurgeResourceOperation> captor,
181                                         final PersistentStorageSession pSession) throws Exception {
182        verify(pSession).persist(captor.capture());
183        final PurgeResourceOperation containerOperation = captor.getValue();
184        assertEquals(fedoraID, containerOperation.getResourceId());
185    }
186
187    @Test
188    public void testAclPurge() throws Exception {
189        when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID);
190        when(acl.isAcl()).thenReturn(true);
191        service.perform(tx, acl, USER);
192        verifyResourceOperation(RESOURCE_ACL_ID, operationCaptor, pSession);
193    }
194
195    @Test(expected = RepositoryRuntimeException.class)
196    public void testBinaryDescriptionPurge() throws Exception {
197        when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID);
198        service.perform(tx, binaryDesc, USER);
199    }
200
201    @Test
202    public void testBinaryPurgeWithAcl() throws Exception {
203        when(binary.getFedoraId()).thenReturn(RESOURCE_ID);
204        when(binary.isAcl()).thenReturn(false);
205        when(binary.getDescription()).thenReturn(binaryDesc);
206        when(binaryDesc.getFedoraId()).thenReturn(RESOURCE_DESCRIPTION_ID);
207        when(binary.getAcl()).thenReturn(acl);
208        when(acl.getFedoraId()).thenReturn(RESOURCE_ACL_ID);
209
210        service.perform(tx, binary, USER);
211
212        verify(pSession, times(3)).persist(operationCaptor.capture());
213        final List<PurgeResourceOperation> operations = operationCaptor.getAllValues();
214        assertEquals(3, operations.size());
215
216        assertEquals(RESOURCE_DESCRIPTION_ID, operations.get(0).getResourceId());
217        assertEquals(RESOURCE_ACL_ID, operations.get(1).getResourceId());
218        assertEquals(RESOURCE_ID, operations.get(2).getResourceId());
219
220        verify(tx).lockResource(RESOURCE_ID);
221        verify(tx).lockResource(RESOURCE_DESCRIPTION_ID);
222        verify(tx).lockResource(RESOURCE_ACL_ID);
223    }
224
225}