View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *  http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.any23.servlet;
    18
    19  import java.io.File;
    20  import java.io.IOException;
    21  import java.net.URISyntaxException;
    22  import java.net.URLEncoder;
    23  import org.apache.any23.http.HTTPClient;
    24  import org.apache.any23.source.DocumentSource;
    25  import org.apache.any23.source.FileDocumentSource;
    26  import org.apache.any23.source.StringDocumentSource;
    27  import org.apache.any23.util.StringUtils;
    28  import org.junit.After;
    29  import org.junit.Assert;
    30  import org.junit.Before;
    31  import org.junit.Test;
    32  import org.eclipse.jetty.http.HttpTester;
    33  import org.eclipse.jetty.servlet.ServletTester;
    34
    35  /**
    36   * Test case for {@link Servlet} class.
    37   */
    38  // TODO: some test verifications are not strict enough.
    39  //       The assertContainsTag() doesn't verify the entire output content.
    40  public class ServletTest {
    41
    42      private static String content;
    43      private static String acceptHeader;
    44      private static String requestedIRI;
    45
    46      private ServletTester tester;
    47
    48      @Before
    49      public void setUp() throws Exception {
    50          tester = new ServletTester();
    51          tester.setContextPath("/");
    52          tester.addServlet(TestableServlet.class, "/*");
    53          tester.start();
    54          content = "test";
    55          acceptHeader = null;
    56          requestedIRI = null;
    57      }
    58
    59      @After
    60      public void tearDown() throws Exception {
    61          tester.stop();
    62          tester = null;
    63      }
    64
    65      @Test
    66      public void testGETOnlyFormat() throws Exception {
    67          HttpTester.Response response = doGetRequest("/xml");
    68          Assert.assertEquals(404, response.getStatus());
    69          assertContains("Missing IRI", response.getContent());
    70      }
    71
    72      @Test
    73      public void testGETWrongFormat() throws Exception {
    74          HttpTester.Response response = doGetRequest("/dummy/foo.com");
    75          Assert.assertEquals(400, response.getStatus());
    76          assertContains("Invalid format", response.getContent());
    77      }
    78
    79      @Test
    80      public void testGETInvalidIRI() throws Exception {
    81          HttpTester.Response response = doGetRequest("/xml/mailto:richard@cyganiak.de");
    82          Assert.assertEquals(400, response.getStatus());
    83          assertContains("Invalid input IRI", response.getContent());
    84      }
    85
    86      @Test
    87      public void testGETWorks() throws Exception {
    88          content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    89          HttpTester.Response response = doGetRequest("/nt/foo.com/bar.html");
    90          Assert.assertEquals(200, response.getStatus());
    91          Assert.assertEquals("http://foo.com/bar.html", requestedIRI);
    92          String res = response.getContent();
    93          assertContains(
    94                  "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2006/vcard/ns#VCard>",
    95                  res
    96          );
    97      }
    98
    99      @Test
    100     public void testGETAddsHTTPScheme() throws Exception {
    101         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    102         HttpTester.Response response = doGetRequest("/nt/foo.com");
    103         Assert.assertEquals(200, response.getStatus());
    104         Assert.assertEquals("http://foo.com", requestedIRI);
    105     }
    106
    107     @Test
    108     public void testGETIncludesQueryString() throws Exception {
    109         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    110         HttpTester.Response response = doGetRequest("/nt/http://foo.com?id=1");
    111         Assert.assertEquals(200, response.getStatus());
    112         Assert.assertEquals("http://foo.com?id=1", requestedIRI);
    113     }
    114
    115     @Test
    116     public void testGETwithIRIinParam() throws Exception {
    117         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    118         HttpTester.Response response = doGetRequest("/nt?uri=http://foo.com?id=1");
    119         Assert.assertEquals(200, response.getStatus());
    120         Assert.assertEquals("http://foo.com?id=1", requestedIRI);
    121     }
    122
    123     @Test
    124     public void testGETwithFormatAndIRIinParam() throws Exception {
    125         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    126         HttpTester.Response response = doGetRequest("/?format=nt&uri=http://foo.com?id=1");
    127         Assert.assertEquals(200, response.getStatus());
    128         Assert.assertEquals("http://foo.com?id=1", requestedIRI);
    129     }
    130
    131     @Test
    132     public void testGETwithURLDecoding() throws Exception {
    133         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    134         HttpTester.Response response = doGetRequest("/nt/http%3A%2F%2Ffoo.com");
    135         Assert.assertEquals(200, response.getStatus());
    136         Assert.assertEquals("http://foo.com", requestedIRI);
    137     }
    138
    139     @Test
    140     public void testGETwithURLDecodingInParam() throws Exception {
    141         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    142         HttpTester.Response response = doGetRequest("/nt?uri=http%3A%2F%2Ffoo.com");
    143         Assert.assertEquals(200, response.getStatus());
    144         Assert.assertEquals("http://foo.com", requestedIRI);
    145     }
    146
    147     @Test
    148     public void testPOSTNothing() throws Exception {
    149         HttpTester.Response response = doPostRequest("/", "", null);
    150         Assert.assertEquals(400, response.getStatus());
    151         assertContains("Invalid POST request", response.getContent());
    152     }
    153
    154     @Test
    155     public void testPOSTWorks() throws Exception {
    156         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    157         HttpTester.Response response = doPostRequest("/", "format=nt&uri=http://foo.com", "application/x-www-form-urlencoded");
    158         Assert.assertEquals(200, response.getStatus());
    159         Assert.assertEquals("http://foo.com", requestedIRI);
    160         String res = response.getContent();
    161         assertContains("<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2006/vcard/ns#VCard>", res);
    162     }
    163
    164     @Test
    165     public void testPOSTWorksWithParametersOnContentType() throws Exception {
    166         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    167         HttpTester.Response response = doPostRequest(
    168                 "/",
    169                 "format=nt&uri=http://foo.com",
    170                 "application/x-www-form-urlencoded;charset=UTF-8"
    171         );
    172         Assert.assertEquals(200, response.getStatus());
    173         Assert.assertEquals("http://foo.com", requestedIRI);
    174         String res = response.getContent();
    175         assertContains(
    176                 "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2006/vcard/ns#VCard>",
    177                 res
    178         );
    179     }
    180
    181     @Test
    182     public void testPOSTBodyWorks() throws Exception {
    183         String body = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    184         HttpTester.Response response = doPostRequest("/nt", body, "text/html");
    185         Assert.assertEquals(200, response.getStatus());
    186         String res = response.getContent();
    187         assertContains(
    188                 "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2006/vcard/ns#VCard>",
    189                 res
    190         );
    191         Assert.assertNull(requestedIRI);
    192     }
    193
    194     @Test
    195     public void testPOSTBodyInParamWorks() throws Exception {
    196         String body = URLEncoder.encode("<html><body><div class=\"vcard fn\">Joe</div></body></html>", "utf-8");
    197         HttpTester.Response response = doPostRequest("/", "format=nt&body=" + body,
    198                 "application/x-www-form-urlencoded");
    199         Assert.assertEquals(200, response.getStatus());
    200         String res = response.getContent();
    201         assertContains(
    202                 "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2006/vcard/ns#VCard>",
    203                 res
    204         );
    205         Assert.assertNull(requestedIRI);
    206     }
    207
    208     @Test
    209     public void testPOSTonlyIRI() throws Exception {
    210         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    211         HttpTester.Response response = doPostRequest("/", "uri=http://foo.com", "application/x-www-form-urlencoded");
    212         Assert.assertEquals(200, response.getStatus());
    213         String res = response.getContent();
    214         assertContains("a vcard:VCard", res);
    215     }
    216
    217     @Test
    218     public void testPOSTonlyFormat() throws Exception {
    219         HttpTester.Response response = doPostRequest("/", "format=rdf", "application/x-www-form-urlencoded");
    220         Assert.assertEquals(400, response.getStatus());
    221         assertContains("uri", response.getContent());
    222     }
    223
    224     /**
    225      * This test has been disabled in order to avoid external resources
    226      * dependencies
    227      *
    228      * @throws Exception if there is an error asserting test data
    229      */
    230     @Test
    231     public void testGETwithURLEncoding() throws Exception {
    232         content = null;
    233         HttpTester.Response response = doGetRequest("/best/http://semanticweb.org/wiki/Knud_M%C3%B6ller");
    234         Assert.assertEquals(200, response.getStatus());
    235     }
    236
    237     /**
    238      * This test has been disabled in order to avoid external resources
    239      * dependencies
    240      *
    241      * @throws Exception if there is an error asserting test data
    242      */
    243     @Test
    244     public void testGETwithURLEncodingWithQuery() throws Exception {
    245         content = null;
    246         HttpTester.Response response = doGetRequest("/best/http://semanticweb.org/wiki/Knud_M%C3%B6ller?appo=xxx");
    247         Assert.assertEquals(200, response.getStatus());
    248     }
    249
    250     /**
    251      * This test has been disabled in order to avoid external resources
    252      * dependencies
    253      *
    254      * @throws Exception if there is an error asserting test data
    255      */
    256     @Test
    257     public void testGETwithURLEncodingWithFragment() throws Exception {
    258         content = null;
    259         HttpTester.Response response = doGetRequest("/best/http://semanticweb.org/wiki/Knud_M%C3%B6ller#abcde");
    260         Assert.assertEquals(200, response.getStatus());
    261     }
    262
    263     @Test
    264     public void testCorrectBaseIRI() throws Exception {
    265         content = "@prefix foaf: <http://xmlns.com/foaf/0.1/> . <> a foaf:Document .";
    266         HttpTester.Response response = doGetRequest("/nt/foo.com/test.n3");
    267         Assert.assertEquals(200, response.getStatus());
    268         assertContains("<http://foo.com/test.n3>", response.getContent());
    269     }
    270
    271     @Test
    272     public void testDefaultBaseIRIinPOST() throws Exception {
    273         String body = "@prefix foaf: <http://xmlns.com/foaf/0.1/> . <> a foaf:Document .";
    274         HttpTester.Response response = doPostRequest("/nt", body, "text/rdf+n3;charset=utf-8");
    275         Assert.assertEquals(200, response.getStatus());
    276         assertContains("<" + Servlet.DEFAULT_BASE_IRI + ">", response.getContent());
    277     }
    278
    279     @Test
    280     public void testPOSTwithoutContentType() throws Exception {
    281         String body = "@prefix foaf: <http://xmlns.com/foaf/0.1/> . <http://example.com/asdf> a foaf:Document .";
    282         HttpTester.Response response = doPostRequest("/nt", body, null);
    283         Assert.assertEquals(400, response.getStatus());
    284         assertContains("Content-Type", response.getContent());
    285     }
    286
    287     @Test
    288     public void testPOSTwithContentTypeParam() throws Exception {
    289         String body = URLEncoder.encode("<http://foo.bar> <http://foo.bar> <http://foo.bar> .", "utf-8");
    290         HttpTester.Response response = doPostRequest("/", "format=nt&body=" + body + "&type=application/x-foobar",
    291                 "application/x-www-form-urlencoded");
    292         Assert.assertEquals(415, response.getStatus());
    293     }
    294
    295     @Test
    296     public void testPOSTbodyMissingFormat() throws Exception {
    297         HttpTester.Response response = doPostRequest(
    298                 "/",
    299                 "<html><body><div class=\"vcard fn\">Joe</div></body></html>", "text/html"
    300         );
    301         Assert.assertEquals(200, response.getStatus());
    302         String res = response.getContent();
    303         assertContains("a vcard:VCard", res);
    304     }
    305
    306     @Test
    307     public void testContentNegotiationDefaultsToTurtle() throws Exception {
    308         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    309         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    310         Assert.assertEquals(200, response.getStatus());
    311         Assert.assertEquals("http://foo.com", requestedIRI);
    312         assertContains("a vcard:VCard", response.getContent());
    313     }
    314
    315     @Test
    316     public void testContentNegotiationForWildcardReturnsTurtle() throws Exception {
    317         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    318         acceptHeader = "*/*";
    319         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    320         Assert.assertEquals(200, response.getStatus());
    321         Assert.assertEquals("http://foo.com", requestedIRI);
    322         assertContains("a vcard:VCard", response.getContent());
    323     }
    324
    325     @Test
    326     public void testContentNegotiationForUnacceptableFormatReturns406() throws Exception {
    327         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    328         acceptHeader = "image/jpeg";
    329         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    330         Assert.assertEquals(406, response.getStatus());
    331         Assert.assertNull(requestedIRI);
    332     }
    333
    334     @Test
    335     public void testContentNegotiationForTurtle() throws Exception {
    336         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    337         acceptHeader = "text/turtle";
    338         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    339         Assert.assertEquals(200, response.getStatus());
    340         Assert.assertEquals("http://foo.com", requestedIRI);
    341         assertContains("a vcard:VCard", response.getContent());
    342     }
    343
    344     @Test
    345     public void testContentNegotiationForTurtleAlias() throws Exception {
    346         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    347         acceptHeader = "application/x-turtle";
    348         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    349         Assert.assertEquals(200, response.getStatus());
    350         Assert.assertEquals("http://foo.com", requestedIRI);
    351         assertContains("a vcard:VCard", response.getContent());
    352     }
    353
    354     @Test
    355     public void testContentNegotiationForRDFXML() throws Exception {
    356         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    357         acceptHeader = "application/rdf+xml";
    358         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    359         Assert.assertEquals(200, response.getStatus());
    360         Assert.assertEquals("http://foo.com", requestedIRI);
    361         assertContains("<rdf1:RDF", response.getContent());
    362     }
    363
    364     @Test
    365     public void testContentNegotiationForNTriples() throws Exception {
    366         content = "<html><body><div class=\"vcard fn\">Joe</div></body></html>";
    367         acceptHeader = "text/plain";
    368         HttpTester.Response response = doGetRequest("/best/http://foo.com");
    369         Assert.assertEquals(200, response.getStatus());
    370         Assert.assertEquals("http://foo.com", requestedIRI);
    371         assertContains("<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>", response.getContent());
    372     }
    373
    374     @Test
    375     public void testResponseWithReport() throws Exception {
    376         content = new FileDocumentSource(
    377                 new File("src/test/resources/org/apache/any23/servlet/missing-og-namespace.html")
    378         ).readStream();
    379         acceptHeader = "text/plain";
    380         HttpTester.Response response = doGetRequest("/best/http://foo.com?validation-mode=validate-fix&report=on");
    381         Assert.assertEquals(200, response.getStatus());
    382         final String content = response.getContent();
    383         assertContainsTag("response", content);
    384         assertContainsTag("extractors", content);
    385         assertContainsTag("report", content);
    386         assertContainsTag("message", true, 1, content);
    387         assertContainsTag("error", true, 1, content);
    388         assertContainsTag("error", true, 1, content);
    389         assertContainsTag("validationReport", content);
    390         assertContainsTag("errors", content);
    391         assertContainsTag("issues", content);
    392         assertContainsTag("ruleActivations", content);
    393         assertContainsTag("data", content);
    394     }
    395
    396     @Test
    397     public void testJSONResponseFormat() throws Exception {
    398         String body = "<http://sub/1> <http://pred/1> \"123\"^^<http://datatype> <http://graph/1>.";
    399         HttpTester.Response response = doPostRequest("/json", body, "application/n-quads");
    400         Assert.assertEquals(200, response.getStatus());
    401         final String EXPECTED_JSON
    402             = "[ {\n"
    403             + "    \"type\" : \"uri\",\n"
    404             + "    \"value\" : \"http://sub/1\"\n"
    405             + "  }, \"http://pred/1\", {\n"
    406             + "    \"type\" : \"literal\",\n"
    407             + "    \"value\" : \"123\",\n"
    408             + "    \"lang\" : null,\n"
    409             + "    \"datatype\" : \"http://datatype\"\n"
    410             + "  }, \"http://graph/1\" ]";
    411         assertContains(EXPECTED_JSON, response.getContent());
    412     }
    413
    414     @Test
    415     public void testJSONLDResponseFormat() throws Exception {
    416         String body = "<http://sub/1> <http://pred/1> \"123\"^^<http://datatype> <http://graph/1>.";
    417         HttpTester.Response response = doPostRequest("/jsonld", body, "application/n-quads");
    418         Assert.assertEquals(200, response.getStatus());
    419         final String EXPECTED_JSON =
    420                 "[ {\n" +
    421                 "  \"@graph\" : [ {\n" +
    422                 "    \"@id\" : \"http://sub/1\",\n" +
    423                 "    \"http://pred/1\" : [ {\n" +
    424                 "      \"@type\" : \"http://datatype\",\n" +
    425                 "      \"@value\" : \"123\"\n" +
    426                 "    } ]\n" +
    427                 "  } ],\n" +
    428                 "  \"@id\" : \"http://graph/1\"\n" +
    429                 "} ]";
    430         assertContains(EXPECTED_JSON, response.getContent());
    431     }
    432
    433     @Test
    434     public void testTriXResponseFormat() throws Exception {
    435         String body = "<http://sub/1> <http://pred/1> \"123\"^^<http://datatype> <http://graph/1>.";
    436         HttpTester.Response response = doPostRequest("/trix", body, "application/n-quads");
    437         Assert.assertEquals(200, response.getStatus());
    438         final String content = response.getContent();
    439         assertContainsTag("graph", false, 1, content);
    440         assertContainsTag("uri", false, 3, content);
    441         assertContainsTag("triple", false, 1, content);
    442     }
    443
    444     private HttpTester.Response doGetRequest(String path) throws Exception {
    445         return doRequest(path, "GET");
    446     }
    447
    448     private HttpTester.Response doPostRequest(String path, String content, String contentType) throws Exception {
    449         HttpTester.Request request = HttpTester.newRequest();
    450
    451         request.setMethod("POST");
    452         request.setVersion("HTTP/1.0");
    453         request.setHeader("Host", "tester");
    454         request.setContent(content);
    455         if (contentType != null) {
    456             request.setHeader("Content-Type", contentType);
    457         }
    458         request.setURI(path);
    459         return HttpTester.parseResponse(tester.getResponses(request.generate()));
    460     }
    461
    462     private HttpTester.Response doRequest(String path, String method) throws Exception {
    463         HttpTester.Request request = HttpTester.newRequest();
    464
    465         request.setMethod(method);
    466         request.setVersion("HTTP/1.0");
    467         request.setHeader("Host", "tester");
    468         if (acceptHeader != null) {
    469             request.setHeader("Accept", acceptHeader);
    470         }
    471
    472         request.setURI(path);
    473         return HttpTester.parseResponse(tester.getResponses(request.generate()));
    474     }
    475
    476     private void assertContains(String expected, String container) {
    477         if (expected.length() == 0) {
    478             throw new IllegalArgumentException("expected string must contains at lease one char.");
    479         }
    480         if (container.contains(expected)) {
    481             return;
    482         }
    483         Assert.fail("expected '" + expected + "' to be contained in '" + container + "'");
    484     }
    485
    486     private void assertContainsTag(String tag, boolean inline, int occurrences, String container) {
    487         if (inline) {
    488             Assert.assertEquals(
    489                     String.format("Cannot find inline tag %s %d times", tag, occurrences),
    490                     occurrences,
    491                     StringUtils.countOccurrences(container, "<" + tag + "/>")
    492             );
    493         } else {
    494             Assert.assertEquals(
    495                     String.format("Cannot find open tag %s %d times", tag, occurrences),
    496                     occurrences,
    497                     StringUtils.countOccurrences(container, "<" + tag + ">")
    498                     + StringUtils.countOccurrences(container, "<" + tag + " ")
    499             );
    500             Assert.assertEquals(
    501                     String.format("Cannot find close tag %s %d times", tag, occurrences),
    502                     occurrences,
    503                     StringUtils.countOccurrences(container, "</" + tag + ">")
    504             );
    505         }
    506     }
    507
    508     private void assertContainsTag(String tag, String container) {
    509         assertContainsTag(tag, false, 1, container);
    510     }
    511
    512     /**
    513      * Test purpose servlet implementation.
    514      */
    515     public static class TestableServlet extends Servlet {
    516
    517         @Override
    518         protected DocumentSource createHTTPDocumentSource(HTTPClient httpClient, String uri)
    519                 throws IOException, URISyntaxException {
    520             requestedIRI = uri;
    521             if (content != null) {
    522                 return new StringDocumentSource(content, uri);
    523             } else {
    524                 return super.createHTTPDocumentSource(httpClient, uri);
    525             }
    526         }
    527
    528     }
    529 }