Update to elasticsearch 7
diff --git a/build.gradle b/build.gradle
index b89a343..927f374 100644
--- a/build.gradle
+++ b/build.gradle
@@ -94,15 +94,16 @@
// querying es
compile 'commons-httpclient:commons-httpclient:3.1'
- compile 'org.apache.commons:commons-lang3:3.8.1'
+ compile 'org.apache.commons:commons-text:1.6'
// testing
testCompile 'junit:junit:4.12'
testRuntime 'org.slf4j:slf4j-simple:1.7.25'
testCompile 'org.mockito:mockito-core:2.13.0'
testCompile 'org.assertj:assertj-core:3.6.2'
- testCompile(group: 'org.elasticsearch', name: 'elasticsearch', version: '2.3.4')
- testCompile(group: 'org.elasticsearch', name: 'elasticsearch', version: '2.3.4', classifier: 'tests')
+
+ testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.4.1"
+ testCompile "org.testcontainers:elasticsearch:1.12.5"
}
test {
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java
index 77f7c11..212a4f9 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java
@@ -17,6 +17,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -26,12 +27,14 @@
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.Test;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
import org.slf4j.Logger;
@@ -53,7 +56,7 @@
/**
* This is the payload which needs to be added to the post to add a
*/
- private static final String ES_POSTDATA = "{\"query\":{\"simple_query_string\":{\"query\":\"%s\",\"default_operator\":\"or\",\"lenient\":\"true\",\"fields\":[\"name^2\",\"_all\"]}}}";
+ private static final String ES_POSTDATA = "{\"_source\": [\"source\", \"type\", \"id\"], \"query\":{\"simple_query_string\":{\"query\":\"%s\",\"default_operator\":\"or\",\"lenient\":\"true\"}}}";
/**
* mainly logs requests on INFO
@@ -68,7 +71,7 @@
/**
* The URL is hard coded
*/
- private String url;
+ private URI url;
/**
* The client is created once and reused
@@ -86,7 +89,7 @@
public ODSFreeTextSearch(EntityLoader entityLoader, String sourceName, String host) throws DataAccessException {
this.loader = entityLoader;
- url = host + "/" + sourceName.toLowerCase() + "/_search?fields=_type,_id,_index&size=50";
+ url = URI.create(host).resolve(sourceName.toLowerCase()).resolve("/_search");
client = new HttpClient();
}
@@ -151,9 +154,9 @@
* @param map the map of all ids for the class of the entity
*/
private void put(JsonElement hit, Map<Class<? extends Entity>, List<String>> map) {
- JsonObject object = hit.getAsJsonObject();
+ JsonObject object = hit.getAsJsonObject().get("_source").getAsJsonObject();
- String type = object.get("_type").getAsString();
+ String type = object.get("type").getAsString();
Class<? extends Entity> clazz = getClass4Type(type);
if (clazz != null) {
@@ -163,7 +166,7 @@
}
List<String> list = map.get(clazz);
- list.add((String) object.get("_id").getAsString());
+ list.add((String) object.get("id").getAsString());
}
}
@@ -175,15 +178,22 @@
private Class<? extends Entity> getClass4Type(String type) {
Class<? extends Entity> clazz;
switch (type) {
+ case "Project":
+ clazz = Project.class;
+ break;
+ case "Pool":
+ clazz = Pool.class;
+ break;
+ case "Test":
+ clazz = Test.class;
+ break;
case "TestStep":
clazz = TestStep.class;
break;
case "Measurement":
clazz = Measurement.class;
break;
- case "Test":
- clazz = Test.class;
- break;
+
default:
clazz = null;
}
@@ -197,7 +207,7 @@
* @return
*/
private JsonElement queryElasticSearch(String inputQuery) {
- PostMethod post = new PostMethod(url);
+ PostMethod post = new PostMethod(url.toString());
String requestJson = buildRequestJson(inputQuery);
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
index 25b2654..a0180be 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
@@ -14,71 +14,59 @@
package org.eclipse.mdm.api.odsadapter.search;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
-import static org.mockito.ArgumentMatchers.anyCollectionOf;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
-import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.http.HttpHost;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
-import org.elasticsearch.client.Client;
-import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.node.Node;
-import org.elasticsearch.node.NodeBuilder;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.RestClient;
import org.junit.Before;
-import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+@Ignore
+//FIXME 05.02.2020: this test needs a docker to run elasticsearch and is not suitable for continous build in Jenkins.
+//Comment this in for local tests only, if docker is available
public class ODSFreeTextSearchTest {
- private static final String HOST = "http://localhost:9301";
+
private EntityLoader loader;
private ODSFreeTextSearch fts;
- private Entity ts;
+ private TestStep ts;
- private static Node elasticSearchNode;
+ private RestClient client;
- private static Client client;
-
- @BeforeClass
- public static void beforeClass() throws Exception {
- File tempDir = File.createTempFile("elasticsearch-temp", Long.toString(System.nanoTime()));
- tempDir.delete();
- tempDir.mkdir();
-
- String clusterName = UUID.randomUUID().toString();
- elasticSearchNode = NodeBuilder.nodeBuilder().local(true).clusterName(clusterName)
- .settings(Settings.settingsBuilder()
- .put("path.home", File.createTempFile("elasticsearch", "").getParent())
- .put("index.number_of_shards", 1).put("index.number_of_replicas", 0).put("http.port", 9301))
- .node();
- elasticSearchNode.start();
- client = elasticSearchNode.client();
- }
+ @ClassRule
+ public static ElasticsearchContainer elasticSearch = new ElasticsearchContainer(
+ "docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0");
@SuppressWarnings("unchecked")
@Before
public void init() throws DataAccessException {
ts = mock(TestStep.class);
loader = mock(EntityLoader.class);
- List<Entity> tsList = new ArrayList<>();
- tsList.add(ts);
+
when(loader.loadAll(any(Key.class), anyCollection())).thenAnswer(new Answer<List<Entity>>() {
@Override
@@ -94,70 +82,111 @@
}
});
- fts = new ODSFreeTextSearch(loader, "mdm", HOST);
+ client = RestClient.builder(HttpHost.create(elasticSearch.getHttpHostAddress())).build();
+ fts = new ODSFreeTextSearch(loader, "mdm", "http://" + elasticSearch.getHttpHostAddress());
}
@Test
public void noIndex_emptyResult() throws DataAccessException {
- ODSFreeTextSearch ftsOtherIndex = new ODSFreeTextSearch(loader, "UNKNOWN_INDEX", HOST);
+ ODSFreeTextSearch ftsOtherIndex = new ODSFreeTextSearch(loader, "UNKNOWN_INDEX",
+ "http://" + elasticSearch.getHttpHostAddress());
Map<Class<? extends Entity>, List<Entity>> map = ftsOtherIndex.search("VAG_002");
- assertTrue(map.isEmpty());
+ assertThat(map).isEmpty();
}
@Test
public void exampleIndex_querySuccessfull() throws Exception {
- createExampleIndex("TestStep", "mdm", "asdf");
+ try {
+ createExampleIndex("mdm", "TestStep", "asdf");
- Map<Class<? extends Entity>, List<Entity>> search = fts.search("asdf");
- assertEquals(ts, search.get(TestStep.class).get(0));
+ assertThat(fts.search("asdf").get(TestStep.class).get(0)).isEqualTo(ts);
+ } finally {
+ deleteIndex("mdm");
+ }
}
@Test
public void specialCharacters_correctlyEscaped() throws InterruptedException {
- createExampleIndex("Measurement", "mdm", "hallo\"!§");
+ try {
+ createExampleIndex("mdm", "Measurement", "hallo\"!§");
- Map<Class<? extends Entity>, List<Entity>> search = fts.search("hallo\"!§");
- assertEquals(ts, search.get(Measurement.class).get(0));
+ Map<Class<? extends Entity>, List<Entity>> search = fts.search("hallo\"!§");
+ assertThat(search.get(Measurement.class).get(0)).isEqualTo(ts);
+ } finally {
+ deleteIndex("mdm");
+ }
}
@Test
public void nonMdmResults_ignored() throws InterruptedException {
- createExampleIndex("NONMDMStuff", "mdm", "test");
+ try {
+ createExampleIndex("mdm", "NONMDMStuff", "test");
- Map<Class<? extends Entity>, List<Entity>> search = fts.search("test");
- assertTrue(search.isEmpty());
+ Map<Class<? extends Entity>, List<Entity>> search = fts.search("test");
+ assertThat(search).isEmpty();
+ } finally {
+ deleteIndex("mdm");
+ }
}
@Test
public void twoResults_twoResultsRetuned() throws InterruptedException {
- createExampleIndex("Test", "mdm", "unicorn ASDF", "0");
- createExampleIndex("Test", "mdm", "unicorn XYZ", "1");
+ try {
+ createExampleIndex("mdm", "Test", "0", "unicorn ASDF");
+ createExampleIndex("mdm", "Test", "1", "unicorn XYZ");
- Map<Class<? extends Entity>, List<Entity>> search = fts.search("unicorn");
- assertEquals(2, search.get(org.eclipse.mdm.api.base.model.Test.class).size());
+ Map<Class<? extends Entity>, List<Entity>> search = fts.search("unicorn");
+ assertThat(search.get(org.eclipse.mdm.api.base.model.Test.class)).hasSize(2);
+ } finally {
+ deleteIndex("mdm");
+ }
}
@Test(expected = IllegalStateException.class)
public void illegalLoadRequest_niceExceptionIsThrown() throws DataAccessException, InterruptedException {
- loader = mock(EntityLoader.class);
- when(loader.loadAll(any(), anyCollectionOf(String.class))).thenThrow(new DataAccessException(""));
- createExampleIndex("TestStep", "mdm2", "asdf");
- ODSFreeTextSearch fts2 = new ODSFreeTextSearch(loader, "mdm2", HOST);
+ try {
+ loader = mock(EntityLoader.class);
+ when(loader.loadAll(any(), anyCollection())).thenThrow(new DataAccessException(""));
+ createExampleIndex("mdm2", "TestStep", "asdf");
+ ODSFreeTextSearch fts2 = new ODSFreeTextSearch(loader, "mdm2",
+ "http://" + elasticSearch.getHttpHostAddress());
- fts2.search("asdf");
+ fts2.search("asdf");
+ } finally {
+ deleteIndex("mdm2");
+ }
}
- private void createExampleIndex(String type, String name, String value) throws InterruptedException {
- createExampleIndex(type, name, value, "0");
+ private void createExampleIndex(String indexName, String type, String value) throws InterruptedException {
+ createExampleIndex(indexName, type, "0", value);
}
- private void createExampleIndex(String type, String name, String value, String id) throws InterruptedException {
- String json = "{\"attr\":\"" + StringEscapeUtils.escapeJson(value) + "\"}";
+ private void createExampleIndex(String indexName, String type, String id, String value)
+ throws InterruptedException {
+ ObjectMapper mapper = new ObjectMapper();
+ Map<String, String> json = new HashMap<>();
+ json.put("id", StringEscapeUtils.escapeJson(id));
+ json.put("type", StringEscapeUtils.escapeJson(type));
+ json.put("attr", StringEscapeUtils.escapeJson(value));
- client.prepareIndex(name, type, id).setSource(json).get();
+ try {
+ Request a = new Request("PUT", indexName + "/_doc/" + type + "-" + id);
+ a.setJsonEntity(mapper.writeValueAsString(json));
+ client.performRequest(a);
+ } catch (IOException e) {
+ throw new RuntimeException("Could not index!");
+ }
Thread.sleep(1000); // let the index some time to populate
}
+ private void deleteIndex(String indexName) {
+ try {
+ client.performRequest(new Request("DELETE", indexName));
+ } catch (IOException e) {
+ throw new RuntimeException("Could not delete index!");
+ }
+ }
+
}