/* Copyright (c) 2013-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.di.caching; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.File; import java.util.Iterator; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import org.geotools.data.DataUtilities; import org.geotools.feature.SchemaException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.locationtech.geogig.api.CommitBuilder; import org.locationtech.geogig.api.Context; import org.locationtech.geogig.api.ObjectId; import org.locationtech.geogig.api.Platform; import org.locationtech.geogig.api.RevCommit; import org.locationtech.geogig.api.RevFeatureType; import org.locationtech.geogig.api.RevFeatureTypeImpl; import org.locationtech.geogig.api.RevObject; import org.locationtech.geogig.api.TestPlatform; import org.locationtech.geogig.di.Decorator; import org.locationtech.geogig.di.DecoratorProvider; import org.locationtech.geogig.di.GuiceInjector; import org.locationtech.geogig.storage.ConfigDatabase; import org.locationtech.geogig.storage.ObjectDatabase; import org.locationtech.geogig.storage.ObjectSerializingFactory; import org.locationtech.geogig.storage.StagingDatabase; import org.locationtech.geogig.storage.datastream.DataStreamSerializationFactoryV1; import org.locationtech.geogig.storage.fs.IniFileConfigDatabase; import org.locationtech.geogig.storage.memory.HeapObjectDatabse; import org.locationtech.geogig.storage.memory.HeapStagingDatabase; import org.locationtech.geogig.test.integration.RepositoryTestCase; import org.opengis.feature.simple.SimpleFeatureType; import com.google.common.base.Throwables; import com.google.common.cache.Cache; import com.google.common.collect.ImmutableList; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Module; import com.google.inject.Scopes; import com.google.inject.multibindings.Multibinder; import com.google.inject.util.Modules; public class CachingModuleTest { private StagingDatabase index; private ObjectDatabase odb; private Cache<ObjectId, RevObject> odbCache; private Cache<ObjectId, RevObject> indexCache; private static final RevObject o1 = obj("o1"), o2 = obj("o2"), o3 = ft("o3"); private static final RevObject s1 = obj("s1"), s2 = obj("s2"), s3 = ft("s3"); @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); @Before public void setUp() throws Exception { odbCache = mock(Cache.class); indexCache = mock(Cache.class); final ObjectDatabaseCacheFactory odbCacheFac = mock(ObjectDatabaseCacheFactory.class); when(odbCacheFac.get()).thenReturn(odbCache); final StagingDatabaseCacheFactory indexCacheFac = mock(StagingDatabaseCacheFactory.class); when(indexCacheFac.get()).thenReturn(indexCache); File workingDirectory = tmpFolder.getRoot(); final Platform platform = new TestPlatform(workingDirectory); Module module = new AbstractModule() { @Override protected void configure() { bind(Context.class).to(GuiceInjector.class).in(Scopes.SINGLETON); Multibinder.newSetBinder(binder(), Decorator.class); bind(DecoratorProvider.class).in(Scopes.SINGLETON); DataStreamSerializationFactoryV1 sfac = DataStreamSerializationFactoryV1.INSTANCE; bind(ObjectSerializingFactory.class).toInstance(sfac); bind(ObjectDatabase.class).to(HeapObjectDatabse.class).in(Scopes.SINGLETON); bind(StagingDatabase.class).to(HeapStagingDatabase.class).in(Scopes.SINGLETON); ConfigDatabase config = new IniFileConfigDatabase(platform); bind(ConfigDatabase.class).toInstance(config); bind(ObjectDatabaseCacheFactory.class).toInstance(odbCacheFac); bind(StagingDatabaseCacheFactory.class).toInstance(indexCacheFac); } }; Context injector = Guice.createInjector(Modules.override(new CachingModule()).with(module)) .getInstance(org.locationtech.geogig.api.Context.class); odb = injector.objectDatabase(); index = injector.stagingDatabase(); odb.open(); index.open(); odb.put(o1); odb.put(o2); odb.put(o3); index.put(s1); index.put(s2); index.put(s3); } private static RevObject obj(String name) { RevCommit c = new CommitBuilder().setTreeId(ObjectId.NULL).setMessage(name).build(); return c; } private static RevFeatureType ft(String name) { SimpleFeatureType type; try { type = DataUtilities.createType("", name, RepositoryTestCase.pointsTypeSpec); } catch (SchemaException e) { throw Throwables.propagate(e); } RevFeatureType rft = RevFeatureTypeImpl.build(type); return rft; } @Test public void delete() { odb.delete(o1.getId()); verify(odbCache).invalidate(eq(o1.getId())); index.delete(s1.getId()); verify(indexCache).invalidate(eq(s1.getId())); } @Test public void deleteAll() { Iterator<ObjectId> ids; ids = ImmutableList.of(o1.getId(), o2.getId()).iterator(); odb.deleteAll(ids); verify(odbCache, times(1)).invalidate(eq(o1.getId())); verify(odbCache, times(1)).invalidate(eq(o2.getId())); ids = ImmutableList.of(s1.getId(), s2.getId()).iterator(); index.deleteAll(ids); verify(indexCache, times(1)).invalidate(eq(s1.getId())); verify(indexCache, times(1)).invalidate(eq(s2.getId())); } @Test public void testGetCacheHit() throws ExecutionException { when(odbCache.get(eq(o1.getId()), any(Callable.class))).thenReturn(o1); assertSame(o1, odb.get(o1.getId())); } }