GitRepositoryManager should be responsible to enable/disable the GC

According to 8df3d44ee129437ac32825cc645172578e9e3e15 JGit library can
perform garbage collection only on FileRepository. Currently Gerrit has
ability to swap the GitRepositoryManager implementation. This means that
we can have more than just LocalDiskRepositoryManager backed by
FileRepository.

Allowing GitRepositoryManager to decide if garbage collection can be
performed fixes the issue with 'Run GC' button hidden when multi-site
plugin installed.

Bug: Issue 14097
Change-Id: I2384a93836c65d90fd7921ed2b63bc45406f74b7
diff --git a/java/com/google/gerrit/server/git/GitRepositoryManager.java b/java/com/google/gerrit/server/git/GitRepositoryManager.java
index f8d8a49..01bbe89 100644
--- a/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -57,4 +57,13 @@
 
   /** @return set of all known projects, sorted by natural NameKey order. */
   SortedSet<Project.NameKey> list();
+
+  /**
+   * Check if garbage collection can be performed by the repository manager.
+   *
+   * @return true if repository can perform garbage collection.
+   */
+  default Boolean canPerformGC() {
+    return false;
+  }
 }
diff --git a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index 85822a8..1fdf194 100644
--- a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -199,6 +199,11 @@
     }
   }
 
+  @Override
+  public Boolean canPerformGC() {
+    return true;
+  }
+
   private boolean isUnreasonableName(Project.NameKey nameKey) {
     final String name = nameKey.get();
 
diff --git a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
index 23115de..800e75e 100644
--- a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
+++ b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
@@ -29,7 +29,6 @@
 import com.google.gerrit.server.config.UrlFormatter;
 import com.google.gerrit.server.git.GarbageCollection;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.ioutil.HexFormat;
 import com.google.gerrit.server.project.ProjectResource;
@@ -66,7 +65,7 @@
       DynamicItem<UrlFormatter> urlFormatter) {
     this.workQueue = workQueue;
     this.urlFormatter = urlFormatter;
-    this.canGC = repoManager instanceof LocalDiskRepositoryManager;
+    this.canGC = repoManager.canPerformGC();
     this.garbageCollectionFactory = garbageCollectionFactory;
   }
 
diff --git a/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
new file mode 100644
index 0000000..ea4a199
--- /dev/null
+++ b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 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.google.gerrit.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gerrit.testing.GerritBaseTests;
+import java.io.IOException;
+import java.util.SortedSet;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitRepositoryManagerTest extends GerritBaseTests {
+
+  private GitRepositoryManager objectUnderTest;
+
+  @Before
+  public void setUp() throws Exception {
+    objectUnderTest = new TestGitRepositoryManager();
+  }
+
+  @Test
+  public void shouldReturnFalseWhenDefaultCanPerformGC() {
+    assertThat(objectUnderTest.canPerformGC()).isFalse();
+  }
+
+  private static class TestGitRepositoryManager implements GitRepositoryManager {
+    @Override
+    public Repository openRepository(NameKey name) throws RepositoryNotFoundException, IOException {
+      throw new UnsupportedOperationException("Not implemented");
+    }
+
+    @Override
+    public Repository createRepository(NameKey name)
+        throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException {
+      throw new UnsupportedOperationException("Not implemented");
+    }
+
+    @Override
+    public SortedSet<NameKey> list() {
+      throw new UnsupportedOperationException("Not implemented");
+    }
+  }
+}
diff --git a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index 4e0cb0c..0b86c22 100644
--- a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -212,6 +212,11 @@
     newRepoManager.createRepository(new Project.NameKey("A"));
   }
 
+  @Test
+  public void testRepositoryCanPerformGC() throws Exception {
+    assertThat(repoManager.canPerformGC()).isTrue();
+  }
+
   private void createSymLink(Project.NameKey project, String link) throws IOException {
     Path base = repoManager.getBasePath(project);
     Path projectDir = base.resolve(project.get() + ".git");