blob: c8a8b66375cba026fd365342cec34bbea601625e [file] [log] [blame]
// Copyright (C) 2022 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.CacheKeysIndex.tempIndexFile;
import static java.util.stream.Collectors.toList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.server.cache.serialize.StringCacheSerializer;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class CacheKeysIndexTest {
private static final String CACHE_NAME = "test-cache";
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
private CacheKeysIndex<String> index;
private File indexFile;
@Before
public void setup() throws IOException {
CacheSerializers.registerCacheKeySerializer(CACHE_NAME, StringCacheSerializer.INSTANCE);
indexFile = temporaryFolder.newFolder().toPath().resolve("cache.index").toFile();
index = new CacheKeysIndex<>(new DisabledMetricMaker(), CACHE_NAME, indexFile, false);
}
@Test
public void add_shouldUpdateElementPositionWhenAlreadyInSet() {
index.add("foo", 2L);
index.add("bar", 1L);
assertThat(keys(index)).containsExactly("foo", "bar");
index.add("foo", 1L);
assertThat(keys(index)).containsExactly("bar", "foo");
}
@Test
public void add_shouldUpdateElementInsertionTimeWhenNewerGetsAdded() {
index.add("foo", 1L);
index.add("foo", 2L);
CacheKeysIndex<String>.TimedKey key = index.keys().iterator().next();
assertThat(key.getKey()).isEqualTo("foo");
assertThat(key.getCreated()).isEqualTo(2L);
}
@Test
public void refresh_shouldRefreshInsertionTimeOnRefresh() {
index.add("foo", 1L);
index.refresh("foo");
CacheKeysIndex<String>.TimedKey key = index.keys().iterator().next();
assertThat(key.getKey()).isEqualTo("foo");
assertThat(key.getCreated()).isGreaterThan(1L);
}
@Test
@SuppressWarnings("unchecked")
public void remove_shouldRemoveAndConsumeKeysOlderThan() {
long than = 5l;
index.add("newerThan", 10L);
index.add("olderThan", 2L);
Consumer<String> consumer = mock(Consumer.class);
index.removeAndConsumeKeysOlderThan(than, consumer);
verify(consumer).accept("olderThan");
assertThat(keys(index)).containsExactly("newerThan");
}
@Test
@SuppressWarnings("unchecked")
public void remove_shouldReturnFalseIfThereIsNoLruToRemove() {
Consumer<String> consumer = mock(Consumer.class);
boolean actual = index.removeAndConsumeLruKey(consumer);
assertThat(actual).isEqualTo(false);
verifyNoInteractions(consumer);
}
@Test
@SuppressWarnings("unchecked")
public void remove_shouldRemoveAndConsumeLruKey() {
index.add("older", 1L);
index.add("newer", 1L);
Consumer<String> consumer = mock(Consumer.class);
boolean actual = index.removeAndConsumeLruKey(consumer);
assertThat(actual).isEqualTo(true);
verify(consumer).accept("older");
assertThat(keys(index)).containsExactly("newer");
}
@Test
public void persist_shouldPersistAndRestoreKeys() {
index.add("older", 1L);
index.add("newer", 1L);
assertThat(indexFile.exists()).isFalse();
index.persist();
assertThat(indexFile.isFile()).isTrue();
assertThat(indexFile.canRead()).isTrue();
index.clear();
assertThat(keys(index)).isEmpty();
index.restore(true);
assertThat(keys(index)).containsExactly("newer", "older");
}
@Test
public void restore_shouldDeleteExistingTemporaryIndexStorageFileDuringRestore()
throws IOException {
File indexTempFile = tempIndexFile(indexFile);
indexTempFile.createNewFile();
assertThat(indexTempFile.isFile()).isTrue();
index.restore(true);
assertThat(indexTempFile.exists()).isFalse();
}
private static List<String> keys(CacheKeysIndex<String> index) {
return index.keys().stream().map(CacheKeysIndex.TimedKey::getKey).collect(toList());
}
}