package alien4cloud.component.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import alien4cloud.common.AlienConstants;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.mapping.MappingBuilder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import alien4cloud.dao.ElasticSearchDAO;
import alien4cloud.dao.IGenericSearchDAO;
import alien4cloud.dao.model.FacetedSearchFacet;
import alien4cloud.dao.model.FacetedSearchResult;
import alien4cloud.dao.model.FetchContext;
import alien4cloud.dao.model.GetMultipleDataResult;
import alien4cloud.exception.IndexingServiceException;
import org.alien4cloud.tosca.model.definitions.CapabilityDefinition;
import org.alien4cloud.tosca.model.types.NodeType;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context-test.xml")
@Slf4j
public class EsDaoPaginatedSearchTest extends AbstractDAOTest {
private final ObjectMapper jsonMapper = new ObjectMapper();
public EsDaoPaginatedSearchTest() {
super();
jsonMapper.setVisibility(PropertyAccessor.ALL, Visibility.PUBLIC_ONLY);
}
@Resource(name = "alien-es-dao")
IGenericSearchDAO dao;
List<NodeType> testDataList = new ArrayList<>();
List<NodeType> jndiTestDataList = new ArrayList<>();
@Override
@Before
public void before() throws Exception {
super.before();
saveDataToES();
}
@Test
public void simpleFindPaginatedTest() throws IOException {
int maxElement;
int size;
// test simple find all search
maxElement = getCount(QueryBuilders.matchAllQuery());
size = 11;
assertTrue(maxElement > 0);
testSimpleSearchWellPaginated(maxElement, size, null);
// test simple find with filters
FilterBuilder filter = FilterBuilders.termFilter("capabilities.type", "jndi");
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
queryBuilder = QueryBuilders.filteredQuery(queryBuilder, filter);
maxElement = getCount(queryBuilder);
size = 4;
assertTrue(maxElement > 0);
Map<String, String[]> filters = new HashMap<String, String[]>();
filters.put("capabilities.type", new String[] { "jndi" });
testSimpleSearchWellPaginated(maxElement, size, filters);
}
@Test
public void textBasedSearchPaginatedTest() throws IndexingServiceException, IOException, InterruptedException {
// text search based
String searchText = "jndi";
int maxElement = getCount(QueryBuilders.matchPhrasePrefixQuery("_all", searchText).maxExpansions(10));
int size = 7;
assertTrue(maxElement > 0);
testTextBasedSearchWellPaginated(maxElement, size, searchText, null);
// text search based with filters
FilterBuilder filter = FilterBuilders.termFilter("capabilities.type", "jndi");
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
queryBuilder = QueryBuilders.filteredQuery(queryBuilder, filter);
maxElement = getCount(queryBuilder);
Map<String, String[]> filters = new HashMap<String, String[]>();
filters.put("capabilities.type", new String[] { "jndi" });
assertTrue(maxElement > 0);
testTextBasedSearchWellPaginated(maxElement, size, searchText, filters);
// test when nothing found
searchText = "pacpac";
maxElement = getCount(QueryBuilders.matchPhrasePrefixQuery("_all", searchText).maxExpansions(10));
assertEquals(0, maxElement);
GetMultipleDataResult<NodeType> searchResp = dao.search(NodeType.class, searchText, null, 0, size);
assertNotNull(searchResp);
assertNotNull(searchResp.getData());
assertNotNull(searchResp.getTypes());
assertEquals(0, searchResp.getData().length);
assertEquals(0, searchResp.getTypes().length);
}
// @Ignore
@Test
public void facetedSearchPaginatedTest() throws IndexingServiceException, IOException, InterruptedException {
String searchText = "jndi";
int maxElement = getCount(QueryBuilders.matchPhrasePrefixQuery("_all", searchText).maxExpansions(10));
int size = 7;
// simple faceted pagination
assertTrue(maxElement > 0);
testFacetedSearchWellPaginated(maxElement, size, searchText, null, null);
// faceted search with filters
FilterBuilder filter = FilterBuilders.termFilter("capabilities.type", "jndi");
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
queryBuilder = QueryBuilders.filteredQuery(queryBuilder, filter);
maxElement = getCount(queryBuilder);
Map<String, String[]> filters = new HashMap<String, String[]>();
filters.put("capabilities.type", new String[] { "jndi" });
assertTrue(maxElement > 0);
testFacetedSearchWellPaginated(maxElement, size, searchText, filters, FetchContext.SUMMARY);
// test nothing found
// test when nothing found
searchText = "pacpac";
maxElement = getCount(QueryBuilders.matchPhrasePrefixQuery("_all", searchText).maxExpansions(10));
assertEquals(0, maxElement);
GetMultipleDataResult<NodeType> searchResp = dao.facetedSearch(NodeType.class, searchText, null, null, 0, size);
assertNotNull(searchResp);
assertNotNull(searchResp.getData());
assertNotNull(searchResp.getTypes());
assertEquals(0, searchResp.getData().length);
assertEquals(0, searchResp.getTypes().length);
}
private static boolean filterContainsValue(Map<String, String[]> filters, String filterValue) {
for (String[] values : filters.values()) {
for (String value : values) {
if ((value == null && filterValue == null) || (value != null && value.equals(filterValue))) {
return true;
}
}
}
return false;
}
private void testSimpleSearchWellPaginated(int maxElement, int size, Map<String, String[]> filters) throws IOException {
List<NodeType> expectedDataList = filters != null && filterContainsValue(filters, "jndi") ? new ArrayList<>(jndiTestDataList)
: new ArrayList<>(testDataList);
GetMultipleDataResult<NodeType> searchResp;
int expectedSize;
for (int from = 0; from < maxElement; from += size) {
expectedSize = (maxElement - from) > size ? size : maxElement - from;
searchResp = dao.find(NodeType.class, filters, from, size);
assertNotNull(searchResp);
assertNotNull(searchResp.getTypes());
assertNotNull(searchResp.getData());
assertEquals(expectedSize, searchResp.getTypes().length);
assertEquals(expectedSize, searchResp.getData().length);
// testing the pertinence of returned data
Object[] data = searchResp.getData();
for (Object element : data) {
NodeType nt = jsonMapper.readValue(jsonMapper.writeValueAsString(element), NodeType.class);
assertTrue(expectedDataList.contains(nt));
expectedDataList.remove(nt);
}
}
// assert the list is empty at the end.
assertTrue(expectedDataList.isEmpty());
}
private void testFacetedSearchWellPaginated(int maxElement, int size, String searchText, Map<String, String[]> filters, String fetchContext)
throws IOException {
List<NodeType> expectedDataList = new ArrayList<>(jndiTestDataList);
String facetNameToCheck;
String factetValueToCheck;
long expectedFacetCount = 0;
FacetedSearchResult<?> searchResp;
int expectedSize = 0;
boolean facetToCheckExist = false;
for (int from = 0; from < maxElement; from += size) {
expectedSize = (maxElement - from) > size ? size : maxElement - from;
searchResp = dao.facetedSearch(NodeType.class, searchText, filters, fetchContext, from, size);
assertNotNull(searchResp);
assertNotNull(searchResp.getTypes());
assertNotNull(searchResp.getData());
assertEquals(expectedSize, searchResp.getTypes().length);
assertEquals(expectedSize, searchResp.getData().length);
// testing the pertinence of returned data
Object[] data = searchResp.getData();
for (Object element : data) {
NodeType nt = jsonMapper.readValue(jsonMapper.writeValueAsString(element), NodeType.class);
// TODO assert fetch context result.
assertTrue(expectedDataList.contains(nt));
expectedDataList.remove(nt);
}
// test returned facets
if (filters != null && filters.containsKey("capabilities.type")) {
facetNameToCheck = "requirements.type";
factetValueToCheck = "network";
expectedFacetCount = 6;
} else {
facetNameToCheck = "capabilities.type";
factetValueToCheck = "war";
expectedFacetCount = 4;
}
assertNotNull(searchResp.getFacets());
assertTrue(!searchResp.getFacets().isEmpty());
FacetedSearchFacet[] facets = searchResp.getFacets().get(facetNameToCheck);
assertNotNull(facets);
long facetCount = 0;
for (FacetedSearchFacet facet : facets) {
if (facet.getFacetValue().equals(factetValueToCheck)) {
facetToCheckExist = true;
facetCount = facet.getCount();
}
}
assertTrue(facetToCheckExist);
assertEquals(expectedFacetCount, facetCount);
}
// assert the list is empty at the end.
assertTrue(expectedDataList.isEmpty());
}
private void testTextBasedSearchWellPaginated(int maxElement, int size, String searchText, Map<String, String[]> filters) throws IOException {
List<NodeType> expectedDataList = new ArrayList<>(jndiTestDataList);
GetMultipleDataResult searchResp;
int expectedSize;
for (int from = 0; from < maxElement; from += size) {
expectedSize = (maxElement - from) > size ? size : maxElement - from;
searchResp = dao.search(NodeType.class, searchText, filters, from, size);
assertNotNull(searchResp);
assertNotNull(searchResp.getTypes());
assertNotNull(searchResp.getData());
assertEquals(expectedSize, searchResp.getTypes().length);
assertEquals(expectedSize, searchResp.getData().length);
// testing the pertinence of returned data
Object[] data = searchResp.getData();
for (Object element : data) {
NodeType nt = jsonMapper.readValue(jsonMapper.writeValueAsString(element), NodeType.class);
assertTrue(expectedDataList.contains(nt));
expectedDataList.remove(nt);
}
}
// assert the list is empty at the end.
assertTrue(expectedDataList.isEmpty());
}
private int getCount(QueryBuilder queryBuilder) {
return (int) nodeClient.prepareCount(ElasticSearchDAO.TOSCA_ELEMENT_INDEX).setTypes(MappingBuilder.indexTypeFromClass(NodeType.class))
.setQuery(queryBuilder).execute().actionGet().getCount();
}
private void saveDataToES() throws IOException, IndexingServiceException {
testDataList.clear();
Path path = Paths.get("src/test/resources/nodetypes-faceted-search-result.json");
FacetedSearchResult res = jsonMapper.readValue(path.toFile(), FacetedSearchResult.class);
Object[] data = res.getData();
for (Object element : data) {
String serializeDatum = jsonMapper.writeValueAsString(element);
NodeType indexedNodeType = jsonMapper.readValue(serializeDatum, NodeType.class);
indexedNodeType.setWorkspace(AlienConstants.GLOBAL_WORKSPACE_ID);
String typeName = MappingBuilder.indexTypeFromClass(NodeType.class);
dao.save(indexedNodeType);
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName, indexedNodeType.getId(), true);
testDataList.add(indexedNodeType);
for (CapabilityDefinition capaDef : indexedNodeType.getCapabilities()) {
if (capaDef.getType().equals("jndi")) {
jndiTestDataList.add(indexedNodeType);
}
}
}
refresh();
}
private void assertDocumentExisit(String indexName, String typeName, String id, boolean expected) {
GetResponse response = getDocument(indexName, typeName, id);
assertEquals(expected, response.isExists());
assertEquals(expected, !response.isSourceEmpty());
}
private GetResponse getDocument(String indexName, String typeName, String id) {
return nodeClient.prepareGet(indexName, typeName, id).execute().actionGet();
}
}