Repository: komoot/photon
Pull request #655 (2022-03-08 10:59:37)

Assorted test reorganization
Some minor reorganisation of the tests (ultimately to better contain ElasticSearch code):
* Use JUnit 5 TempDirs for the temporary test database. This resolves the occasional failure when a test was aborted and makes sure that test really run on clean data.
* Move functions from Server that are only used in tests into a derived class inside the test directory. Also fixes setup of shards. They must only be set when creating the index, not when updating.
* Make `getById` return a PhotonResult instead of a ES-specific GetResponse. For some reason, the result for GetResponse is a completely different type than search, so it needs its own PhotonResult wrapper. This is a crippled version that only implements the functions needed by the tests.

Also adds some tests for ElasticResult and fixed some minor issues the tests uncovered.



Patch:
diff --git a/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java b/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
index 960b6d7..2cfd58e 100644
--- a/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
+++ b/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
@@ -53,9 +53,9 @@ public class ElasticResult implements PhotonResult {
         final Map<String, Double> coordinate = (Map<String, Double>) result.getSource().get("coordinate");
         if (coordinate == null) {
             log.error(String.format("invalid data [id=%s, type=%s], coordinate is missing!",
-                                    result.getSource().get(Constants.OSM_ID),
-                                    result.getSource().get(Constants.OSM_VALUE)));
-            return new double[]{Double.NaN, Double.NaN};
+                    result.getSource().get(Constants.OSM_ID),
+                    result.getSource().get(Constants.OSM_VALUE)));
+            return INVALID_COORDINATES;
         }
 
         return new double[]{coordinate.get(Constants.LON), coordinate.get(Constants.LAT)};
