blob: 5f2c2e4f1fc26a9586cea85c36f4ffc88670fe86 [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.plugins.cachedrefdb;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.registration.DynamicItem;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.Callable;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class CachedRefRepositoryIT {
TestRepository<Repository> tr;
CachedRefRepository objectUnderTest;
TestRefByNameCacheImpl cache;
@Before
public void setUp() throws IOException {
Repository repo = new InMemoryRepository(new DfsRepositoryDescription("repo"));
objectUnderTest = createCachedRepository(repo);
tr = new TestRepository<>(repo);
}
@After
public void tearDown() {
// both CachedRefRepository and TestRepository call close on the underlying repo hence single
// close is sufficient
objectUnderTest.close();
}
@Test
public void shouldResolveFullRefsFromCache() throws Exception {
String master = RefNames.fullName("master");
RevCommit first = tr.update(master, tr.commit().add("first", "foo").create());
String tag = "test_tag";
String fullTag = RefNames.REFS_TAGS + tag;
tr.update(fullTag, tr.tag(tag, first));
tr.update(master, tr.commit().parent(first).add("second", "foo").create());
assertThat(cache.cacheCalled).isEqualTo(0);
assertThat(objectUnderTest.resolve(master)).isEqualTo(repo().resolve(master));
assertThat(objectUnderTest.resolve(fullTag)).isEqualTo(repo().resolve(fullTag));
assertThat(cache.cacheCalled).isEqualTo(2);
}
@Test
public void shouldNotResolveRefsFromCache() throws Exception {
String master = RefNames.fullName("master");
RevCommit first = tr.update(master, tr.commit().add("first", "foo").create());
String tag = "test_tag";
String fullTag = RefNames.REFS_TAGS + tag;
tr.update(fullTag, tr.tag(tag, first));
tr.update(master, tr.commit().parent(first).add("second", "foo").create());
assertThat(objectUnderTest.resolve("master")).isEqualTo(repo().resolve("master"));
assertThat(objectUnderTest.resolve(RefNames.HEAD)).isEqualTo(repo().resolve(RefNames.HEAD));
assertThat(objectUnderTest.resolve(tag)).isEqualTo(repo().resolve(tag));
String mastersParent = master + "^";
ObjectId resolved = objectUnderTest.resolve(mastersParent);
assertThat(resolved).isEqualTo(first);
assertThat(resolved).isEqualTo(repo().resolve(mastersParent));
String mastersParentByTilde = master + "~";
ObjectId resolvedByTilde = objectUnderTest.resolve(mastersParentByTilde);
assertThat(resolvedByTilde).isEqualTo(first);
assertThat(resolvedByTilde).isEqualTo(repo().resolve(mastersParent));
assertThat(cache.cacheCalled).isEqualTo(0);
}
@Test
public void shouldNotResolveSha1sFromCache() throws Exception {
String master = RefNames.fullName("master");
RevCommit first = tr.update(master, tr.commit().add("first", "foo").create());
String tag = "test_tag";
String fullTag = RefNames.REFS_TAGS + tag;
tr.update(fullTag, tr.tag(tag, first));
RevCommit second = tr.update(master, tr.commit().parent(first).add("second", "foo").create());
String secondAbbreviatedName = second.getName().substring(0, 6);
assertThat(objectUnderTest.resolve(second.name())).isEqualTo(repo().resolve(second.name()));
assertThat(objectUnderTest.resolve(secondAbbreviatedName))
.isEqualTo(repo().resolve(secondAbbreviatedName));
String parentRevString = second.name() + "^";
String resolvedName = objectUnderTest.resolve(parentRevString).getName();
assertThat(resolvedName).isEqualTo(first.getName());
assertThat(resolvedName).isEqualTo(repo().resolve(parentRevString).getName());
String ensureIdIsCommit = secondAbbreviatedName + "(commit)";
assertThat(objectUnderTest.resolve(ensureIdIsCommit))
.isEqualTo(repo().resolve(ensureIdIsCommit));
assertThat(cache.cacheCalled).isEqualTo(0);
}
@Test
public void shouldNotResolveTagAndSha1FromCache() throws Exception {
String master = RefNames.fullName("master");
RevCommit first = tr.update(master, tr.commit().add("first", "foo").create());
String tag = "test_tag";
tr.update(RefNames.REFS_TAGS + tag, tr.tag(tag, first));
RevCommit second = tr.update(master, tr.commit().parent(first).add("second", "foo").create());
String tagAndSha = tag + "-1-g" + second.getName().substring(0, 6);
assertThat(objectUnderTest.resolve(tagAndSha)).isEqualTo(repo().resolve(tagAndSha));
assertThat(cache.cacheCalled).isEqualTo(0);
}
private Repository repo() {
return tr.getRepository();
}
private CachedRefRepository createCachedRepository(Repository repo) {
cache = new TestRefByNameCacheImpl(CacheBuilder.newBuilder().build());
RefByNameCacheWrapper wrapper =
new RefByNameCacheWrapper(DynamicItem.itemOf(RefByNameCache.class, cache));
CachedRefDatabase.Factory refDbFactory =
new CachedRefDatabase.Factory() {
@Override
public CachedRefDatabase create(CachedRefRepository repo, RefDatabase delegate) {
return new CachedRefDatabase(wrapper, null, null, null, repo, delegate);
}
};
return new CachedRefRepository(refDbFactory, null, null, "repo", repo);
}
private static class TestRefByNameCacheImpl extends RefByNameCacheImpl {
private int cacheCalled;
private TestRefByNameCacheImpl(Cache<String, Optional<Ref>> refByName) {
super(refByName);
cacheCalled = 0;
}
@Override
public Ref computeIfAbsent(
String identifier, String ref, Callable<? extends Optional<Ref>> loader) {
cacheCalled++;
return super.computeIfAbsent(identifier, ref, loader);
}
}
}