001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.impl.operations;
019
020import static junit.framework.TestCase.assertTrue;
021import static org.fcrepo.kernel.api.RdfCollectors.toModel;
022import static org.fcrepo.kernel.api.RdfLexicon.CREATED_BY;
023import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
024import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_BY;
025import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_DATE;
026import static org.fcrepo.kernel.api.RdfLexicon.RDF_SOURCE;
027import static org.fcrepo.kernel.api.rdf.DefaultRdfStream.fromModel;
028import static org.junit.Assert.assertEquals;
029import static org.junit.Assert.assertFalse;
030import static org.junit.Assert.assertNull;
031
032import java.io.ByteArrayOutputStream;
033import java.io.OutputStream;
034import java.time.Instant;
035import java.util.Calendar;
036import java.util.Date;
037
038import org.fcrepo.config.ServerManagedPropsMode;
039import org.fcrepo.kernel.api.RdfStream;
040import org.fcrepo.kernel.api.Transaction;
041import org.fcrepo.kernel.api.exception.MalformedRdfException;
042import org.fcrepo.kernel.api.identifiers.FedoraId;
043import org.fcrepo.kernel.api.operations.CreateRdfSourceOperation;
044import org.fcrepo.kernel.api.operations.CreateRdfSourceOperationBuilder;
045import org.fcrepo.kernel.api.operations.RdfSourceOperation;
046
047import org.apache.jena.datatypes.xsd.XSDDateTime;
048import org.apache.jena.graph.Node;
049import org.apache.jena.rdf.model.Model;
050import org.apache.jena.rdf.model.ModelFactory;
051import org.apache.jena.rdf.model.Property;
052import org.apache.jena.rdf.model.RDFNode;
053import org.apache.jena.rdf.model.Resource;
054import org.apache.jena.rdf.model.ResourceFactory;
055import org.junit.Before;
056import org.junit.Test;
057import org.junit.runner.RunWith;
058import org.mockito.Mock;
059import org.mockito.junit.MockitoJUnitRunner;
060
061/**
062 * @author bseeger
063 */
064@RunWith(MockitoJUnitRunner.Silent.class)
065public class CreateRdfSourceOperationBuilderTest {
066
067    private CreateRdfSourceOperationBuilder builder;
068
069    private Model model;
070
071    private RdfStream stream;
072
073    private static final FedoraId PARENT_ID = FedoraId.create("info:fedora/parent");
074
075    private static final FedoraId RESOURCE_ID = FedoraId.create("info:fedora/test-subject");
076
077    private static final Resource id = ResourceFactory.createResource(RESOURCE_ID.getResourceId());
078    private static final Node id_node = id.asNode();
079
080    private static final String PROPERTY_ID = "http://example.org/isLinkedTo/";
081
082    private static final Property prop = ResourceFactory.createProperty(PROPERTY_ID);
083
084    private static final String OBJECT_VALUE = "Somebody";
085
086    private static final RDFNode object = ResourceFactory.createPlainLiteral(OBJECT_VALUE);
087
088    private final Instant CREATED_INSTANT = Instant.parse("2019-11-12T10:00:30.0Z");
089    private XSDDateTime Created_xsddatetime;
090
091    private final Instant MODIFIED_INSTANT = Instant.parse("2019-11-12T14:11:05.0Z");
092    private XSDDateTime Modified_xsddatetime;
093
094    private final String USER_PRINCIPAL = "fedoraUser";
095
096    private final Calendar calendar = Calendar.getInstance();
097
098    @Mock
099    private Transaction tx;
100
101    @Before
102    public void setUp() {
103        calendar.setTime(Date.from(CREATED_INSTANT));
104        Created_xsddatetime = new XSDDateTime(calendar);
105        calendar.setTime(Date.from(MODIFIED_INSTANT));
106        Modified_xsddatetime = new XSDDateTime(calendar);
107        builder = new CreateRdfSourceOperationBuilderImpl(tx, RESOURCE_ID, RDF_SOURCE.toString(),
108                ServerManagedPropsMode.STRICT);
109        model = ModelFactory.createDefaultModel();
110        model.add(
111                ResourceFactory.createResource(RESOURCE_ID.getResourceId()),
112                ResourceFactory.createProperty(PROPERTY_ID),
113                ResourceFactory.createPlainLiteral(OBJECT_VALUE)
114        );
115        final OutputStream outputStream = new ByteArrayOutputStream();
116        model.write(outputStream, "TURTLE");
117        stream = fromModel(id_node, model);
118    }
119
120    @Test
121    public void testStream() {
122        final RdfSourceOperation op = builder.triples(stream).build();
123        assertEquals(CreateRdfSourceOperationImpl.class, op.getClass());
124        final var newModel = op.getTriples().collect(toModel());
125        assertTrue(newModel.contains(id, prop, object));
126        assertModelsMatch(model, newModel);
127    }
128
129    private void assertModelsMatch(final Model expected, final Model test) {
130        final var stmtIter = expected.listStatements();
131        while (stmtIter.hasNext()) {
132            final var testStmt = stmtIter.nextStatement();
133            assertTrue(test.contains(testStmt));
134            test.remove(testStmt);
135        }
136        assertTrue(test.isEmpty());
137    }
138
139    @Test
140    public void testRelaxedPropertiesAllFields() {
141        final var resc = model.getResource(RESOURCE_ID.getResourceId());
142        resc.addLiteral(LAST_MODIFIED_DATE, Modified_xsddatetime);
143        resc.addLiteral(LAST_MODIFIED_BY, USER_PRINCIPAL);
144        resc.addLiteral(CREATED_DATE, Created_xsddatetime);
145        resc.addLiteral(CREATED_BY, USER_PRINCIPAL);
146
147        final RdfSourceOperation op = buildOperationWithRelaxProperties(model);
148
149        assertEquals(USER_PRINCIPAL, op.getCreatedBy());
150        assertEquals(USER_PRINCIPAL, op.getLastModifiedBy());
151        assertEquals(CREATED_INSTANT, op.getCreatedDate());
152        assertEquals(MODIFIED_INSTANT, op.getLastModifiedDate());
153    }
154
155    @Test(expected = MalformedRdfException.class)
156    public void testRelaxedPropertiesNonDate() {
157        final var resc = model.getResource(RESOURCE_ID.getResourceId());
158        resc.addLiteral(LAST_MODIFIED_DATE, "Notadate");
159        resc.addLiteral(LAST_MODIFIED_BY, USER_PRINCIPAL);
160        resc.addLiteral(CREATED_DATE, Created_xsddatetime);
161        resc.addLiteral(CREATED_BY, USER_PRINCIPAL);
162
163        final RdfSourceOperation op = buildOperationWithRelaxProperties(model);
164
165        assertEquals(USER_PRINCIPAL, op.getCreatedBy());
166        assertEquals(USER_PRINCIPAL, op.getLastModifiedBy());
167        assertNull(op.getCreatedDate());
168        assertNull(op.getLastModifiedDate());
169    }
170
171    @Test(expected = MalformedRdfException.class)
172    public void testRelaxedPropertiesNonDate2() {
173        final var resc = model.getResource(RESOURCE_ID.getResourceId());
174        resc.addLiteral(LAST_MODIFIED_DATE, Modified_xsddatetime);
175        resc.addLiteral(LAST_MODIFIED_BY, USER_PRINCIPAL);
176        resc.addLiteral(CREATED_DATE, "Notadate");
177        resc.addLiteral(CREATED_BY, USER_PRINCIPAL);
178
179        final RdfSourceOperation op = buildOperationWithRelaxProperties(model);
180
181        assertEquals(USER_PRINCIPAL, op.getCreatedBy());
182        assertEquals(USER_PRINCIPAL, op.getLastModifiedBy());
183        assertNull(op.getCreatedDate());
184        assertNull(op.getLastModifiedDate());
185    }
186
187    @Test
188    public void testRelaxedPropertiesNotRelaxed() {
189        final var resc = model.getResource(RESOURCE_ID.getResourceId());
190        resc.addLiteral(LAST_MODIFIED_DATE, Modified_xsddatetime);
191        resc.addLiteral(LAST_MODIFIED_BY, USER_PRINCIPAL);
192        resc.addLiteral(CREATED_DATE, Created_xsddatetime);
193        resc.addLiteral(CREATED_BY, USER_PRINCIPAL);
194
195        // Relaxed system property not set
196        final RdfSourceOperation op = builder.relaxedProperties(model).build();
197
198        assertNull(op.getCreatedBy());
199        assertNull(op.getLastModifiedBy());
200        assertNull(op.getCreatedDate());
201        assertNull(op.getLastModifiedDate());
202    }
203
204    @Test
205    public void testRelaxedPropertiesNoProperties() {
206        final RdfSourceOperation op = buildOperationWithRelaxProperties(model);
207
208        assertNull(op.getCreatedBy());
209        assertNull(op.getLastModifiedBy());
210        assertNull(op.getCreatedDate());
211        assertNull(op.getLastModifiedDate());
212    }
213
214    @Test
215    public void testArchivalGroupFalseByDefault() {
216        final CreateRdfSourceOperation op = builder.build();
217        assertFalse(op.isArchivalGroup());
218    }
219
220    @Test
221    public void testArchivalGroup() {
222        final CreateRdfSourceOperation op = builder.archivalGroup(true).build();
223        assertTrue(op.isArchivalGroup());
224    }
225
226
227    private RdfSourceOperation buildOperationWithRelaxProperties(final Model model) {
228        builder = new CreateRdfSourceOperationBuilderImpl(tx, RESOURCE_ID, RDF_SOURCE.toString(),
229                ServerManagedPropsMode.RELAXED);
230        return builder.relaxedProperties(model).build();
231    }
232
233    @Test
234    public void testUserPrincipal() {
235        final RdfSourceOperation op = builder.userPrincipal(USER_PRINCIPAL).build();
236
237        assertEquals(USER_PRINCIPAL, op.getUserPrincipal());
238    }
239
240    @Test
241    public void testParentId() {
242        final CreateRdfSourceOperation op = builder.parentId(PARENT_ID).build();
243
244        assertEquals(PARENT_ID, op.getParentId());
245    }
246}