diff --git a/src/main/java/de/komoot/photon/elasticsearch/IndexSettings.java b/src/main/java/de/komoot/photon/elasticsearch/IndexSettings.java
index 2135fe9..1e1ba28 100644
--- a/src/main/java/de/komoot/photon/elasticsearch/IndexSettings.java
+++ b/src/main/java/de/komoot/photon/elasticsearch/IndexSettings.java
@@ -19,6 +19,7 @@ import java.util.*;
  */
 public class IndexSettings {
     private final JSONObject settings;
+    private Integer numShards = null;
 
     /**
      * Create a new settings object and initialize it with the index settings
@@ -39,9 +40,7 @@ public class IndexSettings {
      * @return Return this object for chaining.
      */
     public IndexSettings setShards(Integer numShards) {
-        if (numShards != null) {
-            settings.put("index", new JSONObject().put("number_of_shards", numShards));
-        }
+        this.numShards = numShards;
 
         return this;
     }
@@ -139,10 +138,18 @@ public class IndexSettings {
      * @param indexName Name of the new index
      */
     public void createIndex(Client client, String indexName) {
+        if (numShards != null) {
+            settings.put("index", new JSONObject().put("number_of_shards", numShards));
+        }
+
         client.admin().indices().prepareCreate(indexName)
                 .setSettings(settings.toString(), XContentType.JSON)
                 .execute()
                 .actionGet();
+
+        if (numShards != null) {
+            settings.remove("index");
+        }
     }
 
     /**
diff --git a/src/main/java/de/komoot/photon/elasticsearch/Server.java b/src/main/java/de/komoot/photon/elasticsearch/Server.java
index b68dfe1..7196aac 100644
--- a/src/main/java/de/komoot/photon/elasticsearch/Server.java
+++ b/src/main/java/de/komoot/photon/elasticsearch/Server.java
@@ -7,7 +7,6 @@ import de.komoot.photon.searcher.ReverseHandler;
 import de.komoot.photon.searcher.SearchHandler;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.SystemUtils;
-import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
 import org.elasticsearch.action.get.GetResponse;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.client.transport.TransportClient;
@@ -23,8 +22,7 @@ import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.transport.Netty4Plugin;
 import org.elasticsearch.transport.client.PreBuiltTransportClient;
 
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
 import java.net.InetSocketAddress;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -57,12 +55,10 @@ public class Server {
 
     private Node esNode;
 
-    private Client esClient;
+    protected Client esClient;
 
     private File esDirectory;
 
-    private Integer shards = null;
-
     protected static class MyNode extends Node {
         public MyNode(Settings preparedSettings, Collection<Class<? extends Plugin>> classpathPlugins) {
             super(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), classpathPlugins);
@@ -207,11 +203,11 @@ public class Server {
         }
     }
 
-    private IndexSettings loadIndexSettings() {
-        return new IndexSettings().setShards(shards);
+    protected IndexSettings loadIndexSettings() {
+        return new IndexSettings();
     }
 
-    public void deleteIndex() {
+    private void deleteIndex() {
         try {
             esClient.admin().indices().prepareDelete(PhotonIndex.NAME).execute().actionGet();
         } catch (IndexNotFoundException e) {
@@ -220,20 +216,7 @@ public class Server {
     }
 
 
-    /**
-     * Set the maximum number of shards for the embedded node
-     * This typically only makes sense for testing
-     *
-     * @param shards the maximum number of shards
-     * @return this Server instance for chaining
-     */
-    public Server setMaxShards(Integer shards) {
-        this.shards = shards;
-        return this;
-    }
-
-
-       /**
+   /**
      * Save the global properties to the database.
      *
      * The function saved properties available as members and the database version
@@ -282,14 +265,6 @@ public class Server {
         dbProperties.setLanguages(langString == null ? null : langString.split(","));
     }
 
-    public GetResponse getById(int id) {
-        return esClient.prepareGet(PhotonIndex.NAME,PhotonIndex.TYPE, String.valueOf(id)).execute().actionGet();
-    }
-
-    public void refresh() {
-        esClient.admin().indices().refresh(new RefreshRequest(PhotonIndex.NAME)).actionGet();
-    }
-
     public Importer createImporter(String[] languages, String[] extraTags) {
         return new de.komoot.photon.elasticsearch.Importer(esClient, languages, extraTags);
     }
diff --git a/src/main/java/de/komoot/photon/searcher/PhotonResult.java b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
index a68588e..e97de62 100644
--- a/src/main/java/de/komoot/photon/searcher/PhotonResult.java
+++ b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
@@ -6,6 +6,7 @@ import java.util.Map;
  * A single response object from the database.
  */
 public interface PhotonResult {
+    public double[] INVALID_COORDINATES = new double[]{0, 0};
 
     /**
      * Get the value for the given field.


Test patch:
diff --git a/src/test/java/de/komoot/photon/ESBaseTester.java b/src/test/java/de/komoot/photon/ESBaseTester.java
index ee57d54..48bc34e 100644
--- a/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -4,13 +4,14 @@ import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.GeometryFactory;
 import com.vividsolutions.jts.geom.Point;
 import com.vividsolutions.jts.geom.PrecisionModel;
-import de.komoot.photon.elasticsearch.Server;
+import de.komoot.photon.elasticsearch.ElasticTestServer;
+import de.komoot.photon.searcher.PhotonResult;
 import lombok.extern.slf4j.Slf4j;
-import org.elasticsearch.action.get.GetResponse;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.io.TempDir;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.util.Collections;
 
 /**
@@ -20,38 +21,40 @@ import java.util.Collections;
  */
 @Slf4j
 public class ESBaseTester {
+    @TempDir
+    protected Path dataDirectory;
+
     public static final String TEST_CLUSTER_NAME = "photon-test";
-    private static GeometryFactory FACTORY = new GeometryFactory(new PrecisionModel(), 4326);
+    protected static GeometryFactory FACTORY = new GeometryFactory(new PrecisionModel(), 4326);
 
-    private Server server;
+    private ElasticTestServer server;
 
     protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) {
         Point location = FACTORY.createPoint(new Coordinate(lon, lat));
         return new PhotonDoc(id, "W", osmId, key, value).names(Collections.singletonMap("name", "berlin")).centroid(location);
     }
 
-    protected GetResponse getById(int id) {
+    protected PhotonResult getById(int id) {
         return server.getById(id);
     }
 
 
     @AfterEach
     public void tearDown() {
-        deleteIndex();
         shutdownES();
     }
 
     public void setUpES() throws IOException {
-        setUpES("en");
+        setUpES(dataDirectory, "en");
     }
     /**
      * Setup the ES server
      *
      * @throws IOException
      */
-    public void setUpES(String... languages) throws IOException {
-        server = new Server(new File("./target/es_photon_test").getAbsolutePath()).setMaxShards(1).start(TEST_CLUSTER_NAME, new String[]{});
-        deleteIndex(); // just in case of an abnormal abort previously
+    public void setUpES(Path test_directory, String... languages) throws IOException {
+        server = new ElasticTestServer(test_directory.toString());
+        server.start(TEST_CLUSTER_NAME, new String[]{});
         server.recreateIndex(languages);
         refresh();
     }
@@ -76,7 +79,7 @@ public class ESBaseTester {
         return server.createUpdater(new String[]{"en"}, extraTags);
     }
 
-    protected Server getServer() {
+    protected ElasticTestServer getServer() {
         if (server == null) {
             throw new RuntimeException("call setUpES before using getClient");
         }
@@ -95,9 +98,4 @@ public class ESBaseTester {
         if (server != null)
             server.shutdown();
     }
-
-    public void deleteIndex() {
-        if (server != null)
-            server.deleteIndex();
-    }
 }
diff --git a/src/test/java/de/komoot/photon/PhotonDocTest.java b/src/test/java/de/komoot/photon/PhotonDocTest.java
index a3d301f..4784edb 100644
--- a/src/test/java/de/komoot/photon/PhotonDocTest.java
+++ b/src/test/java/de/komoot/photon/PhotonDocTest.java
@@ -1,10 +1,10 @@
 package de.komoot.photon;
 
-import java.util.HashMap;
-
 import de.komoot.photon.nominatim.model.AddressType;
 import org.junit.jupiter.api.Test;
 
+import java.util.HashMap;
+
 import static org.junit.jupiter.api.Assertions.*;
 
 public class PhotonDocTest {
diff --git a/src/test/java/de/komoot/photon/elasticsearch/DatabasePropertiesTest.java b/src/test/java/de/komoot/photon/elasticsearch/DatabasePropertiesTest.java
index f665460..b366a69 100644
--- a/src/test/java/de/komoot/photon/elasticsearch/DatabasePropertiesTest.java
+++ b/src/test/java/de/komoot/photon/elasticsearch/DatabasePropertiesTest.java
@@ -4,8 +4,6 @@ import de.komoot.photon.DatabaseProperties;
 import de.komoot.photon.ESBaseTester;
 import org.junit.jupiter.api.Test;
 
-import java.io.IOException;
-
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
diff --git a/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java b/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
new file mode 100644
index 0000000..715146b
--- /dev/null
+++ b/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
@@ -0,0 +1,45 @@
+package de.komoot.photon.elasticsearch;
+
+import de.komoot.photon.searcher.PhotonResult;
+import org.apache.commons.lang3.NotImplementedException;
+import org.elasticsearch.action.get.GetResponse;
+
+import java.util.Map;
+
+public class ElasticGetIdResult implements PhotonResult {
+
+    private final GetResponse result;
+
+    ElasticGetIdResult(GetResponse result) {
+        this.result = result;
+    }
+    @Override
+    public Object get(String key) {
+        return result.getSource().get(key);
+    }
+
+    @Override
+    public String getLocalised(String key, String language) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public Map<String, String> getMap(String key) {
+        return (Map<String, String>) result.getSource().get(key);
+    }
+
+    @Override
+    public double[] getCoordinates() {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public double[] getExtent() {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public double getScore() {
+        throw new NotImplementedException();
+    }
+}
diff --git a/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java b/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java
new file mode 100644
index 0000000..71e879f
--- /dev/null
+++ b/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java
@@ -0,0 +1,138 @@
+package de.komoot.photon.elasticsearch;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Point;
+import de.komoot.photon.ESBaseTester;
+import de.komoot.photon.Importer;
+import de.komoot.photon.PhotonDoc;
+import de.komoot.photon.query.PhotonRequest;
+import de.komoot.photon.searcher.PhotonResult;
+import de.komoot.photon.searcher.SearchHandler;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class ElasticResultTest  extends ESBaseTester {
+    @TempDir
+    private static Path instanceTestDirectory;
+
+    private Map<String, String> makeMap(String... kv) {
+        Map<String, String> result = new HashMap<>();
+        for (int i = 0; i < kv.length; i += 2) {
+            result.put(kv[i], kv[i + 1]);
+        }
+
+        return result;
+    }
+
+    protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) {
+        Point location = FACTORY.createPoint(new Coordinate(lon, lat));
+        return new PhotonDoc(id, "W", osmId, key, value).centroid(location);
+    }
+
+
+    @BeforeAll
+    public void setUp() throws Exception {
+        setUpES(instanceTestDirectory, "en", "de", "fr", "it");
+        Importer instance = getServer().createImporter(new String[]{"en", "de", "fr", "it"},
+                 new String[]{"population",  "capital"});
+
+        instance.add(createDoc(45.2, -7.45, 123, 1123, "place", "city")
+                .names(makeMap("name", "München", "name:it", "Monacco", "name:en", "Munich"))
+                .address(Collections.singletonMap("state", "Bavaria"))
+                .countryCode("de")
+                .extraTags(makeMap("population", "many", "capital", "yes", "maxage", "99")));
+        instance.add(createDoc(0, 0, 99, 11999, "place", "locality")
+                .names(makeMap("name", "null island")));
+        instance.add(createDoc(-179, 1.0001, 923, 1923, "place", "house")
+                .houseNumber("34")
+                .bbox(FACTORY.createMultiPoint(new Coordinate[]{new Coordinate(-179.5, 1.0),
+                        new Coordinate(-178.5, 1.1)}))
+                .address(makeMap("street", "Hauptstr", "city", "Hamburg")));
+        instance.add(new PhotonDoc(42, "N", 42, "place", "hamlet")
+                .names(makeMap("name", "nowhere")));
+
+        instance.finish();
+        refresh();
+    }
+
+    @AfterAll
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
+    private PhotonResult search(String query) {
+        SearchHandler handler = getServer().createSearchHandler(new String[]{"en", "de", "it"});
+
+        return handler.search(new PhotonRequest(query, "default")).get(0);
+    }
+
+
+    @Test
+    public void testGet() {
+        PhotonResult result = search("München");
+
+        assertAll("get",
+                () -> assertEquals("DE", result.get("countrycode")),
+                () -> assertNull(result.get("horse"))
+        );
+    }
+
+    @Test
+    public void testGetMap() {
+        assertAll("getMap",
+                () -> assertEquals(makeMap("default", "München", "en", "Munich", "it", "Monacco"),
+                                   search("München").getMap("name")),
+                () -> assertEquals(makeMap("default", "null island"),
+                                   search("null island").getMap("name")),
+                () -> assertNull(search("Hauptstr 34").getMap("name")),
+                () -> assertEquals(makeMap("population", "many", "capital", "yes"),
+                                   search("München").getMap("extra"))
+        );
+    }
+
+    @Test
+    public void testGetLocalized() {
+        PhotonResult result = search("München");
+
+        assertAll("getLocalized",
+                () -> assertEquals("Munich", result.getLocalised("name", "en")),
+                () -> assertEquals("München", result.getLocalised("name", "fr")),
+                () -> assertEquals("Monacco", result.getLocalised("name", "it")),
+                () -> assertNull(result.getLocalised("city", "en"))
+        );
+    }
+
+    @Test
+    public void testGetCoordinates() {
+        assertAll("getCoordinates",
+                () -> assertArrayEquals(new double[]{-179, 1.0001}, search("Hauptstr 34").getCoordinates()),
+                () -> assertArrayEquals(PhotonResult.INVALID_COORDINATES, search("nowhere").getCoordinates())
+        );
+    }
+
+    @Test
+    public void testGetExtent() {
+        assertAll("getExtent",
+                () -> assertNull(search("Munich").getExtent()),
+                () -> assertArrayEquals(new double[]{-179.5, 1.1, -178.5, 1.0}, search("hauptstr 34").getExtent())
+        );
+    }
+
+    @Test
+    public void testGetScore() {
+        assertTrue(Double.isFinite(search("null island").getScore()));
+    }
+}
diff --git a/src/test/java/de/komoot/photon/elasticsearch/ElasticTestServer.java b/src/test/java/de/komoot/photon/elasticsearch/ElasticTestServer.java
new file mode 100644
index 0000000..c9bfd03
--- /dev/null
+++ b/src/test/java/de/komoot/photon/elasticsearch/ElasticTestServer.java
@@ -0,0 +1,26 @@
+package de.komoot.photon.elasticsearch;
+
+import de.komoot.photon.searcher.PhotonResult;
+import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
+import org.elasticsearch.action.get.GetResponse;
+
+public class ElasticTestServer extends Server {
+    public ElasticTestServer(String mainDirectory) {
+        super(mainDirectory);
+    }
+
+    @Override
+    protected IndexSettings loadIndexSettings() {
+        return new IndexSettings().setShards(1);
+    }
+
+    public PhotonResult getById(int id) {
+        GetResponse response =  esClient.prepareGet(PhotonIndex.NAME,PhotonIndex.TYPE, String.valueOf(id)).execute().actionGet();
+
+        return response.isExists() ? new ElasticGetIdResult(response) : null;
+    }
+
+    public void refresh() {
+        esClient.admin().indices().refresh(new RefreshRequest(PhotonIndex.NAME)).actionGet();
+    }
+}
diff --git a/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java b/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
index 521a568..b6866b2 100644
--- a/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
+++ b/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
@@ -1,9 +1,9 @@
 package de.komoot.photon.elasticsearch;
 
 import de.komoot.photon.ESBaseTester;
-import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Importer;
-import org.elasticsearch.action.get.GetResponse;
+import de.komoot.photon.PhotonDoc;
+import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -30,18 +30,16 @@ public class ImporterTest extends ESBaseTester {
         instance.finish();
         refresh();
 
-        GetResponse response = getById(1234);
-
-        assertTrue(response.isExists());
+        PhotonResult response = getById(1234);
 
-        Map<String, Object> source = response.getSource();
+        assertNotNull(response);
 
-        assertEquals("N", source.get("osm_type"));
-        assertEquals(1000, source.get("osm_id"));
-        assertEquals("place", source.get("osm_key"));
-        assertEquals("city", source.get("osm_value"));
+        assertEquals("N", response.get("osm_type"));
+        assertEquals(1000, response.get("osm_id"));
+        assertEquals("place", response.get("osm_key"));
+        assertEquals("city", response.get("osm_value"));
 
-        assertNull(source.get("extra"));
+        assertNull(response.get("extra"));
     }
 
     @Test
@@ -59,10 +57,10 @@ public class ImporterTest extends ESBaseTester {
         instance.finish();
         refresh();
 
-        GetResponse response = getById(1234);
-        assertTrue(response.isExists());
+        PhotonResult response = getById(1234);
+        assertNotNull(response);
 
-        Map<String, String> extra = (Map<String, String>) response.getSource().get("extra");
+        Map<String, String> extra = response.getMap("extra");
         assertNotNull(extra);
 
         assertEquals(2, extra.size());
@@ -70,8 +68,8 @@ public class ImporterTest extends ESBaseTester {
         assertEquals("foo", extra.get("website"));
 
         response = getById(1235);
-        assertTrue(response.isExists());
+        assertNotNull(response);
 
-        assertNull(response.getSource().get("extra"));
+        assertNull(response.get("extra"));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/de/komoot/photon/elasticsearch/UpdaterTest.java b/src/test/java/de/komoot/photon/elasticsearch/UpdaterTest.java
index 02ee605..f8b1179 100644
--- a/src/test/java/de/komoot/photon/elasticsearch/UpdaterTest.java
+++ b/src/test/java/de/komoot/photon/elasticsearch/UpdaterTest.java
@@ -1,10 +1,10 @@
 package de.komoot.photon.elasticsearch;
 
 import de.komoot.photon.ESBaseTester;
-import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Importer;
+import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Updater;
-import org.elasticsearch.action.get.GetResponse;
+import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
@@ -34,10 +34,10 @@ public class UpdaterTest extends ESBaseTester {
         updater.finish();
         refresh();
 
-        GetResponse response = getById(1234);
+        PhotonResult response = getById(1234);
+        assertNotNull(response);
 
-        assertTrue(response.isExists());
-        Map<String, String> out_names = (Map<String, String>) response.getSourceAsMap().get("name");
+        Map<String, String> out_names = response.getMap("name");
         assertEquals("Foo", out_names.get("default"));
         assertEquals("Enfoo", out_names.get("en"));
     }
@@ -61,10 +61,10 @@ public class UpdaterTest extends ESBaseTester {
         updater.finish();
         refresh();
 
-        GetResponse response = getById(1234);
+        PhotonResult response = getById(1234);
+        assertNotNull(response);
 
-        assertTrue(response.isExists());
-        Map<String, String> out_names = (Map<String, String>) response.getSourceAsMap().get("name");
+        Map<String, String> out_names = response.getMap("name");
         assertFalse(out_names.containsKey("default"));
         assertEquals("Enfoo", out_names.get("en"));
     }
@@ -81,10 +81,10 @@ public class UpdaterTest extends ESBaseTester {
         instance.finish();
         refresh();
 
-        GetResponse response = getById(1234);
-        assertTrue(response.isExists());
+        PhotonResult response = getById(1234);
+        assertNotNull(response);
 
-        assertNull(response.getSource().get("extra"));
+        assertNull(response.get("extra"));
 
         doc.extraTags(Collections.singletonMap("website", "http://site.foo"));
         Updater updater = makeUpdaterWithExtra("website");
@@ -93,9 +93,9 @@ public class UpdaterTest extends ESBaseTester {
         refresh();
 
         response = getById(1234);
-        assertTrue(response.isExists());
+        assertNotNull(response);
 
-        Map<String, String> extra = (Map<String, String>) response.getSource().get("extra");
+        Map<String, String> extra = response.getMap("extra");
 
         assertNotNull(extra);
         assertEquals(Collections.singletonMap("website", "http://site.foo"), extra);
diff --git a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
index f8598fd..08e9218 100644
--- a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
+++ b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
@@ -5,13 +5,12 @@ import com.vividsolutions.jts.io.WKTReader;
 import de.komoot.photon.PhotonDoc;
 import lombok.Getter;
 import org.json.JSONObject;
+import org.junit.jupiter.api.Assertions;
 import org.springframework.jdbc.core.JdbcTemplate;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import org.junit.jupiter.api.Assertions;
-
 @Getter
 public class PlacexTestRow {
     private static final WKTReader wkt = new WKTReader();
diff --git a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
index 6363d17..4dc2c0a 100644
--- a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
@@ -1,10 +1,6 @@
 package de.komoot.photon.query;
 
 import com.vividsolutions.jts.geom.Envelope;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.junit.jupiter.params.provider.Arguments.arguments;
-
 import de.komoot.photon.searcher.TagFilter;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -17,6 +13,9 @@ import spark.Request;
 import java.util.*;
 import java.util.stream.Stream;
 
+import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
 /**
  * Tests for correct parsing of the query parameters into a PhotonRequest.
  */
diff --git a/src/test/java/de/komoot/photon/query/QueryByClassificationTest.java b/src/test/java/de/komoot/photon/query/QueryByClassificationTest.java
index 0d63d9a..59c962f 100644
--- a/src/test/java/de/komoot/photon/query/QueryByClassificationTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryByClassificationTest.java
@@ -3,7 +3,6 @@ package de.komoot.photon.query;
 import de.komoot.photon.*;
 import de.komoot.photon.searcher.PhotonResult;
 import lombok.extern.slf4j.Slf4j;
-import org.elasticsearch.action.get.GetResponse;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.junit.jupiter.api.BeforeEach;
@@ -62,7 +61,6 @@ public class QueryByClassificationTest extends ESBaseTester {
             throw new RuntimeException(e);
         }
         try {
-            getServer().setMaxShards(null);
             getServer().updateIndexSettings(synonymPath.toString());
         } catch (IOException e) {
             throw new RuntimeException(e);
@@ -82,8 +80,8 @@ public class QueryByClassificationTest extends ESBaseTester {
 
         assertNotNull(class_term);
 
-        GetResponse response = getById(testDocId);
-        String classification = (String) response.getSource().get(Constants.CLASSIFICATION);
+        PhotonResult response = getById(testDocId);
+        String classification = (String) response.get(Constants.CLASSIFICATION);
         assertEquals(classification, class_term);
 
         List<PhotonResult> result = search(class_term + " curli");
@@ -160,7 +158,6 @@ public class QueryByClassificationTest extends ESBaseTester {
             throw new RuntimeException(e);
         }
         try {
-            getServer().setMaxShards(null);
             getServer().updateIndexSettings(synonymPath.toString());
         } catch (IOException e) {
             throw new RuntimeException(e);
diff --git a/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java b/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
index 382a022..5e43301 100644
--- a/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
@@ -26,7 +26,7 @@ public class QueryByLanguageTest extends ESBaseTester {
 
     private Importer setup(String... languages) throws IOException {
         languageList = languages;
-        setUpES(languages);
+        setUpES(dataDirectory, languages);
         return makeImporterWithLanguages(languages);
     }
 
diff --git a/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java b/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
index 9d645d6..0beec64 100644
--- a/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
@@ -1,24 +1,28 @@
 package de.komoot.photon.query;
 
 import de.komoot.photon.ESBaseTester;
-import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Importer;
-
-import java.util.List;
-import java.util.stream.Stream;
-
+import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.searcher.PhotonResult;
 import de.komoot.photon.searcher.TagFilter;
 import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.io.TempDir;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.Stream;
+
 import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.params.provider.Arguments.arguments;
 
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class QueryFilterTagValueTest extends ESBaseTester {
+    @TempDir
+    private static Path instanceTestDirectory;
+
     private static final String[] TAGS = new String[]{"tourism", "attraction",
                                                       "tourism", "hotel",
                                                       "tourism", "museum",
@@ -31,7 +35,7 @@ public class QueryFilterTagValueTest extends ESBaseTester {
 
     @BeforeAll
     public void setUp() throws Exception {
-        setUpES();
+        setUpES(instanceTestDirectory, "en", "de", "fr");
         Importer instance = makeImporter();
         double lon = 13.38886;
         double lat = 52.51704;
@@ -54,8 +58,7 @@ public class QueryFilterTagValueTest extends ESBaseTester {
     @AfterAll
     @Override
     public void tearDown() {
-        deleteIndex();
-        shutdownES();
+        super.tearDown();
     }
 
     private List<PhotonResult> searchWithTags(String[] params) {
diff --git a/src/test/java/de/komoot/photon/searcher/StreetDupesRemoverTest.java b/src/test/java/de/komoot/photon/searcher/StreetDupesRemoverTest.java
index c5bcf22..fc6fe8f 100644
--- a/src/test/java/de/komoot/photon/searcher/StreetDupesRemoverTest.java
+++ b/src/test/java/de/komoot/photon/searcher/StreetDupesRemoverTest.java
@@ -1,7 +1,6 @@
 package de.komoot.photon.searcher;
 
 import de.komoot.photon.Constants;
-import org.json.JSONObject;
 import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;