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