package org.molgenis.data.cache.l3; import com.google.common.collect.Sets; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.molgenis.data.*; import org.molgenis.data.meta.model.AttributeFactory; import org.molgenis.data.meta.model.EntityType; import org.molgenis.data.meta.model.EntityTypeFactory; import org.molgenis.data.support.DynamicEntity; import org.molgenis.data.support.QueryImpl; import org.molgenis.data.transaction.TransactionInformation; import org.molgenis.test.data.AbstractMolgenisSpringTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.List; import java.util.stream.Stream; import static com.google.common.collect.Lists.newArrayList; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; import static org.molgenis.data.EntityManager.CreationMode.NO_POPULATE; import static org.molgenis.data.RepositoryCapability.CACHEABLE; import static org.molgenis.data.meta.AttributeType.INT; import static org.molgenis.data.meta.model.EntityType.AttributeRole.ROLE_ID; import static org.testng.Assert.assertEquals; @ContextConfiguration(classes = L3CacheRepositoryDecoratorTest.Config.class) public class L3CacheRepositoryDecoratorTest extends AbstractMolgenisSpringTest { private L3CacheRepositoryDecorator l3CacheRepositoryDecorator; private EntityType entityType; private Entity entity1; private Entity entity2; private Entity entity3; private final String repositoryName = "TestRepository"; private static final String COUNTRY = "Country"; private static final String ID = "ID"; @Mock private L3Cache l3Cache; @Mock private Repository<Entity> decoratedRepository; @Mock private TransactionInformation transactionInformation; @Autowired private EntityTypeFactory entityTypeFactory; @Autowired private AttributeFactory attributeFactory; @Autowired private EntityManager entityManager; @Captor private ArgumentCaptor<Stream<Object>> entityIdCaptor; private Query<Entity> query; @Mock private Fetch fetch; @BeforeClass public void beforeClass() { initMocks(this); entityType = entityTypeFactory.create(repositoryName); entityType.addAttribute(attributeFactory.create().setDataType(INT).setName(ID), ROLE_ID); entityType.addAttribute(attributeFactory.create().setName(COUNTRY)); when(entityManager.create(entityType, NO_POPULATE)).thenReturn(new DynamicEntity(entityType)); entity1 = entityManager.create(entityType, NO_POPULATE); entity1.set(ID, 1); entity1.set(COUNTRY, "NL"); entity2 = entityManager.create(entityType, NO_POPULATE); entity2.set(ID, 2); entity2.set(COUNTRY, "NL"); entity3 = entityManager.create(entityType, NO_POPULATE); entity3.set(ID, 3); entity3.set(COUNTRY, "GB"); when(decoratedRepository.getCapabilities()).thenReturn(Sets.newHashSet(CACHEABLE)); l3CacheRepositoryDecorator = new L3CacheRepositoryDecorator(decoratedRepository, l3Cache, transactionInformation); query = new QueryImpl<>().eq(COUNTRY, "GB"); query.pageSize(10); query.sort(new Sort().on(COUNTRY)); query.setFetch(fetch); } @BeforeMethod public void beforeMethod() { reset(l3Cache, transactionInformation, decoratedRepository); when(decoratedRepository.getEntityType()).thenReturn(entityType); when(decoratedRepository.getName()).thenReturn(repositoryName); } @Test public void testFindOneRepositoryClean() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(true); Query<Entity> queryWithPageSizeOne = new QueryImpl<>(query).pageSize(1); when(l3Cache.get(decoratedRepository, queryWithPageSizeOne)).thenReturn(singletonList(3)); when(decoratedRepository.findOneById(3, fetch)).thenReturn(entity3); assertEquals(l3CacheRepositoryDecorator.findOne(queryWithPageSizeOne), entity3); verify(decoratedRepository, times(1)).findOneById(3, fetch); verify(decoratedRepository, atLeast(0)).getName(); verifyNoMoreInteractions(decoratedRepository); } @Test public void testFindOneRepositoryDirty() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(false); when(decoratedRepository.findOne(query)).thenReturn(entity3); assertEquals(l3CacheRepositoryDecorator.findOne(query), entity3); verifyNoMoreInteractions(l3Cache); } @Test public void testFindAllRepositoryClean() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(true); List<Object> ids = asList(1, 2); List<Entity> expectedEntities = newArrayList(entity1, entity2); when(l3Cache.get(decoratedRepository, query)).thenReturn(ids); when(decoratedRepository.findAll(entityIdCaptor.capture(), eq(query.getFetch()))) .thenReturn(expectedEntities.stream()); Stream<Entity> actualEntities = l3CacheRepositoryDecorator.findAll(query); assertEquals(actualEntities.collect(toList()), expectedEntities); assertEquals(entityIdCaptor.getValue().collect(toList()), ids); } @Test public void testFindAllVeryLargePageSize() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(true); Query<Entity> largeQuery = new QueryImpl<>(query).setPageSize(10000); List<Entity> expectedEntities = newArrayList(entity1, entity2); when(decoratedRepository.findAll(largeQuery)).thenReturn(expectedEntities.stream()); List<Entity> actualEntities = l3CacheRepositoryDecorator.findAll(largeQuery).collect(toList()); assertEquals(actualEntities, expectedEntities); verifyNoMoreInteractions(l3Cache); } @Test public void testFindAllZeroPageSize() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(true); Query<Entity> largeQuery = new QueryImpl<>(query).setPageSize(0); List<Entity> expectedEntities = newArrayList(entity1, entity2); when(decoratedRepository.findAll(largeQuery)).thenReturn(expectedEntities.stream()); List<Entity> actualEntities = l3CacheRepositoryDecorator.findAll(largeQuery).collect(toList()); assertEquals(actualEntities, expectedEntities); verifyNoMoreInteractions(l3Cache); } @Test public void testFindAllRepositoryDirty() { when(transactionInformation.isRepositoryCompletelyClean(repositoryName)).thenReturn(false); Query<Entity> query = new QueryImpl<>().eq(COUNTRY, "NL"); query.pageSize(10); query.sort(new Sort()); query.fetch(new Fetch()); List<Entity> expectedEntities = newArrayList(entity1, entity2); when(decoratedRepository.findAll(query)).thenReturn(expectedEntities.stream()); List<Entity> actualEntities = l3CacheRepositoryDecorator.findAll(query).collect(toList()); assertEquals(actualEntities, expectedEntities); verifyNoMoreInteractions(l3Cache); } @Configuration public static class Config { @Bean public EntityManager entityManager() { return mock(EntityManager.class); } } }