| /******************************************************************************** |
| * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| ********************************************************************************/ |
| |
| package org.eclipse.mdm.api.odsadapter.search; |
| |
| import static org.assertj.core.api.Assertions.assertThat; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyCollection; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| 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 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.Request; |
| import org.elasticsearch.client.RestClient; |
| import org.junit.Before; |
| 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 EntityLoader loader; |
| private ODSFreeTextSearch fts; |
| private TestStep ts; |
| |
| private RestClient 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); |
| |
| when(loader.loadAll(any(Key.class), anyCollection())).thenAnswer(new Answer<List<Entity>>() { |
| |
| @Override |
| public List<Entity> answer(InvocationOnMock invocation) throws Throwable { |
| Collection<Long> object = (Collection<Long>) invocation.getArguments()[1]; |
| |
| List<Entity> res = new ArrayList<>(); |
| for (int i = 0; i < object.size(); i++) { |
| res.add(ts); |
| } |
| |
| return res; |
| } |
| }); |
| |
| 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", |
| "http://" + elasticSearch.getHttpHostAddress()); |
| |
| Map<Class<? extends Entity>, List<Entity>> map = ftsOtherIndex.search("VAG_002"); |
| assertThat(map).isEmpty(); |
| } |
| |
| @Test |
| public void exampleIndex_querySuccessfull() throws Exception { |
| try { |
| createExampleIndex("mdm", "TestStep", "asdf"); |
| |
| assertThat(fts.search("asdf").get(TestStep.class).get(0)).isEqualTo(ts); |
| } finally { |
| deleteIndex("mdm"); |
| } |
| } |
| |
| @Test |
| public void specialCharacters_correctlyEscaped() throws InterruptedException { |
| try { |
| createExampleIndex("mdm", "Measurement", "hallo\"!§"); |
| |
| 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 { |
| try { |
| createExampleIndex("mdm", "NONMDMStuff", "test"); |
| |
| Map<Class<? extends Entity>, List<Entity>> search = fts.search("test"); |
| assertThat(search).isEmpty(); |
| } finally { |
| deleteIndex("mdm"); |
| } |
| } |
| |
| @Test |
| public void twoResults_twoResultsRetuned() throws InterruptedException { |
| try { |
| createExampleIndex("mdm", "Test", "0", "unicorn ASDF"); |
| createExampleIndex("mdm", "Test", "1", "unicorn XYZ"); |
| |
| 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 { |
| 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"); |
| } finally { |
| deleteIndex("mdm2"); |
| } |
| } |
| |
| private void createExampleIndex(String indexName, String type, String value) throws InterruptedException { |
| createExampleIndex(indexName, type, "0", 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)); |
| |
| 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!"); |
| } |
| } |
| |
| } |