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.http.commons.api.rdf;
019
020import org.apache.jena.rdf.model.Resource;
021import org.fcrepo.http.commons.session.HttpSession;
022import org.fcrepo.kernel.api.FedoraSession;
023import org.fcrepo.kernel.api.exception.InvalidResourceIdentifierException;
024import org.fcrepo.kernel.api.models.Container;
025import org.fcrepo.kernel.api.models.FedoraBinary;
026import org.fcrepo.kernel.api.models.FedoraResource;
027import org.fcrepo.kernel.api.models.FedoraTimeMap;
028import org.fcrepo.kernel.api.models.FedoraWebacAcl;
029import org.fcrepo.kernel.api.models.NonRdfSourceDescription;
030import org.fcrepo.kernel.modeshape.ContainerImpl;
031import org.fcrepo.kernel.modeshape.FedoraBinaryImpl;
032import org.fcrepo.kernel.modeshape.FedoraResourceImpl;
033import org.fcrepo.kernel.modeshape.FedoraSessionImpl;
034import org.fcrepo.kernel.modeshape.FedoraTimeMapImpl;
035import org.fcrepo.kernel.modeshape.FedoraWebacAclImpl;
036import org.fcrepo.kernel.modeshape.NonRdfSourceDescriptionImpl;
037import org.junit.Before;
038import org.junit.Test;
039import org.junit.runner.RunWith;
040import org.mockito.Mock;
041import org.mockito.junit.MockitoJUnitRunner;
042
043import javax.jcr.Node;
044import javax.jcr.Property;
045import javax.jcr.RepositoryException;
046import javax.jcr.Session;
047import javax.jcr.Workspace;
048import javax.jcr.version.VersionManager;
049import javax.ws.rs.core.UriBuilder;
050
051import static org.apache.jena.rdf.model.ResourceFactory.createResource;
052import static org.fcrepo.http.commons.test.util.TestHelpers.setField;
053import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_BINARY;
054import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION;
055import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_TIME_MAP;
056import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_WEBAC_ACL;
057import static org.fcrepo.kernel.api.FedoraTypes.MEMENTO;
058import static org.fcrepo.kernel.api.FedoraTypes.MEMENTO_ORIGINAL;
059import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_DESCRIPTION;
060import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getJcrNode;
061import static org.junit.Assert.assertEquals;
062import static org.junit.Assert.assertTrue;
063import static org.mockito.Mockito.when;
064
065/**
066 * @author cabeer
067 */
068@RunWith(MockitoJUnitRunner.Silent.class)
069public class HttpResourceConverterTest {
070
071    @Mock
072    private Session session, txSession;
073
074    @Mock
075    private Node node, mementoNode, timeMapNode, descriptionNode, webacAclNode;
076
077    @Mock
078    private Property mockOriginal;
079
080    private FedoraSession testSession, testTxSession;
081
082    private HttpSession testHttpSession, testHttpBatchSession;
083
084    private HttpResourceConverter converter;
085    private final String uriTemplate = "http://localhost:8080/some/{path: .*}";
086    private final String path = "arbitrary/path";
087
088    private final String resourceUri = "http://localhost:8080/some/" + path;
089
090    private final Resource resource = createResource(resourceUri);
091    private final Resource metadataResource = createResource(resource.toString() + "/fcr:metadata");
092
093    @Mock
094    private Workspace mockWorkspace;
095
096    @Mock
097    private VersionManager mockVersionManager;
098
099    @Before
100    public void setUp() throws RepositoryException {
101        final UriBuilder uriBuilder = UriBuilder.fromUri(uriTemplate);
102        testSession = new FedoraSessionImpl(session);
103        testTxSession = new FedoraSessionImpl(txSession);
104        testHttpSession = new HttpSession(testSession);
105        testHttpBatchSession = new HttpSession(testTxSession);
106        testHttpBatchSession.makeBatchSession();
107        converter = new HttpResourceConverter(testHttpSession, uriBuilder);
108
109        when(session.getNode("/" + path)).thenReturn(node);
110        when(session.getNode("/")).thenReturn(node);
111        when(node.getPath()).thenReturn("/" + path);
112        when(node.isNodeType(FEDORA_NON_RDF_SOURCE_DESCRIPTION)).thenReturn(false);
113        when(descriptionNode.getPath()).thenReturn("/" + path + "/" + FEDORA_DESCRIPTION);
114        when(descriptionNode.isNodeType(FEDORA_NON_RDF_SOURCE_DESCRIPTION)).thenReturn(true);
115        when(session.getWorkspace()).thenReturn(mockWorkspace);
116        when(mockWorkspace.getName()).thenReturn("default");
117        when(mockWorkspace.getVersionManager()).thenReturn(mockVersionManager);
118
119        when(mockOriginal.getNode()).thenReturn(node);
120        when(timeMapNode.getProperty(MEMENTO_ORIGINAL)).thenReturn(mockOriginal);
121        when(timeMapNode.isNodeType(FEDORA_TIME_MAP)).thenReturn(true);
122        when(webacAclNode.isNodeType(FEDORA_WEBAC_ACL)).thenReturn(true);
123    }
124
125    @Test
126    public void testDoForward() {
127        final FedoraResource converted = converter.convert(resource);
128        assertEquals(node, getJcrNode(converted));
129    }
130
131    @Test
132    public void testDoForwardWithDatastreamContent() throws Exception {
133        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
134        final FedoraResource converted = converter.convert(resource);
135        assertTrue(converted instanceof FedoraBinary);
136        assertEquals(node, getJcrNode(converted));
137    }
138
139    @Test
140    public void testDoForwardWithDatastreamMetadata() throws Exception {
141        when(session.getNode("/" + path + "/" + FEDORA_DESCRIPTION)).thenReturn(node);
142        when(node.isNodeType(FEDORA_NON_RDF_SOURCE_DESCRIPTION)).thenReturn(true);
143        final FedoraResource converted = converter.convert(metadataResource);
144        assertTrue(converted instanceof NonRdfSourceDescription);
145        assertEquals(node, getJcrNode(converted));
146    }
147
148    @Test
149    public void testDoForwardWithAHash() throws Exception {
150        when(session.getNode("/" + path + "/#/with-a-hash")).thenReturn(node);
151        final FedoraResource converted =
152                converter.convert(createResource("http://localhost:8080/some/" + path + "#with-a-hash"));
153        assertEquals(node, getJcrNode(converted));
154    }
155
156    @Test
157    public void testDoForwardWithTransaction() throws Exception {
158        setField(testTxSession, "id", "xyz");
159        final HttpResourceConverter converter = new HttpResourceConverter(testHttpBatchSession,
160                UriBuilder.fromUri(uriTemplate));
161        when(txSession.getNode("/" + path)).thenReturn(node);
162        when(txSession.getWorkspace()).thenReturn(mockWorkspace);
163        final Resource resource = createResource("http://localhost:8080/some/tx:xyz/" + path);
164        final FedoraResource converted = converter.convert(resource);
165        assertEquals(node, getJcrNode(converted));
166    }
167
168    @Test
169    public void testDoForwardWithUuid() throws Exception {
170        final Resource resource = createResource("http://localhost:8080/some/[xyz]");
171        when(session.getNode("/[xyz]")).thenReturn(node);
172        final FedoraResource converted = converter.convert(resource);
173        assertEquals(node, getJcrNode(converted));
174    }
175
176    @Test
177    public void testDoForwardRoot() {
178        final Resource resource = createResource("http://localhost:8080/some/");
179        final FedoraResource converted = converter.convert(resource);
180        assertEquals(node, getJcrNode(converted));
181        assertTrue(converter.inDomain(resource));
182    }
183
184    @Test
185    public void testDoForwardRootWithoutSlash() {
186        final Resource resource = createResource("http://localhost:8080/some");
187        final FedoraResource converted = converter.convert(resource);
188        assertEquals(node, getJcrNode(converted));
189        assertTrue(converter.inDomain(resource));
190    }
191
192    @Test
193    public void testDoBackward() {
194        final Resource converted = converter.reverse().convert(new FedoraResourceImpl(node));
195        assertEquals(resource, converted);
196    }
197
198    @Test
199    public void testDoBackwardWithDatastreamContent() throws Exception {
200        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
201        final Resource converted = converter.reverse().convert(new FedoraBinaryImpl(node));
202        assertEquals(resource, converted);
203    }
204
205    @Test
206    public void testDoBackwardWithDatastreamMetadata() {
207        final Resource converted = converter.reverse().convert(new NonRdfSourceDescriptionImpl(descriptionNode));
208        assertEquals(metadataResource, converted);
209    }
210
211    @Test
212    public void testDoBackwardWithHash() throws Exception {
213        when(node.getPath()).thenReturn(path + "/#/with-a-hash");
214        final Resource converted = converter.reverse().convert(new FedoraResourceImpl(node));
215        assertEquals(createResource("http://localhost:8080/some/" + path + "#with-a-hash"), converted);
216    }
217
218    @Test
219    public void testDoBackwardWithTransaction() throws Exception {
220        setField(testTxSession, "id", "xyz");
221        final HttpResourceConverter converter = new HttpResourceConverter(testHttpBatchSession,
222                UriBuilder.fromUri(uriTemplate));
223        when(txSession.getNode("/" + path)).thenReturn(node);
224        when(txSession.getWorkspace()).thenReturn(mockWorkspace);
225        when(node.getSession()).thenReturn(txSession);
226        final Resource resource = createResource("http://localhost:8080/some/tx:xyz/" + path);
227        final Resource converted = converter.reverse().convert(new FedoraResourceImpl(node));
228        assertEquals(resource, converted);
229    }
230
231    @Test
232    public void testToStringWithRoot() {
233        assertEquals("/", converter.asString(createResource("http://localhost:8080/some/")));
234    }
235
236    @Test (expected = InvalidResourceIdentifierException.class)
237    public void testToStringWithEmptPathSegment() {
238        converter.asString(createResource("http://localhost:8080/some/test/a//b/c/d"));
239    }
240
241    @Test
242    public void testDoForwardWithTimemap() throws Exception {
243        final Resource resource = createResource("http://localhost:8080/some/container/fcr:versions");
244        when(session.getNode("/container")).thenReturn(node);
245
246        when(session.getNode("/container/fedora:timemap")).thenReturn(timeMapNode);
247
248        final FedoraResource converted = converter.convert(resource);
249        assertTrue("Converted resource must be a timemap", converted instanceof FedoraTimeMap);
250
251        final Node resultNode = getJcrNode(converted);
252        assertEquals(timeMapNode, resultNode);
253    }
254
255    @Test
256    public void testDoForwardWithBinaryTimemap() throws Exception {
257        final Resource resource = createResource("http://localhost:8080/some/binary/fcr:versions");
258        when(session.getNode("/binary")).thenReturn(node);
259        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
260
261        when(session.getNode("/binary/fedora:timemap")).thenReturn(timeMapNode);
262
263        final FedoraResource converted = converter.convert(resource);
264        assertTrue("Converted resource must be a timemap", converted instanceof FedoraTimeMap);
265
266        final Node resultNode = getJcrNode(converted);
267        assertEquals(timeMapNode, resultNode);
268    }
269
270    @Test
271    public void testDoForwardWithBinaryDescriptionTimemap() throws Exception {
272        final Resource resource = createResource("http://localhost:8080/some/binary/fcr:metadata/fcr:versions");
273        when(node.isNodeType(FEDORA_NON_RDF_SOURCE_DESCRIPTION)).thenReturn(true);
274        when(session.getNode("/binary/fedora:description")).thenReturn(node);
275
276        when(session.getNode("/binary/fedora:description/fedora:timemap")).thenReturn(timeMapNode);
277
278        final FedoraResource converted = converter.convert(resource);
279        assertTrue("Converted resource must be a timemap", converted instanceof FedoraTimeMap);
280
281        final Node resultNode = getJcrNode(converted);
282        assertEquals(timeMapNode, resultNode);
283    }
284
285    @Test
286    public void testDoBackWithTimemap() throws Exception {
287        final FedoraTimeMap timemap = new FedoraTimeMapImpl(timeMapNode);
288        when(timeMapNode.getPath()).thenReturn(path + "/fedora:timemap");
289
290        final Resource converted = converter.reverse().convert(timemap);
291        final Resource expectedResource = createResource("http://localhost:8080/some/" + path + "/fcr:versions");
292        assertEquals(expectedResource, converted);
293    }
294
295    @Test
296    public void testDoBackWithBinaryTimemap() throws Exception {
297        final FedoraTimeMap timemap = new FedoraTimeMapImpl(timeMapNode);
298        when(timeMapNode.getPath()).thenReturn(path + "/fedora:timemap");
299
300        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
301
302        final Resource converted = converter.reverse().convert(timemap);
303        final Resource expectedResource = createResource(
304                "http://localhost:8080/some/" + path + "/fcr:versions");
305        assertEquals(expectedResource, converted);
306    }
307
308    @Test
309    public void testDoBackWithBinaryDescriptionTimemap() throws Exception {
310        final FedoraTimeMap timemap = new FedoraTimeMapImpl(timeMapNode);
311        when(timeMapNode.getPath()).thenReturn(path + "/fedora:description/fedora:timemap");
312
313        when(node.isNodeType(FEDORA_NON_RDF_SOURCE_DESCRIPTION)).thenReturn(true);
314
315        final Resource converted = converter.reverse().convert(timemap);
316        final Resource expectedResource = createResource(
317                "http://localhost:8080/some/" + path + "/fcr:metadata/fcr:versions");
318        assertEquals(expectedResource, converted);
319    }
320
321    @Test
322    public void testDoForwardWithMemento() throws Exception {
323        final Resource resource = createResource(
324                "http://localhost:8080/some/container/fcr:versions/20180315180915");
325        when(mementoNode.isNodeType(MEMENTO)).thenReturn(true);
326        when(session.getNode("/container/fedora:timemap/20180315180915")).thenReturn(mementoNode);
327
328        when(session.getNode("/container")).thenReturn(node);
329
330        final FedoraResource converted = converter.convert(resource);
331        assertTrue("Converted resource must be a container", converted instanceof Container);
332
333        final Node resultNode = getJcrNode(converted);
334        assertEquals(mementoNode, resultNode);
335    }
336
337    @Test
338    public void testDoForwardWithMementoWithHash() throws Exception {
339        final Resource resource = createResource(
340                "http://localhost:8080/some/container/fcr:versions/20180315180915#test");
341        when(session.getNode("/container/fedora:timemap/20180315180915/#/test")).thenReturn(node);
342
343        final FedoraResource converted = converter.convert(resource);
344        final Node resultNode = getJcrNode(converted);
345        assertEquals(node, resultNode);
346    }
347
348    @Test
349    public void testDoForwardWithBinaryMemento() throws Exception {
350        final Resource resource = createResource(
351                "http://localhost:8080/some/binary/fcr:versions/20180315180915");
352        when(mementoNode.isNodeType(MEMENTO)).thenReturn(true);
353        when(mementoNode.isNodeType(FEDORA_BINARY)).thenReturn(true);
354        when(session.getNode("/binary/fedora:timemap/20180315180915")).thenReturn(mementoNode);
355
356        when(session.getNode("/binary")).thenReturn(node);
357        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
358
359        final FedoraResource converted = converter.convert(resource);
360        assertTrue("Converted resource must be a binary", converted instanceof FedoraBinary);
361
362        final Node resultNode = getJcrNode(converted);
363        assertEquals(mementoNode, resultNode);
364    }
365
366    @Test
367    public void testDoForwardWithBinaryDescriptionMemento() throws Exception {
368        final Resource resource = createResource(
369                "http://localhost:8080/some/binary/fcr:metadata/fcr:versions/20180315180915");
370        when(mementoNode.isNodeType(MEMENTO)).thenReturn(true);
371        // Timemap for binary description uses fedora:timemap name
372        when(session.getNode("/binary/fedora:description/fedora:timemap/20180315180915")).thenReturn(mementoNode);
373
374        when(session.getNode("/binary/fedora:description")).thenReturn(node);
375
376        final FedoraResource converted = converter.convert(resource);
377        assertTrue("Converted resource must be a container", converted instanceof Container);
378
379        final Node resultNode = getJcrNode(converted);
380        assertEquals(mementoNode, resultNode);
381    }
382
383    @Test
384    public void testDoBackWithMemento() throws Exception {
385        when(node.getPath()).thenReturn("/" + path + "/fedora:timemap/20180315180915");
386        when(node.isNodeType(MEMENTO)).thenReturn(true);
387
388        final Container memento = new ContainerImpl(node);
389
390        final Resource converted = converter.reverse().convert(memento);
391        final Resource expectedResource = createResource(resourceUri + "/fcr:versions/20180315180915");
392        assertEquals(expectedResource, converted);
393    }
394
395    @Test
396    public void testDoBackWithBinaryMemento() throws Exception {
397        when(node.getPath()).thenReturn("/" + path + "/fedora:timemap/20180315180915");
398        when(node.isNodeType(FEDORA_BINARY)).thenReturn(true);
399
400        when(node.isNodeType(MEMENTO)).thenReturn(true);
401
402        final FedoraBinary memento = new FedoraBinaryImpl(node);
403
404        final Resource converted = converter.reverse().convert(memento);
405        final Resource expectedResource = createResource(resourceUri + "/fcr:versions/20180315180915");
406        assertEquals(expectedResource, converted);
407    }
408
409    @Test
410    public void testDoBackWithBinaryDescriptionMemento() throws Exception {
411        when(descriptionNode.getPath()).thenReturn("/" + path + "/fedora:description/fedora:timemap/20180315180915");
412        when(descriptionNode.isNodeType(MEMENTO)).thenReturn(true);
413
414        final NonRdfSourceDescription memento = new NonRdfSourceDescriptionImpl(descriptionNode);
415
416        final Resource converted = converter.reverse().convert(memento);
417        final Resource expectedResource = createResource(resourceUri + "/fcr:metadata/fcr:versions/20180315180915");
418        assertEquals(expectedResource, converted);
419    }
420
421    @Test
422    public void testDoForwardWithWebacAcl() throws Exception {
423        final Resource resource = createResource("http://localhost:8080/some/container/fcr:acl");
424        when(session.getNode("/container")).thenReturn(node);
425
426        when(session.getNode("/container/fedora:acl")).thenReturn(webacAclNode);
427
428        final FedoraResource converted = converter.convert(resource);
429        assertTrue("Converted resource must be a FedoraWebacAcl", converted instanceof FedoraWebacAcl);
430
431        final Node resultNode = getJcrNode(converted);
432        assertEquals(webacAclNode, resultNode);
433    }
434
435    @Test
436    public void testDoBackWithWebacAcl() throws Exception {
437        final FedoraWebacAcl webacAcl = new FedoraWebacAclImpl(webacAclNode);
438        when(webacAclNode.getPath()).thenReturn(path + "/fedora:acl");
439
440        final Resource converted = converter.reverse().convert(webacAcl);
441        final Resource expectedResource = createResource("http://localhost:8080/some/" + path + "/fcr:acl");
442        assertEquals(expectedResource, converted);
443    }
444
445    @Test
446    public void testDoForwardWithWebacAclWithHash() throws Exception {
447        final Resource resource = createResource("http://localhost:8080/some/container/fcr:acl#hash_resource");
448        when(session.getNode("/container")).thenReturn(node);
449
450        when(session.getNode("/container/fedora:acl/#/hash_resource")).thenReturn(webacAclNode);
451
452        final FedoraResource converted = converter.convert(resource);
453        assertTrue("Converted resource must be a FedoraWebacAcl", converted instanceof FedoraWebacAcl);
454
455        final Node resultNode = getJcrNode(converted);
456        assertEquals(webacAclNode, resultNode);
457    }
458
459    @Test
460    public void testDoBackWithWebacAclHash() throws Exception {
461        final FedoraWebacAcl webacAcl = new FedoraWebacAclImpl(webacAclNode);
462        when(webacAclNode.getPath()).thenReturn(path + "/fedora:acl/#/hash_resource");
463
464        final Resource converted = converter.reverse().convert(webacAcl);
465        final Resource expectedResource =
466            createResource("http://localhost:8080/some/" + path + "/fcr:acl#hash_resource");
467        assertEquals(expectedResource, converted);
468    }
469}