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.responses;
019
020import static java.util.stream.Stream.of;
021import static com.google.common.util.concurrent.Futures.addCallback;
022import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDdateTime;
023import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
024import static com.hp.hpl.jena.graph.NodeFactory.createURI;
025import static com.hp.hpl.jena.graph.Triple.create;
026import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel;
027import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
028import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
029import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
030import static javax.ws.rs.core.MediaType.valueOf;
031import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_TYPE;
032import static org.fcrepo.http.commons.responses.RdfStreamStreamingOutput.getValueForObject;
033import static org.junit.Assert.assertEquals;
034import static org.junit.Assert.assertFalse;
035import static org.junit.Assert.assertTrue;
036import static org.mockito.Mockito.mock;
037import static org.mockito.MockitoAnnotations.initMocks;
038import static org.openrdf.model.impl.ValueFactoryImpl.getInstance;
039import static org.openrdf.model.util.Literals.createLiteral;
040import static org.slf4j.LoggerFactory.getLogger;
041
042import java.io.ByteArrayInputStream;
043import java.io.ByteArrayOutputStream;
044import java.io.IOException;
045import java.io.InputStream;
046import java.io.OutputStream;
047import java.util.HashMap;
048import java.util.Map;
049import java.util.stream.Stream;
050
051import javax.jcr.Session;
052import javax.ws.rs.WebApplicationException;
053import javax.ws.rs.core.MediaType;
054
055import com.hp.hpl.jena.rdf.model.RDFNode;
056import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
057import org.fcrepo.kernel.api.RdfStream;
058import org.junit.Before;
059import org.junit.Test;
060import org.mockito.Mock;
061import org.mockito.stubbing.Answer;
062import org.openrdf.model.Value;
063import org.openrdf.model.ValueFactory;
064import org.openrdf.rio.RDFHandlerException;
065import org.slf4j.Logger;
066
067import com.google.common.util.concurrent.FutureCallback;
068import com.hp.hpl.jena.graph.Node;
069import com.hp.hpl.jena.graph.Triple;
070import com.hp.hpl.jena.rdf.model.Model;
071
072/**
073 * <p>RdfStreamStreamingOutputTest class.</p>
074 *
075 * @author ajs6f
076 */
077public class RdfStreamStreamingOutputTest {
078
079    private RdfStreamStreamingOutput testRdfStreamStreamingOutput;
080
081    private static final Triple triple = create(createURI("info:testSubject"),
082            createURI("info:testPredicate"), createURI("info:testObject"));
083
084    @Mock
085    private Node mockNode;
086
087    private final RdfStream testRdfStream = new DefaultRdfStream(triple.getSubject(), of(triple));
088
089    private final Map<String, String> testNamespaces = new HashMap<>();
090
091    @Mock
092    private RdfStream mockRdfStream;
093
094    @Mock
095    private Session mockSession;
096
097    private final MediaType testMediaType = valueOf("application/rdf+xml");
098
099    private static final ValueFactory vf = getInstance();
100
101    private static final Logger LOGGER =
102            getLogger(RdfStreamStreamingOutputTest.class);
103
104    @Before
105    public void setUp() {
106        initMocks(this);
107        testRdfStreamStreamingOutput =
108            new RdfStreamStreamingOutput(testRdfStream, testNamespaces, testMediaType);
109    }
110
111    @Test
112    public void testGetValueForObjectWithResource() {
113        final Node resource = createURI("info:test");
114        final Value result = getValueForObject(resource);
115        assertEquals("Created bad Value!", vf.createURI("info:test"), result);
116    }
117
118    @Test
119    public void testGetValueForObjectWithLiteral() {
120        final Node resource = createLiteral("test");
121        final Value result = getValueForObject(resource);
122        assertEquals("Created bad Value!", createLiteral(vf, "test"), result);
123    }
124
125    @Test
126    public void testWrite() throws IOException {
127        assertOutputContainsTriple(triple);
128    }
129
130    public void assertOutputContainsTriple(final Triple expected) throws IOException {
131        try (final RdfStream input = new DefaultRdfStream(expected.getSubject(), of(expected));
132                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
133            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
134            try ( final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
135                final Model result = createDefaultModel().read(resultStream, null);
136                assertTrue("Didn't find our test triple!", result.contains(result.asStatement(expected)));
137            }
138        }
139    }
140
141    @Test
142    public void testWriteWithNamespace() throws IOException {
143        final Map<String, String> namespaces = new HashMap<>();
144        namespaces.put("a", "info:a");
145        try (final RdfStream input = new DefaultRdfStream(triple.getSubject(), of(triple));
146                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
147            new RdfStreamStreamingOutput(input, namespaces, TURTLE_TYPE).write(output);
148            final String s = output.toString("UTF-8");
149            assertTrue(s.contains("@prefix a: <info:a>"));
150        }
151    }
152
153
154    @Test
155    public void testWriteWithXmlnsNamespace() throws IOException {
156        final Map<String, String> namespaces = new HashMap<>();
157        namespaces.put("xmlns", "info:a");
158        try (final RdfStream input = new DefaultRdfStream(triple.getSubject(), of(triple));
159                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
160            new RdfStreamStreamingOutput(input, namespaces, TURTLE_TYPE).write(output);
161            final String s = output.toString("UTF-8");
162            assertFalse(s.contains("@prefix xmlns"));
163        }
164    }
165
166    @Test
167    public void testWriteWithTypedObject() throws IOException {
168        assertOutputContainsTriple(create(createURI("info:testSubject"),
169                createURI("info:testPredicate"),
170                createTypedLiteral(0).asNode()));
171    }
172
173    @Test
174    public void testWriteWithBlankSubject() throws IOException {
175        try (final RdfStream input = new DefaultRdfStream(createResource().asNode(), of(create(createResource()
176                .asNode(), createURI("info:testPredicate"), createTypedLiteral(0).asNode())));
177                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
178            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
179            try (final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
180                final Model result = createDefaultModel().read(resultStream, null);
181                assertTrue(result.contains(null, createProperty("info:testPredicate"), createTypedLiteral(0)));
182            }
183        }
184    }
185
186
187    @Test
188    public void testWriteWithBlankObject() throws IOException {
189        final Stream<Triple> triples =
190                of(create(createResource().asNode(), createURI("info:testPredicate"), createResource().asNode()));
191        try (final RdfStream input = new DefaultRdfStream(createResource().asNode(), triples);
192                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
193            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
194            try (final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
195                final Model result = createDefaultModel().read(resultStream, null);
196                assertTrue(result.contains(null, createProperty("info:testPredicate"), (RDFNode) null));
197            }
198        }
199    }
200
201    @Test
202    public void testWriteWithDatetimeObject() throws IOException {
203        assertOutputContainsTriple(create(createURI("info:testSubject"),
204                createURI("info:testPredicate"), createLiteral("2014-01-01T01:02:03Z", XSDdateTime)));
205    }
206
207    @Test
208    public void testWriteWithLanguageLiteral() throws IOException {
209        assertOutputContainsTriple(create(createURI("info:testSubject"),
210                createURI("info:testPredicate"),
211                createLiteral("french string", "fr")));
212    }
213
214    @Test(expected = WebApplicationException.class)
215    public void testWriteWithException() throws IOException {
216
217        final FutureCallback<Void> callback = new FutureCallback<Void>() {
218
219            @Override
220            public void onSuccess(final Void v) {
221                throw new AssertionError("Should never happen!");
222            }
223
224            @Override
225            public void onFailure(final Throwable e) {
226                LOGGER.debug("Got exception:", e);
227                assertTrue("Got wrong kind of exception!", e instanceof RDFHandlerException);
228            }
229        };
230        addCallback(testRdfStreamStreamingOutput, callback);
231        try (final OutputStream mockOutputStream = mock(OutputStream.class, (Answer<Object>) invocation -> {
232            throw new IOException("Expected.");
233        })) {
234            testRdfStreamStreamingOutput.write(mockOutputStream);
235        }
236    }
237}