blob: d030732944559e70d2ba9896f26e05207164ae4f [file] [log] [blame]
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.modules.cache.chroniclemap;
import static com.google.common.truth.Truth.assertThat;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_AVG_KEY_SIZE;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_AVG_VALUE_SIZE;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_MAX_BLOAT_FACTOR;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_MAX_ENTRIES;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_PERCENTAGE_FREE_SPACE_EVICTION_THRESHOLD;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.DEFAULT_PERSIST_INDEX_EVERY;
import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheFactory.PRUNE_DELAY;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import com.google.gerrit.server.config.SitePaths;
import java.io.File;
import java.nio.file.Files;
import java.time.Duration;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ChronicleMapCacheConfigTest {
private final String cacheDirectory = ".";
private final String cacheName = "foobar-cache";
private final String cacheKey = "foobar-cache-key";
private final int version = 1;
private final Duration expireAfterWrite = Duration.ofSeconds(10_000);
private final Duration refreshAfterWrite = Duration.ofSeconds(20_000);
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
private SitePaths sitePaths;
private StoredConfig gerritConfig;
@Mock CachesWithoutChronicleMapConfigMetric cachesWithoutConfigMetricMock;
@Before
public void setUp() throws Exception {
sitePaths = new SitePaths(temporaryFolder.newFolder().toPath());
Files.createDirectories(sitePaths.etc_dir);
gerritConfig =
new FileBasedConfig(
sitePaths.resolve("etc").resolve("gerrit.config").toFile(), FS.DETECTED);
gerritConfig.load();
gerritConfig.setString("cache", null, "directory", cacheDirectory);
gerritConfig.save();
}
@Test
public void shouldProvideCacheFile() throws Exception {
assertThat(
configUnderTest(gerritConfig)
.getCacheFile()
.toPath()
.getParent()
.toRealPath()
.toString())
.isEqualTo(sitePaths.resolve(cacheDirectory).toRealPath().toString());
}
@Test
public void shouldProvideIndexFileThatIsRelatedToCacheFile() {
ChronicleMapCacheConfig config = configUnderTest(gerritConfig);
File cacheFile = config.getCacheFile();
File indexFile = config.getIndexFile();
assertThat(indexFile.getParentFile()).isEqualTo(cacheFile.getParentFile());
String cacheFileName = cacheFile.getName();
assertThat(indexFile.getName())
.isEqualTo(
String.format("%s.index", cacheFileName.substring(0, cacheFileName.indexOf(".dat"))));
}
@Test
public void shouldProvideConfiguredMaxEntriesWhenDefined() throws Exception {
long maxEntries = 10;
gerritConfig.setLong("cache", cacheKey, "maxEntries", maxEntries);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getMaxEntries()).isEqualTo(maxEntries);
}
@Test
public void shouldProvideDefaultMaxEntriesWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getMaxEntries()).isEqualTo(DEFAULT_MAX_ENTRIES);
}
@Test
public void shouldProvideAverageKeySizeWhenConfigured() throws Exception {
long averageKeySize = 5;
gerritConfig.setLong("cache", cacheKey, "avgKeySize", averageKeySize);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getAverageKeySize()).isEqualTo(averageKeySize);
}
@Test
public void shouldProvideDefaultAverageKeySizeWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getAverageKeySize()).isEqualTo(DEFAULT_AVG_KEY_SIZE);
}
@Test
public void shouldProvideAverageValueSizeWhenConfigured() throws Exception {
long averageValueSize = 6;
gerritConfig.setLong("cache", cacheKey, "avgValueSize", averageValueSize);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getAverageValueSize()).isEqualTo(averageValueSize);
}
@Test
public void shouldProvideDefaultAverageValueSizeWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getAverageValueSize())
.isEqualTo(DEFAULT_AVG_VALUE_SIZE);
}
@Test
public void shouldProvideMaxDefaultBloatFactorWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getMaxBloatFactor())
.isEqualTo(DEFAULT_MAX_BLOAT_FACTOR);
}
@Test
public void shouldProvideMaxBloatFactorWhenConfigured() throws Exception {
int bloatFactor = 3;
gerritConfig.setInt("cache", cacheKey, "maxBloatFactor", bloatFactor);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getMaxBloatFactor()).isEqualTo(bloatFactor);
}
@Test
public void shouldProvideExpireAfterWriteWhenMaxAgeIsConfgured() throws Exception {
String maxAge = "3 minutes";
gerritConfig.setString("cache", cacheKey, "maxAge", maxAge);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getExpireAfterWrite())
.isEqualTo(Duration.ofSeconds(180));
}
@Test
public void shouldProvideDefinitionExpireAfterWriteWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getExpireAfterWrite()).isEqualTo(expireAfterWrite);
}
@Test
public void shouldProvideRefreshAfterWriteWhenConfigured() throws Exception {
String refreshAfterWrite = "6 minutes";
gerritConfig.setString("cache", cacheKey, "refreshAfterWrite", refreshAfterWrite);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getRefreshAfterWrite())
.isEqualTo(Duration.ofSeconds(360));
}
@Test
public void shouldProvideDefinitionRefreshAfterWriteWhenNotConfigured() throws Exception {
assertThat(configUnderTest(gerritConfig).getRefreshAfterWrite()).isEqualTo(refreshAfterWrite);
}
@Test
public void shouldProvidePercentageFreeSpaceEvictionThresholdWhenConfigured() throws Exception {
int percentageFreeThreshold = 70;
gerritConfig.setInt(
"cache", cacheKey, "percentageFreeSpaceEvictionThreshold", percentageFreeThreshold);
gerritConfig.save();
assertThat(configUnderTest(gerritConfig).getPercentageFreeSpaceEvictionThreshold())
.isEqualTo(percentageFreeThreshold);
}
@Test
public void shouldProvidePercentageFreeSpaceEvictionThresholdDefault() throws Exception {
assertThat(configUnderTest(gerritConfig).getPercentageFreeSpaceEvictionThreshold())
.isEqualTo(DEFAULT_PERCENTAGE_FREE_SPACE_EVICTION_THRESHOLD);
}
@Test
public void shouldProvideDefaultIndexPersistEveryValuesWhenNotConfigured() {
ChronicleMapCacheConfig configUnderTest = configUnderTest(gerritConfig);
assertThat(configUnderTest.getPersistIndexEvery()).isEqualTo(DEFAULT_PERSIST_INDEX_EVERY);
assertThat(configUnderTest.getPersistIndexEveryNthPrune()).isEqualTo(30L);
}
@Test
public void shouldPersistIndexEveryBePruneDelayWhenPersistIndexEveryIsLowerThanPruneDelay() {
gerritConfig.setString(
"cache", null, "persistIndexEvery", String.format("%ds", PRUNE_DELAY - 1L));
ChronicleMapCacheConfig configUnderTest = configUnderTest(gerritConfig);
assertThat(configUnderTest.getPersistIndexEvery()).isEqualTo(Duration.ofSeconds(PRUNE_DELAY));
assertThat(configUnderTest.getPersistIndexEveryNthPrune()).isEqualTo(1L);
}
@Test
public void shouldPersistIndexEveryBeRoundedDownToAMultiplyOfPruneDelay() {
gerritConfig.setString(
"cache", null, "persistIndexEvery", String.format("%ds", 2L * PRUNE_DELAY + 1L));
ChronicleMapCacheConfig configUnderTest = configUnderTest(gerritConfig);
assertThat(configUnderTest.getPersistIndexEvery())
.isEqualTo(Duration.ofSeconds(2L * PRUNE_DELAY));
assertThat(configUnderTest.getPersistIndexEveryNthPrune()).isEqualTo(2L);
}
@Test
public void shouldIncrementCacheMetricWhenCacheHasNoDedicatedConfiguration() {
configUnderTest(gerritConfig);
verify(cachesWithoutConfigMetricMock, atLeastOnce()).incrementForCache(cacheKey);
}
@Test
public void shouldNotIncrementCacheMetricWhenCacheHasAtLeastSingleParameterConfigured() {
gerritConfig.setLong("cache", cacheKey, "maxEntries", 1L);
configUnderTest(gerritConfig);
verify(cachesWithoutConfigMetricMock, never()).incrementForCache(cacheName);
}
private ChronicleMapCacheConfig configUnderTest(StoredConfig gerritConfig) {
File cacheFile =
ChronicleMapCacheFactory.fileName(
sitePaths.site_path.resolve(cacheDirectory), cacheName, version);
sitePaths
.resolve(cacheDirectory)
.resolve(String.format("%s_%s.dat", cacheName, version))
.toFile();
return new ChronicleMapCacheConfig(
gerritConfig,
cachesWithoutConfigMetricMock,
cacheKey,
cacheFile,
expireAfterWrite,
refreshAfterWrite);
}
}