Dynamically load metrics collectors

Allows dynamic loading of metrics collectors.
This groundwork will allow to easily add new metrics collectors
to gather more metrics and informations about the
git repositories.

Added MetricsCollector interface to define collectors API.

Bug: Issue 16208
Change-Id: Iabd18153b5faf43cb91044a9a02fcc7b7efda23f
diff --git a/BUILD b/BUILD
index 1052170..8d79e0c 100644
--- a/BUILD
+++ b/BUILD
@@ -24,15 +24,31 @@
     )
 )
 
+java_library(
+    name = "git-repo-metrics_tests_lib",
+    testonly = True,
+    srcs = glob(
+        ["src/test/java/**/*.java"],
+        exclude = ["src/test/java/**/*Test.java"],
+    ),
+    tags = [
+        "git-repo-metrics",
+    ],
+    deps = [
+        "git-repo-metrics__plugin_test_deps",
+    ],
+)
+
 junit_tests(
     name = "git-repo-metrics_tests",
-    srcs = glob(["src/test/java/**/*.java"]),
+    srcs = glob(["src/test/java/**/*Test.java"]),
     resources = glob(["src/test/resources/**/*"]),
     tags = [
         "git-repo-metrics",
     ],
     deps = [
         ":git-repo-metrics__plugin_test_deps",
+        ":git-repo-metrics_tests_lib",
     ],
 )
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
index 3371786..a08f845 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
@@ -14,18 +14,22 @@
 
 package com.googlesource.gerrit.plugins.gitrepometrics;
 
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
+
 import com.codahale.metrics.MetricRegistry;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitRepoMetric;
-import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
 import java.time.Clock;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -38,19 +42,27 @@
   private final List<String> projects;
   private Map<String, Long> collectedAt;
   private final long gracePeriodMs;
