package org.molgenis.data.cache.l3; import com.google.common.collect.Sets; import com.google.common.util.concurrent.UncheckedExecutionException; 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.MolgenisTransactionManager; import org.molgenis.data.transaction.TransactionInformation; import org.molgenis.test.data.AbstractMolgenisSpringTest; import org.springframework.beans.factory.annotation.Autowired; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.Arrays; import java.util.Collections; import java.util.stream.Stream; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; 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; import static org.testng.Assert.fail; public class L3CacheTest extends AbstractMolgenisSpringTest { private L3Cache l3Cache; 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 Repository<Entity> decoratedRepository; @Mock private TransactionInformation transactionInformation; @Mock private MolgenisTransactionManager molgenisTransactionManager; @Autowired private EntityTypeFactory entityTypeFactory; @Autowired private AttributeFactory attributeFactory; @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)); entity1 = new DynamicEntity(entityType); entity1.set(ID, 1); entity1.set(COUNTRY, "NL"); entity2 = new DynamicEntity(entityType); entity2.set(ID, 2); entity2.set(COUNTRY, "NL"); entity3 = new DynamicEntity(entityType); entity3.set(ID, 3); entity3.set(COUNTRY, "GB"); } @SuppressWarnings("unchecked") @BeforeMethod public void beforeMethod() { reset(decoratedRepository); when(decoratedRepository.getCapabilities()).thenReturn(Sets.newHashSet(CACHEABLE)); when(decoratedRepository.getName()).thenReturn(repositoryName); when(decoratedRepository.getEntityType()).thenReturn(entityType); l3Cache = new L3Cache(molgenisTransactionManager, transactionInformation); } @Test public void testGet() { Fetch idAttributeFetch = new Fetch().field(entityType.getIdAttribute().getName()); Query<Entity> fetchLessQuery = new QueryImpl<>().eq(COUNTRY, "NL").fetch(idAttributeFetch); when(decoratedRepository.findAll(fetchLessQuery)).thenReturn(Stream.of(entity1, entity2)); Fetch fetch = mock(Fetch.class); Query<Entity> query = new QueryImpl<>().eq(COUNTRY, "NL").fetch(fetch); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); verify(decoratedRepository, times(1)).findAll(fetchLessQuery); verify(decoratedRepository, atLeast(0)).getName(); verify(decoratedRepository, atLeast(0)).getEntityType(); verifyNoMoreInteractions(decoratedRepository); } @Test public void testGetThrowsException() { Fetch idAttributeFetch = new Fetch().field(entityType.getIdAttribute().getName()); Query<Entity> fetchLessQuery = new QueryImpl<>().eq(COUNTRY, "NL").fetch(idAttributeFetch); when(decoratedRepository.findAll(fetchLessQuery)).thenThrow(new MolgenisDataException("What table?")); Fetch fetch = mock(Fetch.class); Query<Entity> query = new QueryImpl<>().eq(COUNTRY, "NL").fetch(fetch); try { l3Cache.get(decoratedRepository, query); // check that exception is thrown by the get method fail("Get should throw exception"); } catch (UncheckedExecutionException expected) { } // Check that exception isn't cached. try { l3Cache.get(decoratedRepository, query); fail("Get should throw exception"); } catch (UncheckedExecutionException expected) { } verify(decoratedRepository, times(2)).findAll(fetchLessQuery); } @Test public void testAfterCommitTransactionDirtyRepository() { Fetch idAttributeFetch = new Fetch().field(entityType.getIdAttribute().getName()); Query<Entity> fetchLessQuery = new QueryImpl<>().eq(COUNTRY, "NL").fetch(idAttributeFetch); when(decoratedRepository.findAll(fetchLessQuery)).thenReturn(Stream.of(entity1, entity2)); Fetch fetch = mock(Fetch.class); Query<Entity> query = new QueryImpl<>().eq(COUNTRY, "NL").fetch(fetch); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); when(transactionInformation.getDirtyRepositories()).thenReturn(Collections.singleton(repositoryName)); l3Cache.afterCommitTransaction("ABCDE"); when(decoratedRepository.findAll(fetchLessQuery)).thenReturn(Stream.of(entity3, entity2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(3, 2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(3, 2)); verify(decoratedRepository, times(2)).findAll(fetchLessQuery); } @Test public void testAfterCommitTransactionCleanRepository() { Fetch idAttributeFetch = new Fetch().field(entityType.getIdAttribute().getName()); Query<Entity> fetchLessQuery = new QueryImpl<>().eq(COUNTRY, "NL").fetch(idAttributeFetch); when(decoratedRepository.findAll(fetchLessQuery)).thenReturn(Stream.of(entity1, entity2)); Fetch fetch = mock(Fetch.class); Query<Entity> query = new QueryImpl<>().eq(COUNTRY, "NL").fetch(fetch); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); when(transactionInformation.getDirtyRepositories()).thenReturn(Collections.singleton("blah")); l3Cache.afterCommitTransaction("ABCDE"); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); assertEquals(l3Cache.get(decoratedRepository, query), Arrays.asList(1, 2)); verify(decoratedRepository, times(1)).findAll(fetchLessQuery); verify(decoratedRepository, atLeast(0)).getName(); verify(decoratedRepository, atLeast(0)).getEntityType(); verifyNoMoreInteractions(decoratedRepository); } }