diff --git a/gradle/changelog/meter_stores.yaml b/gradle/changelog/meter_stores.yaml new file mode 100644 index 0000000000..385025019a --- /dev/null +++ b/gradle/changelog/meter_stores.yaml @@ -0,0 +1,2 @@ +- type: added + description: Performance of stores can be measured with Micrometer metrics diff --git a/scm-persistence/src/main/java/sonia/scm/store/StoreInvocationMicrometerWrapper.java b/scm-persistence/src/main/java/sonia/scm/store/StoreInvocationMicrometerWrapper.java new file mode 100644 index 0000000000..7d4aef5853 --- /dev/null +++ b/scm-persistence/src/main/java/sonia/scm/store/StoreInvocationMicrometerWrapper.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2020 - present Cloudogu GmbH + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +package sonia.scm.store; + +import com.google.common.annotations.VisibleForTesting; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import sonia.scm.util.AssertUtil; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.function.Consumer; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public class StoreInvocationMicrometerWrapper implements InvocationHandler { + + private final Object store; + private final MeterRegistry meterRegistry; + private final Consumer timerCustomizer; + + private final Supplier timerBuilder; + + /** + * Creates a wrapper for the given store which will record the time taken for each method call. + * If the {@link MeterRegistry} is {@code null}, the store will not be wrapped and returned as is. + */ + public static T create(String storeType, + TypedStoreParameters storeParameters, + Class storeClass, + T store, + MeterRegistry meterRegistry) { + if (meterRegistry == null) { + return store; + } + return (T) Proxy.newProxyInstance( + storeParameters.getType().getClassLoader(), + new Class[]{storeClass}, + new StoreInvocationMicrometerWrapper( + storeType, + storeParameters, + store, + meterRegistry, + () -> Timer.builder("scm.persistence") + ) + ); + } + + /** + * Creates a wrapper for the given store which will record the time taken for each method call. + * If the {@link MeterRegistry} is {@code null}, the store will not be wrapped and returned as is. + */ + public static Q create(String storeType, + Class clazz, + String[] parentIds, + Class storeClass, + Q store, + MeterRegistry meterRegistry) { + if (meterRegistry == null) { + return store; + } + return (Q) Proxy.newProxyInstance( + clazz.getClassLoader(), + new Class[]{storeClass}, + new StoreInvocationMicrometerWrapper( + storeType, + clazz, + parentIds, + store, + meterRegistry, + () -> Timer.builder("scm.persistence") + ) + ); + } + + @VisibleForTesting + StoreInvocationMicrometerWrapper(String storeType, + TypedStoreParameters storeParameters, + Object store, + MeterRegistry meterRegistry, + Supplier timerBuilder) { + this( + meterRegistry, + store, + timer -> timer + .description("Time taken for store operation in " + storeType) + .tag("type", storeType) + .tag("storeName", storeParameters.getName()) + .tag("repositoryId", storeParameters.getRepositoryId() == null ? "none" : storeParameters.getRepositoryId()) + .tag("namespace", storeParameters.getNamespace() == null ? "none" : storeParameters.getNamespace()), + timerBuilder + ); + } + + @VisibleForTesting + StoreInvocationMicrometerWrapper(String storeType, + Class clazz, + String[] parentIds, + Q store, + MeterRegistry meterRegistry, + Supplier timerBuilder) { + this( + meterRegistry, + store, + timer -> timer + .description("Time taken for store operation in " + storeType) + .tag("type", storeType) + .tag("storeClass", clazz.getName()) + .tag("parentIds", String.join(",", parentIds)), + timerBuilder + ); + } + + private StoreInvocationMicrometerWrapper(MeterRegistry meterRegistry, + Object store, + Consumer timerCustomizer, + Supplier timerBuilder) { + AssertUtil.assertIsNotNull(store); + this.meterRegistry = meterRegistry; + this.store = store; + this.timerCustomizer = timerCustomizer; + this.timerBuilder = timerBuilder; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (meterRegistry == null) { + return method.invoke(store, args); + } + if (QueryableStore.Query.class.isAssignableFrom(method.getReturnType())) { + Object delegate = method.invoke(store, args); + return Proxy.newProxyInstance( + this.getClass().getClassLoader(), + delegate.getClass().getInterfaces(), + new StoreInvocationMicrometerWrapper(meterRegistry, delegate, timerCustomizer, timerBuilder) + ); + } + try { + if (method.getName().equals("close")) { + return method.invoke(store, args); + } + Timer.Builder timer = timerBuilder.get() + .tag("method", method.getName()); + timerCustomizer.accept(timer); + return timer + .register(meterRegistry) + .record(() -> { + try { + return method.invoke(store, args); + } catch (Exception e) { + throw new StoreException("Failed to invoke store method", e); + } + }); + } catch (InvocationTargetException | UndeclaredThrowableException e) { + throw e.getCause(); + } + } +} diff --git a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationEntryStoreFactory.java b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationEntryStoreFactory.java index 53b4e53aba..392ebb841f 100644 --- a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationEntryStoreFactory.java +++ b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationEntryStoreFactory.java @@ -16,17 +16,19 @@ package sonia.scm.store.file; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; +import io.micrometer.core.instrument.MeterRegistry; import sonia.scm.SCMContextProvider; import sonia.scm.repository.RepositoryLocationResolver; import sonia.scm.repository.RepositoryReadOnlyChecker; import sonia.scm.security.KeyGenerator; import sonia.scm.store.ConfigurationEntryStore; import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.store.StoreInvocationMicrometerWrapper; import sonia.scm.store.TypedStoreParameters; - @Singleton public class JAXBConfigurationEntryStoreFactory extends FileBasedStoreFactory implements ConfigurationEntryStoreFactory { @@ -35,17 +37,39 @@ public class JAXBConfigurationEntryStoreFactory extends FileBasedStoreFactory private final StoreCache> storeCache; - @Inject + private final MeterRegistry meterRegistry; + + @VisibleForTesting public JAXBConfigurationEntryStoreFactory( SCMContextProvider contextProvider, RepositoryLocationResolver repositoryLocationResolver, KeyGenerator keyGenerator, RepositoryReadOnlyChecker readOnlyChecker, StoreCacheFactory storeCacheFactory + ) { + this( + contextProvider, + repositoryLocationResolver, + keyGenerator, + readOnlyChecker, + storeCacheFactory, + null + ); + } + + @Inject + public JAXBConfigurationEntryStoreFactory( + SCMContextProvider contextProvider, + RepositoryLocationResolver repositoryLocationResolver, + KeyGenerator keyGenerator, + RepositoryReadOnlyChecker readOnlyChecker, + StoreCacheFactory storeCacheFactory, + MeterRegistry meterRegistry ) { super(contextProvider, repositoryLocationResolver, Store.CONFIG, readOnlyChecker); this.keyGenerator = keyGenerator; this.storeCache = storeCacheFactory.createStoreCache(this::createStore); + this.meterRegistry = meterRegistry; } @Override @@ -54,8 +78,8 @@ public class JAXBConfigurationEntryStoreFactory extends FileBasedStoreFactory return (ConfigurationEntryStore) storeCache.getStore(storeParameters); } - private ConfigurationEntryStore createStore(TypedStoreParameters storeParameters) { - return new JAXBConfigurationEntryStore<>( + private ConfigurationEntryStore createStore(TypedStoreParameters storeParameters) { + JAXBConfigurationEntryStore store = new JAXBConfigurationEntryStore<>( getStoreLocation(storeParameters.getName().concat(StoreConstants.FILE_EXTENSION), storeParameters.getType(), storeParameters.getRepositoryId(), @@ -64,5 +88,13 @@ public class JAXBConfigurationEntryStoreFactory extends FileBasedStoreFactory storeParameters.getType(), TypedStoreContext.of(storeParameters) ); + + return StoreInvocationMicrometerWrapper.create( + "configuration-entry-store", + storeParameters, + ConfigurationEntryStore.class, + store, + meterRegistry + ); } } diff --git a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationStoreFactory.java b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationStoreFactory.java index 609e2b09f1..3ed734e16c 100644 --- a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationStoreFactory.java +++ b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBConfigurationStoreFactory.java @@ -16,14 +16,17 @@ package sonia.scm.store.file; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; +import io.micrometer.core.instrument.MeterRegistry; import sonia.scm.SCMContextProvider; import sonia.scm.repository.RepositoryLocationResolver; import sonia.scm.repository.RepositoryReadOnlyChecker; import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStoreDecoratorFactory; import sonia.scm.store.ConfigurationStoreFactory; +import sonia.scm.store.StoreInvocationMicrometerWrapper; import sonia.scm.store.StoreDecoratorFactory; import sonia.scm.store.TypedStoreParameters; @@ -40,17 +43,39 @@ public class JAXBConfigurationStoreFactory extends FileBasedStoreFactory impleme private final StoreCache> storeCache; - @Inject + private final MeterRegistry meterRegistry; + + @VisibleForTesting public JAXBConfigurationStoreFactory( SCMContextProvider contextProvider, RepositoryLocationResolver repositoryLocationResolver, RepositoryReadOnlyChecker readOnlyChecker, Set decoratorFactories, StoreCacheFactory storeCacheFactory + ) { + this( + contextProvider, + repositoryLocationResolver, + readOnlyChecker, + decoratorFactories, + storeCacheFactory, + null + ); + } + + @Inject + public JAXBConfigurationStoreFactory( + SCMContextProvider contextProvider, + RepositoryLocationResolver repositoryLocationResolver, + RepositoryReadOnlyChecker readOnlyChecker, + Set decoratorFactories, + StoreCacheFactory storeCacheFactory, + MeterRegistry meterRegistry ) { super(contextProvider, repositoryLocationResolver, Store.CONFIG, readOnlyChecker); this.decoratorFactories = decoratorFactories; this.storeCache = storeCacheFactory.createStoreCache(this::createStore); + this.meterRegistry = meterRegistry; } @Override @@ -76,6 +101,12 @@ public class JAXBConfigurationStoreFactory extends FileBasedStoreFactory impleme store = factory.createDecorator(store, new StoreDecoratorFactory.Context(storeParameters)); } - return store; + return StoreInvocationMicrometerWrapper.create( + "configuration-store", + storeParameters, + ConfigurationStore.class, + store, + meterRegistry + ); } } diff --git a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBDataStoreFactory.java b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBDataStoreFactory.java index 908c3af02e..35302ed479 100644 --- a/scm-persistence/src/main/java/sonia/scm/store/file/JAXBDataStoreFactory.java +++ b/scm-persistence/src/main/java/sonia/scm/store/file/JAXBDataStoreFactory.java @@ -16,20 +16,22 @@ package sonia.scm.store.file; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; +import io.micrometer.core.instrument.MeterRegistry; import sonia.scm.SCMContextProvider; import sonia.scm.repository.RepositoryLocationResolver; import sonia.scm.repository.RepositoryReadOnlyChecker; import sonia.scm.security.KeyGenerator; import sonia.scm.store.DataStore; import sonia.scm.store.DataStoreFactory; +import sonia.scm.store.StoreInvocationMicrometerWrapper; import sonia.scm.store.TypedStoreParameters; import sonia.scm.util.IOUtil; import java.io.File; - @Singleton public class JAXBDataStoreFactory extends FileBasedStoreFactory implements DataStoreFactory { @@ -40,7 +42,9 @@ public class JAXBDataStoreFactory extends FileBasedStoreFactory private final DataFileCache dataFileCache; - @Inject + private final MeterRegistry meterRegistry; + + @VisibleForTesting public JAXBDataStoreFactory( SCMContextProvider contextProvider, RepositoryLocationResolver repositoryLocationResolver, @@ -48,11 +52,33 @@ public class JAXBDataStoreFactory extends FileBasedStoreFactory RepositoryReadOnlyChecker readOnlyChecker, DataFileCache dataFileCache, StoreCacheFactory storeCacheFactory + ) { + this( + contextProvider, + repositoryLocationResolver, + keyGenerator, + readOnlyChecker, + dataFileCache, + storeCacheFactory, + null + ); + } + + @Inject + public JAXBDataStoreFactory( + SCMContextProvider contextProvider, + RepositoryLocationResolver repositoryLocationResolver, + KeyGenerator keyGenerator, + RepositoryReadOnlyChecker readOnlyChecker, + DataFileCache dataFileCache, + StoreCacheFactory storeCacheFactory, + MeterRegistry meterRegistry ) { super(contextProvider, repositoryLocationResolver, Store.DATA, readOnlyChecker); this.keyGenerator = keyGenerator; this.dataFileCache = dataFileCache; this.storeCache = storeCacheFactory.createStoreCache(this::createStore); + this.meterRegistry = meterRegistry; } @Override @@ -61,15 +87,25 @@ public class JAXBDataStoreFactory extends FileBasedStoreFactory return (DataStore) storeCache.getStore(storeParameters); } - private DataStore createStore(TypedStoreParameters storeParameters) { + private DataStore createStore(TypedStoreParameters storeParameters) { File storeLocation = getStoreLocation(storeParameters); IOUtil.mkdirs(storeLocation); - return new JAXBDataStore<>( + + // Create a proxy for the created store and use Micrometer to instrument it + JAXBDataStore store = new JAXBDataStore<>( keyGenerator, TypedStoreContext.of(storeParameters), storeLocation, mustBeReadOnly(storeParameters), dataFileCache.instanceFor(storeParameters.getType()) ); + + return StoreInvocationMicrometerWrapper.create( + "data-store", + storeParameters, + DataStore.class, + store, + meterRegistry + ); } } diff --git a/scm-persistence/src/main/java/sonia/scm/store/sqlite/SQLiteQueryableStoreFactory.java b/scm-persistence/src/main/java/sonia/scm/store/sqlite/SQLiteQueryableStoreFactory.java index 4bfed5a5ee..44ce689d56 100644 --- a/scm-persistence/src/main/java/sonia/scm/store/sqlite/SQLiteQueryableStoreFactory.java +++ b/scm-persistence/src/main/java/sonia/scm/store/sqlite/SQLiteQueryableStoreFactory.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; +import io.micrometer.core.instrument.MeterRegistry; import jakarta.inject.Inject; import jakarta.inject.Singleton; import lombok.extern.slf4j.Slf4j; @@ -31,7 +32,10 @@ import sonia.scm.plugin.QueryableTypeDescriptor; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryReadOnlyChecker; import sonia.scm.security.KeyGenerator; +import sonia.scm.store.StoreInvocationMicrometerWrapper; import sonia.scm.store.QueryableMaintenanceStore; +import sonia.scm.store.QueryableMutableStore; +import sonia.scm.store.QueryableStore; import sonia.scm.store.QueryableStoreFactory; import sonia.scm.store.StoreException; @@ -62,6 +66,7 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { private final KeyGenerator keyGenerator; private final DataSource dataSource; private final RepositoryReadOnlyChecker readOnlyChecker; + private final MeterRegistry meterRegistry; private final Map queryableTypes = new HashMap<>(); @@ -73,6 +78,7 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { ObjectMapper objectMapper, KeyGenerator keyGenerator, RepositoryReadOnlyChecker readOnlyChecker, + MeterRegistry meterRegistry, @ConfigValue(key = "queryableStore.maxPoolSize", defaultValue = DEFAULT_MAX_POOL_SIZE) int maxPoolSize, @ConfigValue(key = "queryableStore.connectionTimeout", defaultValue = DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS) int connectionTimeoutInSeconds, @ConfigValue(key = "queryableStore.idleTimeout", defaultValue = DEFAULT_IDLE_TIMEOUT_IN_SECONDS) int idleTimeoutInSeconds, @@ -85,6 +91,7 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { keyGenerator, pluginLoader.getExtensionProcessor().getQueryableTypes(), readOnlyChecker, + meterRegistry, maxPoolSize, connectionTimeoutInSeconds, idleTimeoutInSeconds, @@ -99,7 +106,19 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { KeyGenerator keyGenerator, Iterable queryableTypeIterable, RepositoryReadOnlyChecker readOnlyChecker) { - this(connectionString, objectMapper, keyGenerator, queryableTypeIterable, readOnlyChecker, 10, 30, 600, 1800, 30); + this( + connectionString, + objectMapper, + keyGenerator, + queryableTypeIterable, + readOnlyChecker, + null, + 10, + 30, + 600, + 1800, + 30 + ); } private SQLiteQueryableStoreFactory(String connectionString, @@ -107,6 +126,7 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { KeyGenerator keyGenerator, Iterable queryableTypeIterable, RepositoryReadOnlyChecker readOnlyChecker, + MeterRegistry meterRegistry, int maxPoolSize, int connectionTimeoutInSeconds, int idleTimeoutInSeconds, @@ -120,6 +140,7 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { maxLifetimeInSeconds, leakDetectionThresholdInSeconds); this.readOnlyChecker = readOnlyChecker; + this.meterRegistry = meterRegistry; this.dataSource = new HikariDataSource(config); this.objectMapper = objectMapper @@ -177,9 +198,9 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { } @Override - public SQLiteQueryableStore getReadOnly(Class clazz, String... parentIds) { + public QueryableStore getReadOnly(Class clazz, String... parentIds) { QueryableTypeDescriptor queryableTypeDescriptor = getQueryableTypeDescriptor(clazz); - return new SQLiteQueryableStore<>( + SQLiteQueryableStore store = new SQLiteQueryableStore<>( objectMapper, openDefaultConnection(), clazz, @@ -188,12 +209,21 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { lock, mustBeReadOnly(queryableTypeDescriptor, parentIds) ); + + return StoreInvocationMicrometerWrapper.create( + "QueryableStore", + clazz, + parentIds, + QueryableStore.class, + store, + meterRegistry + ); } @Override public QueryableMaintenanceStore getForMaintenance(Class clazz, String... parentIds) { QueryableTypeDescriptor queryableTypeDescriptor = getQueryableTypeDescriptor(clazz); - return new SQLiteQueryableStore<>( + SQLiteQueryableStore store = new SQLiteQueryableStore<>( objectMapper, openDefaultConnection(), clazz, @@ -202,12 +232,21 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { lock, mustBeReadOnly(queryableTypeDescriptor, parentIds) ); + + return StoreInvocationMicrometerWrapper.create( + "QueryableMaintenanceStore", + clazz, + parentIds, + QueryableMaintenanceStore.class, + store, + meterRegistry + ); } @Override - public SQLiteQueryableMutableStore getMutable(Class clazz, String... parentIds) { + public QueryableMutableStore getMutable(Class clazz, String... parentIds) { QueryableTypeDescriptor queryableTypeDescriptor = getQueryableTypeDescriptor(clazz); - return new SQLiteQueryableMutableStore<>( + SQLiteQueryableMutableStore store = new SQLiteQueryableMutableStore<>( objectMapper, keyGenerator, openDefaultConnection(), @@ -217,6 +256,15 @@ public class SQLiteQueryableStoreFactory implements QueryableStoreFactory { lock, mustBeReadOnly(queryableTypeDescriptor, parentIds) ); + + return StoreInvocationMicrometerWrapper.create( + "QueryableMutableStore", + clazz, + parentIds, + QueryableMutableStore.class, + store, + meterRegistry + ); } private boolean mustBeReadOnly(QueryableTypeDescriptor queryableTypeDescriptor, String... parentIds) { diff --git a/scm-persistence/src/test/java/sonia/scm/store/StoreInvocationMicrometerWrapperTest.java b/scm-persistence/src/test/java/sonia/scm/store/StoreInvocationMicrometerWrapperTest.java new file mode 100644 index 0000000000..edd6e2f501 --- /dev/null +++ b/scm-persistence/src/test/java/sonia/scm/store/StoreInvocationMicrometerWrapperTest.java @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2020 - present Cloudogu GmbH + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +package sonia.scm.store; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.user.User; + +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.function.Supplier; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Answers.RETURNS_SELF; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class StoreInvocationMicrometerWrapperTest { + + @Mock + private MeterRegistry meterRegistry; + @Mock(answer = RETURNS_SELF) + private Timer.Builder timerBuilder; + @Mock + private Timer timer; + + @BeforeEach + void setUpTimer() { + when(timerBuilder.register(any())) + .thenReturn(timer); + when(timer.record(any(Supplier.class))) + .thenAnswer(i -> i.getArgument(0, Supplier.class).get()); + } + + @Nested + class ForSimpleStore { + + @Mock + private DataStore dataStore; + @Mock + private TypedStoreParameters storeParameters; + + @BeforeEach + void setUpStore() { + when(storeParameters.getName()) + .thenReturn("users"); + when(dataStore.get("42")).thenReturn(new User("dent")); + } + + @Test + void shouldMeasureDirectCallForGlobalStore() { + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "data", + storeParameters, + dataStore, + meterRegistry, + () -> timerBuilder + ); + DataStore store = (DataStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{DataStore.class}, handler); + User result = store + .get("42"); + + assertThat(result) + .extracting(User::getName) + .isEqualTo("dent"); + + verify(timerBuilder).description("Time taken for store operation in data"); + verify(timerBuilder).tag("method", "get"); + verify(timerBuilder).tag("type", "data"); + verify(timerBuilder).tag("storeName", "users"); + verify(timerBuilder).tag("repositoryId", "none"); + verify(timerBuilder).tag("namespace", "none"); + + verify(timer, only()).record(any(Supplier.class)); + } + + @Test + void shouldMeasureDirectCallForRepositoryStore() { + when(storeParameters.getRepositoryId()) + .thenReturn("hog"); + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "data", + storeParameters, + dataStore, + meterRegistry, + () -> timerBuilder + ); + DataStore store = (DataStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{DataStore.class}, handler); + User result = store + .get("42"); + + assertThat(result) + .extracting(User::getName) + .isEqualTo("dent"); + + verify(timerBuilder).description("Time taken for store operation in data"); + verify(timerBuilder).tag("method", "get"); + verify(timerBuilder).tag("repositoryId", "hog"); + verify(timerBuilder).tag("namespace", "none"); + + verify(timer, only()).record(any(Supplier.class)); + } + + @Test + void shouldMeasureDirectCallForNamespaceStore() { + when(storeParameters.getNamespace()) + .thenReturn("intergalactic"); + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "data", + storeParameters, + dataStore, + meterRegistry, + () -> timerBuilder + ); + DataStore store = (DataStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{DataStore.class}, handler); + User result = store + .get("42"); + + assertThat(result) + .extracting(User::getName) + .isEqualTo("dent"); + + verify(timerBuilder).description("Time taken for store operation in data"); + verify(timerBuilder).tag("method", "get"); + verify(timerBuilder).tag("namespace", "intergalactic"); + verify(timerBuilder).tag("repositoryId", "none"); + + verify(timer, only()).record(any(Supplier.class)); + } + } + + @Nested + class ForQueryableStore { + + @Mock + private QueryableStore queryableStore; + @Mock + private QueryableStore.Query query; + + @BeforeEach + void setUpStore() { + when(queryableStore.query()) + .thenAnswer(i -> query); + when(query.findAll()) + .thenReturn(List.of(new User("dent"))); + } + + @Test + void shouldMeasureDirectCall() { + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "queryable", + User.class, + new String[]{"intergalactic", "hog"}, + queryableStore, + meterRegistry, + () -> timerBuilder + ); + QueryableStore store = (QueryableStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{QueryableStore.class}, handler); + List result = store + .query() + .findAll(); + + assertThat(result) + .extracting(User::getName) + .containsExactly("dent"); + + verify(timerBuilder).description("Time taken for store operation in queryable"); + verify(timerBuilder).tag("method", "findAll"); + verify(timerBuilder).tag("storeClass", "sonia.scm.user.User"); + verify(timerBuilder).tag("parentIds", "intergalactic,hog"); + + verify(timer, only()).record(any(Supplier.class)); + } + + @Test + void shouldMeasureCallAfterOrder() { + when(query.orderBy(any(), any(QueryableStore.Order.class))) + .thenAnswer(i -> query); + + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "queryable", + User.class, + new String[]{"intergalactic", "hog"}, + queryableStore, + meterRegistry, + () -> timerBuilder + ); + QueryableStore store = (QueryableStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{QueryableStore.class}, handler); + List result = store + .query() + .orderBy(new QueryableStore.IdQueryField(), QueryableStore.Order.DESC) + .findAll(); + + assertThat(result) + .extracting(User::getName) + .containsExactly("dent"); + + verify(timerBuilder).description("Time taken for store operation in queryable"); + verify(timerBuilder).tag("method", "findAll"); + + verify(timer, only()).record(any(Supplier.class)); + } + + @Test + void shouldMeasureCallAfterMultipleIndirection() { + when(query.orderBy(any(), any(QueryableStore.Order.class))) + .thenAnswer(i -> query); + when(query.distinct()) + .thenAnswer(i -> query); + when(query.project(any())) + .thenAnswer(i -> query); + + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "queryable", + User.class, + new String[]{"intergalactic", "hog"}, + queryableStore, + meterRegistry, + () -> timerBuilder + ); + QueryableStore store = (QueryableStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{QueryableStore.class}, handler); + List result = store + .query() + .orderBy(new QueryableStore.IdQueryField(), QueryableStore.Order.DESC) + .distinct() + .project(new QueryableStore.IdQueryField()) + .findAll(); + + assertThat(result) + .extracting(User::getName) + .containsExactly("dent"); + + verify(timerBuilder).description("Time taken for store operation in queryable"); + verify(timerBuilder).tag("method", "findAll"); + + verify(timer, only()).record(any(Supplier.class)); + } + } + + @Nested + class ForQueryableMutableStore { + + @Mock + private QueryableMutableStore queryableMutableStore; + @Mock + private QueryableMutableStore.MutableQuery query; + + @BeforeEach + void setUpStore() { + when(queryableMutableStore.query()) + .thenAnswer(i -> query); + } + + @Test + void shouldMeasureFinalCall() { + when(query.orderBy(any(), any(QueryableStore.Order.class))) + .thenAnswer(i -> query); + + StoreInvocationMicrometerWrapper handler = + new StoreInvocationMicrometerWrapper( + "queryable", + User.class, + new String[]{"intergalactic", "hog"}, + queryableMutableStore, + meterRegistry, + () -> timerBuilder + ); + QueryableMutableStore store = (QueryableMutableStore) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{QueryableMutableStore.class}, handler); + store + .query() + .orderBy(new QueryableStore.IdQueryField(), QueryableStore.Order.DESC) + .retain(100); + + verify(timerBuilder).description("Time taken for store operation in queryable"); + verify(timerBuilder).tag("method", "retain"); + + verify(timer, only()).record(any(Supplier.class)); + } + } +} diff --git a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteParallelizationTest.java b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteParallelizationTest.java index c93c279ffe..ec987fb5ef 100644 --- a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteParallelizationTest.java +++ b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteParallelizationTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import sonia.scm.repository.Repository; import sonia.scm.store.QueryableMaintenanceStore; +import sonia.scm.store.QueryableMutableStore; import sonia.scm.user.User; import java.nio.file.Path; @@ -56,7 +57,7 @@ class SQLiteParallelizationTest { ExecutorService executor = Executors.newFixedThreadPool(numThreads); List> futures = new ArrayList<>(); - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); for (int i = 0; i < numThreads; i++) { final String userId = "user-" + i; diff --git a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableMutableStoreTest.java b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableMutableStoreTest.java index 22de59c125..a78e7407ff 100644 --- a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableMutableStoreTest.java +++ b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableMutableStoreTest.java @@ -88,7 +88,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldPutObjectWithAutoIncrementId() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, IdGenerator.AUTO_INCREMENT).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString, IdGenerator.AUTO_INCREMENT).forClassWithIds(Spaceship.class); store.put(new Spaceship("42")); store.put(new Spaceship("23")); @@ -101,7 +101,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldPutObjectWithGivenIdsThoughAutoIncrementActivated() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, IdGenerator.AUTO_INCREMENT).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString, IdGenerator.AUTO_INCREMENT).forClassWithIds(Spaceship.class); store.put("42", new Spaceship("42", SQLiteQueryableStoreTest.Range.INTER_GALACTIC)); store.put("23", new Spaceship("23", SQLiteQueryableStoreTest.Range.SOLAR_SYSTEM)); @@ -148,7 +148,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldRollback() throws SQLException { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.transactional(() -> { store.put("tricia", new User("trillian")); @@ -163,7 +163,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldDisableAutoCommit() throws SQLException { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.transactional(() -> { store.put("tricia", new User("trillian")); @@ -192,7 +192,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldGetObjectWithoutParent() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian")); User tricia = store.get("tricia"); @@ -205,7 +205,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldReturnForNotExistingValue() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User earth = store.get("earth"); assertThat(earth) @@ -215,7 +215,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldGetObjectWithSingleParent() { new StoreTestBuilder(connectionString, "sonia.Group").withIds("1337").put("tricia", new User("McMillan")); - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("42"); store.put("tricia", new User("trillian")); User tricia = store.get("tricia"); @@ -229,7 +229,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldGetObjectWithMultipleParents() { new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "1337").put("tricia", new User("McMillan")); - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); store.put("tricia", new User("trillian")); User tricia = store.get("tricia"); @@ -243,7 +243,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldGetAllForSingleEntry() { new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "1337").put("tricia", new User("McMillan")); - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); store.put("tricia", new User("trillian")); Map users = store.getAll(); @@ -257,7 +257,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldGetAllForMultipleEntries() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); store.put("dent", new User("arthur")); store.put("tricia", new User("trillian")); @@ -280,7 +280,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldUseIdFromItemOnPut() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); String id = store.put(new SpaceshipWithId("Heart of Gold", 42)); SpaceshipWithId spaceship = store.get("Heart of Gold"); @@ -291,7 +291,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldSetNewIdInItemOnPut() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); String id = store.put(new SpaceshipWithId()); SpaceshipWithId spaceship = store.get(id); @@ -302,7 +302,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldStoreWithNewIdAfterManualChange() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(SpaceshipWithId.class); store.put(new SpaceshipWithId("Heart of Gold", 42)); SpaceshipWithId spaceship = store.get("Heart of Gold"); @@ -321,9 +321,9 @@ class SQLiteQueryableMutableStoreTest { class Clear { @Test void shouldClear() { - SQLiteQueryableMutableStore uneffectedStore = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "1337"); + QueryableMutableStore uneffectedStore = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "1337"); uneffectedStore.put("tricia", new User("McMillan")); - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); store.put("tricia", new User("trillian")); store.clear(); @@ -337,7 +337,7 @@ class SQLiteQueryableMutableStoreTest { class Remove { @Test void shouldRemove() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Company", "sonia.Group").withIds("cloudogu", "42"); store.put("dent", new User("arthur")); store.put("tricia", new User("trillian")); @@ -351,7 +351,7 @@ class SQLiteQueryableMutableStoreTest { class DeleteAll { @Test void shouldDeleteAllInStoreWithoutSubsequentQuery() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -365,7 +365,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldOnlyDeleteElementsMatchingTheQuery() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -383,9 +383,9 @@ class SQLiteQueryableMutableStoreTest { StoreTestBuilder spaceshipStoreBuilder = new StoreTestBuilder(connectionString); StoreTestBuilder crewmateStoreBuilder = new StoreTestBuilder(connectionString, "Spaceship"); try ( - SQLiteQueryableMutableStore spaceshipStore = spaceshipStoreBuilder.forClassWithIds(Spaceship.class); - SQLiteQueryableMutableStore crewmateStoreForShipOne = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "1"); - SQLiteQueryableMutableStore crewmateStoreForShipTwo = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "2") + QueryableMutableStore spaceshipStore = spaceshipStoreBuilder.forClassWithIds(Spaceship.class); + QueryableMutableStore crewmateStoreForShipOne = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "1"); + QueryableMutableStore crewmateStoreForShipTwo = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "2") ) { Spaceship spaceshipOne = new Spaceship("1"); Spaceship spaceshipTwo = new Spaceship("2"); @@ -408,7 +408,7 @@ class SQLiteQueryableMutableStoreTest { class Retain { @Test void shouldRetainOneWithAscendingOrder() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -423,7 +423,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldThrowIllegalArgumentExceptionIfKeptElementsIsNegative() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -436,7 +436,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldRetainOneWithDescendingOrder() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -451,7 +451,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldDeleteUnselectedEntitiesAndRetainKeptElementsFromTheSelectedOnes() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); Spaceship spaceshipOne = new Spaceship("LazyShip"); Spaceship spaceshipTwo = new Spaceship("Biblical Ship"); @@ -477,7 +477,7 @@ class SQLiteQueryableMutableStoreTest { @Test void shouldRetainEverythingIfKeptElementsHigherThanContentQuantity() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put("1", new Spaceship("1")); store.put("2", new Spaceship("2")); store.put("3", new Spaceship("3")); @@ -494,9 +494,9 @@ class SQLiteQueryableMutableStoreTest { StoreTestBuilder spaceshipStoreBuilder = new StoreTestBuilder(connectionString); StoreTestBuilder crewmateStoreBuilder = new StoreTestBuilder(connectionString, "Spaceship"); try ( - SQLiteQueryableMutableStore spaceshipStore = spaceshipStoreBuilder.forClassWithIds(Spaceship.class); - SQLiteQueryableMutableStore crewmateStoreForShipOne = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "1"); - SQLiteQueryableMutableStore crewmateStoreForShipTwo = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "2") + QueryableMutableStore spaceshipStore = spaceshipStoreBuilder.forClassWithIds(Spaceship.class); + QueryableMutableStore crewmateStoreForShipOne = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "1"); + QueryableMutableStore crewmateStoreForShipTwo = crewmateStoreBuilder.forClassWithIds(Crewmate.class, "2") ) { Spaceship spaceshipOne = new Spaceship("1"); Spaceship spaceshipTwo = new Spaceship("2"); @@ -567,7 +567,7 @@ class SQLiteQueryableMutableStoreTest { Repository.class.getName() + ".class" ).readOnly("42"); - SQLiteQueryableMutableStore store = storeTestBuilder.withIds("23"); + QueryableMutableStore store = storeTestBuilder.withIds("23"); store.put("tricia", new User("trillian")); assertThat(store.get("tricia")).isNotNull(); @@ -580,7 +580,7 @@ class SQLiteQueryableMutableStoreTest { Group.class.getName() + ".class" ).readOnly("42"); - SQLiteQueryableMutableStore store = storeTestBuilder.withIds("42"); + QueryableMutableStore store = storeTestBuilder.withIds("42"); store.put("tricia", new User("trillian")); assertThat(store.get("tricia")).isNotNull(); diff --git a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableStoreTest.java b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableStoreTest.java index 8ede882009..9afd146489 100644 --- a/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableStoreTest.java +++ b/scm-persistence/src/test/java/sonia/scm/store/sqlite/SQLiteQueryableStoreTest.java @@ -30,6 +30,7 @@ import sonia.scm.store.Operator; import sonia.scm.store.QueryableMaintenanceStore; import sonia.scm.store.QueryableMaintenanceStore.MaintenanceIterator; import sonia.scm.store.QueryableMaintenanceStore.MaintenanceStoreEntry; +import sonia.scm.store.QueryableMutableStore; import sonia.scm.store.QueryableStore; import sonia.scm.user.User; @@ -71,7 +72,7 @@ class SQLiteQueryableStoreTest { @ParameterizedTest @ValueSource(strings = {"*Of*", "Heart*Gold", "H*", "*d", "*Heart Of Gold*", "Heart Of Gold", "Heart Of *Gold"}) void shouldWorkWithLikes(String searchString) { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Space Shuttle", Range.SOLAR_SYSTEM)); store.put(new Spaceship("Heart Of Gold", Range.INTER_GALACTIC)); @@ -87,7 +88,7 @@ class SQLiteQueryableStoreTest { @ParameterizedTest @ValueSource(strings = {"Of", "*of*", "heart of gold"}) void shouldNotFindNotMatchingValuesWithLike() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Space Shuttle", Range.SOLAR_SYSTEM)); store.put(new Spaceship("Heart Of Gold", Range.INTER_GALACTIC)); @@ -100,7 +101,7 @@ class SQLiteQueryableStoreTest { @Test void shouldWorkWithEnums() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Space Shuttle", Range.SOLAR_SYSTEM)); store.put(new Spaceship("Heart Of Gold", Range.INTER_GALACTIC)); @@ -114,7 +115,7 @@ class SQLiteQueryableStoreTest { @Test void shouldWorkWithLongs() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User trillian = new User("trillian", "McMillan", "tricia@hog.org"); trillian.setCreationDate(10000000000L); store.put(trillian); @@ -134,7 +135,7 @@ class SQLiteQueryableStoreTest { @Test void shouldWorkWithIntegers() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User trillian = new User("trillian", "McMillan", "tricia@hog.org"); trillian.setCreationDate(42L); store.put(trillian); @@ -154,7 +155,7 @@ class SQLiteQueryableStoreTest { @Test void shouldWorkWithNumberCollection() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User trillian = new User("trillian", "McMillan", "tricia@hog.org"); trillian.setActive(true); store.put(trillian); @@ -174,7 +175,7 @@ class SQLiteQueryableStoreTest { @Test void shouldCountAndWorkWithNumberCollection() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User trillian = new User("trillian", "McMillan", "tricia@hog.org"); trillian.setActive(true); store.put(trillian); @@ -197,7 +198,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleCollections() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", "Buzz", "Anndre")); store.put(new Spaceship("Heart Of Gold", "Trillian", "Arthur", "Ford", "Zaphod", "Marvin")); @@ -210,7 +211,7 @@ class SQLiteQueryableStoreTest { @Test void shouldCountAndHandleCollections() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", "Buzz", "Anndre")); store.put(new Spaceship("Heart Of Gold", "Trillian", "Arthur", "Ford", "Zaphod", "Marvin")); @@ -223,7 +224,7 @@ class SQLiteQueryableStoreTest { @Test void shouldCountWithoutConditions() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", "Buzz", "Anndre")); store.put(new Spaceship("Heart Of Gold", "Trillian", "Arthur", "Ford", "Zaphod", "Marvin")); @@ -234,7 +235,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleEmptyCollectionWithMaxString() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); Integer result = store.query().max( SPACESHIP_FLIGHT_COUNT ); @@ -245,7 +246,7 @@ class SQLiteQueryableStoreTest { @Nested class ForAggregations { - SQLiteQueryableMutableStore store; + QueryableMutableStore store; @BeforeEach void createData() { @@ -318,7 +319,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleCollectionSize() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", "Buzz", "Anndre")); store.put(new Spaceship("Heart of Gold", "Trillian", "Arthur", "Ford", "Zaphod", "Marvin")); store.put(new Spaceship("MillenniumFalcon")); @@ -345,7 +346,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleMap() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", Map.of("moon", true, "earth", true))); store.put(new Spaceship("Heart of Gold", Map.of("vogon", true, "earth", true))); store.put(new Spaceship("MillenniumFalcon", Map.of("dagobah", false))); @@ -365,7 +366,7 @@ class SQLiteQueryableStoreTest { @Test void shouldCountAndHandleMap() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", Map.of("moon", true, "earth", true))); store.put(new Spaceship("Heart of Gold", Map.of("vogon", true, "earth", true))); store.put(new Spaceship("MillenniumFalcon", Map.of("dagobah", false))); @@ -386,7 +387,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleMapSize() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); store.put(new Spaceship("Spaceshuttle", Map.of("moon", true, "earth", true))); store.put(new Spaceship("Heart of Gold", Map.of("vogon", true, "earth", true, "dagobah", true))); store.put(new Spaceship("MillenniumFalcon", Map.of())); @@ -413,7 +414,7 @@ class SQLiteQueryableStoreTest { @Test void shouldRetrieveTime() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); Spaceship spaceshuttle = new Spaceship("Spaceshuttle", Range.SOLAR_SYSTEM); spaceshuttle.setInServiceSince(Instant.parse("1981-04-12T10:00:00Z")); store.put(spaceshuttle); @@ -445,7 +446,7 @@ class SQLiteQueryableStoreTest { @Test void shouldLimitQuery() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("trillian", "McMillan", "tricia@hog.org")); store.put(new User("arthur", "Dent", "arthur@hog.org")); store.put(new User("zaphod", "Beeblebrox", "zaphod@hog.org")); @@ -461,7 +462,7 @@ class SQLiteQueryableStoreTest { @Test void shouldOrderResults() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("trillian", "McMillan", "tricia@hog.org")); store.put(new User("arthur", "Dent", "arthur@hog.org")); store.put(new User("zaphod", "Beeblebrox Head 1", "zaphod1@hog.org")); @@ -480,7 +481,7 @@ class SQLiteQueryableStoreTest { @Test void shouldOrderResultsAsNumbers() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("1")); store.put(new User("2")); store.put(new User("10")); @@ -498,7 +499,7 @@ class SQLiteQueryableStoreTest { @Test void shouldOrderResultsAsStrings() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("1")); store.put(new User("2")); store.put(new User("10")); @@ -519,7 +520,7 @@ class SQLiteQueryableStoreTest { class QueryLogicalHandling { @Test void shouldQueryForId() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("1", new User("trillian", "Tricia", "tricia@hog.org")); store.put("2", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("3", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -536,7 +537,7 @@ class SQLiteQueryableStoreTest { @Test void shouldQueryForIdAndOrderByDESC() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("1", new User("trish", "Tricia", "tricia@hog.org")); store.put("2", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("3", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -551,7 +552,7 @@ class SQLiteQueryableStoreTest { @Test void shouldOrderIdsAndPayload() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("1", new User("trish", "Tricia", "tricia@hog.org")); store.put("2", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("3", new User("trillian", "Arthur Dent", "arthur@hog.org")); @@ -576,7 +577,7 @@ class SQLiteQueryableStoreTest { .withIds("1337") .put("tricia", new User("trillian", "Trillian McMillan", "tricia@hog.org")); - SQLiteQueryableStore store = new StoreTestBuilder(connectionString, Group.class.getName()).withIds(); + QueryableStore store = new StoreTestBuilder(connectionString, Group.class.getName()).withIds(); List all = store.query( GROUP.eq("42") @@ -590,7 +591,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleContainsCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); store.put("McMillan", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("dent", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -605,7 +606,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleIsNullCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian", null, "tricia@hog.org")); store.put("dent", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -621,7 +622,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleNotNullCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian", null, "tricia@hog.org")); store.put("dent", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -637,7 +638,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleOr() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); store.put("McMillan", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("dent", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -658,7 +659,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleOrWithMultipleStores() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("CoolGroup"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("CoolGroup"); User tricia = new User("trillian", "Tricia", "tricia@hog.org"); User mcmillan = new User("trillian", "Trillian McMillan", "mcmillan@gmail.com"); User dent = new User("arthur", "Arthur Dent", "arthur@hog.org"); @@ -666,7 +667,7 @@ class SQLiteQueryableStoreTest { store.put("McMillan", mcmillan); store.put("dent", dent); - SQLiteQueryableMutableStore parallelStore = new StoreTestBuilder(connectionString, "sonia.Group").withIds("LameGroup"); + QueryableMutableStore parallelStore = new StoreTestBuilder(connectionString, "sonia.Group").withIds("LameGroup"); parallelStore.put("tricia", new User("trillian", "Trillian IAMINAPARALLELSTORE McMillan", "mcmillan@gmail.com")); List result = store.query( @@ -680,7 +681,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleGroup() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") .withIds("42"); store.put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); new StoreTestBuilder(connectionString, "sonia.Group") @@ -696,7 +697,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleGroupWithCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") .withIds("42"); store .put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); @@ -713,7 +714,7 @@ class SQLiteQueryableStoreTest { @Test void shouldHandleInArrayCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("trillian", "McMillan", "tricia@hog.org")); store.put(new User("arthur", "Dent", "arthur@hog.org")); store.put(new User("zaphod", "Beeblebrox", "zaphod@hog.org")); @@ -731,7 +732,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindAllObjectsWithoutParentWithoutConditions() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian")); List all = store.query().findAll(); @@ -741,7 +742,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindAllObjectsWithoutParentWithCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian")); store.put("dent", new User("arthur")); @@ -751,7 +752,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindAllObjectsWithOneParentAndMultipleConditions() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("CoolGroup"); + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group").withIds("CoolGroup"); User tricia = new User("trillian", "Tricia", "tricia@hog.org"); User mcmillan = new User("trillian", "Trillian McMillan", "mcmillan@gmail.com"); User dent = new User("arthur", "Arthur Dent", "arthur@hog.org"); @@ -770,7 +771,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindAllObjectsWithoutParentWithMultipleConditions() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); store.put("McMillan", new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put("dent", new User("arthur", "Arthur Dent", "arthur@hog.org")); @@ -786,7 +787,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReturnIds() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, Spaceship.class.getName()) + QueryableMutableStore store = new StoreTestBuilder(connectionString, Spaceship.class.getName()) .withIds("hog"); store.put("tricia", new User("trillian", "Tricia", "tricia@hog.org")); @@ -807,13 +808,13 @@ class SQLiteQueryableStoreTest { class FindOne { @Test void shouldReturnEmptyOptionalIfNoResultFound() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); assertThat(store.query(SPACESHIP_NAME.eq("Heart Of Gold")).findOne()).isEmpty(); } @Test void shouldReturnOneResultIfOneIsGiven() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); Spaceship expectedShip = new Spaceship("Heart Of Gold", Range.INNER_GALACTIC); store.put(expectedShip); Spaceship ship = store.query(SPACESHIP_NAME.eq("Heart Of Gold")).findOne().get(); @@ -823,7 +824,7 @@ class SQLiteQueryableStoreTest { @Test void shouldThrowErrorIfMoreThanOneResultIsSaved() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); + QueryableMutableStore store = new StoreTestBuilder(connectionString).forClassWithIds(Spaceship.class); Spaceship expectedShip = new Spaceship("Heart Of Gold", Range.INNER_GALACTIC); Spaceship localShip = new Spaceship("Heart Of Gold", Range.SOLAR_SYSTEM); store.put(expectedShip); @@ -837,7 +838,7 @@ class SQLiteQueryableStoreTest { class FindFirst { @Test void shouldFindFirst() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User expectedUser = new User("trillian", "Tricia", "tricia@hog.org"); store.put("1", expectedUser); @@ -854,7 +855,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindFirstWithMatchingCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User expectedUser = new User("trillian", "Trillian McMillan", "mcmillan-alternate@gmail.com"); store.put("1", new User("trillian", "Tricia", "tricia@hog.org")); @@ -874,7 +875,7 @@ class SQLiteQueryableStoreTest { @Test void shouldFindFirstWithMatchingLogicalCondition() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User expectedUser = new User("trillian", "Trillian McMillan", "mcmillan@gmail.com"); store.put("1", new User("trillian-old", "Tricia", "tricia@hog.org")); @@ -900,7 +901,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReturnEmptyOptionalIfNoResultFound() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); Optional user = store.query( USER_NAME.eq("dave") ) @@ -933,7 +934,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReturnDistinctValuesFromObject() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") .withIds(); List result = store.query().project(USER_NAME).distinct().findAll(); @@ -949,7 +950,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReturnDistinctParentIds() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") .withIds(); List result = store.query().project(GROUP).distinct().findAll(); @@ -963,7 +964,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReturnDistinctCount() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") + QueryableMutableStore store = new StoreTestBuilder(connectionString, "sonia.Group") .withIds(); long count = store.query().project(GROUP).distinct().count(); @@ -976,11 +977,12 @@ class SQLiteQueryableStoreTest { class ForMaintenance { @Test void shouldUpdateRawJson() throws Exception { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); User user = new User("trillian", "Trillian McMillan", "mcmillan@gmail.com"); store.put("1", user); - try (MaintenanceIterator iterator = store.iterateAll()) { + QueryableMaintenanceStore maintenanceStore = new StoreTestBuilder(connectionString).forMaintenanceWithSubIds(); + try (MaintenanceIterator iterator = maintenanceStore.iterateAll()) { assertThat(iterator.hasNext()).isTrue(); MaintenanceStoreEntry entry = iterator.next(); assertThat(entry.getId()).isEqualTo("1"); @@ -997,7 +999,7 @@ class SQLiteQueryableStoreTest { @Test void shouldUpdateRawJsonForItemWithParent() throws Exception { - SQLiteQueryableMutableStore subStore = new StoreTestBuilder(connectionString, Group.class.getName()).withIds("hitchhiker"); + QueryableMutableStore subStore = new StoreTestBuilder(connectionString, Group.class.getName()).withIds("hitchhiker"); User user = new User("trillian", "Trillian McMillan", "mcmillan@gmail.com"); subStore.put("1", user); @@ -1019,11 +1021,12 @@ class SQLiteQueryableStoreTest { @Test void shouldRemoveFromIteratorWithoutParent() { - SQLiteQueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); + QueryableMutableStore store = new StoreTestBuilder(connectionString).withIds(); store.put(new User("trillian", "Trillian McMillan", "mcmillan@gmail.com")); store.put(new User("dent", "Arthur Dent", "dent@gmail.com")); - for (MaintenanceIterator iter = store.iterateAll(); iter.hasNext(); ) { + QueryableMaintenanceStore maintenanceStore = new StoreTestBuilder(connectionString).forMaintenanceWithSubIds(); + for (MaintenanceIterator iter = maintenanceStore.iterateAll(); iter.hasNext(); ) { MaintenanceStoreEntry next = iter.next(); if (next.get().getName().equals("dent")) { iter.remove(); @@ -1039,11 +1042,11 @@ class SQLiteQueryableStoreTest { @Test void shouldRemoveFromIteratorWithParents() { StoreTestBuilder testStoreBuilder = new StoreTestBuilder(connectionString, Repository.class.getName(), Group.class.getName()); - SQLiteQueryableMutableStore hogStore = testStoreBuilder.withIds("42", "hog"); + QueryableMutableStore hogStore = testStoreBuilder.withIds("42", "hog"); hogStore.put("trisha", new User("trillian", "Trillian McMillan", "mcmillan@hog.com")); hogStore.put("dent", new User("dent", "Arthur Dent", "dent@hog.com")); - SQLiteQueryableMutableStore earthStore = testStoreBuilder.withIds("42", "earth"); + QueryableMutableStore earthStore = testStoreBuilder.withIds("42", "earth"); earthStore.put("dent", new User("dent", "Arthur Dent", "dent@gmail.com")); QueryableMaintenanceStore store = testStoreBuilder.forMaintenanceWithSubIds("42"); @@ -1068,7 +1071,7 @@ class SQLiteQueryableStoreTest { @Test void shouldReadAll() { StoreTestBuilder testStoreBuilder = new StoreTestBuilder(connectionString, Repository.class.getName()); - SQLiteQueryableMutableStore hogStore = testStoreBuilder.withIds("42"); + QueryableMutableStore hogStore = testStoreBuilder.withIds("42"); hogStore.put("trisha", new User("trillian", "Trillian McMillan", "mcmillan@hog.com")); hogStore.put("dent", new User("dent", "Arthur Dent", "dent@hog.com")); @@ -1091,9 +1094,9 @@ class SQLiteQueryableStoreTest { @Test void shouldReadAllWithMultipleIds() { StoreTestBuilder testStoreBuilder = new StoreTestBuilder(connectionString, Repository.class.getName(), Group.class.getName()); - SQLiteQueryableMutableStore store1 = testStoreBuilder.withIds("42", "astronauts"); + QueryableMutableStore store1 = testStoreBuilder.withIds("42", "astronauts"); store1.put("trisha", new User("trillian", "Trillian McMillan", "mcmillan@hog.com")); - SQLiteQueryableMutableStore store2 = testStoreBuilder.withIds("42", "earthlings"); + QueryableMutableStore store2 = testStoreBuilder.withIds("42", "earthlings"); store2.put("dent", new User("dent", "Arthur Dent", "dent@hog.com")); QueryableMaintenanceStore store = testStoreBuilder.forMaintenanceWithSubIds("42"); @@ -1128,7 +1131,7 @@ class SQLiteQueryableStoreTest { ) ); - SQLiteQueryableMutableStore hogStore = testStoreBuilder.withIds("42"); + QueryableMaintenanceStore hogStore = testStoreBuilder.forMaintenanceWithSubIds("42"); Collection> allValues = hogStore.readAll(); assertThat(allValues) .extracting("value") @@ -1147,7 +1150,7 @@ class SQLiteQueryableStoreTest { ) ); - SQLiteQueryableMutableStore hogStore = testStoreBuilder.withIds("42"); + QueryableMaintenanceStore hogStore = testStoreBuilder.forMaintenanceWithSubIds("42"); Collection> allValues = hogStore.readAll(); assertThat(allValues) .extracting("value") diff --git a/scm-persistence/src/test/java/sonia/scm/store/sqlite/StoreTestBuilder.java b/scm-persistence/src/test/java/sonia/scm/store/sqlite/StoreTestBuilder.java index b72b076352..245e0bff79 100644 --- a/scm-persistence/src/test/java/sonia/scm/store/sqlite/StoreTestBuilder.java +++ b/scm-persistence/src/test/java/sonia/scm/store/sqlite/StoreTestBuilder.java @@ -24,6 +24,7 @@ import sonia.scm.repository.RepositoryReadOnlyChecker; import sonia.scm.security.UUIDKeyGenerator; import sonia.scm.store.IdGenerator; import sonia.scm.store.QueryableMaintenanceStore; +import sonia.scm.store.QueryableMutableStore; import sonia.scm.store.QueryableStore; import sonia.scm.user.User; @@ -68,7 +69,7 @@ class StoreTestBuilder { this.parentClasses = parentClasses; } - SQLiteQueryableMutableStore withIds(String... ids) { + QueryableMutableStore withIds(String... ids) { return forClassWithIds(User.class, ids); } @@ -86,7 +87,7 @@ class StoreTestBuilder { return createStoreFactory(User.class).getForMaintenance(User.class, ids); } - SQLiteQueryableMutableStore forClassWithIds(Class clazz, String... ids) { + QueryableMutableStore forClassWithIds(Class clazz, String... ids) { return createStoreFactory(clazz).getMutable(clazz, ids); }