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.http.commons.responses;
007
008import static java.util.stream.Stream.of;
009import static com.google.common.util.concurrent.Futures.addCallback;
010import static javax.ws.rs.core.MediaType.valueOf;
011import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDdateTime;
012import static org.apache.jena.graph.NodeFactory.createLiteral;
013import static org.apache.jena.graph.NodeFactory.createURI;
014import static org.apache.jena.graph.Triple.create;
015import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
016import static org.apache.jena.rdf.model.ResourceFactory.createProperty;
017import static org.apache.jena.rdf.model.ResourceFactory.createResource;
018import static org.apache.jena.rdf.model.ResourceFactory.createTypedLiteral;
019import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_TYPE;
020import static org.junit.Assert.assertTrue;
021import static org.mockito.Mockito.mock;
022import static org.slf4j.LoggerFactory.getLogger;
023
024import java.io.ByteArrayInputStream;
025import java.io.ByteArrayOutputStream;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.OutputStream;
029import java.util.HashMap;
030import java.util.Map;
031import java.util.stream.Stream;
032
033import javax.ws.rs.WebApplicationException;
034import javax.ws.rs.core.MediaType;
035
036import com.google.common.util.concurrent.FutureCallback;
037import com.google.common.util.concurrent.MoreExecutors;
038
039import org.apache.jena.rdf.model.RDFNode;
040import org.apache.jena.riot.RiotException;
041import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
042import org.fcrepo.kernel.api.RdfStream;
043import org.junit.Before;
044import org.junit.Test;
045import org.mockito.Mock;
046import org.mockito.stubbing.Answer;
047import org.slf4j.Logger;
048
049import org.apache.jena.graph.Node;
050import org.apache.jena.graph.Triple;
051import org.apache.jena.rdf.model.Model;
052
053import org.junit.runner.RunWith;
054import org.mockito.junit.MockitoJUnitRunner;
055
056/**
057 * <p>RdfStreamStreamingOutputTest class.</p>
058 *
059 * @author ajs6f
060 */
061@RunWith(MockitoJUnitRunner.class)
062public class RdfStreamStreamingOutputTest {
063
064    private RdfStreamStreamingOutput testRdfStreamStreamingOutput;
065
066    private static final Triple triple = create(createURI("info:testSubject"),
067            createURI("info:testPredicate"), createURI("info:testObject"));
068
069    @Mock
070    private Node mockNode;
071
072    private final RdfStream testRdfStream = new DefaultRdfStream(triple.getSubject(), of(triple));
073
074    private final Map<String, String> testNamespaces = new HashMap<>();
075
076    @Mock
077    private RdfStream mockRdfStream;
078
079    private final MediaType testMediaType = valueOf("application/rdf+xml");
080
081    private static final Logger LOGGER =
082            getLogger(RdfStreamStreamingOutputTest.class);
083
084    @Before
085    public void setUp() {
086        testRdfStreamStreamingOutput =
087            new RdfStreamStreamingOutput(testRdfStream, testNamespaces, testMediaType);
088    }
089
090    @Test
091    public void testWrite() throws IOException {
092        assertOutputContainsTriple(triple);
093    }
094
095    public void assertOutputContainsTriple(final Triple expected) throws IOException {
096        try (final RdfStream input = new DefaultRdfStream(expected.getSubject(), of(expected));
097                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
098            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
099            try ( final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
100                final Model result = createDefaultModel().read(resultStream, null);
101                assertTrue("Didn't find our test triple!", result.contains(result.asStatement(expected)));
102            }
103        }
104    }
105
106    @Test
107    public void testWriteWithNamespace() throws IOException {
108        final Map<String, String> namespaces = new HashMap<>();
109        namespaces.put("a", "info:");
110        try (final RdfStream input = new DefaultRdfStream(triple.getSubject(), of(triple));
111                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
112            new RdfStreamStreamingOutput(input, namespaces, TURTLE_TYPE).write(output);
113            final String s = output.toString("UTF-8");
114            assertTrue(s.replaceAll("\\s+", " ").contains("@prefix a: <info:>"));
115        }
116    }
117
118    @Test
119    public void testWriteWithTypedObject() throws IOException {
120        assertOutputContainsTriple(create(createURI("info:testSubject"),
121                createURI("info:testPredicate"),
122                createTypedLiteral(0).asNode()));
123    }
124
125    @Test
126    public void testWriteWithBlankSubject() throws IOException {
127        try (final RdfStream input = new DefaultRdfStream(createResource().asNode(), of(create(createResource()
128                .asNode(), createURI("info:testPredicate"), createTypedLiteral(0).asNode())));
129                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
130            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
131            try (final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
132                final Model result = createDefaultModel().read(resultStream, null);
133                assertTrue(result.contains(null, createProperty("info:testPredicate"), createTypedLiteral(0)));
134            }
135        }
136    }
137
138
139    @Test
140    public void testWriteWithBlankObject() throws IOException {
141        final Stream<Triple> triples =
142                of(create(createResource().asNode(), createURI("info:testPredicate"), createResource().asNode()));
143        try (final RdfStream input = new DefaultRdfStream(createResource().asNode(), triples);
144                final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
145            new RdfStreamStreamingOutput(input, testNamespaces, testMediaType).write(output);
146            try (final InputStream resultStream = new ByteArrayInputStream(output.toByteArray())) {
147                final Model result = createDefaultModel().read(resultStream, null);
148                assertTrue(result.contains(null, createProperty("info:testPredicate"), (RDFNode) null));
149            }
150        }
151    }
152
153    @Test
154    public void testWriteWithDatetimeObject() throws IOException {
155        assertOutputContainsTriple(create(createURI("info:testSubject"),
156                createURI("info:testPredicate"), createLiteral("2014-01-01T01:02:03Z", XSDdateTime)));
157    }
158
159    @Test
160    public void testWriteWithLanguageLiteral() throws IOException {
161        assertOutputContainsTriple(create(createURI("info:testSubject"),
162                createURI("info:testPredicate"),
163                createLiteral("french string", "fr")));
164    }
165
166    @Test(expected = WebApplicationException.class)
167    public void testWriteWithException() throws IOException {
168
169        final FutureCallback<Void> callback = new FutureCallback<Void>() {
170
171            @Override
172            public void onSuccess(final Void v) {
173                throw new AssertionError("Should never happen!");
174            }
175
176            @Override
177            public void onFailure(final Throwable e) {
178                LOGGER.debug("Got exception:", e.getMessage());
179                assertTrue("Got wrong kind of exception!", e instanceof RiotException);
180            }
181        };
182        addCallback(testRdfStreamStreamingOutput, callback, MoreExecutors.directExecutor());
183        try (final OutputStream mockOutputStream = mock(OutputStream.class, (Answer<Object>) invocation -> {
184            throw new RiotException("Expected.");
185        })) {
186            testRdfStreamStreamingOutput.write(mockOutputStream);
187        }
188    }
189}