Establish mockserver with fixtures for backend API responses

Change-Id: I011e529655e9ef63180c004f97b26c3b1f6f1e34
diff --git a/plugin/pom.xml b/plugin/pom.xml
index d9f6c5a..834bb14 100644
--- a/plugin/pom.xml
+++ b/plugin/pom.xml
@@ -74,7 +74,15 @@
             <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
             <version>${jersey.version}</version>
             <scope>test</scope>
-        </dependency>    
+        </dependency>
+
+        <!-- Mock server framework -->
+        <dependency>
+	        <groupId>org.mock-server</groupId>
+          <artifactId>mockserver-netty</artifactId>
+          <version>3.10.2</version>
+	        <scope>test</scope>
+        </dependency>
     </dependencies>
     
     <build>
diff --git a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/IdsExportService.java b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/IdsExportService.java
index 996e132..db6b74b 100644
--- a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/IdsExportService.java
+++ b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/IdsExportService.java
@@ -62,7 +62,7 @@
             @FormParam("format") String format, @FormParam("q") String q,
             @FormParam("ql") String ql, @FormParam("islimit") String il,
             @FormParam("hitc") int hitc) throws IOException {
-
+        
 
         String[][] params = { { "fname", fname }, { "format", format },
                 { "q", q }, { "ql", ql } };
@@ -78,6 +78,7 @@
         ResponseBuilder builder;
         Client client = ClientBuilder.newClient();
 
+        String scheme = properties.getProperty("api.scheme", "https");
         String port = properties.getProperty("api.port", "8089");
         String host = properties.getProperty("api.host", "localhost");
 
@@ -85,7 +86,7 @@
         UriBuilder uri = UriBuilder.fromPath("/api/v1.0/search")
             .host(host)
             .port(Integer.parseInt(port))
-            .scheme("https")
+            .scheme(scheme)
             .queryParam("q", q)
             .queryParam("context", "sentence")
             .queryParam("ql", ql)
@@ -117,7 +118,6 @@
 
         // format == rtf / else
         else {
-
             ObjectMapper mapper = new ObjectMapper();
             JsonFactory factory = mapper.getFactory();
             JsonParser parser = factory.createParser(resp);
@@ -126,7 +126,7 @@
             LinkedList<MatchExport> listMatches = new LinkedList();
             ObjectMapper objectMapper = new ObjectMapper();
             MatchExport match;
-
+                        
 
             for (Iterator<JsonNode> itNode = jsonNode1.elements(); itNode
                     .hasNext();) {
diff --git a/plugin/src/test/java/de/ids_mannheim/korap/plkexport/IdsExportServiceTest.java b/plugin/src/test/java/de/ids_mannheim/korap/plkexport/IdsExportServiceTest.java
index 698c3dd..fd6bbcb 100644
--- a/plugin/src/test/java/de/ids_mannheim/korap/plkexport/IdsExportServiceTest.java
+++ b/plugin/src/test/java/de/ids_mannheim/korap/plkexport/IdsExportServiceTest.java
@@ -2,6 +2,24 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+// Mockserver tests
+import org.mockserver.integration.ClientAndServer;
+import org.mockserver.client.server.MockServerClient;
+import org.mockserver.junit.MockServerRule;
+import static org.mockserver.model.HttpRequest.*;
+import static org.mockserver.model.HttpResponse.*;
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+import org.slf4j.Logger;
+
+// Fixture loading
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URLDecoder;
 
 import java.util.List;
 import java.util.Map;
@@ -30,22 +48,58 @@
 
 public class IdsExportServiceTest extends JerseyTest {
 
+    private static ClientAndServer mockServer;
+	private static MockServerClient mockClient;
+    
+    @BeforeClass
+    public static void startServer() {
+        // Define logging rules for Mock-Server
+        ((ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory
+         .getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME))
+            .setLevel(ch.qos.logback.classic.Level.OFF);
+        ((ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory
+         .getLogger("org.mockserver"))
+            .setLevel(ch.qos.logback.classic.Level.OFF);
+
+        mockServer = ClientAndServer.startClientAndServer(34765);
+        mockClient = new MockServerClient("localhost", mockServer.getPort());
+
+        Properties properties = ExWSConf.properties(null);
+        properties.setProperty("api.host", "localhost");
+        properties.setProperty("api.port", String.valueOf(mockServer.getPort()));
+        properties.setProperty("api.scheme", "http");
+    }
+   
+    @AfterClass
+    public static void stopServer() {
+        mockServer.stop();
+    }
+    
     @Override
     protected Application configure () {
         return new ResourceConfig(IdsExportService.class);
     }
 
-
     // Client is pre-configured in JerseyTest
     /**
      * Tests if webservice returns a document with the right filename
      * and file format and handles empty/missing parameters correctly.
      */
     @Test
-    public void testExportWs () {
+    public void testExportWsJson () {
+        mockClient.reset().when(
+            request()
+            .withMethod("GET")
+            .withPath("/api/v1.0/search")
+            )
+            .respond(
+                response()
+                .withHeader("Content-Type: application/json; charset=utf-8")
+                .withBody("{}")
+                .withStatusCode(200)
+                );
 
         String filenamej = "dateiJson";
-        String filenamer = "dateiRtf";
         MultivaluedHashMap<String, String> frmap = new MultivaluedHashMap<String, String>();
         frmap.add("fname", filenamej);
         frmap.add("format", "json");
@@ -54,12 +108,9 @@
 
         String message;
 
-        Properties properties = ExWSConf.properties(null);
-        properties.setProperty("api.host", "localhost");
-        properties.setProperty("api.port", "8089");
-
         Response responsejson = target("/export").request()
                 .post(Entity.form(frmap));
+        
         assertEquals("Request JSON: Http Response should be 200: ",
                 Status.OK.getStatusCode(), responsejson.getStatus());
         // A JSON document should be returend
@@ -75,12 +126,34 @@
         assertTrue("Request JSON: Filename should be set correctly: ",
                 responsejson.getHeaderString(HttpHeaders.CONTENT_DISPOSITION)
                         .contains("filename=" + filenamej));
+    };
 
-        frmap.putSingle("format", "rtf");
+    
+    @Test
+    public void testExportWsRTF () {
+        mockClient.reset().when(
+            request()
+            .withMethod("GET")
+            .withPath("/api/v1.0/search")
+            )
+            .respond(
+                response()
+                .withHeader("Content-Type: application/json; charset=utf-8")
+                .withBody(getFixture("response_query_baum_o0_c25.json"))
+                .withStatusCode(200)
+                );
+
+        MultivaluedHashMap<String, String> frmap = new MultivaluedHashMap<String, String>();
+        frmap.add("format", "rtf");
+        frmap.add("q", "Wasser");
+        frmap.add("ql", "poliqarp");
+        String filenamer = "dateiRtf";
         frmap.putSingle("fname", filenamer);
 
+        String message;
+
         Response responsertf = target("/export").request()
-                .post(Entity.form(frmap));
+            .post(Entity.form(frmap));
         assertEquals("Request RTF: Http Response should be 200: ",
                 Status.OK.getStatusCode(), responsertf.getStatus());
         // An RTF document should be returned
@@ -89,7 +162,7 @@
                 responsertf.getHeaderString(HttpHeaders.CONTENT_TYPE));
         // Results should not be displayed inline but saved and displayed locally
         assertTrue("Request RTF: Results should not be displayed inline",
-                responsejson.getHeaderString(HttpHeaders.CONTENT_DISPOSITION)
+                responsertf.getHeaderString(HttpHeaders.CONTENT_DISPOSITION)
                         .contains("attachment"));
         // The document should be named correctly
         assertTrue("Request RTF: Filename should be set correctly: ",
@@ -128,4 +201,34 @@
         }
     }
 
-}
+    // Get fixture from ressources
+    private String getFixture (String file) {
+        String filepath = getClass()
+            .getResource("/fixtures/" + file)
+            .getFile();
+        return getFileString(filepath);
+    };
+    
+
+    // Get string from a file
+    public static String getFileString (String filepath) {
+        StringBuilder contentBuilder = new StringBuilder();
+        try {			
+			BufferedReader in = new BufferedReader(
+				new InputStreamReader(
+					new FileInputStream(URLDecoder.decode(filepath, "UTF-8")),
+					"UTF-8"
+					)
+				);
+            String str;
+            while ((str = in.readLine()) != null) {
+                contentBuilder.append(str);
+            };
+            in.close();
+        }
+        catch (IOException e) {
+            fail(e.getMessage());
+        }
+        return contentBuilder.toString();
+    };
+};
diff --git a/plugin/src/test/resources/fixtures/response_query_baum_o0_c25.json b/plugin/src/test/resources/fixtures/response_query_baum_o0_c25.json
new file mode 100644
index 0000000..991b1ee
--- /dev/null
+++ b/plugin/src/test/resources/fixtures/response_query_baum_o0_c25.json
@@ -0,0 +1,73 @@
+{
+  "@context" : "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+  "meta" :  {
+    "count" : 25,
+    "startIndex" : 0,
+    "authorized" : null,
+    "timeout" : 120000,
+    "context" : {
+      "left" : ["token",40],
+      "right" : ["token",40]
+    },
+    "fields" : ["pubDate","subTitle","author","pubPlace","title","textSigle","UID","ID","layerInfos","corpusSigle","docSigle","corpusID","textClass"],
+    "version" : "0.55.7",
+    "benchmark" : "0.120577834 s",
+    "totalResults" : 51,
+    "serialQuery" : "tokens:s:Baum",
+    "itemsPerPage" : 25
+  },
+  "query" : {
+    "@type" : "koral:token",
+    "wrap" : {
+      "@type" : "koral:term",
+      "layer" : "orth",
+      "key" : "Baum",
+      "match" : "match:eq",
+      "foundry" : "opennlp",
+      "rewrites" : [
+        {
+          "@type" : "koral:rewrite",
+          "src" : "Kustvakt",
+          "operation" : "operation:injection",
+          "scope" : "foundry"
+        }
+      ]
+    }
+  },
+  "matches" : [
+    {
+      "field" : "tokens",
+      "pubPlace" : "München",
+      "textSigle" : "GOE/AGI/00000",
+      "docSigle" : "GOE/AGI",
+      "corpusSigle" : "GOE",
+      "title" : "Italienische Reise",
+      "subTitle" : "Auch ich in Arkadien!",
+      "author" : "Goethe, Johann Wolfgang von",
+      "layerInfos" : "base/s=spans corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans malt/d=rels mdp/d=rels opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans",
+      "startMore" : true,
+      "endMore" : true,
+      "snippet" : "<span class=\"context-left\"><span class=\"more\"></span>sie etwas bedeuten zu wollen und machte mit der Oberlippe eine fatale Miene. ich sprach sehr viel mit ihr durch, sie war überall zu Hause und merkte gut auf die Gegenstände. so fragte sie mich einmal, was das für ein </span><span class=\"match\"><mark>Baum</mark></span><span class=\"context-right\"> sei. es war ein schöner großer Ahorn, der erste, der mir auf der ganzen Reise zu Gesichte kam. den hatte sie doch gleich bemerkt und freute sich, da mehrere nach und nach erschienen, daß sie auch diesen Baum unterscheiden könne<span class=\"more\"></span></span>",
+      "matchID" : "match-GOE/AGI/00000-p2030-2031",
+      "UID" : 0,
+      "pubDate" : "1982"
+    },
+    {
+      "field" : "tokens",
+      "pubPlace" : "München",
+      "textSigle" : "GOE/AGI/00001",
+      "docSigle" : "GOE/AGI",
+      "corpusSigle" : "GOE",
+      "title" : "Italienische Reise",
+      "subTitle" : "Auch ich in Arkadien!",
+      "author" : "Goethe, Johann Wolfgang von",
+      "layerInfos" : "base/s=spans corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans malt/d=rels mdp/d=rels opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans",
+      "startMore" : true,
+      "endMore" : true,
+      "snippet" : "<span class=\"context-left\"><span class=\"more\"></span>für ein Baum sei. es war ein schöner großer Ahorn, der erste, der mir auf der ganzen Reise zu Gesichte kam. den hatte sie doch gleich bemerkt und freute sich, da mehrere nach und nach erschienen, daß sie auch diesen </span><span class=\"match\"><mark>Baum</mark></span><span class=\"context-right\"> unterscheiden könne. sie gehe, sagte sie, nach Bozen auf die Messe, wo ich doch wahrscheinlich auch hinzöge. wenn sie mich dort anträfe, müsse ich ihr einen Jahrmarkt kaufen, welches ich ihr denn auch versprach. dort wollte sie auch ihre neue<span class=\"more\"></span></span>",
+      "matchID" : "match-GOE/AGI/00000-p2068-2069",
+      "UID" : 0,
+      "pubDate" : "1982"
+    }
+  ]
+}