package org.molgenis.data.elasticsearch; import org.molgenis.data.*; import org.molgenis.data.QueryRule.Operator; import org.molgenis.data.aggregation.AggregateQuery; import org.molgenis.data.meta.model.Attribute; import org.molgenis.data.meta.model.EntityType; import org.molgenis.data.support.AggregateQueryImpl; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import static com.google.common.collect.Lists.newArrayList; import static org.mockito.Mockito.*; import static org.molgenis.data.QueryRule.Operator.*; import static org.molgenis.data.RepositoryCapability.*; import static org.testng.Assert.assertEquals; public class IndexedRepositoryDecoratorTest { private IndexedRepositoryDecorator indexedRepositoryDecorator; private SearchService searchService; private Repository<Entity> decoratedRepo; private EntityType repositoryEntityType; private String idAttrName; private Query<Entity> query; private Query<Entity> unsupportedQuery; @SuppressWarnings("unchecked") @BeforeMethod public void setUp() throws IOException { searchService = mock(SearchService.class); decoratedRepo = mock(Repository.class); String entityName = "entity"; repositoryEntityType = mock(EntityType.class); when(repositoryEntityType.getName()).thenReturn(entityName); idAttrName = "id"; Attribute idAttr = when(mock(Attribute.class).getName()).thenReturn(idAttrName).getMock(); when(idAttr.getExpression()).thenReturn(null); when(repositoryEntityType.getIdAttribute()).thenReturn(idAttr); when(decoratedRepo.getEntityType()).thenReturn(repositoryEntityType); when(decoratedRepo.getName()).thenReturn("entity"); when(decoratedRepo.getCapabilities()).thenReturn(EnumSet.of(QUERYABLE, MANAGABLE, VALIDATE_NOTNULL_CONSTRAINT)); when(decoratedRepo.getQueryOperators()).thenReturn(EnumSet.of(IN, LESS, EQUALS, AND, OR)); indexedRepositoryDecorator = new IndexedRepositoryDecorator(decoratedRepo, searchService); when(repositoryEntityType.getAtomicAttributes()).thenReturn(newArrayList(idAttr)); query = mock(Query.class); QueryRule rule1 = mock(QueryRule.class); QueryRule rule2 = mock(QueryRule.class); when(rule1.getOperator()).thenReturn(IN); when(rule2.getOperator()).thenReturn(EQUALS); List<QueryRule> queryRules = newArrayList(rule1, rule2); when(query.getRules()).thenReturn(queryRules); unsupportedQuery = mock(Query.class); QueryRule unsupportedRule = mock(QueryRule.class); when(unsupportedRule.getOperator()).thenReturn(FUZZY_MATCH); List<QueryRule> unsupportedQueryRules = newArrayList(rule1, rule2, unsupportedRule); when(unsupportedQuery.getRules()).thenReturn(unsupportedQueryRules); } @SuppressWarnings("resource") @Test(expectedExceptions = NullPointerException.class) public void ElasticSearchRepository() { new IndexedRepositoryDecorator(null, null); } @Test public void addEntity() { String id = "id0"; Entity entity = when(mock(Entity.class).get(idAttrName)).thenReturn(id).getMock(); indexedRepositoryDecorator.add(entity); verify(decoratedRepo).add(entity); verifyZeroInteractions(searchService); } @Test public void addStream() { Stream<Entity> entities = Stream.empty(); indexedRepositoryDecorator.add(entities); verify(decoratedRepo, times(1)).add(entities); verifyZeroInteractions(searchService); } @Test public void aggregate() { when(indexedRepositoryDecorator.getName()).thenReturn("entity"); Attribute xAttr = when(mock(Attribute.class).getName()).thenReturn("xAttr").getMock(); Attribute yAttr = when(mock(Attribute.class).getName()).thenReturn("yAttr").getMock(); Attribute distinctAttr = when(mock(Attribute.class).getName()).thenReturn("distinctAttr").getMock(); @SuppressWarnings("unchecked") Query<Entity> q = mock(Query.class); AggregateQuery aggregateQuery = new AggregateQueryImpl().attrX(xAttr).attrY(yAttr).attrDistinct(distinctAttr) .query(q); indexedRepositoryDecorator.aggregate(aggregateQuery); verify(searchService).aggregate(aggregateQuery, repositoryEntityType); } @Test public void close() throws IOException { indexedRepositoryDecorator.close(); verify(decoratedRepo).close(); verifyZeroInteractions(searchService); } @Test public void count() { indexedRepositoryDecorator.count(); verify(decoratedRepo).count(); verifyZeroInteractions(searchService); } @Test public void countQuery() { indexedRepositoryDecorator.count(query); verify(decoratedRepo).count(query); verifyZeroInteractions(searchService); } @Test public void countQueryUnsupported() { indexedRepositoryDecorator.count(unsupportedQuery); verify(searchService).count(unsupportedQuery, repositoryEntityType); verify(decoratedRepo, never()).count(unsupportedQuery); } @Test public void deleteEntity() { String id = "id0"; Entity entity = when(mock(Entity.class).get(idAttrName)).thenReturn(id).getMock(); indexedRepositoryDecorator.delete(entity); verify(decoratedRepo).delete(entity); verifyZeroInteractions(searchService); } @Test public void deleteStream() { Stream<Entity> entities = Stream.empty(); indexedRepositoryDecorator.delete(entities); verify(decoratedRepo, times(1)).delete(entities); verifyZeroInteractions(searchService); } @Test public void deleteAll() { indexedRepositoryDecorator.deleteAll(); verify(decoratedRepo).deleteAll(); verifyZeroInteractions(searchService); } @Test public void deleteByIdObject() { Object id = "0"; indexedRepositoryDecorator.deleteById(id); verify(decoratedRepo).deleteById(id); verifyZeroInteractions(searchService); } @Test public void findOneQuery() { indexedRepositoryDecorator.findOne(query); verify(decoratedRepo).findOne(query); verifyZeroInteractions(searchService); } @Test public void findOneQueryUnsupported() { Entity entity0 = mock(Entity.class); when(searchService.findOne(unsupportedQuery, repositoryEntityType)).thenReturn(entity0); indexedRepositoryDecorator.findOne(unsupportedQuery); verify(searchService).findOne(unsupportedQuery, repositoryEntityType); verify(decoratedRepo, never()).findOne(unsupportedQuery); } @Test public void findOneById() { Object id = mock(Object.class); indexedRepositoryDecorator.findOneById(id); verify(decoratedRepo).findOneById(id); verifyZeroInteractions(searchService); } @Test public void findOneByIdFetch() { Object id = mock(Object.class); Fetch fetch = new Fetch(); Entity entity = mock(Entity.class); when(decoratedRepo.findOneById(id, fetch)).thenReturn(entity); assertEquals(indexedRepositoryDecorator.findOneById(id, fetch), entity); verify(decoratedRepo, times(1)).findOneById(id, fetch); verifyZeroInteractions(searchService); } @Test public void getEntityType() { assertEquals(indexedRepositoryDecorator.getEntityType(), repositoryEntityType); } @Test public void getName() { assertEquals(indexedRepositoryDecorator.getName(), repositoryEntityType.getName()); } @Test public void updateEntity() { String id = "id0"; Entity entity = when(mock(Entity.class).get(idAttrName)).thenReturn(id).getMock(); indexedRepositoryDecorator.update(entity); verify(decoratedRepo).update(entity); verifyZeroInteractions(searchService); } @Test public void updateStream() { Stream<Entity> entities = Stream.empty(); indexedRepositoryDecorator.update(entities); verify(decoratedRepo, times(1)).update(entities); verifyZeroInteractions(searchService); } @Test public void findAllStream() { Object id0 = "id0"; Object id1 = "id1"; Entity entity0 = mock(Entity.class); Entity entity1 = mock(Entity.class); Stream<Object> entityIds = Stream.of(id0, id1); when(decoratedRepo.findAll(entityIds)).thenReturn(Stream.of(entity0, entity1)); Stream<Entity> expectedEntities = indexedRepositoryDecorator.findAll(entityIds); assertEquals(expectedEntities.collect(Collectors.toList()), Arrays.asList(entity0, entity1)); verifyZeroInteractions(searchService); } @Test public void findAllStreamFetch() { Fetch fetch = new Fetch(); Object id0 = "id0"; Object id1 = "id1"; Entity entity0 = mock(Entity.class); Entity entity1 = mock(Entity.class); Stream<Object> entityIds = Stream.of(id0, id1); when(decoratedRepo.findAll(entityIds, fetch)).thenReturn(Stream.of(entity0, entity1)); Stream<Entity> expectedEntities = indexedRepositoryDecorator.findAll(entityIds, fetch); assertEquals(expectedEntities.collect(Collectors.toList()), Arrays.asList(entity0, entity1)); verifyZeroInteractions(searchService); } @Test public void findAllQuery() { indexedRepositoryDecorator.findAll(query); verify(decoratedRepo, times(1)).findAll(query); verifyZeroInteractions(searchService); } @Test public void findAllQueryUnsupported() { indexedRepositoryDecorator.findAll(unsupportedQuery); verify(searchService).searchAsStream(unsupportedQuery, repositoryEntityType); verify(decoratedRepo, never()).findAll(unsupportedQuery); } @Test public void forEachBatched() { Fetch fetch = new Fetch(); @SuppressWarnings("unchecked") Consumer<List<Entity>> consumer = mock(Consumer.class); indexedRepositoryDecorator.forEachBatched(fetch, consumer, 12); verify(decoratedRepo, times(1)).forEachBatched(fetch, consumer, 12); } @Test public void iterator() { indexedRepositoryDecorator.iterator(); verify(decoratedRepo, times(1)).iterator(); verifyZeroInteractions(searchService); } @Test public void getCapabilities() { assertEquals(indexedRepositoryDecorator.getCapabilities(), EnumSet.of(AGGREGATEABLE, QUERYABLE, MANAGABLE, VALIDATE_NOTNULL_CONSTRAINT)); } @Test public void getQueryOperators() { assertEquals(indexedRepositoryDecorator.getQueryOperators(), EnumSet.allOf(Operator.class)); } @Test public void query() { assertEquals(indexedRepositoryDecorator.query().getRepository(), indexedRepositoryDecorator); verifyZeroInteractions(searchService); } @Test public void unsupportedQueryWithComputedAttributes() { @SuppressWarnings("unchecked") Query<Entity> q = mock(Query.class); QueryRule qRule1 = mock(QueryRule.class); QueryRule qRule2 = mock(QueryRule.class); when(qRule1.getField()).thenReturn("attr1"); when(qRule2.getField()).thenReturn("attr2"); when(qRule1.getOperator()).thenReturn(EQUALS); when(qRule2.getOperator()).thenReturn(OR); when(qRule1.getNestedRules()).thenReturn(Collections.emptyList()); when(qRule2.getNestedRules()).thenReturn(Collections.emptyList()); when(q.getRules()).thenReturn(newArrayList(qRule1, qRule2)); Attribute attr1 = mock(Attribute.class); when(repositoryEntityType.getAttribute("attr1")).thenReturn(attr1); when(attr1.hasExpression()).thenReturn(true); Attribute attr2 = mock(Attribute.class); when(repositoryEntityType.getAttribute("attr2")).thenReturn(attr2); when(attr2.hasExpression()).thenReturn(true); indexedRepositoryDecorator.count(q); verify(searchService).count(q, repositoryEntityType); verify(decoratedRepo, never()).count(q); } @Test public void unsupportedQueryWithSortOnComputedAttributes() { @SuppressWarnings("unchecked") Query<Entity> q = mock(Query.class); Sort sort = mock(Sort.class); when(q.getSort()).thenReturn(sort); Attribute attr1 = mock(Attribute.class); when(repositoryEntityType.getAttribute("attr1")).thenReturn(attr1); when(attr1.hasExpression()).thenReturn(true); Attribute attr2 = mock(Attribute.class); when(repositoryEntityType.getAttribute("attr2")).thenReturn(attr2); when(attr2.hasExpression()).thenReturn(true); Sort.Order o1 = mock(Sort.Order.class); Sort.Order o2 = mock(Sort.Order.class); when(o1.getAttr()).thenReturn("attr1"); when(o2.getAttr()).thenReturn("attr2"); when(sort.spliterator()).thenReturn(newArrayList(o1, o2).spliterator()); indexedRepositoryDecorator.count(q); verify(searchService).count(q, repositoryEntityType); verify(decoratedRepo, never()).count(q); } }