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.apache.jena.vocabulary.DC_11.title; 009import static org.junit.Assert.assertEquals; 010import static org.junit.Assert.assertTrue; 011import static org.mockito.ArgumentMatchers.any; 012import static org.mockito.ArgumentMatchers.nullable; 013import static org.mockito.Mockito.times; 014import static org.mockito.Mockito.verify; 015import static org.mockito.Mockito.when; 016import static org.springframework.test.util.ReflectionTestUtils.setField; 017 018import java.time.Instant; 019import java.util.List; 020 021import org.fcrepo.config.FedoraPropsConfig; 022import org.fcrepo.config.ServerManagedPropsMode; 023import org.fcrepo.kernel.api.RdfCollectors; 024import org.fcrepo.kernel.api.RdfLexicon; 025import org.fcrepo.kernel.api.RdfStream; 026import org.fcrepo.kernel.api.Transaction; 027import org.fcrepo.kernel.api.cache.UserTypesCache; 028import org.fcrepo.kernel.api.identifiers.FedoraId; 029import org.fcrepo.kernel.api.models.ResourceHeaders; 030import org.fcrepo.kernel.api.observer.EventAccumulator; 031import org.fcrepo.kernel.api.operations.NonRdfSourceOperationFactory; 032import org.fcrepo.kernel.api.operations.RdfSourceOperation; 033import org.fcrepo.kernel.api.operations.RdfSourceOperationFactory; 034import org.fcrepo.kernel.api.services.MembershipService; 035import org.fcrepo.kernel.api.services.ReferenceService; 036import org.fcrepo.kernel.impl.operations.NonRdfSourceOperationFactoryImpl; 037import org.fcrepo.kernel.impl.operations.RdfSourceOperationFactoryImpl; 038import org.fcrepo.kernel.impl.operations.UpdateRdfSourceOperation; 039import org.fcrepo.persistence.api.PersistentStorageSession; 040import org.fcrepo.persistence.api.PersistentStorageSessionManager; 041 042import org.apache.commons.io.IOUtils; 043import org.apache.jena.rdf.model.Model; 044import org.apache.jena.rdf.model.ModelFactory; 045import org.apache.jena.rdf.model.ResourceFactory; 046import org.apache.jena.riot.Lang; 047import org.apache.jena.riot.RDFDataMgr; 048import org.fcrepo.search.api.SearchIndex; 049import org.junit.Before; 050import org.junit.Test; 051import org.junit.runner.RunWith; 052import org.mockito.ArgumentCaptor; 053import org.mockito.Captor; 054import org.mockito.InjectMocks; 055import org.mockito.Mock; 056import org.mockito.junit.MockitoJUnitRunner; 057 058/** 059 * DeleteResourceServiceTest 060 * 061 * @author bseeger 062 */ 063@RunWith(MockitoJUnitRunner.Strict.class) 064public class ReplacePropertiesServiceImplTest { 065 066 private static final String USER_PRINCIPAL = "fedoraUser"; 067 068 @Mock 069 private Transaction tx; 070 071 @Mock 072 private PersistentStorageSession pSession; 073 074 @Mock 075 private PersistentStorageSessionManager psManager; 076 077 @Mock 078 private EventAccumulator eventAccumulator; 079 080 @Mock 081 private ReferenceService referenceService; 082 083 @Mock 084 private MembershipService membershipService; 085 086 @Mock 087 private SearchIndex searchIndex; 088 089 @Mock 090 private ResourceHeaders headers; 091 092 @Mock 093 private UserTypesCache userTypesCache; 094 095 @InjectMocks 096 private UpdateRdfSourceOperation operation; 097 098 @InjectMocks 099 private ReplacePropertiesServiceImpl service; 100 101 private RdfSourceOperationFactory factory; 102 103 private NonRdfSourceOperationFactory nonRdfFactory; 104 105 @Captor 106 private ArgumentCaptor<RdfSourceOperation> operationCaptor; 107 108 private FedoraPropsConfig propsConfig; 109 110 private static final FedoraId FEDORA_ID = FedoraId.create("info:fedora/resource1"); 111 private static final String TX_ID = "tx-1234"; 112 private static final String RDF = 113 "<" + FEDORA_ID + "> <" + title + "> 'fancy title' .\n" + 114 "<" + FEDORA_ID + "> <" + title + "> 'another fancy title' ."; 115 116 @Before 117 public void setup() { 118 propsConfig = new FedoraPropsConfig(); 119 factory = new RdfSourceOperationFactoryImpl(); 120 nonRdfFactory = new NonRdfSourceOperationFactoryImpl(); 121 setField(service, "factory", factory); 122 setField(service, "nonRdfFactory", nonRdfFactory); 123 setField(service, "eventAccumulator", eventAccumulator); 124 setField(service, "referenceService", referenceService); 125 setField(service, "membershipService", membershipService); 126 setField(service, "searchIndex", searchIndex); 127 setField(service, "fedoraPropsConfig", propsConfig); 128 setField(service, "userTypesCache", userTypesCache); 129 propsConfig.setServerManagedPropsMode(ServerManagedPropsMode.STRICT); 130 when(psManager.getSession(any(Transaction.class))).thenReturn(pSession); 131 when(pSession.getHeaders(any(FedoraId.class), nullable(Instant.class))).thenReturn(headers); 132 } 133 134 @Test 135 public void testReplaceProperties() throws Exception { 136 final Model model = ModelFactory.createDefaultModel(); 137 RDFDataMgr.read(model, IOUtils.toInputStream(RDF, "UTF-8"), Lang.NTRIPLES); 138 139 when(headers.getInteractionModel()).thenReturn(RdfLexicon.RDF_SOURCE.toString()); 140 141 service.perform(tx, USER_PRINCIPAL, FEDORA_ID, model); 142 verify(tx).lockResource(FEDORA_ID); 143 verify(pSession).persist(operationCaptor.capture()); 144 assertEquals(FEDORA_ID, operationCaptor.getValue().getResourceId()); 145 final RdfStream stream = operationCaptor.getValue().getTriples(); 146 final Model captureModel = stream.collect(RdfCollectors.toModel()); 147 148 assertTrue(captureModel.contains(ResourceFactory.createResource(FEDORA_ID.getResourceId()), 149 ResourceFactory.createProperty(title.getURI()), 150 "another fancy title")); 151 assertTrue(captureModel.contains(ResourceFactory.createResource(FEDORA_ID.getResourceId()), 152 ResourceFactory.createProperty(title.getURI()), 153 "fancy title")); 154 } 155 156 @Test 157 public void lockRelatedResourcesOnBinaryDescInAg() throws Exception { 158 final Model model = ModelFactory.createDefaultModel(); 159 RDFDataMgr.read(model, IOUtils.toInputStream(RDF, "UTF-8"), Lang.NTRIPLES); 160 161 final var agId = FedoraId.create("ag"); 162 final var binaryId = agId.resolve("bin"); 163 final var descId = binaryId.asDescription(); 164 165 when(headers.getInteractionModel()).thenReturn(RdfLexicon.FEDORA_NON_RDF_SOURCE_DESCRIPTION_URI); 166 when(headers.getArchivalGroupId()).thenReturn(agId); 167 168 service.perform(tx, USER_PRINCIPAL, descId, model); 169 verify(tx).lockResource(agId); 170 verify(tx).lockResource(binaryId); 171 verify(tx).lockResource(descId); 172 verify(pSession, times(2)).persist(operationCaptor.capture()); 173 174 final var updateOp = getOperation(operationCaptor.getAllValues(), UpdateRdfSourceOperation.class); 175 assertEquals(descId, updateOp.getResourceId()); 176 } 177 178 private <T extends RdfSourceOperation> T getOperation(final List<RdfSourceOperation> ops, final Class<T> clazz) { 179 return ops.stream() 180 .filter(clazz::isInstance) 181 .findFirst() 182 .map(clazz::cast) 183 .orElseThrow(); 184 } 185 186} 187