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