-  private List<GitRepoMetric> metricsNames;
+  private ImmutableList<GitRepoMetric> metricsNames;
+  private DynamicSet<MetricsCollector> collectors;
 
   private final Clock clock;
 
   @VisibleForTesting
   GitRepoMetricsCache(
+      DynamicSet<MetricsCollector> collectors,
       MetricMaker metricMaker,
       MetricRegistry metricRegistry,
       GitRepoMetricsConfig config,
       Clock clock) {
+    this.collectors = collectors;
     this.metricMaker = metricMaker;
     this.metricRegistry = metricRegistry;
-    this.metricsNames = new ArrayList<>(GitStats.availableMetrics());
+
+    this.metricsNames =
+        collectors.stream()
+            .flatMap(c -> c.availableMetrics().stream())
+            .collect(collectingAndThen(toList(), ImmutableList::copyOf));
+
     this.projects = config.getRepositoryNames();
     this.metrics = Maps.newHashMap();
     this.collectedAt = Maps.newHashMap();
@@ -60,8 +72,11 @@
 
   @Inject
   GitRepoMetricsCache(
-      MetricMaker metricMaker, MetricRegistry metricRegistry, GitRepoMetricsConfig config) {
-    this(metricMaker, metricRegistry, config, Clock.systemDefaultZone());
+      DynamicSet<MetricsCollector> collectors,
+      MetricMaker metricMaker,
+      MetricRegistry metricRegistry,
+      GitRepoMetricsConfig config) {
+    this(collectors, metricMaker, metricRegistry, config, Clock.systemDefaultZone());
   }
 
   public Map<String, Long> getMetrics() {
@@ -77,6 +92,10 @@
     return metricsNames;
   }
 
+  public DynamicSet<MetricsCollector> getCollectors() {
+    return collectors;
+  }
+
   @VisibleForTesting
   public Map<String, Long> getCollectedAt() {
     return collectedAt;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
index f743ccb..1ffb65c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
@@ -18,6 +18,8 @@
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.inject.Scopes;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStatsMetricsCollector;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
 import java.util.concurrent.ExecutorService;
 
 public class Module extends LifecycleModule {
@@ -30,6 +32,8 @@
         .toProvider(UpdateGitMetricsExecutorProvider.class);
     bind(GitRepoUpdateListener.class);
     DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(GitRepoUpdateListener.class);
+    DynamicSet.setOf(binder(), MetricsCollector.class);
+    DynamicSet.bind(binder(), MetricsCollector.class).to(GitStatsMetricsCollector.class);
     listener().to(PluginStartup.class);
     install(new UpdateGitMetricsTaskModule());
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
index 7dc726d..a1acb24 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
@@ -20,10 +20,12 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
-import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.lib.Repository;
@@ -56,18 +58,29 @@
       logger.atInfo().log(
           "Running task to collect stats: repo %s, project %s",
           repository.getIdentifier(), projectName);
-      // TODO Loop through all the collectors
-      Project project = Project.builder(projectNameKey).build();
 
       Repository unwrappedRepo =
           repository instanceof DelegateRepository
               ? ((DelegateRepository) repository).delegate()
               : repository;
 
-      GitStats gitStats = new GitStats((FileRepository) unwrappedRepo, project);
-      Map<String, Long> newMetrics = gitStats.get();
+      Iterable<MetricsCollector> iterable = () -> gitRepoMetricsCache.getCollectors().iterator();
+      HashMap<String, Long> newMetrics =
+          StreamSupport.stream(iterable.spliterator(), false)
+              .map(
+                  metricsCollector ->
+                      metricsCollector.collect((FileRepository) unwrappedRepo, projectName))
+              .reduce(
+                  new HashMap<>(),
+                  (accumulator, latestMetrics) -> {
+                    HashMap<String, Long> newVal = new HashMap<>();
+                    newVal.putAll(accumulator);
+                    newVal.putAll(latestMetrics);
+                    return newVal;
+                  });
+
       logger.atInfo().log(
-          "Here all the metrics for %s - %s", project.getName(), getStringFromMap(newMetrics));
+          "Here all the metrics for %s - %s", projectNameKey.get(), getStringFromMap(newMetrics));
       gitRepoMetricsCache.setMetrics(newMetrics, projectName);
     } catch (RepositoryNotFoundException e) {
       logger.atSevere().withCause(e).log("Cannot find repository for %s", projectName);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
similarity index 63%
rename from src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
rename to src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
index 2eab2f9..00182e4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
@@ -14,25 +14,17 @@
 
 package com.googlesource.gerrit.plugins.gitrepometrics.collectors;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Project;
 import com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCache;
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.HashMap;
 import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.internal.storage.file.GC;
 
-// TODO Add an interface
-// TODO implement multiple collectors
-public class GitStats {
+public class GitStatsMetricsCollector implements MetricsCollector {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
-  private final FileRepository repository;
-  private final Project p;
-
   public static String numberOfPackedObjects = "numberOfPackedObjects";
   public static String numberOfPackFiles = "numberOfPackFiles";
   public static String numberOfLooseObjects = "numberOfLooseObjects";
@@ -42,23 +34,21 @@
   public static String sizeOfPackedObjects = "sizeOfPackedObjects";
   public static String numberOfBitmaps = "numberOfBitmaps";
 
-  public GitStats(FileRepository repository, Project project) {
-    this.repository = repository;
-    this.p = project;
-  }
+  public GitStatsMetricsCollector() {}
 
-  public Map<String, Long> get() {
-    Map<String, Long> metrics = new java.util.HashMap<>(Collections.emptyMap());
+  @Override
+  public HashMap<String, Long> collect(FileRepository repository, String projectName) {
+    HashMap<String, Long> metrics = new HashMap<>(availableMetrics().size());
     try {
       GC.RepoStatistics statistics = new GC(repository).getStatistics();
-      putMetric(metrics, numberOfPackedObjects, statistics.numberOfPackedObjects);
-      putMetric(metrics, numberOfPackFiles, statistics.numberOfPackFiles);
-      putMetric(metrics, numberOfLooseObjects, statistics.numberOfLooseObjects);
-      putMetric(metrics, numberOfLooseRefs, statistics.numberOfLooseRefs);
-      putMetric(metrics, numberOfPackedRefs, statistics.numberOfPackedRefs);
-      putMetric(metrics, sizeOfLooseObjects, statistics.sizeOfLooseObjects);
-      putMetric(metrics, sizeOfPackedObjects, statistics.sizeOfPackedObjects);
-      putMetric(metrics, numberOfBitmaps, statistics.numberOfBitmaps);
+      putMetric(projectName, metrics, numberOfPackedObjects, statistics.numberOfPackedObjects);
+      putMetric(projectName, metrics, numberOfPackFiles, statistics.numberOfPackFiles);
+      putMetric(projectName, metrics, numberOfLooseObjects, statistics.numberOfLooseObjects);
+      putMetric(projectName, metrics, numberOfLooseRefs, statistics.numberOfLooseRefs);
+      putMetric(projectName, metrics, numberOfPackedRefs, statistics.numberOfPackedRefs);
+      putMetric(projectName, metrics, sizeOfLooseObjects, statistics.sizeOfLooseObjects);
+      putMetric(projectName, metrics, sizeOfPackedObjects, statistics.sizeOfPackedObjects);
+      putMetric(projectName, metrics, numberOfBitmaps, statistics.numberOfBitmaps);
       logger.atInfo().log("New Git Statistics metrics collected: %s", statistics.toString());
     } catch (IOException e) {
       logger.atSevere().log("Something went wrong: %s", e.getMessage());
@@ -66,8 +56,9 @@
     return metrics;
   }
 
-  public static List<GitRepoMetric> availableMetrics() {
-    return Arrays.asList(
+  @Override
+  public ImmutableList<GitRepoMetric> availableMetrics() {
+    return ImmutableList.of(
         new GitRepoMetric(numberOfPackedObjects, "Number of packed objects", "Count"),
         new GitRepoMetric(numberOfPackFiles, "Number of pack files", "Count"),
         new GitRepoMetric(numberOfLooseObjects, "Number of loose objects", "Count"),
@@ -78,11 +69,13 @@
         new GitRepoMetric(numberOfBitmaps, "Number of bitmaps", "Count"));
   }
 
-  private void putMetric(Map<String, Long> metrics, String metricName, long value) {
-    metrics.put(GitRepoMetricsCache.getMetricName(metricName, p.getName()), value);
+  private void putMetric(
+      String projectName, HashMap<String, Long> metrics, String metricName, long value) {
+    metrics.put(GitRepoMetricsCache.getMetricName(metricName, projectName), value);
   }
 
-  public String getStatName() {
+  @Override
+  public String getMetricsCollectorName() {
     return "git-statistics";
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java
new file mode 100644
index 0000000..311a707
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java
@@ -0,0 +1,48 @@
+// 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.gitrepometrics.collectors;
+
+import com.google.common.collect.ImmutableList;
+import java.util.HashMap;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+
+/** This interface is meant to be implemented by Git repository metrics collectors. * */
+public interface MetricsCollector {
+
+  /**
+   * Collect metrics from a {@link FileRepository}.
+   *
+   * @param projectName to collect metrics for
+   * @param repository {@link FileRepository} to collect metrics from
+   * @return {@code HashMap<String, Long>} where the key is the metric name and the value is the
+   *     corresponding metric value collected.
+   */
+  HashMap<String, Long> collect(FileRepository repository, String projectName);
+
+  /**
+   * Returns the name of the metric collector.
+   *
+   * @return {@code String} with the metric collector name
+   */
+  String getMetricsCollectorName();
+
+  /**
+   * Returns the list of available metrics provided by the collector.
+   *
+   * @return {@code ImmutableList<GitRepoMetric>} with the {@link GitRepoMetric} provided by the
+   *     metric collector implementation.
+   */
+  ImmutableList<GitRepoMetric> availableMetrics();
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/FakeMetricsCollector.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/FakeMetricsCollector.java
new file mode 100644
index 0000000..c0148c6
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/FakeMetricsCollector.java
@@ -0,0 +1,42 @@
+// 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.gitrepometrics;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitRepoMetric;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
+import java.util.HashMap;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+
+class FakeMetricsCollector implements MetricsCollector {
+  @Override
+  public HashMap<String, Long> collect(FileRepository repository, String projectName) {
+    return Maps.newHashMap(ImmutableMap.of("fake-metrics-1", 1L, "fake-metrics-2", 2L));
+  }
+
+  @Override
+  public String getMetricsCollectorName() {
+    return "fake-metrics-collector";
+  }
+
+  @Override
+  public ImmutableList<GitRepoMetric> availableMetrics() {
+    return ImmutableList.of(
+        new GitRepoMetric("fake-metric-1", "Fake metric 1", "Count"),
+        new GitRepoMetric("fake-metric-2", "Fake metric 2", "Count"));
+  }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
index e98a25f..e379813 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
@@ -19,10 +19,11 @@
 import com.codahale.metrics.Metric;
 import com.codahale.metrics.MetricRegistry;
 import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.metrics.CallbackMetric0;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.DisabledMetricMaker;
-import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
 import java.io.IOException;
 import java.time.Clock;
 import java.time.Instant;
@@ -38,31 +39,40 @@
   private ConfigSetupUtils configSetupUtils;
   private final String enabledRepo = "enabledRepo";
 
+  private FakeMetricsCollector fakeStatsCollector;
+  private DynamicSet<MetricsCollector> ds;
+
   @Before
   public void setupRepo() throws IOException {
     configSetupUtils = new ConfigSetupUtils(Collections.singletonList(enabledRepo));
+
+    fakeStatsCollector = new FakeMetricsCollector();
+    ds = new DynamicSet<>();
+    ds.add("git-repo-metrics", fakeStatsCollector);
   }
 
   @Test
-  public void shouldRegisterMetrics() throws IOException {
+  public void shouldRegisterMetrics() {
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     fakeMetricMaker = new FakeMetricMaker();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(fakeMetricMaker, new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(ds, fakeMetricMaker, new MetricRegistry(), gitRepoMetricsConfig);
     gitRepoMetricsCache.initCache();
-    assertThat(fakeMetricMaker.callsCounter).isEqualTo(GitStats.availableMetrics().size());
+    assertThat(fakeMetricMaker.callsCounter)
+        .isEqualTo(fakeStatsCollector.availableMetrics().size());
   }
 
   @Test
-  public void shouldRegisterMetricsOnlyOnce() throws IOException {
+  public void shouldRegisterMetricsOnlyOnce() {
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     MetricRegistry metricRegistry = new MetricRegistry();
     fakeMetricMaker = new FakeMetricMaker();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(fakeMetricMaker, metricRegistry, gitRepoMetricsConfig);
+        new GitRepoMetricsCache(ds, fakeMetricMaker, metricRegistry, gitRepoMetricsConfig);
 
     gitRepoMetricsCache.initCache();
-    assertThat(fakeMetricMaker.callsCounter).isEqualTo(GitStats.availableMetrics().size());
+    assertThat(fakeMetricMaker.callsCounter)
+        .isEqualTo(fakeStatsCollector.availableMetrics().size());
 
     gitRepoMetricsCache
         .getMetricsNames()
@@ -74,24 +84,27 @@
                     new FakeMetric()));
 
     gitRepoMetricsCache.initCache();
-    assertThat(fakeMetricMaker.callsCounter).isEqualTo(GitStats.availableMetrics().size());
+    assertThat(fakeMetricMaker.callsCounter)
+        .isEqualTo(fakeStatsCollector.availableMetrics().size());
   }
 
   @Test
-  public void shouldCollectStatsForEnabledRepo() throws IOException {
+  public void shouldCollectStatsForEnabledRepo() {
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(
+            ds, new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
 
     assertThat(gitRepoMetricsCache.shouldCollectStats(enabledRepo)).isTrue();
   }
 
   @Test
-  public void shouldNotCollectStatsForDisabledRepo() throws IOException {
+  public void shouldNotCollectStatsForDisabledRepo() {
     String disabledRepo = "disabledRepo";
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(
+            ds, new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
 
     assertThat(gitRepoMetricsCache.shouldCollectStats(disabledRepo)).isFalse();
   }
@@ -102,7 +115,8 @@
         new ConfigSetupUtils(Collections.singletonList(enabledRepo));
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(
+            ds, new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
 
     gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
 
@@ -115,7 +129,8 @@
         new ConfigSetupUtils(Collections.singletonList(enabledRepo), "5 m");
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(
+            ds, new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
 
     gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
 
@@ -129,6 +144,7 @@
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
         new GitRepoMetricsCache(
+            ds,
             new FakeMetricMaker(),
             new MetricRegistry(),
             gitRepoMetricsConfig,
@@ -146,7 +162,8 @@
         new ConfigSetupUtils(Collections.singletonList(enabledRepo));
     gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
     gitRepoMetricsCache =
-        new GitRepoMetricsCache(new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
+        new GitRepoMetricsCache(
+            ds, new FakeMetricMaker(), new MetricRegistry(), gitRepoMetricsConfig);
 
     long currentTimeStamp = System.currentTimeMillis();
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
index f6cdb11..a97adc2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.extensions.api.changes.NotifyHandling;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.metrics.DisabledMetricMaker;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.testing.InMemoryModule;
@@ -65,6 +66,7 @@
         new ConfigSetupUtils(Collections.singletonList(testProject));
     gitRepoMetricsCache =
         new GitRepoMetricsCache(
+            new DynamicSet<>(),
             new DisabledMetricMaker(),
             new MetricRegistry(),
             configSetupUtils.getGitRepoMetricsConfig());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
index 45fb988..fcb0e05 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
@@ -19,6 +19,7 @@
 
 import com.codahale.metrics.MetricRegistry;
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.metrics.DisabledMetricMaker;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePath;
@@ -27,6 +28,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Provides;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
 import java.io.File;
 import java.nio.file.Path;
 import java.util.Collections;
@@ -42,14 +44,22 @@
   private Repository testRepository;
   private Project testProject;
   private GitRepoMetricsCache gitRepoMetricsCache;
+  private FakeMetricsCollector fakeStatsCollector;
+  private DynamicSet<MetricsCollector> ds;
 
   @Inject private UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory;
 
   @Before
   public void setupRepository() throws Exception {
     ConfigSetupUtils configSetupUtils = new ConfigSetupUtils(Collections.singletonList("repo1"));
+
+    fakeStatsCollector = new FakeMetricsCollector();
+    ds = new DynamicSet<>();
+    ds.add("git-repo-metrics", fakeStatsCollector);
+
     gitRepoMetricsCache =
         new GitRepoMetricsCache(
+            ds,
             new DisabledMetricMaker(),
             new MetricRegistry(),
             configSetupUtils.getGitRepoMetricsConfig());