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