package edu.kit.aifb.cumulus.webapp; import static edu.kit.aifb.cumulus.WebTestUtils.newTripleStore; import static edu.kit.aifb.cumulus.WebTestUtils.numOfRes; import static edu.kit.aifb.cumulus.WebTestUtils.randomString; import static edu.kit.aifb.cumulus.util.Util.parseNX; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.Test; import org.openrdf.model.Model; import org.openrdf.model.Statement; import org.openrdf.model.impl.LinkedHashModel; import org.openrdf.rio.RDFFormat; import org.openrdf.rio.Rio; import edu.kit.aifb.cumulus.framework.Environment; import edu.kit.aifb.cumulus.framework.Environment.ConfigParams; import edu.kit.aifb.cumulus.util.Util; import edu.kit.aifb.cumulus.webapp.HttpProtocol.Headers; import edu.kit.aifb.cumulus.webapp.HttpProtocol.MimeTypes; /** * Test case for Post REST service ({@link CRUDServlet}) over a CumulusRDF triple store. * * @author Andreas Wagner * @author Andrea Gazzarini * @since 1.0 */ public class CRUDServletPostTest extends AbstractCRUDServletTest { //CHECKSTYLE:OFF private String[] _data = { "<http://gridpedia.org/id/Device> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> . \n <http://gridpedia.org/id/Device> <http://semantic-mediawiki.org/swivt/1.0#page> <http://gridpedia.org/wiki/Device> .", "<http://gridpedia.org/id/Device> <http://www.w3.org/2000/01/rdf-schema#label> \"Device\"^^<http://www.w3.org/2001/XMLSchema#string> .", "<http://gridpedia.org/id/Device> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://gridpedia.org/id/Actor> . \n <http://gridpedia.org/id/Device> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://gridpedia.org/id/Actor> ." }; //CHECKSTYLE:ON /** * Positive test for HTTP Post on the ({@link CRUDServlet}). * * @throws Exception hopefully never, otherwise the test fails. */ @Test public void postData() throws Exception { for (String tripleAsString : _data) { for (String mime_type : MimeTypes.RDF_SERIALIZATIONS) { Model model = new LinkedHashModel(parseNX(tripleAsString)); /* * clean data */ TRIPLE_STORE.removeData(model.iterator()); for (Statement statement : model) { assertEquals("This triple " + tripleAsString + " mustn't exist in the store", 0, numOfRes(TRIPLE_STORE.query(Util.toValueArray(statement)))); } /* * convert to desired RDF serialization */ final ByteArrayOutputStream out = new ByteArrayOutputStream(); Rio.write(model, out, RDFFormat.forMIMEType(mime_type)); /* * prepare mock ... */ final HttpServletRequest request = createMockHttpRequest(null, null, null, null, null); when(request.getHeader(Headers.CONTENT_TYPE)).thenReturn(mime_type); final HttpServletResponse response = mock(HttpServletResponse.class); when(request.getInputStream()).thenReturn(new ServletInputStream() { final InputStream _inputStream = new ByteArrayInputStream(out.toByteArray()); @Override public int read() throws IOException { return _inputStream.read(); } }); /* * POST data ... */ _classUnderTest.doPost(request, response); /* * verify HTTP POST */ verify(response).setStatus(HttpServletResponse.SC_CREATED); for (Statement statement : model) { assertEquals("HTTP POST failed for content-type: '" + mime_type + "' and statement: '" + statement + "'", 1, numOfRes(TRIPLE_STORE.query(Util.toValueArray(statement)))); } } } } /** * If CumulusStoreException occurs during deletion the service must * answer with 500 HTTP status code. Note that this doesn't cover any * possible scenarios...it just uses an uninitialized store in order to see * if a correct response code is returned. * * @throws Exception hopefully never, otherwise the test fails. */ @Test public void postWithCumulusInternalServerFailure() throws Exception { when(_context.getAttribute(ConfigParams.STORE)).thenReturn(newTripleStore()); final HttpServletRequest request = createMockHttpRequest(null, null, null, null, null); when(request.getHeader(Headers.CONTENT_TYPE)).thenReturn(MimeTypes.TEXT_PLAIN); final ServletInputStream stream = new ServletInputStream() { final InputStream _inputStream = new ByteArrayInputStream(_triplesAsString.getBytes(Environment.CHARSET_UTF8)); @Override public int read() throws IOException { return _inputStream.read(); } }; when(request.getInputStream()).thenReturn(stream); final HttpServletResponse response = mock(HttpServletResponse.class); _classUnderTest.doPost(request, response); verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); verify(request).setAttribute("javax.servlet.error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } /** * If request body contains malformed data then an appropriate (400 BAD_REQUEST) response code must be returned. * * @throws Exception hopefully never, otherwise the test fails. * */ @Test public void postWithMalformedData() throws Exception { final HttpServletRequest request = createMockHttpRequest(null, null, null, null, null); for (String content_type : MimeTypes.RDF_SERIALIZATIONS) { when(request.getHeader(Headers.CONTENT_TYPE)).thenReturn(content_type); final ServletInputStream stream = new ServletInputStream() { final InputStream _inputStream = new ByteArrayInputStream(randomString().getBytes(Environment.CHARSET_UTF8)); @Override public int read() throws IOException { return _inputStream.read(); } }; when(request.getInputStream()).thenReturn(stream); final HttpServletResponse response = mock(HttpServletResponse.class); _classUnderTest.doPost(request, response); verify(response).setStatus(HttpServletResponse.SC_BAD_REQUEST); } } /** * If an internal server error occurs during deletion the service must * answer with 500 HTTP status code. Note that this doesn't cover any * possible scenarios...just emulating an uncaught exception in order to see * if a correct response code is returned. * * @throws Exception hopefully never, otherwise the test fails. */ @Test public void postWithUnknownInternalServerFailure() throws Exception { when(_context.getAttribute(ConfigParams.STORE)).thenReturn(null); final HttpServletRequest request = createMockHttpRequest(null, null, null, null, null); when(request.getHeader(Headers.CONTENT_TYPE)).thenReturn(MimeTypes.TEXT_PLAIN); final ServletInputStream stream = new ServletInputStream() { final InputStream _inputStream = new ByteArrayInputStream(_triplesAsString.getBytes(Environment.CHARSET_UTF8)); @Override public int read() throws IOException { return _inputStream.read(); } }; when(request.getInputStream()).thenReturn(stream); final HttpServletResponse response = mock(HttpServletResponse.class); _classUnderTest.doPost(request, response); verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } }